diff options
Diffstat (limited to 'indra')
82 files changed, 31216 insertions, 23374 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 279d577a27..7fccf3327f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -42,7 +42,6 @@ set(cmake_SOURCE_FILES LLAudio.cmake LLCharacter.cmake LLCommon.cmake - LLConvexDecomposition.cmake LLCrashLogger.cmake LLDatabase.cmake LLImage.cmake @@ -53,6 +52,7 @@ set(cmake_SOURCE_FILES LLMessage.cmake LLPlugin.cmake LLPrimitive.cmake + LLPhysicsExtensions.cmake LLRender.cmake LLScene.cmake LLTestCommand.cmake diff --git a/indra/cmake/LLConvexDecomposition.cmake b/indra/cmake/LLConvexDecomposition.cmake deleted file mode 100644 index 8e44504782..0000000000 --- a/indra/cmake/LLConvexDecomposition.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -set(LLCONVEXDECOMP_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) - -if (INSTALL_PROPRIETARY AND NOT STANDALONE) - use_prebuilt_binary(llconvexdecomposition) - set(LLCONVEXDECOMP_LIBRARY llconvexdecomposition) -else (INSTALL_PROPRIETARY AND NOT STANDALONE) - use_prebuilt_binary(llconvexdecompositionstub) - set(LLCONVEXDECOMP_LIBRARY llconvexdecompositionstub) -endif (INSTALL_PROPRIETARY AND NOT STANDALONE) diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake new file mode 100644 index 0000000000..73d5dd59cf --- /dev/null +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -0,0 +1,29 @@ +# -*- cmake -*- +include(Prebuilt) + +if (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensions) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensions) +else (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensionsstub) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensionsstub) +endif (INSTALL_PROPRIETARY AND NOT STANDALONE) + +set(LLPHYSICS_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/lib/include) + +set(LLPHYSICS_DEBUG_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug) +set(LLPHYSICS_RELEASE_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release) + +find_library(LL_PHYSICS_DEBUG_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_DEBUG_LIBRARY_PATH}) +find_library(LL_PHYSICS_RELEASE_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_RELEASE_LIBRARY_PATH}) + +set(LLPHYSICS_LIBRARIES + + debug ${LL_PHYSICS_DEBUG_LIB} + optimized ${LL_PHYSICS_RELEASE_LIB} +) + +if (LINUX) + list(INSERT LLPHYSICS_LIBRARIES 0 -Wl,--start-group) + list(APPEND LLPHYSICS_LIBRARIES -Wl,--end-group) +endif (LINUX) diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index affa040602..88c09c8dca 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -140,6 +140,10 @@ public: } protected: +#ifdef LL_LIBRARY_INCLUDE + void ref(); + void unref(); +#else void ref() { if (mPointer) @@ -162,7 +166,7 @@ protected: } } } - +#endif protected: Type* mPointer; }; diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index b419101b7e..bc66832ad0 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1,2170 +1,2249 @@ -/** - * @file llsdserialize.cpp - * @author Phoenix - * @date 2006-03-05 - * @brief Implementation of LLSD parsers and formatters - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#include "linden_common.h" -#include "llsdserialize.h" -#include "llpointer.h" -#include "llstreamtools.h" // for fullread - -#include <iostream> -#include "apr_base64.h" - -#ifdef LL_STANDALONE -# include <zlib.h> -#else -# include "zlib/zlib.h" // for davep's dirty little zip functions -#endif - -#if !LL_WINDOWS -#include <netinet/in.h> // htonl & ntohl -#endif - -#include "lldate.h" -#include "llsd.h" -#include "llstring.h" -#include "lluri.h" - -// File constants -static const int MAX_HDR_LEN = 20; -static const char LEGACY_NON_HEADER[] = "<llsd>"; -const std::string LLSD_BINARY_HEADER("LLSD/Binary"); -const std::string LLSD_XML_HEADER("LLSD/XML"); - -/** - * LLSDSerialize - */ - -// static -void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options) -{ - LLPointer<LLSDFormatter> f = NULL; - - switch (type) - { - case LLSD_BINARY: - str << "<? " << LLSD_BINARY_HEADER << " ?>\n"; - f = new LLSDBinaryFormatter; - break; - - case LLSD_XML: - str << "<? " << LLSD_XML_HEADER << " ?>\n"; - f = new LLSDXMLFormatter; - break; - - default: - llwarns << "serialize request for unknown ELLSD_Serialize" << llendl; - } - - if (f.notNull()) - { - f->format(sd, str, options); - } -} - -// static -bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) -{ - LLPointer<LLSDParser> p = NULL; - char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ - int i; - int inbuf = 0; - bool legacy_no_header = false; - bool fail_if_not_legacy = false; - std::string header; - - /* - * Get the first line before anything. - */ - str.get(hdr_buf, MAX_HDR_LEN, '\n'); - if (str.fail()) - { - str.clear(); - fail_if_not_legacy = true; - } - - if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ - { - legacy_no_header = true; - inbuf = (int)str.gcount(); - } - else - { - if (fail_if_not_legacy) - goto fail; - /* - * Remove the newline chars - */ - for (i = 0; i < MAX_HDR_LEN; i++) - { - if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' || - hdr_buf[i] == '\n') - { - hdr_buf[i] = 0; - break; - } - } - header = hdr_buf; - - std::string::size_type start = std::string::npos; - std::string::size_type end = std::string::npos; - start = header.find_first_not_of("<? "); - if (start != std::string::npos) - { - end = header.find_first_of(" ?", start); - } - if ((start == std::string::npos) || (end == std::string::npos)) - goto fail; - - header = header.substr(start, end - start); - ws(str); - } - /* - * Create the parser as appropriate - */ - if (legacy_no_header) - { // Create a LLSD XML parser, and parse the first chunk read above - LLSDXMLParser* x = new LLSDXMLParser(); - x->parsePart(hdr_buf, inbuf); // Parse the first part that was already read - x->parseLines(str, sd); // Parse the rest of it - delete x; - return true; - } - - if (header == LLSD_BINARY_HEADER) - { - p = new LLSDBinaryParser; - } - else if (header == LLSD_XML_HEADER) - { - p = new LLSDXMLParser; - } - else - { - llwarns << "deserialize request for unknown ELLSD_Serialize" << llendl; - } - - if (p.notNull()) - { - p->parse(str, sd, max_bytes); - return true; - } - -fail: - llwarns << "deserialize LLSD parse failure" << llendl; - return false; -} - -/** - * Endian handlers - */ -#if LL_BIG_ENDIAN -U64 ll_htonll(U64 hostlonglong) { return hostlonglong; } -U64 ll_ntohll(U64 netlonglong) { return netlonglong; } -F64 ll_htond(F64 hostlonglong) { return hostlonglong; } -F64 ll_ntohd(F64 netlonglong) { return netlonglong; } -#else -// I read some comments one a indicating that doing an integer add -// here would be faster than a bitwise or. For now, the or has -// programmer clarity, since the intended outcome matches the -// operation. -U64 ll_htonll(U64 hostlonglong) -{ - return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); -} -U64 ll_ntohll(U64 netlonglong) -{ - return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); -} -union LLEndianSwapper -{ - F64 d; - U64 i; -}; -F64 ll_htond(F64 hostdouble) -{ - LLEndianSwapper tmp; - tmp.d = hostdouble; - tmp.i = ll_htonll(tmp.i); - return tmp.d; -} -F64 ll_ntohd(F64 netdouble) -{ - LLEndianSwapper tmp; - tmp.d = netdouble; - tmp.i = ll_ntohll(tmp.i); - return tmp.d; -} -#endif - -/** - * Local functions. - */ -/** - * @brief Figure out what kind of string it is (raw or delimited) and handoff. - * - * @param istr The stream to read from. - * @param value [out] The string which was found. - * @param max_bytes The maximum possible length of the string. Passing in - * a negative value will skip this check. - * @return Returns number of bytes read off of the stream. Returns - * PARSE_FAILURE (-1) on failure. - */ -int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes); - -/** - * @brief Parse a delimited string. - * - * @param istr The stream to read from, with the delimiter already popped. - * @param value [out] The string which was found. - * @param d The delimiter to use. - * @return Returns number of bytes read off of the stream. Returns - * PARSE_FAILURE (-1) on failure. - */ -int deserialize_string_delim(std::istream& istr, std::string& value, char d); - -/** - * @brief Read a raw string off the stream. - * - * @param istr The stream to read from, with the (len) parameter - * leading the stream. - * @param value [out] The string which was found. - * @param d The delimiter to use. - * @param max_bytes The maximum possible length of the string. Passing in - * a negative value will skip this check. - * @return Returns number of bytes read off of the stream. Returns - * PARSE_FAILURE (-1) on failure. - */ -int deserialize_string_raw( - std::istream& istr, - std::string& value, - S32 max_bytes); - -/** - * @brief helper method for dealing with the different notation boolean format. - * - * @param istr The stream to read from with the leading character stripped. - * @param data [out] the result of the parse. - * @param compare The string to compare the boolean against - * @param vale The value to assign to data if the parse succeeds. - * @return Returns number of bytes read off of the stream. Returns - * PARSE_FAILURE (-1) on failure. - */ -int deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value); - -/** - * @brief Do notation escaping of a string to an ostream. - * - * @param value The string to escape and serialize - * @param str The stream to serialize to. - */ -void serialize_string(const std::string& value, std::ostream& str); - - -/** - * Local constants. - */ -static const std::string NOTATION_TRUE_SERIAL("true"); -static const std::string NOTATION_FALSE_SERIAL("false"); - -static const char BINARY_TRUE_SERIAL = '1'; -static const char BINARY_FALSE_SERIAL = '0'; - - -/** - * LLSDParser - */ -LLSDParser::LLSDParser() - : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false) -{ -} - -// virtual -LLSDParser::~LLSDParser() -{ } - -S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes) -{ - mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; - mMaxBytesLeft = max_bytes; - return doParse(istr, data); -} - - -// Parse using routine to get() lines, faster than parse() -S32 LLSDParser::parseLines(std::istream& istr, LLSD& data) -{ - mCheckLimits = false; - mParseLines = true; - return doParse(istr, data); -} - - -int LLSDParser::get(std::istream& istr) const -{ - if(mCheckLimits) --mMaxBytesLeft; - return istr.get(); -} - -std::istream& LLSDParser::get( - std::istream& istr, - char* s, - std::streamsize n, - char delim) const -{ - istr.get(s, n, delim); - if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount(); - return istr; -} - -std::istream& LLSDParser::get( - std::istream& istr, - std::streambuf& sb, - char delim) const -{ - istr.get(sb, delim); - if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount(); - return istr; -} - -std::istream& LLSDParser::ignore(std::istream& istr) const -{ - istr.ignore(); - if(mCheckLimits) --mMaxBytesLeft; - return istr; -} - -std::istream& LLSDParser::putback(std::istream& istr, char c) const -{ - istr.putback(c); - if(mCheckLimits) ++mMaxBytesLeft; - return istr; -} - -std::istream& LLSDParser::read( - std::istream& istr, - char* s, - std::streamsize n) const -{ - istr.read(s, n); - if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount(); - return istr; -} - -void LLSDParser::account(S32 bytes) const -{ - if(mCheckLimits) mMaxBytesLeft -= bytes; -} - - -/** - * LLSDNotationParser - */ -LLSDNotationParser::LLSDNotationParser() -{ -} - -// virtual -LLSDNotationParser::~LLSDNotationParser() -{ } - -// virtual -S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const -{ - // map: { string:object, string:object } - // array: [ object, object, object ] - // undef: ! - // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE - // integer: i#### - // real: r#### - // uuid: u#### - // string: "g'day" | 'have a "nice" day' | s(size)"raw data" - // uri: l"escaped" - // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" - // binary: b##"ff3120ab1" | b(size)"raw data" - char c; - c = istr.peek(); - while(isspace(c)) - { - // pop the whitespace. - c = get(istr); - c = istr.peek(); - continue; - } - if(!istr.good()) - { - return 0; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading map." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading array." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - c = get(istr); - data.clear(); - break; - - case '0': - c = get(istr); - data = false; - break; - - case 'F': - case 'f': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - int cnt = deserialize_boolean( - istr, - data, - NOTATION_FALSE_SERIAL, - false); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = false; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading boolean." << llendl; - parse_count = PARSE_FAILURE; - } - break; - - case '1': - c = get(istr); - data = true; - break; - - case 'T': - case 't': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = true; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading boolean." << llendl; - parse_count = PARSE_FAILURE; - } - break; - - case 'i': - { - c = get(istr); - S32 integer = 0; - istr >> integer; - data = integer; - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading integer." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'r': - { - c = get(istr); - F64 real = 0.0; - istr >> real; - data = real; - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading real." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'u': - { - c = get(istr); - LLUUID id; - istr >> id; - data = id; - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading uuid." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case '\"': - case '\'': - case 's': - if(!parseString(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading string." << llendl; - parse_count = PARSE_FAILURE; - } - break; - - case 'l': - { - c = get(istr); // pop the 'l' - c = get(istr); // pop the delimiter - std::string str; - int cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLURI(str); - account(cnt); - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading link." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - c = get(istr); // pop the 'd' - c = get(istr); // pop the delimiter - std::string str; - int cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLDate(str); - account(cnt); - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading date." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - if(!parseBinary(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading data." << llendl; - parse_count = PARSE_FAILURE; - } - break; - - default: - parse_count = PARSE_FAILURE; - llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; -} - -S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const -{ - // map: { string:object, string:object } - map = LLSD::emptyMap(); - S32 parse_count = 0; - char c = get(istr); - if(c == '{') - { - // eat commas, white - bool found_name = false; - std::string name; - c = get(istr); - while(c != '}' && istr.good()) - { - if(!found_name) - { - if((c == '\"') || (c == '\'') || (c == 's')) - { - putback(istr, c); - found_name = true; - int count = deserialize_string(istr, name, mMaxBytesLeft); - if(PARSE_FAILURE == count) return PARSE_FAILURE; - account(count); - } - c = get(istr); - } - else - { - if(isspace(c) || (c == ':')) - { - c = get(istr); - continue; - } - putback(istr, c); - LLSD child; - S32 count = doParse(istr, child); - if(count > 0) - { - // There must be a value for every key, thus - // child_count must be greater than 0. - parse_count += count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - found_name = false; - c = get(istr); - } - } - if(c != '}') - { - map.clear(); - return PARSE_FAILURE; - } - } - return parse_count; -} - -S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const -{ - // array: [ object, object, object ] - array = LLSD::emptyArray(); - S32 parse_count = 0; - char c = get(istr); - if(c == '[') - { - // eat commas, white - c = get(istr); - while((c != ']') && istr.good()) - { - LLSD child; - if(isspace(c) || (c == ',')) - { - c = get(istr); - continue; - } - putback(istr, c); - S32 count = doParse(istr, child); - if(PARSE_FAILURE == count) - { - return PARSE_FAILURE; - } - else - { - parse_count += count; - array.append(child); - } - c = get(istr); - } - if(c != ']') - { - return PARSE_FAILURE; - } - } - return parse_count; -} - -bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const -{ - std::string value; - int count = deserialize_string(istr, value, mMaxBytesLeft); - if(PARSE_FAILURE == count) return false; - account(count); - data = value; - return true; -} - -bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const -{ - // binary: b##"ff3120ab1" - // or: b(len)"..." - - // I want to manually control those values here to make sure the - // parser doesn't break when someone changes a constant somewhere - // else. - const U32 BINARY_BUFFER_SIZE = 256; - const U32 STREAM_GET_COUNT = 255; - - // need to read the base out. - char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ - get(istr, buf, STREAM_GET_COUNT, '"'); - char c = get(istr); - if(c != '"') return false; - if(0 == strncmp("b(", buf, 2)) - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - S32 len = strtol(buf + 2, NULL, 0); - if(mCheckLimits && (len > mMaxBytesLeft)) return false; - std::vector<U8> value; - if(len) - { - value.resize(len); - account((int)fullread(istr, (char *)&value[0], len)); - } - c = get(istr); // strip off the trailing double-quote - data = value; - } - else if(0 == strncmp("b64", buf, 3)) - { - // *FIX: A bit inefficient, but works for now. To make the - // format better, I would need to add a hint into the - // serialization format that indicated how long it was. - std::stringstream coded_stream; - get(istr, *(coded_stream.rdbuf()), '\"'); - c = get(istr); - std::string encoded(coded_stream.str()); - S32 len = apr_base64_decode_len(encoded.c_str()); - std::vector<U8> value; - if(len) - { - value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); - value.resize(len); - } - data = value; - } - else if(0 == strncmp("b16", buf, 3)) - { - // yay, base 16. We pop the next character which is either a - // double quote or base 16 data. If it's a double quote, we're - // done parsing. If it's not, put the data back, and read the - // stream until the next double quote. - char* read; /*Flawfinder: ignore*/ - U8 byte; - U8 byte_buffer[BINARY_BUFFER_SIZE]; - U8* write; - std::vector<U8> value; - c = get(istr); - while(c != '"') - { - putback(istr, c); - read = buf; - write = byte_buffer; - get(istr, buf, STREAM_GET_COUNT, '"'); - c = get(istr); - while(*read != '\0') /*Flawfinder: ignore*/ - { - byte = hex_as_nybble(*read++); - byte = byte << 4; - byte |= hex_as_nybble(*read++); - *write++ = byte; - } - // copy the data out of the byte buffer - value.insert(value.end(), byte_buffer, write); - } - data = value; - } - else - { - return false; - } - return true; -} - - -/** - * LLSDBinaryParser - */ -LLSDBinaryParser::LLSDBinaryParser() -{ -} - -// virtual -LLSDBinaryParser::~LLSDBinaryParser() -{ -} - -// virtual -S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const -{ -/** - * Undefined: '!'<br> - * Boolean: 't' for true 'f' for false<br> - * Integer: 'i' + 4 bytes network byte order<br> - * Real: 'r' + 8 bytes IEEE double<br> - * UUID: 'u' + 16 byte unsigned integer<br> - * String: 's' + 4 byte integer size + string<br> - * strings also secretly support the notation format - * Date: 'd' + 8 byte IEEE double for seconds since epoch<br> - * URI: 'l' + 4 byte integer size + string uri<br> - * Binary: 'b' + 4 byte integer size + binary data<br> - * Array: '[' + 4 byte integer size + all values + ']'<br> - * Map: '{' + 4 byte integer size every(key + value) + '}'<br> - * map keys are serialized as s + 4 byte integer size + string or in the - * notation format. - */ - char c; - c = get(istr); - if(!istr.good()) - { - return 0; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary map." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary array." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - data.clear(); - break; - - case '0': - data = false; - break; - - case '1': - data = true; - break; - - case 'i': - { - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - data = (S32)ntohl(value_nbo); - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary integer." << llendl; - } - break; - } - - case 'r': - { - F64 real_nbo = 0.0; - read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ - data = ll_ntohd(real_nbo); - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary real." << llendl; - } - break; - } - - case 'u': - { - LLUUID id; - read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ - data = id; - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary uuid." << llendl; - } - break; - } - - case '\'': - case '"': - { - std::string value; - int cnt = deserialize_string_delim(istr, value, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = value; - account(cnt); - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary (notation-style) string." - << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 's': - { - std::string value; - if(parseString(istr, value)) - { - data = value; - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary string." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'l': - { - std::string value; - if(parseString(istr, value)) - { - data = LLURI(value); - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary link." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - F64 real = 0.0; - read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ - data = LLDate(real); - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary date." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - U32 size_nbo = 0; - read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(size_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) - { - parse_count = PARSE_FAILURE; - } - else - { - std::vector<U8> value; - if(size > 0) - { - value.resize(size); - account((int)fullread(istr, (char*)&value[0], size)); - } - data = value; - } - if(istr.fail()) - { - llinfos << "STREAM FAILURE reading binary." << llendl; - parse_count = PARSE_FAILURE; - } - break; - } - - default: - parse_count = PARSE_FAILURE; - llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; -} - -S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const -{ - map = LLSD::emptyMap(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - S32 parse_count = 0; - S32 count = 0; - char c = get(istr); - while(c != '}' && (count < size) && istr.good()) - { - std::string name; - switch(c) - { - case 'k': - if(!parseString(istr, name)) - { - return PARSE_FAILURE; - } - break; - case '\'': - case '"': - { - int cnt = deserialize_string_delim(istr, name, c); - if(PARSE_FAILURE == cnt) return PARSE_FAILURE; - account(cnt); - break; - } - } - LLSD child; - S32 child_count = doParse(istr, child); - if(child_count > 0) - { - // There must be a value for every key, thus child_count - // must be greater than 0. - parse_count += child_count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - ++count; - c = get(istr); - } - if((c != '}') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; -} - -S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const -{ - array = LLSD::emptyArray(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - - // *FIX: This would be a good place to reserve some space in the - // array... - - S32 parse_count = 0; - S32 count = 0; - char c = istr.peek(); - while((c != ']') && (count < size) && istr.good()) - { - LLSD child; - S32 child_count = doParse(istr, child); - if(PARSE_FAILURE == child_count) - { - return PARSE_FAILURE; - } - if(child_count) - { - parse_count += child_count; - array.append(child); - } - ++count; - c = istr.peek(); - } - c = get(istr); - if((c != ']') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; -} - -bool LLSDBinaryParser::parseString( - std::istream& istr, - std::string& value) const -{ - // *FIX: This is memory inefficient. - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) return false; - std::vector<char> buf; - if(size) - { - buf.resize(size); - account((int)fullread(istr, &buf[0], size)); - value.assign(buf.begin(), buf.end()); - } - return true; -} - - -/** - * LLSDFormatter - */ -LLSDFormatter::LLSDFormatter() : - mBoolAlpha(false) -{ -} - -// virtual -LLSDFormatter::~LLSDFormatter() -{ } - -void LLSDFormatter::boolalpha(bool alpha) -{ - mBoolAlpha = alpha; -} - -void LLSDFormatter::realFormat(const std::string& format) -{ - mRealFormat = format; -} - -void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const -{ - std::string buffer = llformat(mRealFormat.c_str(), real); - ostr << buffer; -} - -/** - * LLSDNotationFormatter - */ -LLSDNotationFormatter::LLSDNotationFormatter() -{ -} - -// virtual -LLSDNotationFormatter::~LLSDNotationFormatter() -{ } - -// static -std::string LLSDNotationFormatter::escapeString(const std::string& in) -{ - std::ostringstream ostr; - serialize_string(in, ostr); - return ostr.str(); -} - -// virtual -S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const -{ - S32 format_count = 1; - switch(data.type()) - { - case LLSD::TypeMap: - { - ostr << "{"; - bool need_comma = false; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - ostr << '\''; - serialize_string((*iter).first, ostr); - ostr << "':"; - format_count += format((*iter).second, ostr); - } - ostr << "}"; - break; - } - - case LLSD::TypeArray: - { - ostr << "["; - bool need_comma = false; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - format_count += format(*iter, ostr); - } - ostr << "]"; - break; - } - - case LLSD::TypeUndefined: - ostr << "!"; - break; - - case LLSD::TypeBoolean: - if(mBoolAlpha || -#if( LL_WINDOWS || __GNUC__ > 2) - (ostr.flags() & std::ios::boolalpha) -#else - (ostr.flags() & 0x0100) -#endif - ) - { - ostr << (data.asBoolean() - ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); - } - else - { - ostr << (data.asBoolean() ? 1 : 0); - } - break; - - case LLSD::TypeInteger: - ostr << "i" << data.asInteger(); - break; - - case LLSD::TypeReal: - ostr << "r"; - if(mRealFormat.empty()) - { - ostr << data.asReal(); - } - else - { - formatReal(data.asReal(), ostr); - } - break; - - case LLSD::TypeUUID: - ostr << "u" << data.asUUID(); - break; - - case LLSD::TypeString: - ostr << '\''; - serialize_string(data.asString(), ostr); - ostr << '\''; - break; - - case LLSD::TypeDate: - ostr << "d\"" << data.asDate() << "\""; - break; - - case LLSD::TypeURI: - ostr << "l\""; - serialize_string(data.asString(), ostr); - ostr << "\""; - break; - - case LLSD::TypeBinary: - { - // *FIX: memory inefficient. - std::vector<U8> buffer = data.asBinary(); - ostr << "b(" << buffer.size() << ")\""; - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); - ostr << "\""; - break; - } - - default: - // *NOTE: This should never happen. - ostr << "!"; - break; - } - return format_count; -} - - -/** - * LLSDBinaryFormatter - */ -LLSDBinaryFormatter::LLSDBinaryFormatter() -{ -} - -// virtual -LLSDBinaryFormatter::~LLSDBinaryFormatter() -{ } - -// virtual -S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const -{ - S32 format_count = 1; - switch(data.type()) - { - case LLSD::TypeMap: - { - ostr.put('{'); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - ostr.put('k'); - formatString((*iter).first, ostr); - format_count += format((*iter).second, ostr); - } - ostr.put('}'); - break; - } - - case LLSD::TypeArray: - { - ostr.put('['); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - format_count += format(*iter, ostr); - } - ostr.put(']'); - break; - } - - case LLSD::TypeUndefined: - ostr.put('!'); - break; - - case LLSD::TypeBoolean: - if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); - else ostr.put(BINARY_FALSE_SERIAL); - break; - - case LLSD::TypeInteger: - { - ostr.put('i'); - U32 value_nbo = htonl(data.asInteger()); - ostr.write((const char*)(&value_nbo), sizeof(U32)); - break; - } - - case LLSD::TypeReal: - { - ostr.put('r'); - F64 value_nbo = ll_htond(data.asReal()); - ostr.write((const char*)(&value_nbo), sizeof(F64)); - break; - } - - case LLSD::TypeUUID: - ostr.put('u'); - ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES); - break; - - case LLSD::TypeString: - ostr.put('s'); - formatString(data.asString(), ostr); - break; - - case LLSD::TypeDate: - { - ostr.put('d'); - F64 value = data.asReal(); - ostr.write((const char*)(&value), sizeof(F64)); - break; - } - - case LLSD::TypeURI: - ostr.put('l'); - formatString(data.asString(), ostr); - break; - - case LLSD::TypeBinary: - { - // *FIX: memory inefficient. - ostr.put('b'); - std::vector<U8> buffer = data.asBinary(); - U32 size_nbo = htonl(buffer.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); - break; - } - - default: - // *NOTE: This should never happen. - ostr.put('!'); - break; - } - return format_count; -} - -void LLSDBinaryFormatter::formatString( - const std::string& string, - std::ostream& ostr) const -{ - U32 size_nbo = htonl(string.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - ostr.write(string.c_str(), string.size()); -} - -/** - * local functions - */ -int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes) -{ - int c = istr.get(); - if(istr.fail()) - { - // No data in stream, bail out but mention the character we - // grabbed. - return LLSDParser::PARSE_FAILURE; - } - - int rv = LLSDParser::PARSE_FAILURE; - switch(c) - { - case '\'': - case '"': - rv = deserialize_string_delim(istr, value, c); - break; - case 's': - // technically, less than max_bytes, but this is just meant to - // catch egregious protocol errors. parse errors will be - // caught in the case of incorrect counts. - rv = deserialize_string_raw(istr, value, max_bytes); - break; - default: - break; - } - if(LLSDParser::PARSE_FAILURE == rv) return rv; - return rv + 1; // account for the character grabbed at the top. -} - -int deserialize_string_delim( - std::istream& istr, - std::string& value, - char delim) -{ - std::ostringstream write_buffer; - bool found_escape = false; - bool found_hex = false; - bool found_digit = false; - U8 byte = 0; - int count = 0; - - while (true) - { - int next_byte = istr.get(); - ++count; - - if(istr.fail()) - { - // If our stream is empty, break out - value = write_buffer.str(); - return LLSDParser::PARSE_FAILURE; - } - - char next_char = (char)next_byte; // Now that we know it's not EOF - - if(found_escape) - { - // next character(s) is a special sequence. - if(found_hex) - { - if(found_digit) - { - found_digit = false; - found_hex = false; - found_escape = false; - byte = byte << 4; - byte |= hex_as_nybble(next_char); - write_buffer << byte; - byte = 0; - } - else - { - // next character is the first nybble of - // - found_digit = true; - byte = hex_as_nybble(next_char); - } - } - else if(next_char == 'x') - { - found_hex = true; - } - else - { - switch(next_char) - { - case 'a': - write_buffer << '\a'; - break; - case 'b': - write_buffer << '\b'; - break; - case 'f': - write_buffer << '\f'; - break; - case 'n': - write_buffer << '\n'; - break; - case 'r': - write_buffer << '\r'; - break; - case 't': - write_buffer << '\t'; - break; - case 'v': - write_buffer << '\v'; - break; - default: - write_buffer << next_char; - break; - } - found_escape = false; - } - } - else if(next_char == '\\') - { - found_escape = true; - } - else if(next_char == delim) - { - break; - } - else - { - write_buffer << next_char; - } - } - - value = write_buffer.str(); - return count; -} - -int deserialize_string_raw( - std::istream& istr, - std::string& value, - S32 max_bytes) -{ - int count = 0; - const S32 BUF_LEN = 20; - char buf[BUF_LEN]; /* Flawfinder: ignore */ - istr.get(buf, BUF_LEN - 1, ')'); - count += (int)istr.gcount(); - int c = istr.get(); - c = istr.get(); - count += 2; - if(((c == '"') || (c == '\'')) && (buf[0] == '(')) - { - // We probably have a valid raw string. determine - // the size, and read it. - // *FIX: This is memory inefficient. - S32 len = strtol(buf + 1, NULL, 0); - if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector<char> buf; - if(len) - { - buf.resize(len); - count += (int)fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); - } - c = istr.get(); - ++count; - if(!((c == '"') || (c == '\''))) - { - return LLSDParser::PARSE_FAILURE; - } - } - else - { - return LLSDParser::PARSE_FAILURE; - } - return count; -} - -static const char* NOTATION_STRING_CHARACTERS[256] = -{ - "\\x00", // 0 - "\\x01", // 1 - "\\x02", // 2 - "\\x03", // 3 - "\\x04", // 4 - "\\x05", // 5 - "\\x06", // 6 - "\\a", // 7 - "\\b", // 8 - "\\t", // 9 - "\\n", // 10 - "\\v", // 11 - "\\f", // 12 - "\\r", // 13 - "\\x0e", // 14 - "\\x0f", // 15 - "\\x10", // 16 - "\\x11", // 17 - "\\x12", // 18 - "\\x13", // 19 - "\\x14", // 20 - "\\x15", // 21 - "\\x16", // 22 - "\\x17", // 23 - "\\x18", // 24 - "\\x19", // 25 - "\\x1a", // 26 - "\\x1b", // 27 - "\\x1c", // 28 - "\\x1d", // 29 - "\\x1e", // 30 - "\\x1f", // 31 - " ", // 32 - "!", // 33 - "\"", // 34 - "#", // 35 - "$", // 36 - "%", // 37 - "&", // 38 - "\\'", // 39 - "(", // 40 - ")", // 41 - "*", // 42 - "+", // 43 - ",", // 44 - "-", // 45 - ".", // 46 - "/", // 47 - "0", // 48 - "1", // 49 - "2", // 50 - "3", // 51 - "4", // 52 - "5", // 53 - "6", // 54 - "7", // 55 - "8", // 56 - "9", // 57 - ":", // 58 - ";", // 59 - "<", // 60 - "=", // 61 - ">", // 62 - "?", // 63 - "@", // 64 - "A", // 65 - "B", // 66 - "C", // 67 - "D", // 68 - "E", // 69 - "F", // 70 - "G", // 71 - "H", // 72 - "I", // 73 - "J", // 74 - "K", // 75 - "L", // 76 - "M", // 77 - "N", // 78 - "O", // 79 - "P", // 80 - "Q", // 81 - "R", // 82 - "S", // 83 - "T", // 84 - "U", // 85 - "V", // 86 - "W", // 87 - "X", // 88 - "Y", // 89 - "Z", // 90 - "[", // 91 - "\\\\", // 92 - "]", // 93 - "^", // 94 - "_", // 95 - "`", // 96 - "a", // 97 - "b", // 98 - "c", // 99 - "d", // 100 - "e", // 101 - "f", // 102 - "g", // 103 - "h", // 104 - "i", // 105 - "j", // 106 - "k", // 107 - "l", // 108 - "m", // 109 - "n", // 110 - "o", // 111 - "p", // 112 - "q", // 113 - "r", // 114 - "s", // 115 - "t", // 116 - "u", // 117 - "v", // 118 - "w", // 119 - "x", // 120 - "y", // 121 - "z", // 122 - "{", // 123 - "|", // 124 - "}", // 125 - "~", // 126 - "\\x7f", // 127 - "\\x80", // 128 - "\\x81", // 129 - "\\x82", // 130 - "\\x83", // 131 - "\\x84", // 132 - "\\x85", // 133 - "\\x86", // 134 - "\\x87", // 135 - "\\x88", // 136 - "\\x89", // 137 - "\\x8a", // 138 - "\\x8b", // 139 - "\\x8c", // 140 - "\\x8d", // 141 - "\\x8e", // 142 - "\\x8f", // 143 - "\\x90", // 144 - "\\x91", // 145 - "\\x92", // 146 - "\\x93", // 147 - "\\x94", // 148 - "\\x95", // 149 - "\\x96", // 150 - "\\x97", // 151 - "\\x98", // 152 - "\\x99", // 153 - "\\x9a", // 154 - "\\x9b", // 155 - "\\x9c", // 156 - "\\x9d", // 157 - "\\x9e", // 158 - "\\x9f", // 159 - "\\xa0", // 160 - "\\xa1", // 161 - "\\xa2", // 162 - "\\xa3", // 163 - "\\xa4", // 164 - "\\xa5", // 165 - "\\xa6", // 166 - "\\xa7", // 167 - "\\xa8", // 168 - "\\xa9", // 169 - "\\xaa", // 170 - "\\xab", // 171 - "\\xac", // 172 - "\\xad", // 173 - "\\xae", // 174 - "\\xaf", // 175 - "\\xb0", // 176 - "\\xb1", // 177 - "\\xb2", // 178 - "\\xb3", // 179 - "\\xb4", // 180 - "\\xb5", // 181 - "\\xb6", // 182 - "\\xb7", // 183 - "\\xb8", // 184 - "\\xb9", // 185 - "\\xba", // 186 - "\\xbb", // 187 - "\\xbc", // 188 - "\\xbd", // 189 - "\\xbe", // 190 - "\\xbf", // 191 - "\\xc0", // 192 - "\\xc1", // 193 - "\\xc2", // 194 - "\\xc3", // 195 - "\\xc4", // 196 - "\\xc5", // 197 - "\\xc6", // 198 - "\\xc7", // 199 - "\\xc8", // 200 - "\\xc9", // 201 - "\\xca", // 202 - "\\xcb", // 203 - "\\xcc", // 204 - "\\xcd", // 205 - "\\xce", // 206 - "\\xcf", // 207 - "\\xd0", // 208 - "\\xd1", // 209 - "\\xd2", // 210 - "\\xd3", // 211 - "\\xd4", // 212 - "\\xd5", // 213 - "\\xd6", // 214 - "\\xd7", // 215 - "\\xd8", // 216 - "\\xd9", // 217 - "\\xda", // 218 - "\\xdb", // 219 - "\\xdc", // 220 - "\\xdd", // 221 - "\\xde", // 222 - "\\xdf", // 223 - "\\xe0", // 224 - "\\xe1", // 225 - "\\xe2", // 226 - "\\xe3", // 227 - "\\xe4", // 228 - "\\xe5", // 229 - "\\xe6", // 230 - "\\xe7", // 231 - "\\xe8", // 232 - "\\xe9", // 233 - "\\xea", // 234 - "\\xeb", // 235 - "\\xec", // 236 - "\\xed", // 237 - "\\xee", // 238 - "\\xef", // 239 - "\\xf0", // 240 - "\\xf1", // 241 - "\\xf2", // 242 - "\\xf3", // 243 - "\\xf4", // 244 - "\\xf5", // 245 - "\\xf6", // 246 - "\\xf7", // 247 - "\\xf8", // 248 - "\\xf9", // 249 - "\\xfa", // 250 - "\\xfb", // 251 - "\\xfc", // 252 - "\\xfd", // 253 - "\\xfe", // 254 - "\\xff" // 255 -}; - -void serialize_string(const std::string& value, std::ostream& str) -{ - std::string::const_iterator it = value.begin(); - std::string::const_iterator end = value.end(); - U8 c; - for(; it != end; ++it) - { - c = (U8)(*it); - str << NOTATION_STRING_CHARACTERS[c]; - } -} - -int deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value) -{ - // - // this method is a little goofy, because it gets the stream at - // the point where the t or f has already been - // consumed. Basically, parse for a patch to the string passed in - // starting at index 1. If it's a match: - // * assign data to value - // * return the number of bytes read - // otherwise: - // * set data to LLSD::null - // * return LLSDParser::PARSE_FAILURE (-1) - // - int bytes_read = 0; - std::string::size_type ii = 0; - char c = istr.peek(); - while((++ii < compare.size()) - && (tolower(c) == (int)compare[ii]) - && istr.good()) - { - istr.ignore(); - ++bytes_read; - c = istr.peek(); - } - if(compare.size() != ii) - { - data.clear(); - return LLSDParser::PARSE_FAILURE; - } - data = value; - return bytes_read; -} - -std::ostream& operator<<(std::ostream& s, const LLSD& llsd) -{ - s << LLSDNotationStreamer(llsd); - return s; -} - - -//dirty little zippers -- yell at davep if these are horrid - -//return a string containing gzipped bytes of binary serialized LLSD -// VERY inefficient -- creates several copies of LLSD block in memory -std::string zip_llsd(LLSD& data) -{ - std::stringstream llsd_strm; - - LLSDSerialize::toBinary(data, llsd_strm); - - const U32 CHUNK = 65536; - - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); - if (ret != Z_OK) - { - llwarns << "Failed to compress LLSD block." << llendl; - return std::string(); - } - - std::string source = llsd_strm.str(); - - U8 out[CHUNK]; - - strm.avail_in = source.size(); - strm.next_in = (U8*) source.data(); - U8* output = NULL; - - U32 cur_size = 0; - - U32 have = 0; - - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, Z_FINISH); - if (ret == Z_OK || ret == Z_STREAM_END) - { //copy result into output - if (strm.avail_out >= CHUNK) - { - free(output); - llwarns << "Failed to compress LLSD block." << llendl; - return std::string(); - } - - have = CHUNK-strm.avail_out; - output = (U8*) realloc(output, cur_size+have); - memcpy(output+cur_size, out, have); - cur_size += have; - } - else - { - free(output); - llwarns << "Failed to compress LLSD block." << llendl; - return std::string(); - } - } - while (ret == Z_OK); - - std::string::size_type size = cur_size; - - std::string result((char*) output, size); - deflateEnd(&strm); - free(output); - -#if 0 //verify results work with unzip_llsd - std::istringstream test(result); - LLSD test_sd; - if (!unzip_llsd(test_sd, test, result.size())) - { - llerrs << "Invalid compression result!" << llendl; - } -#endif - - return result; -} - -//decompress a block of LLSD from provided istream -// not very efficient -- creats a copy of decompressed LLSD block in memory -// and deserializes from that copy using LLSDSerialize -bool unzip_llsd(LLSD& data, std::istream& is, S32 size) -{ - U8* result = NULL; - U32 cur_size = 0; - z_stream strm; - - const U32 CHUNK = 65536; - - U8 *in = new U8[size]; - is.read((char*) in, size); - - U8 out[CHUNK]; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = size; - strm.next_in = in; - - S32 ret = inflateInit(&strm); - - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - ret = inflate(&strm, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) - { - inflateEnd(&strm); - free(result); - delete [] in; - return false; - } - - switch (ret) - { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&strm); - free(result); - delete [] in; - return false; - break; - } - - U32 have = CHUNK-strm.avail_out; - - result = (U8*) realloc(result, cur_size + have); - memcpy(result+cur_size, out, have); - cur_size += have; - - } while (ret == Z_OK); - - inflateEnd(&strm); - delete [] in; - - if (ret != Z_STREAM_END) - { - free(result); - return false; - } - - //result now points to the decompressed LLSD block - { - std::string res_str((char*) result, cur_size); - - std::string deprecated_header("<? LLSD/Binary ?>"); - - if (res_str.substr(0, deprecated_header.size()) == deprecated_header) - { - res_str = res_str.substr(deprecated_header.size()+1, cur_size); - } - cur_size = res_str.size(); - - std::istringstream istr(res_str); - - if (!LLSDSerialize::fromBinary(data, istr, cur_size)) - { - llwarns << "Failed to unzip LLSD block" << llendl; - free(result); - return false; - } - } - - free(result); - return true; -} - - - +/**
+ * @file llsdserialize.cpp
+ * @author Phoenix
+ * @date 2006-03-05
+ * @brief Implementation of LLSD parsers and formatters
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+#include "linden_common.h"
+#include "llsdserialize.h"
+#include "llpointer.h"
+#include "llstreamtools.h" // for fullread
+
+#include <iostream>
+#include "apr_base64.h"
+
+#ifdef LL_STANDALONE
+# include <zlib.h>
+#else
+# include "zlib/zlib.h" // for davep's dirty little zip functions
+#endif
+
+#if !LL_WINDOWS
+#include <netinet/in.h> // htonl & ntohl
+#endif
+
+#include "lldate.h"
+#include "llsd.h"
+#include "llstring.h"
+#include "lluri.h"
+
+// File constants
+static const int MAX_HDR_LEN = 20;
+static const char LEGACY_NON_HEADER[] = "<llsd>";
+const std::string LLSD_BINARY_HEADER("LLSD/Binary");
+const std::string LLSD_XML_HEADER("LLSD/XML");
+
+//used to deflate a gzipped asset (currently used for navmeshes)
+#define windowBits 15
+#define ENABLE_ZLIB_GZIP 32
+
+/**
+ * LLSDSerialize
+ */
+
+// static
+void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options)
+{
+ LLPointer<LLSDFormatter> f = NULL;
+
+ switch (type)
+ {
+ case LLSD_BINARY:
+ str << "<? " << LLSD_BINARY_HEADER << " ?>\n";
+ f = new LLSDBinaryFormatter;
+ break;
+
+ case LLSD_XML:
+ str << "<? " << LLSD_XML_HEADER << " ?>\n";
+ f = new LLSDXMLFormatter;
+ break;
+
+ default:
+ llwarns << "serialize request for unknown ELLSD_Serialize" << llendl;
+ }
+
+ if (f.notNull())
+ {
+ f->format(sd, str, options);
+ }
+}
+
+// static
+bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
+{
+ LLPointer<LLSDParser> p = NULL;
+ char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */
+ int i;
+ int inbuf = 0;
+ bool legacy_no_header = false;
+ bool fail_if_not_legacy = false;
+ std::string header;
+
+ /*
+ * Get the first line before anything.
+ */
+ str.get(hdr_buf, MAX_HDR_LEN, '\n');
+ if (str.fail())
+ {
+ str.clear();
+ fail_if_not_legacy = true;
+ }
+
+ if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */
+ {
+ legacy_no_header = true;
+ inbuf = (int)str.gcount();
+ }
+ else
+ {
+ if (fail_if_not_legacy)
+ goto fail;
+ /*
+ * Remove the newline chars
+ */
+ for (i = 0; i < MAX_HDR_LEN; i++)
+ {
+ if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' ||
+ hdr_buf[i] == '\n')
+ {
+ hdr_buf[i] = 0;
+ break;
+ }
+ }
+ header = hdr_buf;
+
+ std::string::size_type start = std::string::npos;
+ std::string::size_type end = std::string::npos;
+ start = header.find_first_not_of("<? ");
+ if (start != std::string::npos)
+ {
+ end = header.find_first_of(" ?", start);
+ }
+ if ((start == std::string::npos) || (end == std::string::npos))
+ goto fail;
+
+ header = header.substr(start, end - start);
+ ws(str);
+ }
+ /*
+ * Create the parser as appropriate
+ */
+ if (legacy_no_header)
+ { // Create a LLSD XML parser, and parse the first chunk read above
+ LLSDXMLParser* x = new LLSDXMLParser();
+ x->parsePart(hdr_buf, inbuf); // Parse the first part that was already read
+ x->parseLines(str, sd); // Parse the rest of it
+ delete x;
+ return true;
+ }
+
+ if (header == LLSD_BINARY_HEADER)
+ {
+ p = new LLSDBinaryParser;
+ }
+ else if (header == LLSD_XML_HEADER)
+ {
+ p = new LLSDXMLParser;
+ }
+ else
+ {
+ llwarns << "deserialize request for unknown ELLSD_Serialize" << llendl;
+ }
+
+ if (p.notNull())
+ {
+ p->parse(str, sd, max_bytes);
+ return true;
+ }
+
+fail:
+ llwarns << "deserialize LLSD parse failure" << llendl;
+ return false;
+}
+
+/**
+ * Endian handlers
+ */
+#if LL_BIG_ENDIAN
+U64 ll_htonll(U64 hostlonglong) { return hostlonglong; }
+U64 ll_ntohll(U64 netlonglong) { return netlonglong; }
+F64 ll_htond(F64 hostlonglong) { return hostlonglong; }
+F64 ll_ntohd(F64 netlonglong) { return netlonglong; }
+#else
+// I read some comments one a indicating that doing an integer add
+// here would be faster than a bitwise or. For now, the or has
+// programmer clarity, since the intended outcome matches the
+// operation.
+U64 ll_htonll(U64 hostlonglong)
+{
+ return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) |
+ ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32));
+}
+U64 ll_ntohll(U64 netlonglong)
+{
+ return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) |
+ ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32));
+}
+union LLEndianSwapper
+{
+ F64 d;
+ U64 i;
+};
+F64 ll_htond(F64 hostdouble)
+{
+ LLEndianSwapper tmp;
+ tmp.d = hostdouble;
+ tmp.i = ll_htonll(tmp.i);
+ return tmp.d;
+}
+F64 ll_ntohd(F64 netdouble)
+{
+ LLEndianSwapper tmp;
+ tmp.d = netdouble;
+ tmp.i = ll_ntohll(tmp.i);
+ return tmp.d;
+}
+#endif
+
+/**
+ * Local functions.
+ */
+/**
+ * @brief Figure out what kind of string it is (raw or delimited) and handoff.
+ *
+ * @param istr The stream to read from.
+ * @param value [out] The string which was found.
+ * @param max_bytes The maximum possible length of the string. Passing in
+ * a negative value will skip this check.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes);
+
+/**
+ * @brief Parse a delimited string.
+ *
+ * @param istr The stream to read from, with the delimiter already popped.
+ * @param value [out] The string which was found.
+ * @param d The delimiter to use.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string_delim(std::istream& istr, std::string& value, char d);
+
+/**
+ * @brief Read a raw string off the stream.
+ *
+ * @param istr The stream to read from, with the (len) parameter
+ * leading the stream.
+ * @param value [out] The string which was found.
+ * @param d The delimiter to use.
+ * @param max_bytes The maximum possible length of the string. Passing in
+ * a negative value will skip this check.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string_raw(
+ std::istream& istr,
+ std::string& value,
+ S32 max_bytes);
+
+/**
+ * @brief helper method for dealing with the different notation boolean format.
+ *
+ * @param istr The stream to read from with the leading character stripped.
+ * @param data [out] the result of the parse.
+ * @param compare The string to compare the boolean against
+ * @param vale The value to assign to data if the parse succeeds.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_boolean(
+ std::istream& istr,
+ LLSD& data,
+ const std::string& compare,
+ bool value);
+
+/**
+ * @brief Do notation escaping of a string to an ostream.
+ *
+ * @param value The string to escape and serialize
+ * @param str The stream to serialize to.
+ */
+void serialize_string(const std::string& value, std::ostream& str);
+
+
+/**
+ * Local constants.
+ */
+static const std::string NOTATION_TRUE_SERIAL("true");
+static const std::string NOTATION_FALSE_SERIAL("false");
+
+static const char BINARY_TRUE_SERIAL = '1';
+static const char BINARY_FALSE_SERIAL = '0';
+
+
+/**
+ * LLSDParser
+ */
+LLSDParser::LLSDParser()
+ : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false)
+{
+}
+
+// virtual
+LLSDParser::~LLSDParser()
+{ }
+
+S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes)
+{
+ mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true;
+ mMaxBytesLeft = max_bytes;
+ return doParse(istr, data);
+}
+
+
+// Parse using routine to get() lines, faster than parse()
+S32 LLSDParser::parseLines(std::istream& istr, LLSD& data)
+{
+ mCheckLimits = false;
+ mParseLines = true;
+ return doParse(istr, data);
+}
+
+
+int LLSDParser::get(std::istream& istr) const
+{
+ if(mCheckLimits) --mMaxBytesLeft;
+ return istr.get();
+}
+
+std::istream& LLSDParser::get(
+ std::istream& istr,
+ char* s,
+ std::streamsize n,
+ char delim) const
+{
+ istr.get(s, n, delim);
+ if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+ return istr;
+}
+
+std::istream& LLSDParser::get(
+ std::istream& istr,
+ std::streambuf& sb,
+ char delim) const
+{
+ istr.get(sb, delim);
+ if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+ return istr;
+}
+
+std::istream& LLSDParser::ignore(std::istream& istr) const
+{
+ istr.ignore();
+ if(mCheckLimits) --mMaxBytesLeft;
+ return istr;
+}
+
+std::istream& LLSDParser::putback(std::istream& istr, char c) const
+{
+ istr.putback(c);
+ if(mCheckLimits) ++mMaxBytesLeft;
+ return istr;
+}
+
+std::istream& LLSDParser::read(
+ std::istream& istr,
+ char* s,
+ std::streamsize n) const
+{
+ istr.read(s, n);
+ if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+ return istr;
+}
+
+void LLSDParser::account(S32 bytes) const
+{
+ if(mCheckLimits) mMaxBytesLeft -= bytes;
+}
+
+
+/**
+ * LLSDNotationParser
+ */
+LLSDNotationParser::LLSDNotationParser()
+{
+}
+
+// virtual
+LLSDNotationParser::~LLSDNotationParser()
+{ }
+
+// virtual
+S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
+{
+ // map: { string:object, string:object }
+ // array: [ object, object, object ]
+ // undef: !
+ // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE
+ // integer: i####
+ // real: r####
+ // uuid: u####
+ // string: "g'day" | 'have a "nice" day' | s(size)"raw data"
+ // uri: l"escaped"
+ // date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
+ // binary: b##"ff3120ab1" | b(size)"raw data"
+ char c;
+ c = istr.peek();
+ while(isspace(c))
+ {
+ // pop the whitespace.
+ c = get(istr);
+ c = istr.peek();
+ continue;
+ }
+ if(!istr.good())
+ {
+ return 0;
+ }
+ S32 parse_count = 1;
+ switch(c)
+ {
+ case '{':
+ {
+ S32 child_count = parseMap(istr, data);
+ if((child_count == PARSE_FAILURE) || data.isUndefined())
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ parse_count += child_count;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading map." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case '[':
+ {
+ S32 child_count = parseArray(istr, data);
+ if((child_count == PARSE_FAILURE) || data.isUndefined())
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ parse_count += child_count;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading array." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case '!':
+ c = get(istr);
+ data.clear();
+ break;
+
+ case '0':
+ c = get(istr);
+ data = false;
+ break;
+
+ case 'F':
+ case 'f':
+ ignore(istr);
+ c = istr.peek();
+ if(isalpha(c))
+ {
+ int cnt = deserialize_boolean(
+ istr,
+ data,
+ NOTATION_FALSE_SERIAL,
+ false);
+ if(PARSE_FAILURE == cnt) parse_count = cnt;
+ else account(cnt);
+ }
+ else
+ {
+ data = false;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading boolean." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+
+ case '1':
+ c = get(istr);
+ data = true;
+ break;
+
+ case 'T':
+ case 't':
+ ignore(istr);
+ c = istr.peek();
+ if(isalpha(c))
+ {
+ int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true);
+ if(PARSE_FAILURE == cnt) parse_count = cnt;
+ else account(cnt);
+ }
+ else
+ {
+ data = true;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading boolean." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+
+ case 'i':
+ {
+ c = get(istr);
+ S32 integer = 0;
+ istr >> integer;
+ data = integer;
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading integer." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'r':
+ {
+ c = get(istr);
+ F64 real = 0.0;
+ istr >> real;
+ data = real;
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading real." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'u':
+ {
+ c = get(istr);
+ LLUUID id;
+ istr >> id;
+ data = id;
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading uuid." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case '\"':
+ case '\'':
+ case 's':
+ if(!parseString(istr, data))
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading string." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+
+ case 'l':
+ {
+ c = get(istr); // pop the 'l'
+ c = get(istr); // pop the delimiter
+ std::string str;
+ int cnt = deserialize_string_delim(istr, str, c);
+ if(PARSE_FAILURE == cnt)
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ data = LLURI(str);
+ account(cnt);
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading link." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'd':
+ {
+ c = get(istr); // pop the 'd'
+ c = get(istr); // pop the delimiter
+ std::string str;
+ int cnt = deserialize_string_delim(istr, str, c);
+ if(PARSE_FAILURE == cnt)
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ data = LLDate(str);
+ account(cnt);
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading date." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'b':
+ if(!parseBinary(istr, data))
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading data." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+
+ default:
+ parse_count = PARSE_FAILURE;
+ llinfos << "Unrecognized character while parsing: int(" << (int)c
+ << ")" << llendl;
+ break;
+ }
+ if(PARSE_FAILURE == parse_count)
+ {
+ data.clear();
+ }
+ return parse_count;
+}
+
+S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
+{
+ // map: { string:object, string:object }
+ map = LLSD::emptyMap();
+ S32 parse_count = 0;
+ char c = get(istr);
+ if(c == '{')
+ {
+ // eat commas, white
+ bool found_name = false;
+ std::string name;
+ c = get(istr);
+ while(c != '}' && istr.good())
+ {
+ if(!found_name)
+ {
+ if((c == '\"') || (c == '\'') || (c == 's'))
+ {
+ putback(istr, c);
+ found_name = true;
+ int count = deserialize_string(istr, name, mMaxBytesLeft);
+ if(PARSE_FAILURE == count) return PARSE_FAILURE;
+ account(count);
+ }
+ c = get(istr);
+ }
+ else
+ {
+ if(isspace(c) || (c == ':'))
+ {
+ c = get(istr);
+ continue;
+ }
+ putback(istr, c);
+ LLSD child;
+ S32 count = doParse(istr, child);
+ if(count > 0)
+ {
+ // There must be a value for every key, thus
+ // child_count must be greater than 0.
+ parse_count += count;
+ map.insert(name, child);
+ }
+ else
+ {
+ return PARSE_FAILURE;
+ }
+ found_name = false;
+ c = get(istr);
+ }
+ }
+ if(c != '}')
+ {
+ map.clear();
+ return PARSE_FAILURE;
+ }
+ }
+ return parse_count;
+}
+
+S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const
+{
+ // array: [ object, object, object ]
+ array = LLSD::emptyArray();
+ S32 parse_count = 0;
+ char c = get(istr);
+ if(c == '[')
+ {
+ // eat commas, white
+ c = get(istr);
+ while((c != ']') && istr.good())
+ {
+ LLSD child;
+ if(isspace(c) || (c == ','))
+ {
+ c = get(istr);
+ continue;
+ }
+ putback(istr, c);
+ S32 count = doParse(istr, child);
+ if(PARSE_FAILURE == count)
+ {
+ return PARSE_FAILURE;
+ }
+ else
+ {
+ parse_count += count;
+ array.append(child);
+ }
+ c = get(istr);
+ }
+ if(c != ']')
+ {
+ return PARSE_FAILURE;
+ }
+ }
+ return parse_count;
+}
+
+bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
+{
+ std::string value;
+ int count = deserialize_string(istr, value, mMaxBytesLeft);
+ if(PARSE_FAILURE == count) return false;
+ account(count);
+ data = value;
+ return true;
+}
+
+bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
+{
+ // binary: b##"ff3120ab1"
+ // or: b(len)"..."
+
+ // I want to manually control those values here to make sure the
+ // parser doesn't break when someone changes a constant somewhere
+ // else.
+ const U32 BINARY_BUFFER_SIZE = 256;
+ const U32 STREAM_GET_COUNT = 255;
+
+ // need to read the base out.
+ char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */
+ get(istr, buf, STREAM_GET_COUNT, '"');
+ char c = get(istr);
+ if(c != '"') return false;
+ if(0 == strncmp("b(", buf, 2))
+ {
+ // We probably have a valid raw binary stream. determine
+ // the size, and read it.
+ S32 len = strtol(buf + 2, NULL, 0);
+ if(mCheckLimits && (len > mMaxBytesLeft)) return false;
+ std::vector<U8> value;
+ if(len)
+ {
+ value.resize(len);
+ account((int)fullread(istr, (char *)&value[0], len));
+ }
+ c = get(istr); // strip off the trailing double-quote
+ data = value;
+ }
+ else if(0 == strncmp("b64", buf, 3))
+ {
+ // *FIX: A bit inefficient, but works for now. To make the
+ // format better, I would need to add a hint into the
+ // serialization format that indicated how long it was.
+ std::stringstream coded_stream;
+ get(istr, *(coded_stream.rdbuf()), '\"');
+ c = get(istr);
+ std::string encoded(coded_stream.str());
+ S32 len = apr_base64_decode_len(encoded.c_str());
+ std::vector<U8> value;
+ if(len)
+ {
+ value.resize(len);
+ len = apr_base64_decode_binary(&value[0], encoded.c_str());
+ value.resize(len);
+ }
+ data = value;
+ }
+ else if(0 == strncmp("b16", buf, 3))
+ {
+ // yay, base 16. We pop the next character which is either a
+ // double quote or base 16 data. If it's a double quote, we're
+ // done parsing. If it's not, put the data back, and read the
+ // stream until the next double quote.
+ char* read; /*Flawfinder: ignore*/
+ U8 byte;
+ U8 byte_buffer[BINARY_BUFFER_SIZE];
+ U8* write;
+ std::vector<U8> value;
+ c = get(istr);
+ while(c != '"')
+ {
+ putback(istr, c);
+ read = buf;
+ write = byte_buffer;
+ get(istr, buf, STREAM_GET_COUNT, '"');
+ c = get(istr);
+ while(*read != '\0') /*Flawfinder: ignore*/
+ {
+ byte = hex_as_nybble(*read++);
+ byte = byte << 4;
+ byte |= hex_as_nybble(*read++);
+ *write++ = byte;
+ }
+ // copy the data out of the byte buffer
+ value.insert(value.end(), byte_buffer, write);
+ }
+ data = value;
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ * LLSDBinaryParser
+ */
+LLSDBinaryParser::LLSDBinaryParser()
+{
+}
+
+// virtual
+LLSDBinaryParser::~LLSDBinaryParser()
+{
+}
+
+// virtual
+S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
+{
+/**
+ * Undefined: '!'<br>
+ * Boolean: 't' for true 'f' for false<br>
+ * Integer: 'i' + 4 bytes network byte order<br>
+ * Real: 'r' + 8 bytes IEEE double<br>
+ * UUID: 'u' + 16 byte unsigned integer<br>
+ * String: 's' + 4 byte integer size + string<br>
+ * strings also secretly support the notation format
+ * Date: 'd' + 8 byte IEEE double for seconds since epoch<br>
+ * URI: 'l' + 4 byte integer size + string uri<br>
+ * Binary: 'b' + 4 byte integer size + binary data<br>
+ * Array: '[' + 4 byte integer size + all values + ']'<br>
+ * Map: '{' + 4 byte integer size every(key + value) + '}'<br>
+ * map keys are serialized as s + 4 byte integer size + string or in the
+ * notation format.
+ */
+ char c;
+ c = get(istr);
+ if(!istr.good())
+ {
+ return 0;
+ }
+ S32 parse_count = 1;
+ switch(c)
+ {
+ case '{':
+ {
+ S32 child_count = parseMap(istr, data);
+ if((child_count == PARSE_FAILURE) || data.isUndefined())
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ parse_count += child_count;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary map." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case '[':
+ {
+ S32 child_count = parseArray(istr, data);
+ if((child_count == PARSE_FAILURE) || data.isUndefined())
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ parse_count += child_count;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary array." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case '!':
+ data.clear();
+ break;
+
+ case '0':
+ data = false;
+ break;
+
+ case '1':
+ data = true;
+ break;
+
+ case 'i':
+ {
+ U32 value_nbo = 0;
+ read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
+ data = (S32)ntohl(value_nbo);
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary integer." << llendl;
+ }
+ break;
+ }
+
+ case 'r':
+ {
+ F64 real_nbo = 0.0;
+ read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/
+ data = ll_ntohd(real_nbo);
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary real." << llendl;
+ }
+ break;
+ }
+
+ case 'u':
+ {
+ LLUUID id;
+ read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/
+ data = id;
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary uuid." << llendl;
+ }
+ break;
+ }
+
+ case '\'':
+ case '"':
+ {
+ std::string value;
+ int cnt = deserialize_string_delim(istr, value, c);
+ if(PARSE_FAILURE == cnt)
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ data = value;
+ account(cnt);
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary (notation-style) string."
+ << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 's':
+ {
+ std::string value;
+ if(parseString(istr, value))
+ {
+ data = value;
+ }
+ else
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary string." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'l':
+ {
+ std::string value;
+ if(parseString(istr, value))
+ {
+ data = LLURI(value);
+ }
+ else
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary link." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'd':
+ {
+ F64 real = 0.0;
+ read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/
+ data = LLDate(real);
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary date." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ case 'b':
+ {
+ // We probably have a valid raw binary stream. determine
+ // the size, and read it.
+ U32 size_nbo = 0;
+ read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/
+ S32 size = (S32)ntohl(size_nbo);
+ if(mCheckLimits && (size > mMaxBytesLeft))
+ {
+ parse_count = PARSE_FAILURE;
+ }
+ else
+ {
+ std::vector<U8> value;
+ if(size > 0)
+ {
+ value.resize(size);
+ account((int)fullread(istr, (char*)&value[0], size));
+ }
+ data = value;
+ }
+ if(istr.fail())
+ {
+ llinfos << "STREAM FAILURE reading binary." << llendl;
+ parse_count = PARSE_FAILURE;
+ }
+ break;
+ }
+
+ default:
+ parse_count = PARSE_FAILURE;
+ llinfos << "Unrecognized character while parsing: int(" << (int)c
+ << ")" << llendl;
+ break;
+ }
+ if(PARSE_FAILURE == parse_count)
+ {
+ data.clear();
+ }
+ return parse_count;
+}
+
+S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
+{
+ map = LLSD::emptyMap();
+ U32 value_nbo = 0;
+ read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
+ S32 size = (S32)ntohl(value_nbo);
+ S32 parse_count = 0;
+ S32 count = 0;
+ char c = get(istr);
+ while(c != '}' && (count < size) && istr.good())
+ {
+ std::string name;
+ switch(c)
+ {
+ case 'k':
+ if(!parseString(istr, name))
+ {
+ return PARSE_FAILURE;
+ }
+ break;
+ case '\'':
+ case '"':
+ {
+ int cnt = deserialize_string_delim(istr, name, c);
+ if(PARSE_FAILURE == cnt) return PARSE_FAILURE;
+ account(cnt);
+ break;
+ }
+ }
+ LLSD child;
+ S32 child_count = doParse(istr, child);
+ if(child_count > 0)
+ {
+ // There must be a value for every key, thus child_count
+ // must be greater than 0.
+ parse_count += child_count;
+ map.insert(name, child);
+ }
+ else
+ {
+ return PARSE_FAILURE;
+ }
+ ++count;
+ c = get(istr);
+ }
+ if((c != '}') || (count < size))
+ {
+ // Make sure it is correctly terminated and we parsed as many
+ // as were said to be there.
+ return PARSE_FAILURE;
+ }
+ return parse_count;
+}
+
+S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const
+{
+ array = LLSD::emptyArray();
+ U32 value_nbo = 0;
+ read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
+ S32 size = (S32)ntohl(value_nbo);
+
+ // *FIX: This would be a good place to reserve some space in the
+ // array...
+
+ S32 parse_count = 0;
+ S32 count = 0;
+ char c = istr.peek();
+ while((c != ']') && (count < size) && istr.good())
+ {
+ LLSD child;
+ S32 child_count = doParse(istr, child);
+ if(PARSE_FAILURE == child_count)
+ {
+ return PARSE_FAILURE;
+ }
+ if(child_count)
+ {
+ parse_count += child_count;
+ array.append(child);
+ }
+ ++count;
+ c = istr.peek();
+ }
+ c = get(istr);
+ if((c != ']') || (count < size))
+ {
+ // Make sure it is correctly terminated and we parsed as many
+ // as were said to be there.
+ return PARSE_FAILURE;
+ }
+ return parse_count;
+}
+
+bool LLSDBinaryParser::parseString(
+ std::istream& istr,
+ std::string& value) const
+{
+ // *FIX: This is memory inefficient.
+ U32 value_nbo = 0;
+ read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
+ S32 size = (S32)ntohl(value_nbo);
+ if(mCheckLimits && (size > mMaxBytesLeft)) return false;
+ std::vector<char> buf;
+ if(size)
+ {
+ buf.resize(size);
+ account((int)fullread(istr, &buf[0], size));
+ value.assign(buf.begin(), buf.end());
+ }
+ return true;
+}
+
+
+/**
+ * LLSDFormatter
+ */
+LLSDFormatter::LLSDFormatter() :
+ mBoolAlpha(false)
+{
+}
+
+// virtual
+LLSDFormatter::~LLSDFormatter()
+{ }
+
+void LLSDFormatter::boolalpha(bool alpha)
+{
+ mBoolAlpha = alpha;
+}
+
+void LLSDFormatter::realFormat(const std::string& format)
+{
+ mRealFormat = format;
+}
+
+void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
+{
+ std::string buffer = llformat(mRealFormat.c_str(), real);
+ ostr << buffer;
+}
+
+/**
+ * LLSDNotationFormatter
+ */
+LLSDNotationFormatter::LLSDNotationFormatter()
+{
+}
+
+// virtual
+LLSDNotationFormatter::~LLSDNotationFormatter()
+{ }
+
+// static
+std::string LLSDNotationFormatter::escapeString(const std::string& in)
+{
+ std::ostringstream ostr;
+ serialize_string(in, ostr);
+ return ostr.str();
+}
+
+// virtual
+S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+{
+ S32 format_count = 1;
+ switch(data.type())
+ {
+ case LLSD::TypeMap:
+ {
+ ostr << "{";
+ bool need_comma = false;
+ LLSD::map_const_iterator iter = data.beginMap();
+ LLSD::map_const_iterator end = data.endMap();
+ for(; iter != end; ++iter)
+ {
+ if(need_comma) ostr << ",";
+ need_comma = true;
+ ostr << '\'';
+ serialize_string((*iter).first, ostr);
+ ostr << "':";
+ format_count += format((*iter).second, ostr);
+ }
+ ostr << "}";
+ break;
+ }
+
+ case LLSD::TypeArray:
+ {
+ ostr << "[";
+ bool need_comma = false;
+ LLSD::array_const_iterator iter = data.beginArray();
+ LLSD::array_const_iterator end = data.endArray();
+ for(; iter != end; ++iter)
+ {
+ if(need_comma) ostr << ",";
+ need_comma = true;
+ format_count += format(*iter, ostr);
+ }
+ ostr << "]";
+ break;
+ }
+
+ case LLSD::TypeUndefined:
+ ostr << "!";
+ break;
+
+ case LLSD::TypeBoolean:
+ if(mBoolAlpha ||
+#if( LL_WINDOWS || __GNUC__ > 2)
+ (ostr.flags() & std::ios::boolalpha)
+#else
+ (ostr.flags() & 0x0100)
+#endif
+ )
+ {
+ ostr << (data.asBoolean()
+ ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL);
+ }
+ else
+ {
+ ostr << (data.asBoolean() ? 1 : 0);
+ }
+ break;
+
+ case LLSD::TypeInteger:
+ ostr << "i" << data.asInteger();
+ break;
+
+ case LLSD::TypeReal:
+ ostr << "r";
+ if(mRealFormat.empty())
+ {
+ ostr << data.asReal();
+ }
+ else
+ {
+ formatReal(data.asReal(), ostr);
+ }
+ break;
+
+ case LLSD::TypeUUID:
+ ostr << "u" << data.asUUID();
+ break;
+
+ case LLSD::TypeString:
+ ostr << '\'';
+ serialize_string(data.asString(), ostr);
+ ostr << '\'';
+ break;
+
+ case LLSD::TypeDate:
+ ostr << "d\"" << data.asDate() << "\"";
+ break;
+
+ case LLSD::TypeURI:
+ ostr << "l\"";
+ serialize_string(data.asString(), ostr);
+ ostr << "\"";
+ break;
+
+ case LLSD::TypeBinary:
+ {
+ // *FIX: memory inefficient.
+ std::vector<U8> buffer = data.asBinary();
+ ostr << "b(" << buffer.size() << ")\"";
+ if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
+ ostr << "\"";
+ break;
+ }
+
+ default:
+ // *NOTE: This should never happen.
+ ostr << "!";
+ break;
+ }
+ return format_count;
+}
+
+
+/**
+ * LLSDBinaryFormatter
+ */
+LLSDBinaryFormatter::LLSDBinaryFormatter()
+{
+}
+
+// virtual
+LLSDBinaryFormatter::~LLSDBinaryFormatter()
+{ }
+
+// virtual
+S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+{
+ S32 format_count = 1;
+ switch(data.type())
+ {
+ case LLSD::TypeMap:
+ {
+ ostr.put('{');
+ U32 size_nbo = htonl(data.size());
+ ostr.write((const char*)(&size_nbo), sizeof(U32));
+ LLSD::map_const_iterator iter = data.beginMap();
+ LLSD::map_const_iterator end = data.endMap();
+ for(; iter != end; ++iter)
+ {
+ ostr.put('k');
+ formatString((*iter).first, ostr);
+ format_count += format((*iter).second, ostr);
+ }
+ ostr.put('}');
+ break;
+ }
+
+ case LLSD::TypeArray:
+ {
+ ostr.put('[');
+ U32 size_nbo = htonl(data.size());
+ ostr.write((const char*)(&size_nbo), sizeof(U32));
+ LLSD::array_const_iterator iter = data.beginArray();
+ LLSD::array_const_iterator end = data.endArray();
+ for(; iter != end; ++iter)
+ {
+ format_count += format(*iter, ostr);
+ }
+ ostr.put(']');
+ break;
+ }
+
+ case LLSD::TypeUndefined:
+ ostr.put('!');
+ break;
+
+ case LLSD::TypeBoolean:
+ if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL);
+ else ostr.put(BINARY_FALSE_SERIAL);
+ break;
+
+ case LLSD::TypeInteger:
+ {
+ ostr.put('i');
+ U32 value_nbo = htonl(data.asInteger());
+ ostr.write((const char*)(&value_nbo), sizeof(U32));
+ break;
+ }
+
+ case LLSD::TypeReal:
+ {
+ ostr.put('r');
+ F64 value_nbo = ll_htond(data.asReal());
+ ostr.write((const char*)(&value_nbo), sizeof(F64));
+ break;
+ }
+
+ case LLSD::TypeUUID:
+ ostr.put('u');
+ ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
+ break;
+
+ case LLSD::TypeString:
+ ostr.put('s');
+ formatString(data.asString(), ostr);
+ break;
+
+ case LLSD::TypeDate:
+ {
+ ostr.put('d');
+ F64 value = data.asReal();
+ ostr.write((const char*)(&value), sizeof(F64));
+ break;
+ }
+
+ case LLSD::TypeURI:
+ ostr.put('l');
+ formatString(data.asString(), ostr);
+ break;
+
+ case LLSD::TypeBinary:
+ {
+ // *FIX: memory inefficient.
+ ostr.put('b');
+ std::vector<U8> buffer = data.asBinary();
+ U32 size_nbo = htonl(buffer.size());
+ ostr.write((const char*)(&size_nbo), sizeof(U32));
+ if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
+ break;
+ }
+
+ default:
+ // *NOTE: This should never happen.
+ ostr.put('!');
+ break;
+ }
+ return format_count;
+}
+
+void LLSDBinaryFormatter::formatString(
+ const std::string& string,
+ std::ostream& ostr) const
+{
+ U32 size_nbo = htonl(string.size());
+ ostr.write((const char*)(&size_nbo), sizeof(U32));
+ ostr.write(string.c_str(), string.size());
+}
+
+/**
+ * local functions
+ */
+int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
+{
+ int c = istr.get();
+ if(istr.fail())
+ {
+ // No data in stream, bail out but mention the character we
+ // grabbed.
+ return LLSDParser::PARSE_FAILURE;
+ }
+
+ int rv = LLSDParser::PARSE_FAILURE;
+ switch(c)
+ {
+ case '\'':
+ case '"':
+ rv = deserialize_string_delim(istr, value, c);
+ break;
+ case 's':
+ // technically, less than max_bytes, but this is just meant to
+ // catch egregious protocol errors. parse errors will be
+ // caught in the case of incorrect counts.
+ rv = deserialize_string_raw(istr, value, max_bytes);
+ break;
+ default:
+ break;
+ }
+ if(LLSDParser::PARSE_FAILURE == rv) return rv;
+ return rv + 1; // account for the character grabbed at the top.
+}
+
+int deserialize_string_delim(
+ std::istream& istr,
+ std::string& value,
+ char delim)
+{
+ std::ostringstream write_buffer;
+ bool found_escape = false;
+ bool found_hex = false;
+ bool found_digit = false;
+ U8 byte = 0;
+ int count = 0;
+
+ while (true)
+ {
+ int next_byte = istr.get();
+ ++count;
+
+ if(istr.fail())
+ {
+ // If our stream is empty, break out
+ value = write_buffer.str();
+ return LLSDParser::PARSE_FAILURE;
+ }
+
+ char next_char = (char)next_byte; // Now that we know it's not EOF
+
+ if(found_escape)
+ {
+ // next character(s) is a special sequence.
+ if(found_hex)
+ {
+ if(found_digit)
+ {
+ found_digit = false;
+ found_hex = false;
+ found_escape = false;
+ byte = byte << 4;
+ byte |= hex_as_nybble(next_char);
+ write_buffer << byte;
+ byte = 0;
+ }
+ else
+ {
+ // next character is the first nybble of
+ //
+ found_digit = true;
+ byte = hex_as_nybble(next_char);
+ }
+ }
+ else if(next_char == 'x')
+ {
+ found_hex = true;
+ }
+ else
+ {
+ switch(next_char)
+ {
+ case 'a':
+ write_buffer << '\a';
+ break;
+ case 'b':
+ write_buffer << '\b';
+ break;
+ case 'f':
+ write_buffer << '\f';
+ break;
+ case 'n':
+ write_buffer << '\n';
+ break;
+ case 'r':
+ write_buffer << '\r';
+ break;
+ case 't':
+ write_buffer << '\t';
+ break;
+ case 'v':
+ write_buffer << '\v';
+ break;
+ default:
+ write_buffer << next_char;
+ break;
+ }
+ found_escape = false;
+ }
+ }
+ else if(next_char == '\\')
+ {
+ found_escape = true;
+ }
+ else if(next_char == delim)
+ {
+ break;
+ }
+ else
+ {
+ write_buffer << next_char;
+ }
+ }
+
+ value = write_buffer.str();
+ return count;
+}
+
+int deserialize_string_raw(
+ std::istream& istr,
+ std::string& value,
+ S32 max_bytes)
+{
+ int count = 0;
+ const S32 BUF_LEN = 20;
+ char buf[BUF_LEN]; /* Flawfinder: ignore */
+ istr.get(buf, BUF_LEN - 1, ')');
+ count += (int)istr.gcount();
+ int c = istr.get();
+ c = istr.get();
+ count += 2;
+ if(((c == '"') || (c == '\'')) && (buf[0] == '('))
+ {
+ // We probably have a valid raw string. determine
+ // the size, and read it.
+ // *FIX: This is memory inefficient.
+ S32 len = strtol(buf + 1, NULL, 0);
+ if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
+ std::vector<char> buf;
+ if(len)
+ {
+ buf.resize(len);
+ count += (int)fullread(istr, (char *)&buf[0], len);
+ value.assign(buf.begin(), buf.end());
+ }
+ c = istr.get();
+ ++count;
+ if(!((c == '"') || (c == '\'')))
+ {
+ return LLSDParser::PARSE_FAILURE;
+ }
+ }
+ else
+ {
+ return LLSDParser::PARSE_FAILURE;
+ }
+ return count;
+}
+
+static const char* NOTATION_STRING_CHARACTERS[256] =
+{
+ "\\x00", // 0
+ "\\x01", // 1
+ "\\x02", // 2
+ "\\x03", // 3
+ "\\x04", // 4
+ "\\x05", // 5
+ "\\x06", // 6
+ "\\a", // 7
+ "\\b", // 8
+ "\\t", // 9
+ "\\n", // 10
+ "\\v", // 11
+ "\\f", // 12
+ "\\r", // 13
+ "\\x0e", // 14
+ "\\x0f", // 15
+ "\\x10", // 16
+ "\\x11", // 17
+ "\\x12", // 18
+ "\\x13", // 19
+ "\\x14", // 20
+ "\\x15", // 21
+ "\\x16", // 22
+ "\\x17", // 23
+ "\\x18", // 24
+ "\\x19", // 25
+ "\\x1a", // 26
+ "\\x1b", // 27
+ "\\x1c", // 28
+ "\\x1d", // 29
+ "\\x1e", // 30
+ "\\x1f", // 31
+ " ", // 32
+ "!", // 33
+ "\"", // 34
+ "#", // 35
+ "$", // 36
+ "%", // 37
+ "&", // 38
+ "\\'", // 39
+ "(", // 40
+ ")", // 41
+ "*", // 42
+ "+", // 43
+ ",", // 44
+ "-", // 45
+ ".", // 46
+ "/", // 47
+ "0", // 48
+ "1", // 49
+ "2", // 50
+ "3", // 51
+ "4", // 52
+ "5", // 53
+ "6", // 54
+ "7", // 55
+ "8", // 56
+ "9", // 57
+ ":", // 58
+ ";", // 59
+ "<", // 60
+ "=", // 61
+ ">", // 62
+ "?", // 63
+ "@", // 64
+ "A", // 65
+ "B", // 66
+ "C", // 67
+ "D", // 68
+ "E", // 69
+ "F", // 70
+ "G", // 71
+ "H", // 72
+ "I", // 73
+ "J", // 74
+ "K", // 75
+ "L", // 76
+ "M", // 77
+ "N", // 78
+ "O", // 79
+ "P", // 80
+ "Q", // 81
+ "R", // 82
+ "S", // 83
+ "T", // 84
+ "U", // 85
+ "V", // 86
+ "W", // 87
+ "X", // 88
+ "Y", // 89
+ "Z", // 90
+ "[", // 91
+ "\\\\", // 92
+ "]", // 93
+ "^", // 94
+ "_", // 95
+ "`", // 96
+ "a", // 97
+ "b", // 98
+ "c", // 99
+ "d", // 100
+ "e", // 101
+ "f", // 102
+ "g", // 103
+ "h", // 104
+ "i", // 105
+ "j", // 106
+ "k", // 107
+ "l", // 108
+ "m", // 109
+ "n", // 110
+ "o", // 111
+ "p", // 112
+ "q", // 113
+ "r", // 114
+ "s", // 115
+ "t", // 116
+ "u", // 117
+ "v", // 118
+ "w", // 119
+ "x", // 120
+ "y", // 121
+ "z", // 122
+ "{", // 123
+ "|", // 124
+ "}", // 125
+ "~", // 126
+ "\\x7f", // 127
+ "\\x80", // 128
+ "\\x81", // 129
+ "\\x82", // 130
+ "\\x83", // 131
+ "\\x84", // 132
+ "\\x85", // 133
+ "\\x86", // 134
+ "\\x87", // 135
+ "\\x88", // 136
+ "\\x89", // 137
+ "\\x8a", // 138
+ "\\x8b", // 139
+ "\\x8c", // 140
+ "\\x8d", // 141
+ "\\x8e", // 142
+ "\\x8f", // 143
+ "\\x90", // 144
+ "\\x91", // 145
+ "\\x92", // 146
+ "\\x93", // 147
+ "\\x94", // 148
+ "\\x95", // 149
+ "\\x96", // 150
+ "\\x97", // 151
+ "\\x98", // 152
+ "\\x99", // 153
+ "\\x9a", // 154
+ "\\x9b", // 155
+ "\\x9c", // 156
+ "\\x9d", // 157
+ "\\x9e", // 158
+ "\\x9f", // 159
+ "\\xa0", // 160
+ "\\xa1", // 161
+ "\\xa2", // 162
+ "\\xa3", // 163
+ "\\xa4", // 164
+ "\\xa5", // 165
+ "\\xa6", // 166
+ "\\xa7", // 167
+ "\\xa8", // 168
+ "\\xa9", // 169
+ "\\xaa", // 170
+ "\\xab", // 171
+ "\\xac", // 172
+ "\\xad", // 173
+ "\\xae", // 174
+ "\\xaf", // 175
+ "\\xb0", // 176
+ "\\xb1", // 177
+ "\\xb2", // 178
+ "\\xb3", // 179
+ "\\xb4", // 180
+ "\\xb5", // 181
+ "\\xb6", // 182
+ "\\xb7", // 183
+ "\\xb8", // 184
+ "\\xb9", // 185
+ "\\xba", // 186
+ "\\xbb", // 187
+ "\\xbc", // 188
+ "\\xbd", // 189
+ "\\xbe", // 190
+ "\\xbf", // 191
+ "\\xc0", // 192
+ "\\xc1", // 193
+ "\\xc2", // 194
+ "\\xc3", // 195
+ "\\xc4", // 196
+ "\\xc5", // 197
+ "\\xc6", // 198
+ "\\xc7", // 199
+ "\\xc8", // 200
+ "\\xc9", // 201
+ "\\xca", // 202
+ "\\xcb", // 203
+ "\\xcc", // 204
+ "\\xcd", // 205
+ "\\xce", // 206
+ "\\xcf", // 207
+ "\\xd0", // 208
+ "\\xd1", // 209
+ "\\xd2", // 210
+ "\\xd3", // 211
+ "\\xd4", // 212
+ "\\xd5", // 213
+ "\\xd6", // 214
+ "\\xd7", // 215
+ "\\xd8", // 216
+ "\\xd9", // 217
+ "\\xda", // 218
+ "\\xdb", // 219
+ "\\xdc", // 220
+ "\\xdd", // 221
+ "\\xde", // 222
+ "\\xdf", // 223
+ "\\xe0", // 224
+ "\\xe1", // 225
+ "\\xe2", // 226
+ "\\xe3", // 227
+ "\\xe4", // 228
+ "\\xe5", // 229
+ "\\xe6", // 230
+ "\\xe7", // 231
+ "\\xe8", // 232
+ "\\xe9", // 233
+ "\\xea", // 234
+ "\\xeb", // 235
+ "\\xec", // 236
+ "\\xed", // 237
+ "\\xee", // 238
+ "\\xef", // 239
+ "\\xf0", // 240
+ "\\xf1", // 241
+ "\\xf2", // 242
+ "\\xf3", // 243
+ "\\xf4", // 244
+ "\\xf5", // 245
+ "\\xf6", // 246
+ "\\xf7", // 247
+ "\\xf8", // 248
+ "\\xf9", // 249
+ "\\xfa", // 250
+ "\\xfb", // 251
+ "\\xfc", // 252
+ "\\xfd", // 253
+ "\\xfe", // 254
+ "\\xff" // 255
+};
+
+void serialize_string(const std::string& value, std::ostream& str)
+{
+ std::string::const_iterator it = value.begin();
+ std::string::const_iterator end = value.end();
+ U8 c;
+ for(; it != end; ++it)
+ {
+ c = (U8)(*it);
+ str << NOTATION_STRING_CHARACTERS[c];
+ }
+}
+
+int deserialize_boolean(
+ std::istream& istr,
+ LLSD& data,
+ const std::string& compare,
+ bool value)
+{
+ //
+ // this method is a little goofy, because it gets the stream at
+ // the point where the t or f has already been
+ // consumed. Basically, parse for a patch to the string passed in
+ // starting at index 1. If it's a match:
+ // * assign data to value
+ // * return the number of bytes read
+ // otherwise:
+ // * set data to LLSD::null
+ // * return LLSDParser::PARSE_FAILURE (-1)
+ //
+ int bytes_read = 0;
+ std::string::size_type ii = 0;
+ char c = istr.peek();
+ while((++ii < compare.size())
+ && (tolower(c) == (int)compare[ii])
+ && istr.good())
+ {
+ istr.ignore();
+ ++bytes_read;
+ c = istr.peek();
+ }
+ if(compare.size() != ii)
+ {
+ data.clear();
+ return LLSDParser::PARSE_FAILURE;
+ }
+ data = value;
+ return bytes_read;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
+{
+ s << LLSDNotationStreamer(llsd);
+ return s;
+}
+
+
+//dirty little zippers -- yell at davep if these are horrid
+
+//return a string containing gzipped bytes of binary serialized LLSD
+// VERY inefficient -- creates several copies of LLSD block in memory
+std::string zip_llsd(LLSD& data)
+{
+ std::stringstream llsd_strm;
+
+ LLSDSerialize::toBinary(data, llsd_strm);
+
+ const U32 CHUNK = 65536;
+
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+ if (ret != Z_OK)
+ {
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+
+ std::string source = llsd_strm.str();
+
+ U8 out[CHUNK];
+
+ strm.avail_in = source.size();
+ strm.next_in = (U8*) source.data();
+ U8* output = NULL;
+
+ U32 cur_size = 0;
+
+ U32 have = 0;
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+
+ ret = deflate(&strm, Z_FINISH);
+ if (ret == Z_OK || ret == Z_STREAM_END)
+ { //copy result into output
+ if (strm.avail_out >= CHUNK)
+ {
+ free(output);
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+
+ have = CHUNK-strm.avail_out;
+ output = (U8*) realloc(output, cur_size+have);
+ memcpy(output+cur_size, out, have);
+ cur_size += have;
+ }
+ else
+ {
+ free(output);
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+ }
+ while (ret == Z_OK);
+
+ std::string::size_type size = cur_size;
+
+ std::string result((char*) output, size);
+ deflateEnd(&strm);
+ free(output);
+
+#if 0 //verify results work with unzip_llsd
+ std::istringstream test(result);
+ LLSD test_sd;
+ if (!unzip_llsd(test_sd, test, result.size()))
+ {
+ llerrs << "Invalid compression result!" << llendl;
+ }
+#endif
+
+ return result;
+}
+
+//decompress a block of LLSD from provided istream
+// not very efficient -- creats a copy of decompressed LLSD block in memory
+// and deserializes from that copy using LLSDSerialize
+bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
+{
+ U8* result = NULL;
+ U32 cur_size = 0;
+ z_stream strm;
+
+ const U32 CHUNK = 65536;
+
+ U8 *in = new U8[size];
+ is.read((char*) in, size);
+
+ U8 out[CHUNK];
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = size;
+ strm.next_in = in;
+
+ S32 ret = inflateInit(&strm);
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR)
+ {
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ }
+
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ break;
+ }
+
+ U32 have = CHUNK-strm.avail_out;
+
+ result = (U8*) realloc(result, cur_size + have);
+ memcpy(result+cur_size, out, have);
+ cur_size += have;
+
+ } while (ret == Z_OK);
+
+ inflateEnd(&strm);
+ delete [] in;
+
+ if (ret != Z_STREAM_END)
+ {
+ free(result);
+ return false;
+ }
+
+ //result now points to the decompressed LLSD block
+ {
+ std::string res_str((char*) result, cur_size);
+
+ std::string deprecated_header("<? LLSD/Binary ?>");
+
+ if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
+ {
+ res_str = res_str.substr(deprecated_header.size()+1, cur_size);
+ }
+ cur_size = res_str.size();
+
+ std::istringstream istr(res_str);
+
+ if (!LLSDSerialize::fromBinary(data, istr, cur_size))
+ {
+ llwarns << "Failed to unzip LLSD block" << llendl;
+ free(result);
+ return false;
+ }
+ }
+
+ free(result);
+ return true;
+}
+//This unzip function will only work with a gzip header and trailer - while the contents
+//of the actual compressed data is the same for either format (gzip vs zlib ), the headers
+//and trailers are different for the formats.
+U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size )
+{
+ U8* result = NULL;
+ U32 cur_size = 0;
+ z_stream strm;
+
+ const U32 CHUNK = 0x4000;
+
+ U8 *in = new U8[size];
+ is.read((char*) in, size);
+
+ U8 out[CHUNK];
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = size;
+ strm.next_in = in;
+
+
+ S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP );
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR)
+ {
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ valid = false;
+ }
+
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ valid = false;
+ break;
+ }
+
+ U32 have = CHUNK-strm.avail_out;
+
+ result = (U8*) realloc(result, cur_size + have);
+ memcpy(result+cur_size, out, have);
+ cur_size += have;
+
+ } while (ret == Z_OK);
+
+ inflateEnd(&strm);
+ delete [] in;
+
+ if (ret != Z_STREAM_END)
+ {
+ free(result);
+ valid = false;
+ return NULL;
+ }
+
+ //result now points to the decompressed LLSD block
+ {
+ outsize= cur_size;
+ valid = true;
+ }
+
+ return result;
+}
+
+
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 99a3ea3cd4..86e3fc864c 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -793,5 +793,5 @@ public: //dirty little zip functions -- yell at davep LL_COMMON_API std::string zip_llsd(LLSD& data); LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size); - +LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size); #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl index 37819fea3c..270f1e905b 100644 --- a/indra/llmath/llmatrix3a.inl +++ b/indra/llmath/llmatrix3a.inl @@ -66,7 +66,6 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src) inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const { - llassert( column < 3 ); return mColumns[column]; } diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 2be5452f8d..3970a5de31 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -27,7 +27,7 @@ #ifndef LL_M3MATH_H #define LL_M3MATH_H -#include "llerror.h" +//#include "llerror.h" #include "stdtypes.h" class LLVector4; diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 56cb2ae73e..4e77d9e5ff 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -30,7 +30,7 @@ class LLColor4; class LLVector4; -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 578dcdc8ea..fba549a3b7 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -27,7 +27,7 @@ #ifndef LL_V3DMATH_H #define LL_V3DMATH_H -#include "llerror.h" +//#include "llerror.h" #include "v3math.h" class LLVector3d diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 0432aeba4c..206a99b567 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -27,7 +27,7 @@ #ifndef LL_V3MATH_H #define LL_V3MATH_H -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index b047f86e6e..6946b570ab 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -27,7 +27,7 @@ #ifndef LL_V4COLOR_H #define LL_V4COLOR_H -#include "llerror.h" +//#include "llerror.h" //#include "vmath.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 623c8b2003..f999e0533e 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -27,7 +27,7 @@ #ifndef LL_V4MATH_H #define LL_V4MATH_H -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "v3math.h" diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index e71fb96540..54bd469621 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -999,7 +999,6 @@ char const* const _PREHASH_SnapshotID = LLMessageStringTable::getInstance()->get char const* const _PREHASH_Aspect = LLMessageStringTable::getInstance()->getString("Aspect"); char const* const _PREHASH_ParamSize = LLMessageStringTable::getInstance()->getString("ParamSize"); char const* const _PREHASH_VoteCast = LLMessageStringTable::getInstance()->getString("VoteCast"); -char const* const _PREHASH_CastsShadows = LLMessageStringTable::getInstance()->getString("CastsShadows"); char const* const _PREHASH_EveryoneMask = LLMessageStringTable::getInstance()->getString("EveryoneMask"); char const* const _PREHASH_ObjectSpinUpdate = LLMessageStringTable::getInstance()->getString("ObjectSpinUpdate"); char const* const _PREHASH_MaturePublish = LLMessageStringTable::getInstance()->getString("MaturePublish"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index dd2c2dbd64..8a60ba1629 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -999,7 +999,6 @@ extern char const* const _PREHASH_SnapshotID; extern char const* const _PREHASH_Aspect; extern char const* const _PREHASH_ParamSize; extern char const* const _PREHASH_VoteCast; -extern char const* const _PREHASH_CastsShadows; extern char const* const _PREHASH_EveryoneMask; extern char const* const _PREHASH_ObjectSpinUpdate; extern char const* const _PREHASH_MaturePublish; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index cb32a510b8..768d3a6ae8 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -28,7 +28,7 @@ #include "llmodel.h" #include "llmemory.h" -#include "llconvexdecomposition.h" +#include "LLConvexDecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" #if LL_MSVC diff --git a/indra/llprimitive/object_flags.h b/indra/llprimitive/object_flags.h index 94c559d757..f7f6841b53 100644 --- a/indra/llprimitive/object_flags.h +++ b/indra/llprimitive/object_flags.h @@ -1,80 +1,75 @@ -/** - * @file object_flags.h - * @brief Flags for object creation and transmission - * - * $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_OBJECT_FLAGS_H -#define LL_OBJECT_FLAGS_H - -// downstream flags from sim->viewer -const U32 FLAGS_USE_PHYSICS = 0x00000001; -const U32 FLAGS_CREATE_SELECTED = 0x00000002; -const U32 FLAGS_OBJECT_MODIFY = 0x00000004; -const U32 FLAGS_OBJECT_COPY = 0x00000008; -const U32 FLAGS_OBJECT_ANY_OWNER = 0x00000010; -const U32 FLAGS_OBJECT_YOU_OWNER = 0x00000020; -const U32 FLAGS_SCRIPTED = 0x00000040; -const U32 FLAGS_HANDLE_TOUCH = 0x00000080; -const U32 FLAGS_OBJECT_MOVE = 0x00000100; -const U32 FLAGS_TAKES_MONEY = 0x00000200; -const U32 FLAGS_PHANTOM = 0x00000400; -const U32 FLAGS_INVENTORY_EMPTY = 0x00000800; - -const U32 FLAGS_JOINT_HINGE = 0x00001000; -const U32 FLAGS_JOINT_P2P = 0x00002000; -const U32 FLAGS_JOINT_LP2P = 0x00004000; -// const U32 FLAGS_JOINT_WHEEL = 0x00008000; -const U32 FLAGS_INCLUDE_IN_SEARCH = 0x00008000; - -const U32 FLAGS_ALLOW_INVENTORY_DROP = 0x00010000; -const U32 FLAGS_OBJECT_TRANSFER = 0x00020000; -const U32 FLAGS_OBJECT_GROUP_OWNED = 0x00040000; -//const U32 FLAGS_OBJECT_YOU_OFFICER = 0x00080000; - -const U32 FLAGS_CAMERA_DECOUPLED = 0x00100000; -const U32 FLAGS_ANIM_SOURCE = 0x00200000; -const U32 FLAGS_CAMERA_SOURCE = 0x00400000; - -const U32 FLAGS_CAST_SHADOWS = 0x00800000; - -const U32 FLAGS_OBJECT_OWNER_MODIFY = 0x10000000; - -const U32 FLAGS_TEMPORARY_ON_REZ = 0x20000000; -const U32 FLAGS_TEMPORARY = 0x40000000; -const U32 FLAGS_ZLIB_COMPRESSED = 0x80000000; - -const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE; - -typedef enum e_havok_joint_type -{ - HJT_INVALID = 0, - HJT_HINGE = 1, - HJT_POINT = 2, -// HJT_LPOINT = 3, -// HJT_WHEEL = 4, - HJT_EOF = 3 -} EHavokJointType; - -#endif - +/**
+ * @file object_flags.h
+ * @brief Flags for object creation and transmission
+ *
+ * $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_OBJECT_FLAGS_H
+#define LL_OBJECT_FLAGS_H
+
+// downstream flags from sim->viewer
+const U32 FLAGS_USE_PHYSICS = (1U << 0);
+const U32 FLAGS_CREATE_SELECTED = (1U << 1);
+const U32 FLAGS_OBJECT_MODIFY = (1U << 2);
+const U32 FLAGS_OBJECT_COPY = (1U << 3);
+const U32 FLAGS_OBJECT_ANY_OWNER = (1U << 4);
+const U32 FLAGS_OBJECT_YOU_OWNER = (1U << 5);
+const U32 FLAGS_SCRIPTED = (1U << 6);
+const U32 FLAGS_HANDLE_TOUCH = (1U << 7);
+const U32 FLAGS_OBJECT_MOVE = (1U << 8);
+const U32 FLAGS_TAKES_MONEY = (1U << 9);
+const U32 FLAGS_PHANTOM = (1U << 10);
+const U32 FLAGS_INVENTORY_EMPTY = (1U << 11);
+const U32 FLAGS_OBJECT_PERMANENT = (1U << 12);
+const U32 FLAGS_CHARACTER = (1U << 13);
+//const U32 FLAGS_UNUSED_000 = (1U << 14); // was FLAGS_JOINT_LP2P
+const U32 FLAGS_INCLUDE_IN_SEARCH = (1U << 15);
+const U32 FLAGS_ALLOW_INVENTORY_DROP = (1U << 16);
+const U32 FLAGS_OBJECT_TRANSFER = (1U << 17);
+const U32 FLAGS_OBJECT_GROUP_OWNED = (1U << 18);
+//const U32 FLAGS_UNUSED_001 = (1U << 19); // was FLAGS_OBJECT_YOU_OFFICER
+const U32 FLAGS_CAMERA_DECOUPLED = (1U << 20);
+const U32 FLAGS_ANIM_SOURCE = (1U << 21);
+const U32 FLAGS_CAMERA_SOURCE = (1U << 22);
+//const U32 FLAGS_UNUSED_002 = (1U << 23); // was FLAGS_CAST_SHADOWS
+//const U32 FLAGS_UNUSED_003 = (1U << 24);
+//const U32 FLAGS_UNUSED_004 = (1U << 25);
+//const U32 FLAGS_UNUSED_005 = (1U << 26);
+//const U32 FLAGS_UNUSED_006 = (1U << 27);
+const U32 FLAGS_OBJECT_OWNER_MODIFY = (1U << 28);
+const U32 FLAGS_TEMPORARY_ON_REZ = (1U << 29);
+//const U32 FLAGS_UNUSED_007 = (1U << 30); // was FLAGS_TEMPORARY
+//const U32 FLAGS_UNUSED_008 = (1U << 31); // was FLAGS_ZLIB_COMPRESSED
+const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE;
+
+typedef enum e_havok_joint_type
+{
+ HJT_INVALID = 0,
+ HJT_HINGE = 1,
+ HJT_POINT = 2,
+// HJT_LPOINT = 3,
+// HJT_WHEEL = 4,
+ HJT_EOF = 3
+} EHavokJointType;
+
+#endif
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 5c13df9f81..516af93316 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -36,6 +36,7 @@ set(llrender_SOURCE_FILES llglslshader.cpp llimagegl.cpp llpostprocess.cpp + llrendernavprim.cpp llrendersphere.cpp llshadermgr.cpp lltexture.cpp @@ -59,6 +60,7 @@ set(llrender_HEADER_FILES llimagegl.h llpostprocess.h llrender.h + llrendernavprim.h llrendersphere.h llshadermgr.h lltexture.h diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp new file mode 100644 index 0000000000..ebc453a32c --- /dev/null +++ b/indra/llrender/llrendernavprim.cpp @@ -0,0 +1,83 @@ +/**
+ * @file LLRenderNavPrim.cpp
+ * @brief Renderable primitives used by the pathing library
+ *
+ * $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$
+ */
+
+
+#include "linden_common.h"
+#include "llrendernavprim.h"
+#include "llerror.h"
+#include "llglheaders.h"
+#include "llvertexbuffer.h"
+#include "llglslshader.h"
+
+//=============================================================================
+LLRenderNavPrim gRenderNav;
+//=============================================================================
+void LLRenderNavPrim::renderSegment( const LLVector3& start, const LLVector3& end, int color, bool overlayMode ) const
+{
+ LLColor4 colorA( color );
+ gGL.color3fv( colorA.mV );
+
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv( start.mV );
+ gGL.vertex3fv( end.mV );
+ }
+ gGL.end();
+}
+//=============================================================================
+void LLRenderNavPrim::renderTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, int color, bool overlayMode ) const
+{
+ LLColor4 colorA( color );
+ colorA*=1.25f;
+ gGL.color4fv( colorA.mV );
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ gGL.vertex3fv( a.mV );
+ gGL.vertex3fv( b.mV );
+ gGL.vertex3fv( c.mV );
+ }
+ gGL.end();
+}
+//=============================================================================
+void LLRenderNavPrim::renderNavMeshVB( LLVertexBuffer* pVBO, int vertCnt )
+{
+ pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+ pVBO->drawArrays( LLRender::TRIANGLES, 0, vertCnt );
+}
+//=============================================================================
+void LLRenderNavPrim::renderStar( const LLVector3& center, const float scale, int color ) const
+{
+ for (int k=0; k<3; k++)
+ {
+ LLVector3 star, pt1, pt2;
+ star = LLVector3( 0.0f,0.0f,0.0f);
+ star[k] = 0.5f;
+ pt1 = center + star;
+ pt2 = center - star;
+ renderSegment( pt1, pt2, color, false );
+ }
+}
+//=============================================================================
diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h new file mode 100644 index 0000000000..d88fe656b7 --- /dev/null +++ b/indra/llrender/llrendernavprim.h @@ -0,0 +1,56 @@ +/**
+ * @file LLRenderNavPrim.h
+ * @brief
+ *
+ * $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_RENDER_NAVPRIM_H
+#define LL_RENDER_NAVPRIM_H
+
+#include "llmath.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "v4color.h"
+#include "llgl.h"
+
+
+class LLRenderNavPrim
+{
+public:
+ //Draw a line
+ void renderSegment( const LLVector3& start, const LLVector3& end, int color, bool overlayMode ) const;
+ //Draw simple tri
+ void renderTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, int color, bool overlayMode ) const;
+ //Draw the contents of vertex buffer
+ void renderNavMeshVB( LLVertexBuffer* pVBO, int vertCnt );
+ //Draw a star
+ void renderStar( const LLVector3& center, const float scale, int color ) const;
+
+private:
+};
+
+extern LLRenderNavPrim gRenderNav;
+
+#endif
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index e4a5cd0299..b562c91e3e 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1,2290 +1,2293 @@ -/** - * @file llvertexbuffer.cpp - * @brief LLVertexBuffer implementation - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#include "linden_common.h" - -#include <boost/static_assert.hpp> -#include "llsys.h" -#include "llvertexbuffer.h" -// #include "llrender.h" -#include "llglheaders.h" -#include "llmemtype.h" -#include "llrender.h" -#include "llvector4a.h" -#include "llshadermgr.h" -#include "llglslshader.h" -#include "llmemory.h" - -//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 -U32 nhpo2(U32 v) -{ - U32 r = 1; - while (r < v) { - r *= 2; - } - return r; -} - - -//============================================================================ - -//static -LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB); -LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB); -LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); -LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); -U32 LLVBOPool::sBytesPooled = 0; - -LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL; -U32 LLVertexBuffer::sBindCount = 0; -U32 LLVertexBuffer::sSetCount = 0; -S32 LLVertexBuffer::sCount = 0; -S32 LLVertexBuffer::sGLCount = 0; -S32 LLVertexBuffer::sMappedCount = 0; -bool LLVertexBuffer::sDisableVBOMapping = false; -bool LLVertexBuffer::sEnableVBOs = true; -U32 LLVertexBuffer::sGLRenderBuffer = 0; -U32 LLVertexBuffer::sGLRenderArray = 0; -U32 LLVertexBuffer::sGLRenderIndices = 0; -U32 LLVertexBuffer::sLastMask = 0; -bool LLVertexBuffer::sVBOActive = false; -bool LLVertexBuffer::sIBOActive = false; -U32 LLVertexBuffer::sAllocatedBytes = 0; -bool LLVertexBuffer::sMapped = false; -bool LLVertexBuffer::sUseStreamDraw = true; -bool LLVertexBuffer::sUseVAO = false; -bool LLVertexBuffer::sPreferStreamDraw = false; - -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms - -class LLGLSyncFence : public LLGLFence -{ -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() - { -#ifdef GL_ARB_sync - mSync = 0; -#endif - } - - virtual ~LLGLSyncFence() - { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif - } - - void placeFence() - { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif - } - - void wait() - { -#ifdef GL_ARB_sync - if (mSync) - { - while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - static S32 waits = 0; - waits++; - } - } -#endif - } - - -}; - - -//which power of 2 is i? -//assumes i is a power of 2 > 0 -U32 wpo2(U32 i) -{ - llassert(i > 0); - llassert(nhpo2(i) == i); - - U32 r = 0; - - while (i >>= 1) ++r; - - return r; -} - -volatile U8* LLVBOPool::allocate(U32& name, U32 size) -{ - llassert(nhpo2(size) == size); - - U32 i = wpo2(size); - - if (mFreeList.size() <= i) - { - mFreeList.resize(i+1); - } - - volatile U8* ret = NULL; - - if (mFreeList[i].empty()) - { - //make a new buffer - glGenBuffersARB(1, &name); - glBindBufferARB(mType, name); - LLVertexBuffer::sAllocatedBytes += size; - - if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) - { - glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); - } - else - { //always use a true hint of static draw when allocating non-client-backed buffers - glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); - } - - glBindBufferARB(mType, 0); - } - else - { - name = mFreeList[i].front().mGLName; - ret = mFreeList[i].front().mClientData; - - sBytesPooled -= size; - - mFreeList[i].pop_front(); - } - - return ret; -} - -void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) -{ - llassert(nhpo2(size) == size); - - U32 i = wpo2(size); - - llassert(mFreeList.size() > i); - - Record rec; - rec.mGLName = name; - rec.mClientData = buffer; - - if (buffer == NULL) - { - glDeleteBuffersARB(1, &rec.mGLName); - } - else - { - sBytesPooled += size; - mFreeList[i].push_back(rec); - } -} - -void LLVBOPool::cleanup() -{ - U32 size = 1; - - for (U32 i = 0; i < mFreeList.size(); ++i) - { - record_list_t& l = mFreeList[i]; - - while (!l.empty()) - { - Record& r = l.front(); - - glDeleteBuffersARB(1, &r.mGLName); - - if (r.mClientData) - { - ll_aligned_free_16((void*) r.mClientData); - } - - l.pop_front(); - - LLVertexBuffer::sAllocatedBytes -= size; - sBytesPooled -= size; - } - - size *= 2; - } -} - - -//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware -S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = -{ - sizeof(LLVector4), // TYPE_VERTEX, - sizeof(LLVector4), // TYPE_NORMAL, - sizeof(LLVector2), // TYPE_TEXCOORD0, - sizeof(LLVector2), // TYPE_TEXCOORD1, - sizeof(LLVector2), // TYPE_TEXCOORD2, - sizeof(LLVector2), // TYPE_TEXCOORD3, - sizeof(LLColor4U), // TYPE_COLOR, - sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently - sizeof(LLVector4), // TYPE_BINORMAL, - sizeof(F32), // TYPE_WEIGHT, - sizeof(LLVector4), // TYPE_WEIGHT4, - sizeof(LLVector4), // TYPE_CLOTHWEIGHT, - sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes -}; - -U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_QUADS, - GL_LINE_LOOP, -}; - - -//static -void LLVertexBuffer::setupClientArrays(U32 data_mask) -{ - if (sLastMask != data_mask) - { - bool error = false; - - if (LLGLSLShader::sNoFixedFunction) - { - for (U32 i = 0; i < TYPE_MAX; ++i) - { - S32 loc = i; - - U32 mask = 1 << i; - - if (sLastMask & (1 << i)) - { //was enabled - if (!(data_mask & mask)) - { //needs to be disabled - glDisableVertexAttribArrayARB(loc); - } - } - else - { //was disabled - if (data_mask & mask) - { //needs to be enabled - glEnableVertexAttribArrayARB(loc); - } - } - } - } - else - { - - GLenum array[] = - { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_TEXTURE_COORD_ARRAY, - GL_COLOR_ARRAY, - }; - - GLenum mask[] = - { - MAP_VERTEX, - MAP_NORMAL, - MAP_TEXCOORD0, - MAP_COLOR - }; - - - - for (U32 i = 0; i < 4; ++i) - { - if (sLastMask & mask[i]) - { //was enabled - if (!(data_mask & mask[i])) - { //needs to be disabled - glDisableClientState(array[i]); - } - else if (gDebugGL) - { //needs to be enabled, make sure it was (DEBUG) - if (!glIsEnabled(array[i])) - { - if (gDebugSession) - { - error = true; - gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; - } - else - { - llerrs << "Bad client state! " << array[i] << " disabled." << llendl; - } - } - } - } - else - { //was disabled - if (data_mask & mask[i]) - { //needs to be enabled - glEnableClientState(array[i]); - } - else if (gDebugGL && glIsEnabled(array[i])) - { //needs to be disabled, make sure it was (DEBUG TEMPORARY) - if (gDebugSession) - { - error = true; - gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; - } - else - { - llerrs << "Bad client state! " << array[i] << " enabled." << llendl; - } - } - } - } - - U32 map_tc[] = - { - MAP_TEXCOORD1, - MAP_TEXCOORD2, - MAP_TEXCOORD3 - }; - - for (U32 i = 0; i < 3; i++) - { - if (sLastMask & map_tc[i]) - { - if (!(data_mask & map_tc[i])) - { //disable - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - else if (data_mask & map_tc[i]) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - - if (sLastMask & MAP_BINORMAL) - { - if (!(data_mask & MAP_BINORMAL)) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - else if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - - sLastMask = data_mask; - } -} - -//static -void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - gGL.syncMatrices(); - - U32 count = pos.size(); - llassert_always(norm.size() >= pos.size()); - llassert_always(count > 0); - - unbind(); - - setupClientArrays(MAP_VERTEX | MAP_NORMAL); - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); - } - loc = LLVertexBuffer::TYPE_NORMAL; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); - } - } - else - { - glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); - glNormalPointer(GL_FLOAT, 0, norm[0].mV); - } - - glDrawArrays(sGLMode[mode], 0, count); -} - -//static -void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - - gGL.syncMatrices(); - - U32 mask = LLVertexBuffer::MAP_VERTEX; - if (tc) - { - mask = mask | LLVertexBuffer::MAP_TEXCOORD0; - } - - unbind(); - - setupClientArrays(mask); - - if (LLGLSLShader::sNoFixedFunction) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); - - if (tc) - { - loc = LLVertexBuffer::TYPE_TEXCOORD0; - glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); - } - } - else - { - glTexCoordPointer(2, GL_FLOAT, 0, tc); - glVertexPointer(3, GL_FLOAT, 16, pos); - } - - glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); -} - -void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const -{ - if (start >= (U32) mNumVerts || - end >= (U32) mNumVerts) - { - llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl; - } - - llassert(mNumIndices >= 0); - - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) - { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; - } - - if (gDebugGL && !useVBOs()) - { - U16* idx = ((U16*) getIndicesPointer())+indices_offset; - for (U32 i = 0; i < count; ++i) - { - if (idx[i] < start || idx[i] > end) - { - llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; - } - } - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader && shader->mFeatures.mIndexedTextureChannels > 1) - { - LLStrider<LLVector4a> v; - //hack to get non-const reference - LLVertexBuffer* vb = (LLVertexBuffer*) this; - vb->getVertexStrider(v); - - for (U32 i = start; i < end; i++) - { - S32 idx = (S32) (v[i][3]+0.25f); - if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) - { - llerrs << "Bad texture index found in vertex data stream." << llendl; - } - } - } - } -} - -void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const -{ - validateRange(start, end, count, indices_offset); - mMappable = false; - gGL.syncMatrices(); - - llassert(mNumVerts >= 0); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLIndices != sGLRenderIndices) - { - llerrs << "Wrong index buffer bound." << llendl; - } - - if (mGLBuffer != sGLRenderBuffer) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (gDebugGL && !mGLArray && useVBOs()) - { - GLint elem = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); - - if (elem != mGLIndices) - { - llerrs << "Wrong index buffer bound!" << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - U16* idx = ((U16*) getIndicesPointer())+indices_offset; - - stop_glerror(); - glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, - idx); - stop_glerror(); - placeFence(); -} - -void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - mMappable = false; - gGL.syncMatrices(); - - llassert(mNumIndices >= 0); - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) - { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; - } - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLIndices != sGLRenderIndices) - { - llerrs << "Wrong index buffer bound." << llendl; - } - - if (mGLBuffer != sGLRenderBuffer) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - stop_glerror(); - glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, - ((U16*) getIndicesPointer()) + indices_offset); - stop_glerror(); - placeFence(); -} - -void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - mMappable = false; - gGL.syncMatrices(); - - llassert(mNumVerts >= 0); - if (first >= (U32) mNumVerts || - first + count > (U32) mNumVerts) - { - llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; - } - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - stop_glerror(); - glDrawArrays(sGLMode[mode], first, count); - stop_glerror(); - placeFence(); -} - -//static -void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) -{ - sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject; - sDisableVBOMapping = sEnableVBOs && no_vbo_mapping; - - if (!sPrivatePoolp) - { - sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC); - } -} - -//static -void LLVertexBuffer::unbind() -{ - if (sGLRenderArray) - { -#if GL_ARB_vertex_array_object - glBindVertexArray(0); -#endif - sGLRenderArray = 0; - sGLRenderIndices = 0; - sIBOActive = false; - } - - if (sVBOActive) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - sVBOActive = false; - } - if (sIBOActive) - { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - sIBOActive = false; - } - - sGLRenderBuffer = 0; - sGLRenderIndices = 0; - - setupClientArrays(0); -} - -//static -void LLVertexBuffer::cleanupClass() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); - unbind(); - - sStreamIBOPool.cleanup(); - sDynamicIBOPool.cleanup(); - sStreamVBOPool.cleanup(); - sDynamicVBOPool.cleanup(); - - if(sPrivatePoolp) - { - LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp); - sPrivatePoolp = NULL; - } -} - -//---------------------------------------------------------------------------- - -S32 LLVertexBuffer::determineUsage(S32 usage) -{ - S32 ret_usage = usage; - - if (!sEnableVBOs) - { - ret_usage = 0; - } - - if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) - { - ret_usage = 0; - } - - if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw) - { - ret_usage = GL_STREAM_DRAW_ARB; - } - - if (ret_usage == 0 && LLRender::sGLCoreProfile) - { //MUST use VBOs for all rendering - ret_usage = GL_STREAM_DRAW_ARB; - } - - if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB) - { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default - if (sDisableVBOMapping) - { //always use stream draw if VBO mapping is disabled - ret_usage = GL_STREAM_DRAW_ARB; - } - else - { - ret_usage = GL_DYNAMIC_DRAW_ARB; - } - } - - return ret_usage; -} - -LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : - LLRefCount(), - - mNumVerts(0), - mNumIndices(0), - mAlignedOffset(0), - mAlignedIndexOffset(0), - mSize(0), - mIndicesSize(0), - mTypeMask(typemask), - mUsage(LLVertexBuffer::determineUsage(usage)), - mGLBuffer(0), - mGLIndices(0), - mGLArray(0), - mMappedData(NULL), - mMappedIndexData(NULL), - mMappedDataUsingVBOs(false), - mMappedIndexDataUsingVBOs(false), - mVertexLocked(false), - mIndexLocked(false), - mFinal(false), - mEmpty(true), - mMappable(false), - mFence(NULL) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); - - mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping); - - //zero out offsets - for (U32 i = 0; i < TYPE_MAX; i++) - { - mOffsets[i] = 0; - } - - sCount++; -} - -//static -S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) -{ - S32 offset = 0; - for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - if (offsets && LLVertexBuffer::sTypeSize[i]) - { - offsets[i] = offset; - offset += LLVertexBuffer::sTypeSize[i]*num_vertices; - offset = (offset + 0xF) & ~0xF; - } - } - } - - offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; - - return offset+16; -} - -//static -S32 LLVertexBuffer::calcVertexSize(const U32& typemask) -{ - S32 size = 0; - for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - size += LLVertexBuffer::sTypeSize[i]; - } - } - - return size; -} - -S32 LLVertexBuffer::getSize() const -{ - return mSize; -} - -// protected, use unref() -//virtual -LLVertexBuffer::~LLVertexBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR); - destroyGLBuffer(); - destroyGLIndices(); - - if (mGLArray) - { -#if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); -#endif - } - - sCount--; - - if (mFence) - { - delete mFence; - } - - mFence = NULL; - - llassert_always(!mMappedData && !mMappedIndexData); -}; - -void LLVertexBuffer::placeFence() const -{ - /*if (!mFence && useVBOs()) - { - if (gGLManager.mHasSync) - { - mFence = new LLGLSyncFence(); - } - } - - if (mFence) - { - mFence->placeFence(); - }*/ -} - -void LLVertexBuffer::waitFence() const -{ - /*if (mFence) - { - mFence->wait(); - }*/ -} - -//---------------------------------------------------------------------------- - -void LLVertexBuffer::genBuffer(U32 size) -{ - mSize = nhpo2(size); - - if (mUsage == GL_STREAM_DRAW_ARB) - { - mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize); - } - else - { - mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); - } - - sGLCount++; -} - -void LLVertexBuffer::genIndices(U32 size) -{ - mIndicesSize = nhpo2(size); - - if (mUsage == GL_STREAM_DRAW_ARB) - { - mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize); - } - else - { - mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize); - } - - sGLCount++; -} - -void LLVertexBuffer::releaseBuffer() -{ - if (mUsage == GL_STREAM_DRAW_ARB) - { - sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); - } - else - { - sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); - } - - mGLBuffer = 0; - mMappedData = NULL; - - sGLCount--; -} - -void LLVertexBuffer::releaseIndices() -{ - if (mUsage == GL_STREAM_DRAW_ARB) - { - sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); - } - else - { - sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); - } - - mGLIndices = 0; - mMappedIndexData = NULL; - - sGLCount--; -} - -void LLVertexBuffer::createGLBuffer(U32 size) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES); - - if (mGLBuffer) - { - destroyGLBuffer(); - } - - if (size == 0) - { - return; - } - - mEmpty = true; - - mMappedDataUsingVBOs = useVBOs(); - - if (mMappedDataUsingVBOs) - { - genBuffer(size); - } - else - { - static int gl_buffer_idx = 0; - mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); - mSize = size; - } -} - -void LLVertexBuffer::createGLIndices(U32 size) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES); - - if (mGLIndices) - { - destroyGLIndices(); - } - - if (size == 0) - { - return; - } - - mEmpty = true; - - //pad by 16 bytes for aligned copies - size += 16; - - mMappedIndexDataUsingVBOs = useVBOs(); - - if (mMappedIndexDataUsingVBOs) - { - //pad by another 16 bytes for VBO pointer adjustment - size += 16; - genIndices(size); - } - else - { - mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); - static int gl_buffer_idx = 0; - mGLIndices = ++gl_buffer_idx; - mIndicesSize = size; - } -} - -void LLVertexBuffer::destroyGLBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER); - if (mGLBuffer) - { - if (mMappedDataUsingVBOs) - { - releaseBuffer(); - } - else - { - FREE_MEM(sPrivatePoolp, (void*) mMappedData); - mMappedData = NULL; - mEmpty = true; - } - } - - mGLBuffer = 0; - //unbind(); -} - -void LLVertexBuffer::destroyGLIndices() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES); - if (mGLIndices) - { - if (mMappedIndexDataUsingVBOs) - { - releaseIndices(); - } - else - { - FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData); - mMappedIndexData = NULL; - mEmpty = true; - } - } - - mGLIndices = 0; - //unbind(); -} - -void LLVertexBuffer::updateNumVerts(S32 nverts) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); - - llassert(nverts >= 0); - - if (nverts >= 65535) - { - llwarns << "Vertex buffer overflow!" << llendl; - nverts = 65535; - } - - U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); - - if (needed_size > mSize || needed_size <= mSize/2) - { - createGLBuffer(needed_size); - } - - mNumVerts = nverts; -} - -void LLVertexBuffer::updateNumIndices(S32 nindices) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); - - llassert(nindices >= 0); - - U32 needed_size = sizeof(U16) * nindices; - - if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2) - { - createGLIndices(needed_size); - } - - mNumIndices = nindices; -} - -void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); - - stop_glerror(); - - if (nverts < 0 || nindices < 0 || - nverts > 65536) - { - llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; - } - - updateNumVerts(nverts); - updateNumIndices(nindices); - - if (create && (nverts || nindices)) - { - //actually allocate space for the vertex buffer if using VBO mapping - flush(); - - if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) - { -#if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); -#endif - setupVertexArray(); - } - } -} - -static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); - -void LLVertexBuffer::setupVertexArray() -{ - if (!mGLArray) - { - return; - } - - LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); -#if GL_ARB_vertex_array_object - glBindVertexArray(mGLArray); -#endif - sGLRenderArray = mGLArray; - - U32 attrib_size[] = - { - 3, //TYPE_VERTEX, - 3, //TYPE_NORMAL, - 2, //TYPE_TEXCOORD0, - 2, //TYPE_TEXCOORD1, - 2, //TYPE_TEXCOORD2, - 2, //TYPE_TEXCOORD3, - 4, //TYPE_COLOR, - 4, //TYPE_EMISSIVE, - 3, //TYPE_BINORMAL, - 1, //TYPE_WEIGHT, - 4, //TYPE_WEIGHT4, - 4, //TYPE_CLOTHWEIGHT, - 1, //TYPE_TEXTURE_INDEX - }; - - U32 attrib_type[] = - { - GL_FLOAT, //TYPE_VERTEX, - GL_FLOAT, //TYPE_NORMAL, - GL_FLOAT, //TYPE_TEXCOORD0, - GL_FLOAT, //TYPE_TEXCOORD1, - GL_FLOAT, //TYPE_TEXCOORD2, - GL_FLOAT, //TYPE_TEXCOORD3, - GL_UNSIGNED_BYTE, //TYPE_COLOR, - GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, - GL_FLOAT, //TYPE_BINORMAL, - GL_FLOAT, //TYPE_WEIGHT, - GL_FLOAT, //TYPE_WEIGHT4, - GL_FLOAT, //TYPE_CLOTHWEIGHT, - GL_FLOAT, //TYPE_TEXTURE_INDEX - }; - - U32 attrib_normalized[] = - { - GL_FALSE, //TYPE_VERTEX, - GL_FALSE, //TYPE_NORMAL, - GL_FALSE, //TYPE_TEXCOORD0, - GL_FALSE, //TYPE_TEXCOORD1, - GL_FALSE, //TYPE_TEXCOORD2, - GL_FALSE, //TYPE_TEXCOORD3, - GL_TRUE, //TYPE_COLOR, - GL_TRUE, //TYPE_EMISSIVE, - GL_FALSE, //TYPE_BINORMAL, - GL_FALSE, //TYPE_WEIGHT, - GL_FALSE, //TYPE_WEIGHT4, - GL_FALSE, //TYPE_CLOTHWEIGHT, - GL_FALSE, //TYPE_TEXTURE_INDEX - }; - - bindGLBuffer(true); - bindGLIndices(true); - - for (U32 i = 0; i < TYPE_MAX; ++i) - { - if (mTypeMask & (1 << i)) - { - glEnableVertexAttribArrayARB(i); - glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); - } - else - { - glDisableVertexAttribArrayARB(i); - } - } - - //draw a dummy triangle to set index array pointer - //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL); - - unbind(); -} - -void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) -{ - llassert(newnverts >= 0); - llassert(newnindices >= 0); - - LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); - - updateNumVerts(newnverts); - updateNumIndices(newnindices); - - if (useVBOs()) - { - flush(); - - if (mGLArray) - { //if size changed, offsets changed - setupVertexArray(); - } - } -} - -bool LLVertexBuffer::useVBOs() const -{ - //it's generally ineffective to use VBO for things that are streaming on apple - return (mUsage != 0); -} - -//---------------------------------------------------------------------------- - -bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) -{ - S32 end = index+count; - S32 region_end = region.mIndex+region.mCount; - - if (end < region.mIndex || - index > region_end) - { //gap exists, do not merge - return false; - } - - S32 new_end = llmax(end, region_end); - S32 new_index = llmin(index, region.mIndex); - region.mIndex = new_index; - region.mCount = new_end-new_index; - return true; -} - -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); - -// Map for data access -volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) -{ - bindGLBuffer(true); - LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); - if (mFinal) - { - llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl; - } - if (!useVBOs() && !mMappedData && !mMappedIndexData) - { - llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl; - } - - if (useVBOs()) - { - if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (count == -1) - { - count = mNumVerts-index; - } - - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - MappedRegion& region = mMappedVertexRegions[i]; - if (region.mType == type) - { - if (expand_region(region, index, count)) - { - mapped = true; - break; - } - } - } - - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(type, mMappable && map_range ? -1 : index, count); - mMappedVertexRegions.push_back(region); - } - } - - if (mVertexLocked && map_range) - { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; - } - - if (!mVertexLocked) - { - LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); - mVertexLocked = true; - sMappedCount++; - stop_glerror(); - - if(!mMappable) - { - map_range = false; - } - else - { - volatile U8* src = NULL; - waitFence(); - if (gGLManager.mHasMapBufferRange) - { - if (map_range) - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE); - S32 offset = mOffsets[type] + sTypeSize[type]*index; - S32 length = (sTypeSize[type]*count+0xF) & ~0xF; - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_INVALIDATE_RANGE_BIT); -#endif - } - else - { -#ifdef GL_ARB_map_buffer_range - - if (gDebugGL) - { - GLint size = 0; - glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); - - if (size < mSize) - { - llerrs << "Invalid buffer size." << llendl; - } - } - - LLFastTimer t(FTM_VBO_MAP_BUFFER); - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT); -#endif - } - } - else if (gGLManager.mHasFlushBufferRange) - { - if (map_range) - { - glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); - glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - else - { - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - } - else - { - map_range = false; - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - - llassert(src != NULL); - - mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src); - mAlignedOffset = mMappedData - src; - - stop_glerror(); - } - - if (!mMappedData) - { - log_glerror(); - - //check the availability of memory - LLMemory::logMemoryInfo(true); - - if(mMappable) - { - //-------------------- - //print out more debug info before crash - llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl; - GLint size; - glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); - llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl; - //-------------------- - - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - - - llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; - } - else - { - llerrs << "memory allocation for vertex data failed." << llendl; - } - } - } - } - else - { - map_range = false; - } - - if (map_range && gGLManager.mHasMapBufferRange && mMappable) - { - return mMappedData; - } - else - { - return mMappedData+mOffsets[type]+sTypeSize[type]*index; - } -} - - -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); - -volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); - bindGLIndices(true); - if (mFinal) - { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; - } - if (!useVBOs() && !mMappedData && !mMappedIndexData) - { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl; - } - - if (useVBOs()) - { - if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (count == -1) - { - count = mNumIndices-index; - } - - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - MappedRegion& region = mMappedIndexRegions[i]; - if (expand_region(region, index, count)) - { - mapped = true; - break; - } - } - - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); - mMappedIndexRegions.push_back(region); - } - } - - if (mIndexLocked && map_range) - { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; - } - - if (!mIndexLocked) - { - LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); - - mIndexLocked = true; - sMappedCount++; - stop_glerror(); - - if (gDebugGL && useVBOs()) - { - GLint elem = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); - - if (elem != mGLIndices) - { - llerrs << "Wrong index buffer bound!" << llendl; - } - } - - if(!mMappable) - { - map_range = false; - } - else - { - volatile U8* src = NULL; - waitFence(); - if (gGLManager.mHasMapBufferRange) - { - if (map_range) - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE); - S32 offset = sizeof(U16)*index; - S32 length = sizeof(U16)*count; - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_INVALIDATE_RANGE_BIT); -#endif - } - else - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX); - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT); -#endif - } - } - else if (gGLManager.mHasFlushBufferRange) - { - if (map_range) - { - glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); - glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - else - { - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - } - else - { - LLFastTimer t(FTM_VBO_MAP_INDEX); - map_range = false; - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - - llassert(src != NULL); - - - mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src); - mAlignedIndexOffset = mMappedIndexData - src; - stop_glerror(); - } - } - - if (!mMappedIndexData) - { - log_glerror(); - LLMemory::logMemoryInfo(true); - - if(mMappable) - { - GLint buff; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - - llerrs << "glMapBuffer returned NULL (no index data)" << llendl; - } - else - { - llerrs << "memory allocation for Index data failed. " << llendl; - } - } - } - else - { - map_range = false; - } - - if (map_range && gGLManager.mHasMapBufferRange && mMappable) - { - return mMappedIndexData; - } - else - { - return mMappedIndexData + sizeof(U16)*index; - } -} - -static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap"); -static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range"); - - -static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap"); -static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range"); - -void LLVertexBuffer::unmapBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); - if (!useVBOs()) - { - return; //nothing to unmap - } - - bool updated_all = false; - - if (mMappedData && mVertexLocked) - { - LLFastTimer t(FTM_VBO_UNMAP); - bindGLBuffer(true); - updated_all = mIndexLocked; //both vertex and index buffers done updating - - if(!mMappable) - { - if (!mMappedVertexRegions.empty()) - { - stop_glerror(); - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); - stop_glerror(); - } - - mMappedVertexRegions.clear(); - } - else - { - stop_glerror(); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); - stop_glerror(); - } - } - else - { - if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (!mMappedVertexRegions.empty()) - { - stop_glerror(); - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; - if (gGLManager.mHasMapBufferRange) - { - LLFastTimer t(FTM_VBO_FLUSH_RANGE); -#ifdef GL_ARB_map_buffer_range - glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); -#endif - } - else if (gGLManager.mHasFlushBufferRange) - { - glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); - } - stop_glerror(); - } - - mMappedVertexRegions.clear(); - } - } - stop_glerror(); - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - stop_glerror(); - - mMappedData = NULL; - } - - mVertexLocked = false; - sMappedCount--; - } - - if (mMappedIndexData && mIndexLocked) - { - LLFastTimer t(FTM_IBO_UNMAP); - bindGLIndices(); - if(!mMappable) - { - if (!mMappedIndexRegions.empty()) - { - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); - stop_glerror(); - } - - mMappedIndexRegions.clear(); - } - else - { - stop_glerror(); - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); - stop_glerror(); - } - } - else - { - if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (!mMappedIndexRegions.empty()) - { - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; - if (gGLManager.mHasMapBufferRange) - { - LLFastTimer t(FTM_IBO_FLUSH_RANGE); -#ifdef GL_ARB_map_buffer_range - glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); -#endif - } - else if (gGLManager.mHasFlushBufferRange) - { -#ifdef GL_APPLE_flush_buffer_range - glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); -#endif - } - stop_glerror(); - } - - mMappedIndexRegions.clear(); - } - } - stop_glerror(); - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); - stop_glerror(); - - mMappedIndexData = NULL; - } - - mIndexLocked = false; - sMappedCount--; - } - - if(updated_all) - { - mEmpty = false; - } -} - -//---------------------------------------------------------------------------- - -template <class T,S32 type> struct VertexBufferStrider -{ - typedef LLStrider<T> strider_t; - static bool get(LLVertexBuffer& vbo, - strider_t& strider, - S32 index, S32 count, bool map_range) - { - if (type == LLVertexBuffer::TYPE_INDEX) - { - volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); - - if (ptr == NULL) - { - llwarns << "mapIndexBuffer failed!" << llendl; - return false; - } - - strider = (T*)ptr; - strider.setStride(0); - return true; - } - else if (vbo.hasDataType(type)) - { - S32 stride = LLVertexBuffer::sTypeSize[type]; - - volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); - - if (ptr == NULL) - { - llwarns << "mapVertexBuffer failed!" << llendl; - return false; - } - - strider = (T*)ptr; - strider.setStride(stride); - return true; - } - else - { - llerrs << "VertexBufferStrider could not find valid vertex data." << llendl; - } - return false; - } -}; - -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range); -} - -//---------------------------------------------------------------------------- - -static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); -bool LLVertexBuffer::bindGLArray() -{ - if (mGLArray && sGLRenderArray != mGLArray) - { - { - LLFastTimer t(FTM_BIND_GL_ARRAY); -#if GL_ARB_vertex_array_object - glBindVertexArray(mGLArray); -#endif - sGLRenderArray = mGLArray; - } - - //really shouldn't be necessary, but some drivers don't properly restore the - //state of GL_ELEMENT_ARRAY_BUFFER_BINDING - bindGLIndices(); - - return true; - } - - return false; -} - -static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); - -bool LLVertexBuffer::bindGLBuffer(bool force_bind) -{ - bindGLArray(); - - bool ret = false; - - if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) - { - LLFastTimer t(FTM_BIND_GL_BUFFER); - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); - sGLRenderBuffer = mGLBuffer; - sBindCount++; - sVBOActive = true; - - if (mGLArray) - { - llassert(sGLRenderArray == mGLArray); - //mCachedRenderBuffer = mGLBuffer; - } - - ret = true; - } - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); - -bool LLVertexBuffer::bindGLIndices(bool force_bind) -{ - bindGLArray(); - - bool ret = false; - if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) - { - LLFastTimer t(FTM_BIND_GL_INDICES); - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); - sGLRenderIndices = mGLIndices; - stop_glerror(); - sBindCount++; - sIBOActive = true; - ret = true; - } - - return ret; -} - -void LLVertexBuffer::flush() -{ - if (useVBOs()) - { - unmapBuffer(); - } -} - -// Set for rendering -void LLVertexBuffer::setBuffer(U32 data_mask) -{ - flush(); - - LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER); - //set up pointers if the data mask is different ... - bool setup = (sLastMask != data_mask); - - if (gDebugGL && data_mask != 0) - { //make sure data requirements are fulfilled - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - U32 required_mask = 0; - for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i) - { - if (shader->getAttribLocation(i) > -1) - { - U32 required = 1 << i; - if ((data_mask & required) == 0) - { - llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl; - } - - required_mask |= required; - } - } - - if ((data_mask & required_mask) != required_mask) - { - llerrs << "Shader consumption mismatches data provision." << llendl; - } - } - } - - if (useVBOs()) - { - if (mGLArray) - { - bindGLArray(); - setup = false; //do NOT perform pointer setup if using VAO - } - else - { - const bool bindBuffer = bindGLBuffer(); - const bool bindIndices = bindGLIndices(); - - setup = setup || bindBuffer || bindIndices; - } - - bool error = false; - if (gDebugGL && !mGLArray) - { - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - if (gDebugSession) - { - error = true; - gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl; - } - else - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - } - - if (mGLIndices) - { - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - if (gDebugSession) - { - error = true; - gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; - } - else - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - } - } - } - - - } - else - { - if (sGLRenderArray) - { -#if GL_ARB_vertex_array_object - glBindVertexArray(0); -#endif - sGLRenderArray = 0; - sGLRenderIndices = 0; - sIBOActive = false; - } - - if (mGLBuffer) - { - if (sVBOActive) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - sBindCount++; - sVBOActive = false; - setup = true; // ... or a VBO is deactivated - } - if (sGLRenderBuffer != mGLBuffer) - { - sGLRenderBuffer = mGLBuffer; - setup = true; // ... or a client memory pointer changed - } - } - if (mGLIndices) - { - if (sIBOActive) - { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - sBindCount++; - sIBOActive = false; - } - - sGLRenderIndices = mGLIndices; - } - } - - if (!mGLArray) - { - setupClientArrays(data_mask); - } - - if (mGLBuffer) - { - if (data_mask && setup) - { - setupVertexBuffer(data_mask); // subclass specific setup (virtual function) - sSetCount++; - } - } -} - -// virtual (default) -void LLVertexBuffer::setupVertexBuffer(U32 data_mask) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); - stop_glerror(); - volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - - /*if ((data_mask & mTypeMask) != data_mask) - { - llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; - }*/ - - if (LLGLSLShader::sNoFixedFunction) - { - if (data_mask & MAP_NORMAL) - { - S32 loc = TYPE_NORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); - } - if (data_mask & MAP_TEXCOORD3) - { - S32 loc = TYPE_TEXCOORD3; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); - } - if (data_mask & MAP_TEXCOORD2) - { - S32 loc = TYPE_TEXCOORD2; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); - } - if (data_mask & MAP_TEXCOORD1) - { - S32 loc = TYPE_TEXCOORD1; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); - } - if (data_mask & MAP_BINORMAL) - { - S32 loc = TYPE_BINORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); - } - if (data_mask & MAP_TEXCOORD0) - { - S32 loc = TYPE_TEXCOORD0; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); - } - if (data_mask & MAP_COLOR) - { - S32 loc = TYPE_COLOR; - void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); - } - if (data_mask & MAP_EMISSIVE) - { - S32 loc = TYPE_EMISSIVE; - void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); - } - if (data_mask & MAP_WEIGHT) - { - S32 loc = TYPE_WEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); - glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); - } - if (data_mask & MAP_WEIGHT4) - { - S32 loc = TYPE_WEIGHT4; - void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); - } - if (data_mask & MAP_CLOTHWEIGHT) - { - S32 loc = TYPE_CLOTHWEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); - } - if (data_mask & MAP_TEXTURE_INDEX) - { - S32 loc = TYPE_TEXTURE_INDEX; - void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); - glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); - } - if (data_mask & MAP_VERTEX) - { - S32 loc = TYPE_VERTEX; - void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); - } - } - else - { - if (data_mask & MAP_NORMAL) - { - glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); - } - if (data_mask & MAP_TEXCOORD3) - { - glClientActiveTextureARB(GL_TEXTURE3_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD2) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD1) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD0) - { - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - } - if (data_mask & MAP_COLOR) - { - glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); - } - if (data_mask & MAP_VERTEX) - { - glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); - } - } - - llglassertok(); -} - -LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) -: mType(type), mIndex(index), mCount(count) -{ - llassert(mType == LLVertexBuffer::TYPE_INDEX || - mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); -} - - +/**
+ * @file llvertexbuffer.cpp
+ * @brief LLVertexBuffer implementation
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#include "linden_common.h"
+
+#include <boost/static_assert.hpp>
+#include "llsys.h"
+#include "llvertexbuffer.h"
+// #include "llrender.h"
+#include "llglheaders.h"
+#include "llmemtype.h"
+#include "llrender.h"
+#include "llvector4a.h"
+#include "llshadermgr.h"
+#include "llglslshader.h"
+#include "llmemory.h"
+
+//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
+U32 nhpo2(U32 v)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
+
+//============================================================================
+
+//static
+LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+U32 LLVBOPool::sBytesPooled = 0;
+
+LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
+U32 LLVertexBuffer::sBindCount = 0;
+U32 LLVertexBuffer::sSetCount = 0;
+S32 LLVertexBuffer::sCount = 0;
+S32 LLVertexBuffer::sGLCount = 0;
+S32 LLVertexBuffer::sMappedCount = 0;
+bool LLVertexBuffer::sDisableVBOMapping = false;
+bool LLVertexBuffer::sEnableVBOs = true;
+U32 LLVertexBuffer::sGLRenderBuffer = 0;
+U32 LLVertexBuffer::sGLRenderArray = 0;
+U32 LLVertexBuffer::sGLRenderIndices = 0;
+U32 LLVertexBuffer::sLastMask = 0;
+bool LLVertexBuffer::sVBOActive = false;
+bool LLVertexBuffer::sIBOActive = false;
+U32 LLVertexBuffer::sAllocatedBytes = 0;
+bool LLVertexBuffer::sMapped = false;
+bool LLVertexBuffer::sUseStreamDraw = true;
+bool LLVertexBuffer::sUseVAO = false;
+bool LLVertexBuffer::sPreferStreamDraw = false;
+
+const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
+
+class LLGLSyncFence : public LLGLFence
+{
+public:
+#ifdef GL_ARB_sync
+ GLsync mSync;
+#endif
+
+ LLGLSyncFence()
+ {
+#ifdef GL_ARB_sync
+ mSync = 0;
+#endif
+ }
+
+ virtual ~LLGLSyncFence()
+ {
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+#endif
+ }
+
+ void placeFence()
+ {
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+ mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+ }
+
+ void wait()
+ {
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
+ { //track the number of times we've waited here
+ static S32 waits = 0;
+ waits++;
+ }
+ }
+#endif
+ }
+
+
+};
+
+
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+ llassert(i > 0);
+ llassert(nhpo2(i) == i);
+
+ U32 r = 0;
+
+ while (i >>= 1) ++r;
+
+ return r;
+}
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ if (mFreeList.size() <= i)
+ {
+ mFreeList.resize(i+1);
+ }
+
+ volatile U8* ret = NULL;
+
+ if (mFreeList[i].empty())
+ {
+ //make a new buffer
+ glGenBuffersARB(1, &name);
+ glBindBufferARB(mType, name);
+ LLVertexBuffer::sAllocatedBytes += size;
+
+ if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
+ {
+ glBufferDataARB(mType, size, 0, mUsage);
+ ret = (U8*) ll_aligned_malloc_16(size);
+ }
+ else
+ { //always use a true hint of static draw when allocating non-client-backed buffers
+ glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
+ }
+
+ glBindBufferARB(mType, 0);
+ }
+ else
+ {
+ name = mFreeList[i].front().mGLName;
+ ret = mFreeList[i].front().mClientData;
+
+ sBytesPooled -= size;
+
+ mFreeList[i].pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = buffer;
+
+ if (buffer == NULL)
+
+ {
+ glDeleteBuffersARB(1, &rec.mGLName);
+ }
+ else
+ {
+ sBytesPooled += size;
+ mFreeList[i].push_back(rec);
+}
+}
+
+void LLVBOPool::cleanup()
+{
+ U32 size = 1;
+
+ for (U32 i = 0; i < mFreeList.size(); ++i)
+ {
+ record_list_t& l = mFreeList[i];
+
+ while (!l.empty())
+ {
+ Record& r = l.front();
+
+ glDeleteBuffersARB(1, &r.mGLName);
+
+ if (r.mClientData)
+ {
+ ll_aligned_free_16((void*) r.mClientData);
+ }
+
+ l.pop_front();
+
+ LLVertexBuffer::sAllocatedBytes -= size;
+ sBytesPooled -= size;
+ }
+
+ size *= 2;
+ }
+}
+
+
+//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
+S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
+{
+ sizeof(LLVector4), // TYPE_VERTEX,
+ sizeof(LLVector4), // TYPE_NORMAL,
+ sizeof(LLVector2), // TYPE_TEXCOORD0,
+ sizeof(LLVector2), // TYPE_TEXCOORD1,
+ sizeof(LLVector2), // TYPE_TEXCOORD2,
+ sizeof(LLVector2), // TYPE_TEXCOORD3,
+ sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
+ sizeof(LLVector4), // TYPE_BINORMAL,
+ sizeof(F32), // TYPE_WEIGHT,
+ sizeof(LLVector4), // TYPE_WEIGHT4,
+ sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+ sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
+};
+
+U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
+{
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN,
+ GL_POINTS,
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_QUADS,
+ GL_LINE_LOOP,
+};
+
+
+//static
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
+{
+ if (sLastMask != data_mask)
+ {
+ bool error = false;
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ S32 loc = i;
+
+ U32 mask = 1 << i;
+
+ if (sLastMask & (1 << i))
+ { //was enabled
+ if (!(data_mask & mask))
+ { //needs to be disabled
+ glDisableVertexAttribArrayARB(loc);
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask)
+ { //needs to be enabled
+ glEnableVertexAttribArrayARB(loc);
+ }
+ }
+ }
+ }
+ else
+ {
+
+ GLenum array[] =
+ {
+ GL_VERTEX_ARRAY,
+ GL_NORMAL_ARRAY,
+ GL_TEXTURE_COORD_ARRAY,
+ GL_COLOR_ARRAY,
+ };
+
+ GLenum mask[] =
+ {
+ MAP_VERTEX,
+ MAP_NORMAL,
+ MAP_TEXCOORD0,
+ MAP_COLOR
+ };
+
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ if (sLastMask & mask[i])
+ { //was enabled
+ if (!(data_mask & mask[i]))
+ { //needs to be disabled
+ glDisableClientState(array[i]);
+ }
+ else if (gDebugGL)
+ { //needs to be enabled, make sure it was (DEBUG)
+ if (!glIsEnabled(array[i]))
+ {
+ if (gDebugSession)
+ {
+ error = true;
+ gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ }
+ }
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask[i])
+ { //needs to be enabled
+ glEnableClientState(array[i]);
+ }
+ else if (gDebugGL && glIsEnabled(array[i]))
+ { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
+ if (gDebugSession)
+ {
+ error = true;
+ gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
+ }
+ }
+ }
+ }
+
+ U32 map_tc[] =
+ {
+ MAP_TEXCOORD1,
+ MAP_TEXCOORD2,
+ MAP_TEXCOORD3
+ };
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (sLastMask & map_tc[i])
+ {
+ if (!(data_mask & map_tc[i]))
+ { //disable
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+ else if (data_mask & map_tc[i])
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+
+ if (sLastMask & MAP_BINORMAL)
+ {
+ if (!(data_mask & MAP_BINORMAL))
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+ else if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+
+ sLastMask = data_mask;
+ }
+}
+
+//static
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ gGL.syncMatrices();
+
+ U32 count = pos.size();
+ llassert_always(norm.size() >= pos.size());
+ llassert_always(count > 0);
+
+ unbind();
+
+ setupClientArrays(MAP_VERTEX | MAP_NORMAL);
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
+ }
+ loc = LLVertexBuffer::TYPE_NORMAL;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
+ }
+ }
+ else
+ {
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ }
+
+ glDrawArrays(sGLMode[mode], 0, count);
+}
+
+//static
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ if (tc)
+ {
+ mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+ }
+
+ unbind();
+
+ setupClientArrays(mask);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
+
+ if (tc)
+ {
+ loc = LLVertexBuffer::TYPE_TEXCOORD0;
+ glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
+ }
+ }
+ else
+ {
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(3, GL_FLOAT, 16, pos);
+ }
+
+ glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+}
+
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ if (start >= (U32) mNumVerts ||
+ end >= (U32) mNumVerts)
+ {
+ llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
+ }
+
+ llassert(mNumIndices >= 0);
+
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
+ {
+ llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
+ }
+
+ if (gDebugGL && !useVBOs())
+ {
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+ for (U32 i = 0; i < count; ++i)
+ {
+ if (idx[i] < start || idx[i] > end)
+ {
+ llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
+ }
+ }
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
+ {
+ LLStrider<LLVector4a> v;
+ //hack to get non-const reference
+ LLVertexBuffer* vb = (LLVertexBuffer*) this;
+ vb->getVertexStrider(v);
+
+ for (U32 i = start; i < end; i++)
+ {
+ S32 idx = (S32) (v[i][3]+0.25f);
+ if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+ {
+ llerrs << "Bad texture index found in vertex data stream." << llendl;
+ }
+ }
+ }
+ }
+}
+
+void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ validateRange(start, end, count, indices_offset);
+ mMappable = false;
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (gDebugGL && !mGLArray && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+
+ stop_glerror();
+ glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
+ idx);
+ stop_glerror();
+ placeFence();
+}
+
+void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = false;
+ gGL.syncMatrices();
+
+ llassert(mNumIndices >= 0);
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
+ {
+ llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
+ }
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ stop_glerror();
+ glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
+ ((U16*) getIndicesPointer()) + indices_offset);
+ stop_glerror();
+ placeFence();
+}
+
+void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = false;
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ if (first >= (U32) mNumVerts ||
+ first + count > (U32) mNumVerts)
+ {
+ llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
+ }
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ bool uvb = useVBOs();
+ if (mGLBuffer != sGLRenderBuffer || uvb != sVBOActive)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ stop_glerror();
+ glDrawArrays(sGLMode[mode], first, count);
+ stop_glerror();
+ placeFence();
+}
+
+//static
+void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
+{
+ sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject;
+ sDisableVBOMapping = sEnableVBOs && no_vbo_mapping;
+
+ if (!sPrivatePoolp)
+ {
+ sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
+ }
+}
+
+//static
+void LLVertexBuffer::unbind()
+{
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = false;
+ }
+
+ if (sVBOActive)
+ {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ sVBOActive = false;
+ }
+ if (sIBOActive)
+ {
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sIBOActive = false;
+ }
+
+ sGLRenderBuffer = 0;
+ sGLRenderIndices = 0;
+
+ setupClientArrays(0);
+}
+
+//static
+void LLVertexBuffer::cleanupClass()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
+ unbind();
+
+ sStreamIBOPool.cleanup();
+ sDynamicIBOPool.cleanup();
+ sStreamVBOPool.cleanup();
+ sDynamicVBOPool.cleanup();
+
+ if(sPrivatePoolp)
+ {
+ LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp);
+ sPrivatePoolp = NULL;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+S32 LLVertexBuffer::determineUsage(S32 usage)
+{
+ S32 ret_usage = usage;
+
+ if (!sEnableVBOs)
+ {
+ ret_usage = 0;
+ }
+
+ if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+ {
+ ret_usage = 0;
+ }
+
+ if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
+ {
+ ret_usage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (ret_usage == 0 && LLRender::sGLCoreProfile)
+ { //MUST use VBOs for all rendering
+ ret_usage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
+ { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+ if (sDisableVBOMapping)
+ { //always use stream draw if VBO mapping is disabled
+ ret_usage = GL_STREAM_DRAW_ARB;
+ }
+ else
+ {
+ret_usage = GL_DYNAMIC_DRAW_ARB;
+
+ }
+ }
+
+ return ret_usage;
+}
+
+LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
+ LLRefCount(),
+
+ mNumVerts(0),
+ mNumIndices(0),
+ mAlignedOffset(0),
+ mAlignedIndexOffset(0),
+ mSize(0),
+ mIndicesSize(0),
+ mTypeMask(typemask),
+ mUsage(LLVertexBuffer::determineUsage(usage)),
+ mGLBuffer(0),
+ mGLIndices(0),
+ mGLArray(0),
+ mMappedData(NULL),
+ mMappedIndexData(NULL),
+ mMappedDataUsingVBOs(false),
+ mMappedIndexDataUsingVBOs(false),
+ mVertexLocked(false),
+ mIndexLocked(false),
+ mFinal(false),
+ mEmpty(true),
+ mMappable(false),
+ mFence(NULL)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
+
+ mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
+
+ //zero out offsets
+ for (U32 i = 0; i < TYPE_MAX; i++)
+ {
+ mOffsets[i] = 0;
+ }
+
+ sCount++;
+}
+
+//static
+S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
+{
+ S32 offset = 0;
+ for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ if (offsets && LLVertexBuffer::sTypeSize[i])
+ {
+ offsets[i] = offset;
+ offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
+ offset = (offset + 0xF) & ~0xF;
+ }
+ }
+ }
+
+ offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
+
+ return offset+16;
+}
+
+//static
+S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
+{
+ S32 size = 0;
+ for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ size += LLVertexBuffer::sTypeSize[i];
+ }
+ }
+
+ return size;
+}
+
+S32 LLVertexBuffer::getSize() const
+{
+ return mSize;
+}
+
+// protected, use unref()
+//virtual
+LLVertexBuffer::~LLVertexBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
+ destroyGLBuffer();
+ destroyGLIndices();
+
+ if (mGLArray)
+ {
+#if GL_ARB_vertex_array_object
+ glDeleteVertexArrays(1, &mGLArray);
+#endif
+ }
+
+ sCount--;
+
+ if (mFence)
+ {
+ delete mFence;
+ }
+
+ mFence = NULL;
+
+ llassert_always(!mMappedData && !mMappedIndexData);
+};
+
+void LLVertexBuffer::placeFence() const
+{
+ /*if (!mFence && useVBOs())
+ {
+ if (gGLManager.mHasSync)
+ {
+ mFence = new LLGLSyncFence();
+ }
+ }
+
+ if (mFence)
+ {
+ mFence->placeFence();
+ }*/
+}
+
+void LLVertexBuffer::waitFence() const
+{
+ /*if (mFence)
+ {
+ mFence->wait();
+ }*/
+}
+
+//----------------------------------------------------------------------------
+
+void LLVertexBuffer::genBuffer(U32 size)
+{
+ mSize = nhpo2(size);
+
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
+ }
+ else
+ {
+ mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
+ }
+
+ sGLCount++;
+}
+
+void LLVertexBuffer::genIndices(U32 size)
+{
+ mIndicesSize = nhpo2(size);
+
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize);
+ }
+ else
+ {
+ mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize);
+ }
+
+ sGLCount++;
+}
+
+void LLVertexBuffer::releaseBuffer()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamVBOPool.release(mGLBuffer, mMappedData, mSize);
+ }
+ else
+ {
+ sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize);
+ }
+
+ mGLBuffer = 0;
+ mMappedData = NULL;
+
+ sGLCount--;
+}
+
+void LLVertexBuffer::releaseIndices()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
+ }
+ else
+ {
+ sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
+ }
+
+ mGLIndices = 0;
+ mMappedIndexData = NULL;
+
+ sGLCount--;
+}
+
+void LLVertexBuffer::createGLBuffer(U32 size)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
+
+ if (mGLBuffer)
+ {
+ destroyGLBuffer();
+ }
+
+ if (size == 0)
+ {
+ return;
+ }
+
+ mEmpty = true;
+
+ mMappedDataUsingVBOs = useVBOs();
+
+ if (mMappedDataUsingVBOs)
+ {
+ genBuffer(size);
+ }
+ else
+ {
+ static int gl_buffer_idx = 0;
+ mGLBuffer = ++gl_buffer_idx;
+ mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
+ mSize = size;
+ }
+}
+
+void LLVertexBuffer::createGLIndices(U32 size)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
+
+ if (mGLIndices)
+ {
+ destroyGLIndices();
+ }
+
+ if (size == 0)
+ {
+ return;
+ }
+
+ mEmpty = true;
+
+ //pad by 16 bytes for aligned copies
+ size += 16;
+
+ mMappedIndexDataUsingVBOs = useVBOs();
+
+ if (mMappedIndexDataUsingVBOs)
+ {
+ //pad by another 16 bytes for VBO pointer adjustment
+ size += 16;
+ genIndices(size);
+ }
+ else
+ {
+ mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
+ static int gl_buffer_idx = 0;
+ mGLIndices = ++gl_buffer_idx;
+ mIndicesSize = size;
+ }
+}
+
+void LLVertexBuffer::destroyGLBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
+ if (mGLBuffer)
+ {
+ if (mMappedDataUsingVBOs)
+ {
+ releaseBuffer();
+ }
+ else
+ {
+ FREE_MEM(sPrivatePoolp, (void*) mMappedData);
+ mMappedData = NULL;
+ mEmpty = true;
+ }
+ }
+
+ mGLBuffer = 0;
+ //unbind();
+}
+
+void LLVertexBuffer::destroyGLIndices()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
+ if (mGLIndices)
+ {
+ if (mMappedIndexDataUsingVBOs)
+ {
+ releaseIndices();
+ }
+ else
+ {
+ FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData);
+ mMappedIndexData = NULL;
+ mEmpty = true;
+ }
+ }
+
+ mGLIndices = 0;
+ //unbind();
+}
+
+void LLVertexBuffer::updateNumVerts(S32 nverts)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
+
+ llassert(nverts >= 0);
+
+ if (nverts >= 65535)
+ {
+ llwarns << "Vertex buffer overflow!" << llendl;
+ nverts = 65535;
+ }
+
+ U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
+
+ if (needed_size > mSize || needed_size <= mSize/2)
+ {
+ createGLBuffer(needed_size);
+ }
+
+ mNumVerts = nverts;
+}
+
+void LLVertexBuffer::updateNumIndices(S32 nindices)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
+
+ llassert(nindices >= 0);
+
+ U32 needed_size = sizeof(U16) * nindices;
+
+ if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
+ {
+ createGLIndices(needed_size);
+ }
+
+ mNumIndices = nindices;
+}
+
+void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
+
+ stop_glerror();
+
+ if (nverts < 0 || nindices < 0 ||
+ nverts > 65536)
+ {
+ llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
+ }
+
+ updateNumVerts(nverts);
+ updateNumIndices(nindices);
+
+ if (create && (nverts || nindices))
+ {
+ //actually allocate space for the vertex buffer if using VBO mapping
+ flush();
+
+ if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
+ {
+#if GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &mGLArray);
+#endif
+ setupVertexArray();
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO");
+
+void LLVertexBuffer::setupVertexArray()
+{
+ if (!mGLArray)
+ {
+ return;
+ }
+
+ LLFastTimer t(FTM_SETUP_VERTEX_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+
+ U32 attrib_size[] =
+ {
+ 3, //TYPE_VERTEX,
+ 3, //TYPE_NORMAL,
+ 2, //TYPE_TEXCOORD0,
+ 2, //TYPE_TEXCOORD1,
+ 2, //TYPE_TEXCOORD2,
+ 2, //TYPE_TEXCOORD3,
+ 4, //TYPE_COLOR,
+ 4, //TYPE_EMISSIVE,
+ 3, //TYPE_BINORMAL,
+ 1, //TYPE_WEIGHT,
+ 4, //TYPE_WEIGHT4,
+ 4, //TYPE_CLOTHWEIGHT,
+ 1, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_type[] =
+ {
+ GL_FLOAT, //TYPE_VERTEX,
+ GL_FLOAT, //TYPE_NORMAL,
+ GL_FLOAT, //TYPE_TEXCOORD0,
+ GL_FLOAT, //TYPE_TEXCOORD1,
+ GL_FLOAT, //TYPE_TEXCOORD2,
+ GL_FLOAT, //TYPE_TEXCOORD3,
+ GL_UNSIGNED_BYTE, //TYPE_COLOR,
+ GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
+ GL_FLOAT, //TYPE_BINORMAL,
+ GL_FLOAT, //TYPE_WEIGHT,
+ GL_FLOAT, //TYPE_WEIGHT4,
+ GL_FLOAT, //TYPE_CLOTHWEIGHT,
+ GL_FLOAT, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_normalized[] =
+ {
+ GL_FALSE, //TYPE_VERTEX,
+ GL_FALSE, //TYPE_NORMAL,
+ GL_FALSE, //TYPE_TEXCOORD0,
+ GL_FALSE, //TYPE_TEXCOORD1,
+ GL_FALSE, //TYPE_TEXCOORD2,
+ GL_FALSE, //TYPE_TEXCOORD3,
+ GL_TRUE, //TYPE_COLOR,
+ GL_TRUE, //TYPE_EMISSIVE,
+ GL_FALSE, //TYPE_BINORMAL,
+ GL_FALSE, //TYPE_WEIGHT,
+ GL_FALSE, //TYPE_WEIGHT4,
+ GL_FALSE, //TYPE_CLOTHWEIGHT,
+ GL_FALSE, //TYPE_TEXTURE_INDEX
+ };
+
+ bindGLBuffer(true);
+ bindGLIndices(true);
+
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ if (mTypeMask & (1 << i))
+ {
+ glEnableVertexAttribArrayARB(i);
+ glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);
+ }
+ else
+ {
+ glDisableVertexAttribArrayARB(i);
+ }
+ }
+
+ //draw a dummy triangle to set index array pointer
+ //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL);
+
+ unbind();
+}
+
+void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
+{
+ llassert(newnverts >= 0);
+ llassert(newnindices >= 0);
+
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
+
+ updateNumVerts(newnverts);
+ updateNumIndices(newnindices);
+
+ if (useVBOs())
+ {
+ flush();
+
+ if (mGLArray)
+ { //if size changed, offsets changed
+ setupVertexArray();
+ }
+ }
+}
+
+bool LLVertexBuffer::useVBOs() const
+{
+ //it's generally ineffective to use VBO for things that are streaming on apple
+ return (mUsage != 0);
+}
+
+//----------------------------------------------------------------------------
+
+bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
+{
+ S32 end = index+count;
+ S32 region_end = region.mIndex+region.mCount;
+
+ if (end < region.mIndex ||
+ index > region_end)
+ { //gap exists, do not merge
+ return false;
+ }
+
+ S32 new_end = llmax(end, region_end);
+ S32 new_index = llmin(index, region.mIndex);
+ region.mIndex = new_index;
+ region.mCount = new_end-new_index;
+ return true;
+}
+
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
+
+// Map for data access
+volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+{
+ bindGLBuffer(true);
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ if (mFinal)
+ {
+ llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
+ }
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
+ {
+ llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;
+ }
+
+ if (useVBOs())
+ {
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (count == -1)
+ {
+ count = mNumVerts-index;
+ }
+
+ bool mapped = false;
+ //see if range is already mapped
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedVertexRegions[i];
+ if (region.mType == type)
+ {
+ if (expand_region(region, index, count))
+ {
+ mapped = true;
+ break;
+ }
+ }
+ }
+
+ if (!mapped)
+ {
+ //not already mapped, map new region
+ MappedRegion region(type, mMappable && map_range ? -1 : index, count);
+ mMappedVertexRegions.push_back(region);
+ }
+ }
+
+ if (mVertexLocked && map_range)
+ {
+ llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
+ }
+
+ if (!mVertexLocked)
+ {
+ LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
+ mVertexLocked = true;
+ sMappedCount++;
+ stop_glerror();
+
+ if(!mMappable)
+ {
+ map_range = false;
+ }
+ else
+ {
+ volatile U8* src = NULL;
+ waitFence();
+ if (gGLManager.mHasMapBufferRange)
+ {
+ if (map_range)
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE);
+ S32 offset = mOffsets[type] + sTypeSize[type]*index;
+ S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
+ src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
+ }
+ else
+ {
+#ifdef GL_ARB_map_buffer_range
+
+ if (gDebugGL)
+ {
+ GLint size = 0;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+
+ if (size < mSize)
+ {
+ llerrs << "Invalid buffer size." << llendl;
+ }
+ }
+
+ LLFastTimer t(FTM_VBO_MAP_BUFFER);
+ src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ }
+ else
+ {
+ map_range = false;
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+
+ llassert(src != NULL);
+
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
+ mAlignedOffset = mMappedData - src;
+
+ stop_glerror();
+ }
+
+ if (!mMappedData)
+ {
+ log_glerror();
+
+ //check the availability of memory
+ LLMemory::logMemoryInfo(true);
+
+ if(mMappable)
+ {
+ //--------------------
+ //print out more debug info before crash
+ llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl;
+ GLint size;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+ llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl;
+ //--------------------
+
+ GLint buff;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLBuffer)
+ {
+ llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ }
+
+
+ llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for vertex data failed." << llendl;
+ }
+ }
+ }
+ }
+ else
+ {
+ map_range = false;
+ }
+
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
+ {
+ return mMappedData;
+ }
+ else
+ {
+ return mMappedData+mOffsets[type]+sTypeSize[type]*index;
+ }
+}
+
+
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
+
+volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ bindGLIndices(true);
+ if (mFinal)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
+ }
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl;
+ }
+
+ if (useVBOs())
+ {
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (count == -1)
+ {
+ count = mNumIndices-index;
+ }
+
+ bool mapped = false;
+ //see if range is already mapped
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedIndexRegions[i];
+ if (expand_region(region, index, count))
+ {
+ mapped = true;
+ break;
+ }
+ }
+
+ if (!mapped)
+ {
+ //not already mapped, map new region
+ MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
+ mMappedIndexRegions.push_back(region);
+ }
+ }
+
+ if (mIndexLocked && map_range)
+ {
+ llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
+ }
+
+ if (!mIndexLocked)
+ {
+ LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
+
+ mIndexLocked = true;
+ sMappedCount++;
+ stop_glerror();
+
+ if (gDebugGL && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
+ if(!mMappable)
+ {
+ map_range = false;
+ }
+ else
+ {
+ volatile U8* src = NULL;
+ waitFence();
+ if (gGLManager.mHasMapBufferRange)
+ {
+ if (map_range)
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE);
+ S32 offset = sizeof(U16)*index;
+ S32 length = sizeof(U16)*count;
+ src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
+ }
+ else
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
+ src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ }
+ else
+ {
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
+ map_range = false;
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+
+ llassert(src != NULL);
+
+
+ mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedIndexOffset = mMappedIndexData - src;
+ stop_glerror();
+ }
+ }
+
+ if (!mMappedIndexData)
+ {
+ log_glerror();
+ LLMemory::logMemoryInfo(true);
+
+ if(mMappable)
+ {
+ GLint buff;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLIndices)
+ {
+ llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+ }
+
+ llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for Index data failed. " << llendl;
+ }
+ }
+ }
+ else
+ {
+ map_range = false;
+ }
+
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
+ {
+ return mMappedIndexData;
+ }
+ else
+ {
+ return mMappedIndexData + sizeof(U16)*index;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap");
+static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range");
+
+
+static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap");
+static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range");
+
+void LLVertexBuffer::unmapBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
+ if (!useVBOs())
+ {
+ return; //nothing to unmap
+ }
+
+ bool updated_all = false;
+
+ if (mMappedData && mVertexLocked)
+ {
+ LLFastTimer t(FTM_VBO_UNMAP);
+ bindGLBuffer(true);
+ updated_all = mIndexLocked; //both vertex and index buffers done updating
+
+ if(!mMappable)
+ {
+ if (!mMappedVertexRegions.empty())
+ {
+ stop_glerror();
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedVertexRegions[i];
+ S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+ S32 length = sTypeSize[region.mType]*region.mCount;
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
+ stop_glerror();
+ }
+
+ mMappedVertexRegions.clear();
+ }
+ else
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData);
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (!mMappedVertexRegions.empty())
+ {
+ stop_glerror();
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedVertexRegions[i];
+ S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+ S32 length = sTypeSize[region.mType]*region.mCount;
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_VBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
+ }
+ stop_glerror();
+ }
+
+ mMappedVertexRegions.clear();
+ }
+ }
+ stop_glerror();
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ stop_glerror();
+
+ mMappedData = NULL;
+ }
+
+ mVertexLocked = false;
+ sMappedCount--;
+ }
+
+ if (mMappedIndexData && mIndexLocked)
+ {
+ LLFastTimer t(FTM_IBO_UNMAP);
+ bindGLIndices();
+ if(!mMappable)
+ {
+ if (!mMappedIndexRegions.empty())
+ {
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedIndexRegions[i];
+ S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
+ S32 length = sizeof(U16)*region.mCount;
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset);
+ stop_glerror();
+ }
+
+ mMappedIndexRegions.clear();
+ }
+ else
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData);
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (!mMappedIndexRegions.empty())
+ {
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedIndexRegions[i];
+ S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
+ S32 length = sizeof(U16)*region.mCount;
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_IBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+#ifdef GL_APPLE_flush_buffer_range
+ glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ stop_glerror();
+ }
+
+ mMappedIndexRegions.clear();
+ }
+ }
+ stop_glerror();
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+ stop_glerror();
+
+ mMappedIndexData = NULL;
+ }
+
+ mIndexLocked = false;
+ sMappedCount--;
+ }
+
+ if(updated_all)
+ {
+ mEmpty = false;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+template <class T,S32 type> struct VertexBufferStrider
+{
+ typedef LLStrider<T> strider_t;
+ static bool get(LLVertexBuffer& vbo,
+ strider_t& strider,
+ S32 index, S32 count, bool map_range)
+ {
+ if (type == LLVertexBuffer::TYPE_INDEX)
+ {
+ volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+
+ if (ptr == NULL)
+ {
+ llwarns << "mapIndexBuffer failed!" << llendl;
+ return false;
+ }
+
+ strider = (T*)ptr;
+ strider.setStride(0);
+ return true;
+ }
+ else if (vbo.hasDataType(type))
+ {
+ S32 stride = LLVertexBuffer::sTypeSize[type];
+
+ volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+
+ if (ptr == NULL)
+ {
+ llwarns << "mapVertexBuffer failed!" << llendl;
+ return false;
+ }
+
+ strider = (T*)ptr;
+ strider.setStride(stride);
+ return true;
+ }
+ else
+ {
+ llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
+ }
+ return false;
+ }
+};
+
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
+}
+
+//----------------------------------------------------------------------------
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array");
+bool LLVertexBuffer::bindGLArray()
+{
+ if (mGLArray && sGLRenderArray != mGLArray)
+ {
+ {
+ LLFastTimer t(FTM_BIND_GL_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+ }
+
+ //really shouldn't be necessary, but some drivers don't properly restore the
+ //state of GL_ELEMENT_ARRAY_BUFFER_BINDING
+ bindGLIndices();
+
+ return true;
+ }
+
+ return false;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer");
+
+bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+
+ if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_BUFFER);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
+ sBindCount++;
+ sVBOActive = true;
+
+ if (mGLArray)
+ {
+ llassert(sGLRenderArray == mGLArray);
+ //mCachedRenderBuffer = mGLBuffer;
+ }
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices");
+
+bool LLVertexBuffer::bindGLIndices(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+ if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_INDICES);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+ sGLRenderIndices = mGLIndices;
+ stop_glerror();
+ sBindCount++;
+ sIBOActive = true;
+ ret = true;
+ }
+
+ return ret;
+}
+
+void LLVertexBuffer::flush()
+{
+ if (useVBOs())
+ {
+ unmapBuffer();
+ }
+}
+
+// Set for rendering
+void LLVertexBuffer::setBuffer(U32 data_mask)
+{
+ flush();
+
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
+ //set up pointers if the data mask is different ...
+ bool setup = (sLastMask != data_mask);
+
+ if (gDebugGL && data_mask != 0)
+ { //make sure data requirements are fulfilled
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ U32 required_mask = 0;
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
+ {
+ if (shader->getAttribLocation(i) > -1)
+ {
+ U32 required = 1 << i;
+ if ((data_mask & required) == 0)
+ {
+ llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl;
+ }
+
+ required_mask |= required;
+ }
+ }
+
+ if ((data_mask & required_mask) != required_mask)
+ {
+ llerrs << "Shader consumption mismatches data provision." << llendl;
+ }
+ }
+ }
+
+ if (useVBOs())
+ {
+ if (mGLArray)
+ {
+ bindGLArray();
+ setup = false; //do NOT perform pointer setup if using VAO
+ }
+ else
+ {
+ const bool bindBuffer = bindGLBuffer();
+ const bool bindIndices = bindGLIndices();
+
+ setup = setup || bindBuffer || bindIndices;
+ }
+
+ bool error = false;
+ if (gDebugGL && !mGLArray)
+ {
+ GLint buff;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLBuffer)
+ {
+ if (gDebugSession)
+ {
+ error = true;
+ gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
+ }
+ else
+ {
+ llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ }
+ }
+
+ if (mGLIndices)
+ {
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLIndices)
+ {
+ if (gDebugSession)
+ {
+ error = true;
+ gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
+ }
+ else
+ {
+ llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+ }
+ }
+ }
+ }
+
+
+ }
+ else
+ {
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = false;
+ }
+
+ if (mGLBuffer)
+ {
+ if (sVBOActive)
+ {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sVBOActive = false;
+ setup = true; // ... or a VBO is deactivated
+ }
+ if (sGLRenderBuffer != mGLBuffer)
+ {
+ sGLRenderBuffer = mGLBuffer;
+ setup = true; // ... or a client memory pointer changed
+ }
+ }
+ if (mGLIndices)
+ {
+ if (sIBOActive)
+ {
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sIBOActive = false;
+ }
+
+ sGLRenderIndices = mGLIndices;
+ }
+ }
+
+ if (!mGLArray)
+ {
+ setupClientArrays(data_mask);
+ }
+
+ if (mGLBuffer)
+ {
+ if (data_mask && setup)
+ {
+ setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
+ sSetCount++;
+ }
+ }
+}
+
+// virtual (default)
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
+ stop_glerror();
+ volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+ /*if ((data_mask & mTypeMask) != data_mask)
+ {
+ llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+ }*/
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ if (data_mask & MAP_NORMAL)
+ {
+ S32 loc = TYPE_NORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ S32 loc = TYPE_TEXCOORD3;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ S32 loc = TYPE_TEXCOORD2;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ S32 loc = TYPE_TEXCOORD1;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ S32 loc = TYPE_BINORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ S32 loc = TYPE_TEXCOORD0;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ S32 loc = TYPE_COLOR;
+ void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+ }
+ if (data_mask & MAP_EMISSIVE)
+ {
+ S32 loc = TYPE_EMISSIVE;
+ void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+ }
+ if (data_mask & MAP_WEIGHT)
+ {
+ S32 loc = TYPE_WEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+ }
+ if (data_mask & MAP_WEIGHT4)
+ {
+ S32 loc = TYPE_WEIGHT4;
+ void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+ }
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ S32 loc = TYPE_CLOTHWEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+ }
+ if (data_mask & MAP_TEXTURE_INDEX)
+ {
+ S32 loc = TYPE_TEXTURE_INDEX;
+ void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ S32 loc = TYPE_VERTEX;
+ void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ }
+ else
+ {
+ if (data_mask & MAP_NORMAL)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ }
+
+ llglassertok();
+}
+
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
+{
+ llassert(mType == LLVertexBuffer::TYPE_INDEX ||
+ mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+}
+
+
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 466fac33ea..f7017064d7 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -389,6 +389,22 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const return ret; } +S32 LLScrollListCtrl::getNumSelected() const +{ + S32 numSelected = 0; + + for(item_list::const_iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + ++numSelected; + } + } + + return numSelected; +} + S32 LLScrollListCtrl::getFirstSelectedIndex() const { S32 CurSelectedIndex = 0; diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index ae8aea9245..44d9635838 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -257,6 +257,7 @@ public: LLScrollListItem* getFirstSelected() const; virtual S32 getFirstSelectedIndex() const; std::vector<LLScrollListItem*> getAllSelected() const; + S32 getNumSelected() const; LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } // iterate over all items diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3c9bde34b7..b586c6e31f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -17,12 +17,12 @@ include(JsonCpp) include(LLAudio) include(LLCharacter) include(LLCommon) -include(LLConvexDecomposition) include(LLImage) include(LLImageJ2COJ) include(LLInventory) include(LLMath) include(LLMessage) +include(LLPhysicsExtensions) include(LLPlugin) include(LLPrimitive) include(LLRender) @@ -51,7 +51,7 @@ include_directories( ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} - ${LLCONVEXDECOMP_INCLUDE_DIRS} + ${LLPHYSICS_INCLUDE_DIRS} ${FMOD_INCLUDE_DIR} ${LLIMAGE_INCLUDE_DIRS} ${LLKDU_INCLUDE_DIRS} @@ -217,6 +217,10 @@ set(viewer_SOURCE_FILES llfloaterobjectweights.cpp llfloateropenobject.cpp llfloateroutbox.cpp + llfloaterpathfindingbasic.cpp + llfloaterpathfindingcharacters.cpp + llfloaterpathfindingconsole.cpp + llfloaterpathfindinglinksets.cpp llfloaterpay.cpp llfloaterperms.cpp llfloaterpostprocess.cpp @@ -412,6 +416,12 @@ set(viewer_SOURCE_FILES llparcelselection.cpp llparticipantlist.cpp llpatchvertexarray.cpp + llpathfindingcharacter.cpp + llpathfindinglinkset.cpp + llpathfindinglinksetlist.cpp + llpathfindingmanager.cpp + llpathfindingnavmesh.cpp + llpathfindingnavmeshzone.cpp llphysicsmotion.cpp llphysicsshapebuilderutil.cpp llplacesinventorybridge.cpp @@ -773,6 +783,10 @@ set(viewer_HEADER_FILES llfloaterobjectweights.h llfloateropenobject.h llfloateroutbox.h + llfloaterpathfindingbasic.h + llfloaterpathfindingcharacters.h + llfloaterpathfindingconsole.h + llfloaterpathfindinglinksets.h llfloaterpay.h llfloaterperms.h llfloaterpostprocess.h @@ -957,6 +971,12 @@ set(viewer_HEADER_FILES llparcelselection.h llparticipantlist.h llpatchvertexarray.h + llpathfindingcharacter.h + llpathfindinglinkset.h + llpathfindinglinksetlist.h + llpathfindingmanager.h + llpathfindingnavmesh.h + llpathfindingnavmeshzone.h llphysicsmotion.h llphysicsshapebuilderutil.h llplacesinventorybridge.h @@ -1514,9 +1534,9 @@ if (WINDOWS) PROPERTIES # *TODO -reenable this once we get server usage sorted out #LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\"" - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc" + LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc " LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO" - LINK_FLAGS_RELEASE "" + LINK_FLAGS_RELEASE "/FORCE:MULTIPLE" ) if(USE_PRECOMPILED_HEADERS) set_target_properties( @@ -1730,6 +1750,7 @@ endif (WINDOWS) # To work around this, higher level modules should be listed before the modules # that they depend upon. -brad target_link_libraries(${VIEWER_BINARY_NAME} + ${LLPATHING_LIBRARIES} ${UPDATER_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} ${LLAUDIO_LIBRARIES} @@ -1768,7 +1789,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${LLLOGIN_LIBRARIES} - ${LLCONVEXDECOMP_LIBRARY} + ${LLPHYSICS_LIBRARIES} ${TCMALLOC_LIBRARIES} ) diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 73df064ab2..ff4d9ceb93 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -157,6 +157,46 @@ is_running_function="Floater.IsOpen" is_running_parameters="people" /> + <command name="pathfinding_basic" + available_in_toybox="false" + icon="Command_PF_Basic_Icon" + label_ref="Command_PF_Basic_Label" + tooltip_ref="Command_PF_Basic_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_basic" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_basic" + /> + <command name="pathfinding_console" + available_in_toybox="false" + icon="Command_Pathfinding_Icon" + label_ref="Command_Pathfinding_Label" + tooltip_ref="Command_Pathfinding_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_console" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_console" + /> + <command name="pathfinding_characters" + available_in_toybox="false" + icon="Command_PF_Characters_Icon" + label_ref="Command_PF_Characters_Label" + tooltip_ref="Command_PF_Characters_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_characters" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_characters" + /> + <command name="pathfinding_linksets" + available_in_toybox="false" + icon="Command_PF_Linksets_Icon" + label_ref="Command_PF_Linksets_Label" + tooltip_ref="Command_PF_Linksets_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_linksets" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_linksets" + /> <command name="picks" available_in_toybox="true" icon="Command_Picks_Icon" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ee8c15752b..eb2b0834e9 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13494,5 +13494,28 @@ <key>Value</key> <integer>0</integer> </map> + <key>RetrieveNeighboringRegion</key> + <map> + <key>Comment</key> + <string>Download a neighboring region when visualize a navmesh (default val 99 is for the current region).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>99</integer> + </map> + <key>EnableVBOForNavMeshVisualization</key> + <map> + <key>Comment</key> + <string>Enable the use of VBOs for navmesh visualization.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + </map> </llsd> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3870a3be2e..cbd08ad1c3 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -88,6 +88,7 @@ #include "llworld.h" #include "llworldmap.h" #include "stringize.h" +#include "llfloaterpathfindingconsole.h" using namespace LLVOAvatarDefines; @@ -395,6 +396,7 @@ void LLAgent::ageChat() //----------------------------------------------------------------------------- void LLAgent::moveAt(S32 direction, bool reset) { + mMoveTimer.reset(); LLFirstUse::notMoving(false); @@ -644,6 +646,7 @@ void LLAgent::setFlying(BOOL fly) // static void LLAgent::toggleFlying() { + if ( gAgent.mAutoPilot ) { LLToolPie::instance().stopClickToWalk(); @@ -2702,6 +2705,7 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) void LLAgent::sendWalkRun(bool running) { + LLMessageSystem* msgsys = gMessageSystem; if (msgsys) { @@ -3633,6 +3637,9 @@ void LLAgent::setTeleportState(ETeleportState state) // Let the interested parties know we've teleported. LLViewerParcelMgr::getInstance()->onTeleportFinished(false, getPositionGlobal()); + + //Since we teleported into a new region, we need to cleanup up any navmesh residuals + if ( LLPathingLib::getInstance() ) { LLPathingLib::getInstance()->cleanupResidual(); } break; default: diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1174d108d2..c1217fc402 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -106,6 +106,7 @@ #include "llvfsthread.h" #include "llvolumemgr.h" #include "llxfermanager.h" +#include "LLPhysicsExtensions.h" #include "llnotificationmanager.h" #include "llnotifications.h" @@ -1548,6 +1549,9 @@ bool LLAppViewer::cleanup() // shut down mesh streamer gMeshRepo.shutdown(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); + // Must clean up texture references before viewer window is destroyed. if(LLHUDManager::instanceExists()) { diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index b539ac38ed..b539ac38ed 100755..100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp diff --git a/indra/newview/llfloaterpathfindingbasic.cpp b/indra/newview/llfloaterpathfindingbasic.cpp new file mode 100644 index 0000000000..d1103088ab --- /dev/null +++ b/indra/newview/llfloaterpathfindingbasic.cpp @@ -0,0 +1,167 @@ +/**
+* @file llfloaterpathfindingbasic.cpp
+* @author William Todd Stinson
+* @brief "Pathfinding basic" floater, allowing for basic freezing and unfreezing of the pathfinding avatar mode.
+*
+* $LicenseInfo:firstyear=2002&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$
+*/
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterpathfindingbasic.h"
+#include "llsd.h"
+#include "lltextbase.h"
+#include "llbutton.h"
+#include "llpathfindingmanager.h"
+
+#include <boost/bind.hpp>
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingBasic
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingBasic::postBuild()
+{
+ mStatusText = findChild<LLTextBase>("status_label");
+ llassert(mStatusText != NULL);
+
+ mUnfreezeLabel = findChild<LLTextBase>("unfreeze_label");
+ llassert(mUnfreezeLabel != NULL);
+
+ mUnfreezeButton = findChild<LLButton>("enter_unfrozen_mode");
+ llassert(mUnfreezeButton != NULL);
+ mUnfreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingBasic::onUnfreezeClicked, this));
+
+ mFreezeLabel = findChild<LLTextBase>("freeze_label");
+ llassert(mFreezeLabel != NULL);
+
+ mFreezeButton = findChild<LLButton>("enter_frozen_mode");
+ llassert(mFreezeButton != NULL);
+ mFreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingBasic::onFreezeClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingBasic::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+
+ if (!mAgentStateSlot.connected())
+ {
+ mAgentStateSlot = LLPathfindingManager::getInstance()->registerAgentStateListener(boost::bind(&LLFloaterPathfindingBasic::onAgentStateCB, this, _1));
+ }
+ setAgentState(LLPathfindingManager::getInstance()->getAgentState());
+}
+
+void LLFloaterPathfindingBasic::onClose(bool pIsAppQuitting)
+{
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+
+ LLFloater::onClose(pIsAppQuitting);
+}
+
+LLFloaterPathfindingBasic::LLFloaterPathfindingBasic(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mStatusText(NULL),
+ mUnfreezeLabel(NULL),
+ mUnfreezeButton(NULL),
+ mFreezeLabel(NULL),
+ mFreezeButton(NULL),
+ mAgentStateSlot()
+{
+}
+
+LLFloaterPathfindingBasic::~LLFloaterPathfindingBasic()
+{
+}
+
+void LLFloaterPathfindingBasic::onUnfreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateUnfrozen);
+}
+
+void LLFloaterPathfindingBasic::onFreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateFrozen);
+}
+
+void LLFloaterPathfindingBasic::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ setAgentState(pAgentState);
+}
+
+void LLFloaterPathfindingBasic::setAgentState(LLPathfindingManager::EAgentState pAgentState)
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+ LLStyle::Params styleParams;
+
+ switch (pAgentState)
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ mStatusText->setVisible(TRUE);
+ mStatusText->setText((LLStringExplicit)getString("status_querying_state"), styleParams);
+ break;
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mStatusText->setVisible(TRUE);
+ styleParams.color = warningColor;
+ mStatusText->setText((LLStringExplicit)getString("status_pathfinding_not_enabled"), styleParams);
+ break;
+ case LLPathfindingManager::kAgentStateError :
+ mStatusText->setVisible(TRUE);
+ styleParams.color = warningColor;
+ mStatusText->setText((LLStringExplicit)getString("status_unable_to_change_state"), styleParams);
+ break;
+ default :
+ mStatusText->setVisible(FALSE);
+ break;
+ }
+
+ switch (LLPathfindingManager::getInstance()->getLastKnownNonErrorAgentState())
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateFrozen :
+ mUnfreezeLabel->setEnabled(TRUE);
+ mUnfreezeButton->setEnabled(TRUE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateUnfrozen :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(TRUE);
+ mFreezeButton->setEnabled(TRUE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
diff --git a/indra/newview/llfloaterpathfindingbasic.h b/indra/newview/llfloaterpathfindingbasic.h new file mode 100644 index 0000000000..286985c022 --- /dev/null +++ b/indra/newview/llfloaterpathfindingbasic.h @@ -0,0 +1,71 @@ +/** + * @file llfloaterpathfindingbasic.h + * @author William Todd Stinson + * @brief "Pathfinding basic" floater, allowing for basic freezing and unfreezing of the pathfinding avatar mode. + * + * $LicenseInfo:firstyear=2002&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_LLFLOATERPATHFINDINGBASIC_H +#define LL_LLFLOATERPATHFINDINGBASIC_H + +#include "llfloater.h" +#include "llpathfindingmanager.h" + +class LLSD; +class LLTextBase; +class LLButton; + +class LLFloaterPathfindingBasic +: public LLFloater +{ + friend class LLFloaterReg; + +public: + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& pKey); + virtual void onClose(bool pIsAppQuitting); + +protected: + +private: + // Does its own instance management, so clients not allowed + // to allocate or destroy. + LLFloaterPathfindingBasic(const LLSD& pSeed); + virtual ~LLFloaterPathfindingBasic(); + + void onUnfreezeClicked(); + void onFreezeClicked(); + + void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState); + + void setAgentState(LLPathfindingManager::EAgentState pAgentState); + + LLTextBase *mStatusText; + LLTextBase *mUnfreezeLabel; + LLButton *mUnfreezeButton; + LLTextBase *mFreezeLabel; + LLButton *mFreezeButton; + LLPathfindingManager::agent_state_slot_t mAgentStateSlot; +}; + +#endif // LL_LLFLOATERPATHFINDINGBASIC_H diff --git a/indra/newview/llfloaterpathfindingcharacters.cpp b/indra/newview/llfloaterpathfindingcharacters.cpp new file mode 100644 index 0000000000..fd84af74e1 --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.cpp @@ -0,0 +1,622 @@ +/**
+ * @file llfloaterpathfindingcharacters.cpp
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloater.h"
+#include "llfloaterpathfindingcharacters.h"
+#include "llpathfindingcharacter.h"
+#include "llsd.h"
+#include "llagent.h"
+#include "llhandle.h"
+#include "llfloaterreg.h"
+#include "lltextbase.h"
+#include "llscrolllistitem.h"
+#include "llscrolllistctrl.h"
+#include "llcheckboxctrl.h"
+#include "llradiogroup.h"
+#include "llbutton.h"
+#include "llresmgr.h"
+#include "llviewerregion.h"
+#include "llhttpclient.h"
+#include "lluuid.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewermenu.h"
+#include "llselectmgr.h"
+
+//---------------------------------------------------------------------------
+// CharactersGetResponder
+//---------------------------------------------------------------------------
+
+class CharactersGetResponder : public LLHTTPClient::Responder
+{
+public:
+ CharactersGetResponder(const std::string& pCharactersDataGetURL,
+ const LLHandle<LLFloaterPathfindingCharacters> &pCharactersFloaterHandle);
+ virtual ~CharactersGetResponder();
+
+ virtual void result(const LLSD& pContent);
+ virtual void error(U32 pStatus, const std::string& pReason);
+
+private:
+ CharactersGetResponder(const CharactersGetResponder& pOther);
+
+ std::string mCharactersDataGetURL;
+ LLHandle<LLFloaterPathfindingCharacters> mCharactersFloaterHandle;
+};
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingCharacters
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingCharacters::postBuild()
+{
+ childSetAction("refresh_characters_list", boost::bind(&LLFloaterPathfindingCharacters::onRefreshCharactersClicked, this));
+ childSetAction("select_all_characters", boost::bind(&LLFloaterPathfindingCharacters::onSelectAllCharactersClicked, this));
+ childSetAction("select_none_characters", boost::bind(&LLFloaterPathfindingCharacters::onSelectNoneCharactersClicked, this));
+
+ mCharactersScrollList = findChild<LLScrollListCtrl>("pathfinding_characters");
+ llassert(mCharactersScrollList != NULL);
+ mCharactersScrollList->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onCharactersSelectionChange, this));
+ mCharactersScrollList->sortByColumnIndex(0, true);
+
+ mCharactersStatus = findChild<LLTextBase>("characters_status");
+ llassert(mCharactersStatus != NULL);
+
+ mLabelActions = findChild<LLTextBase>("actions_label");
+ llassert(mLabelActions != NULL);
+
+ mShowBeaconCheckBox = findChild<LLCheckBoxCtrl>("show_beacon");
+ llassert(mShowBeaconCheckBox != NULL);
+
+ mTakeBtn = findChild<LLButton>("take_characters");
+ llassert(mTakeBtn != NULL)
+ mTakeBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTakeCharactersClicked, this));
+
+ mTakeCopyBtn = findChild<LLButton>("take_copy_characters");
+ llassert(mTakeCopyBtn != NULL)
+ mTakeCopyBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTakeCopyCharactersClicked, this));
+
+ mReturnBtn = findChild<LLButton>("return_characters");
+ llassert(mReturnBtn != NULL)
+ mReturnBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onReturnCharactersClicked, this));
+
+ mDeleteBtn = findChild<LLButton>("delete_characters");
+ llassert(mDeleteBtn != NULL)
+ mDeleteBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onDeleteCharactersClicked, this));
+
+ mTeleportBtn = findChild<LLButton>("teleport_to_character");
+ llassert(mTeleportBtn != NULL)
+ mTeleportBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTeleportCharacterToMeClicked, this));
+
+ setEnableActionFields(false);
+ setMessagingState(kMessagingInitial);
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingCharacters::onOpen(const LLSD& pKey)
+{
+ sendCharactersDataGetRequest();
+ selectNoneCharacters();
+
+ if (!mSelectionUpdateSlot.connected())
+ {
+ mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect(boost::bind(&LLFloaterPathfindingCharacters::updateActionFields, this));
+ }
+
+ mCharactersScrollList->setCommitOnSelectionChange(true);
+}
+
+void LLFloaterPathfindingCharacters::onClose(bool app_quitting)
+{
+ mCharactersScrollList->setCommitOnSelectionChange(false);
+
+ if (mSelectionUpdateSlot.connected())
+ {
+ mSelectionUpdateSlot.disconnect();
+ }
+
+ selectNoneCharacters();
+ if (mCharacterSelection.notNull())
+ {
+ std::vector<LLViewerObject *> selectedObjects;
+
+ LLObjectSelection *charactersSelected = mCharacterSelection.get();
+ for (LLObjectSelection::valid_iterator characterIter = charactersSelected->valid_begin();
+ characterIter != charactersSelected->valid_end(); ++characterIter)
+ {
+ LLSelectNode *characterNode = *characterIter;
+ selectedObjects.push_back(characterNode->getObject());
+ }
+
+ for (std::vector<LLViewerObject *>::const_iterator selectedObjectIter = selectedObjects.begin();
+ selectedObjectIter != selectedObjects.end(); ++selectedObjectIter)
+ {
+ LLViewerObject *selectedObject = *selectedObjectIter;
+ LLSelectMgr::getInstance()->deselectObjectAndFamily(selectedObject);
+ }
+
+ mCharacterSelection.clear();
+ }
+}
+
+void LLFloaterPathfindingCharacters::draw()
+{
+ if (mShowBeaconCheckBox->get())
+ {
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ const std::string &objectName = selectedItem->getColumn(0)->getValue().asString();
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ gObjectList.addDebugBeacon(viewerObject->getPositionAgent(), objectName, LLColor4(0.f, 0.f, 1.f, 0.8f), LLColor4(1.f, 1.f, 1.f, 1.f), 6);
+ }
+ }
+ }
+ }
+
+ LLFloater::draw();
+}
+
+void LLFloaterPathfindingCharacters::openCharactersViewer()
+{
+ LLFloaterReg::toggleInstanceOrBringToFront("pathfinding_characters");
+}
+
+LLFloaterPathfindingCharacters::EMessagingState LLFloaterPathfindingCharacters::getMessagingState() const
+{
+ return mMessagingState;
+}
+
+BOOL LLFloaterPathfindingCharacters::isMessagingInProgress() const
+{
+ BOOL retVal;
+ switch (getMessagingState())
+ {
+ case kMessagingFetchStarting :
+ case kMessagingFetchRequestSent :
+ case kMessagingFetchRequestSent_MultiRequested :
+ case kMessagingFetchReceived :
+ retVal = true;
+ break;
+ default :
+ retVal = false;
+ break;
+ }
+
+ return retVal;
+}
+
+LLFloaterPathfindingCharacters::LLFloaterPathfindingCharacters(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mSelfHandle(),
+ mPathfindingCharacters(),
+ mMessagingState(kMessagingInitial),
+ mCharactersScrollList(NULL),
+ mCharactersStatus(NULL),
+ mLabelActions(NULL),
+ mShowBeaconCheckBox(NULL),
+ mTakeBtn(NULL),
+ mTakeCopyBtn(NULL),
+ mReturnBtn(NULL),
+ mDeleteBtn(NULL),
+ mTeleportBtn(NULL),
+ mCharacterSelection(),
+ mSelectionUpdateSlot()
+{
+ mSelfHandle.bind(this);
+}
+
+LLFloaterPathfindingCharacters::~LLFloaterPathfindingCharacters()
+{
+ mPathfindingCharacters.clear();
+ mCharacterSelection.clear();
+}
+
+void LLFloaterPathfindingCharacters::sendCharactersDataGetRequest()
+{
+ if (isMessagingInProgress())
+ {
+ if (getMessagingState() == kMessagingFetchRequestSent)
+ {
+ setMessagingState(kMessagingFetchRequestSent_MultiRequested);
+ }
+ }
+ else
+ {
+ setMessagingState(kMessagingFetchStarting);
+ mPathfindingCharacters.clear();
+ updateCharactersList();
+
+ std::string charactersDataURL = getCapabilityURL();
+ if (charactersDataURL.empty())
+ {
+ setMessagingState(kMessagingServiceNotAvailable);
+ llwarns << "cannot query pathfinding characters from current region '" << getRegionName() << "'" << llendl;
+ }
+ else
+ {
+ setMessagingState(kMessagingFetchRequestSent);
+ LLHTTPClient::get(charactersDataURL, new CharactersGetResponder(charactersDataURL, mSelfHandle));
+ }
+ }
+}
+
+void LLFloaterPathfindingCharacters::handleCharactersDataGetReply(const LLSD& pCharactersData)
+{
+ setMessagingState(kMessagingFetchReceived);
+ mPathfindingCharacters.clear();
+ parseCharactersData(pCharactersData);
+ updateCharactersList();
+ setMessagingState(kMessagingComplete);
+}
+
+void LLFloaterPathfindingCharacters::handleCharactersDataGetError(const std::string& pURL, const std::string& pErrorReason)
+{
+ setMessagingState(kMessagingFetchError);
+ mPathfindingCharacters.clear();
+ updateCharactersList();
+ llwarns << "Error fetching pathfinding characters from URL '" << pURL << "' because " << pErrorReason << llendl;
+}
+
+std::string LLFloaterPathfindingCharacters::getRegionName() const
+{
+ std::string regionName("");
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ regionName = region->getName();
+ }
+
+ return regionName;
+}
+
+std::string LLFloaterPathfindingCharacters::getCapabilityURL() const
+{
+ std::string charactersDataURL("");
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ charactersDataURL = region->getCapability("CharacterProperties");
+ }
+
+ return charactersDataURL;
+}
+
+void LLFloaterPathfindingCharacters::parseCharactersData(const LLSD &pCharactersData)
+{
+ for (LLSD::map_const_iterator characterItemIter = pCharactersData.beginMap();
+ characterItemIter != pCharactersData.endMap(); ++characterItemIter)
+ {
+ const std::string &uuid(characterItemIter->first);
+ const LLSD &characterData(characterItemIter->second);
+ LLPathfindingCharacter character(uuid, characterData);
+
+ mPathfindingCharacters.insert(std::pair<std::string, LLPathfindingCharacter>(uuid, character));
+ }
+}
+
+void LLFloaterPathfindingCharacters::setMessagingState(EMessagingState pMessagingState)
+{
+ mMessagingState = pMessagingState;
+ updateCharactersList();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::onCharactersSelectionChange()
+{
+ mCharacterSelection.clear();
+ LLSelectMgr::getInstance()->deselectAll();
+
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ viewerObjects.push_back(viewerObject);
+ }
+ }
+
+ if (!viewerObjects.empty())
+ {
+ mCharacterSelection = LLSelectMgr::getInstance()->selectObjectAndFamily(viewerObjects);
+ }
+ }
+
+ updateCharactersStatusMessage();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::onRefreshCharactersClicked()
+{
+ sendCharactersDataGetRequest();
+}
+
+void LLFloaterPathfindingCharacters::onSelectAllCharactersClicked()
+{
+ selectAllCharacters();
+}
+
+void LLFloaterPathfindingCharacters::onSelectNoneCharactersClicked()
+{
+ selectNoneCharacters();
+}
+
+void LLFloaterPathfindingCharacters::onTakeCharactersClicked()
+{
+ handle_take();
+}
+
+void LLFloaterPathfindingCharacters::onTakeCopyCharactersClicked()
+{
+ handle_take_copy();
+}
+
+void LLFloaterPathfindingCharacters::onReturnCharactersClicked()
+{
+ handle_object_return();
+}
+
+void LLFloaterPathfindingCharacters::onDeleteCharactersClicked()
+{
+ handle_object_delete();
+}
+
+void LLFloaterPathfindingCharacters::onTeleportCharacterToMeClicked()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ llassert(selectedItems.size() == 1);
+ if (selectedItems.size() == 1)
+ {
+ std::vector<LLScrollListItem*>::const_reference selectedItemRef = selectedItems.front();
+ const LLScrollListItem *selectedItem = selectedItemRef;
+ PathfindingCharacterMap::const_iterator characterIter = mPathfindingCharacters.find(selectedItem->getUUID().asString());
+ const LLPathfindingCharacter &character = characterIter->second;
+ LLVector3 characterLocation = character.getLocation();
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ gAgent.teleportRequest(region->getHandle(), characterLocation, true);
+ }
+ }
+}
+
+void LLFloaterPathfindingCharacters::updateCharactersList()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ uuid_vec_t selectedUUIDs;
+ if (numSelectedItems > 0)
+ {
+ selectedUUIDs.reserve(selectedItems.size());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ selectedUUIDs.push_back(listItem->getUUID());
+ }
+ }
+
+ mCharactersScrollList->deleteAllItems();
+ updateCharactersStatusMessage();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ for (PathfindingCharacterMap::const_iterator characterIter = mPathfindingCharacters.begin();
+ characterIter != mPathfindingCharacters.end(); ++characterIter)
+ {
+ const LLPathfindingCharacter& character(characterIter->second);
+
+ LLSD columns;
+
+ columns[0]["column"] = "name";
+ columns[0]["value"] = character.getName();
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = character.getDescription();
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "owner";
+ columns[2]["value"] = character.getOwnerName();
+ columns[2]["font"] = "SANSSERIF";
+
+ S32 cpuTime = llround(character.getCPUTime());
+ std::string cpuTimeString = llformat("%d", cpuTime);
+ LLStringUtil::format_map_t string_args;
+ string_args["[CPU_TIME]"] = cpuTimeString;
+
+ columns[3]["column"] = "cpu_time";
+ columns[3]["value"] = getString("character_cpu_time", string_args);
+ columns[3]["font"] = "SANSSERIF";
+
+ columns[4]["column"] = "altitude";
+ columns[4]["value"] = llformat("%1.0f m", character.getLocation()[2]);
+ columns[4]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["id"] = character.getUUID().asString();
+ element["column"] = columns;
+
+ mCharactersScrollList->addElement(element);
+ }
+
+ mCharactersScrollList->selectMultiple(selectedUUIDs);
+ updateCharactersStatusMessage();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::selectAllCharacters()
+{
+ mCharactersScrollList->selectAll();
+}
+
+void LLFloaterPathfindingCharacters::selectNoneCharacters()
+{
+ mCharactersScrollList->deselectAllItems();
+}
+
+void LLFloaterPathfindingCharacters::updateCharactersStatusMessage()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ switch (getMessagingState())
+ {
+ case kMessagingInitial:
+ statusText = getString("characters_messaging_initial");
+ break;
+ case kMessagingFetchStarting :
+ statusText = getString("characters_messaging_fetch_starting");
+ break;
+ case kMessagingFetchRequestSent :
+ statusText = getString("characters_messaging_fetch_inprogress");
+ break;
+ case kMessagingFetchRequestSent_MultiRequested :
+ statusText = getString("characters_messaging_fetch_inprogress_multi_request");
+ break;
+ case kMessagingFetchReceived :
+ statusText = getString("characters_messaging_fetch_received");
+ break;
+ case kMessagingFetchError :
+ statusText = getString("characters_messaging_fetch_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingComplete :
+ if (mCharactersScrollList->isEmpty())
+ {
+ statusText = getString("characters_messaging_complete_none_found");
+ }
+ else
+ {
+ S32 numItems = mCharactersScrollList->getItemCount();
+ S32 numSelectedItems = mCharactersScrollList->getNumSelected();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ std::string numItemsString;
+ LLResMgr::getInstance()->getIntegerString(numItemsString, numItems);
+
+ std::string numSelectedItemsString;
+ LLResMgr::getInstance()->getIntegerString(numSelectedItemsString, numSelectedItems);
+
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUM_SELECTED]"] = numSelectedItemsString;
+ string_args["[NUM_TOTAL]"] = numItemsString;
+ statusText = getString("characters_messaging_complete_available", string_args);
+ }
+ break;
+ case kMessagingServiceNotAvailable:
+ statusText = getString("characters_messaging_service_not_available");
+ styleParams.color = warningColor;
+ break;
+ default:
+ statusText = getString("characters_messaging_initial");
+ llassert(0);
+ break;
+ }
+
+ mCharactersStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+void LLFloaterPathfindingCharacters::updateActionFields()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ setEnableActionFields(!selectedItems.empty());
+}
+
+void LLFloaterPathfindingCharacters::setEnableActionFields(BOOL pEnabled)
+{
+ mLabelActions->setEnabled(pEnabled);
+ mShowBeaconCheckBox->setEnabled(pEnabled);
+ mTakeBtn->setEnabled(pEnabled && visible_take_object());
+ mTakeCopyBtn->setEnabled(pEnabled && enable_object_take_copy());
+ mReturnBtn->setEnabled(pEnabled && enable_object_return());
+ mDeleteBtn->setEnabled(pEnabled && enable_object_delete());
+ mTeleportBtn->setEnabled(pEnabled && (mCharactersScrollList->getNumSelected() == 1));
+}
+
+//---------------------------------------------------------------------------
+// CharactersGetResponder
+//---------------------------------------------------------------------------
+
+CharactersGetResponder::CharactersGetResponder(const std::string& pCharactersDataGetURL,
+ const LLHandle<LLFloaterPathfindingCharacters> &pCharactersFloaterHandle)
+ : mCharactersDataGetURL(pCharactersDataGetURL),
+ mCharactersFloaterHandle(pCharactersFloaterHandle)
+{
+}
+
+CharactersGetResponder::~CharactersGetResponder()
+{
+}
+
+void CharactersGetResponder::result(const LLSD& pContent)
+{
+ LLFloaterPathfindingCharacters *charactersFloater = mCharactersFloaterHandle.get();
+ if (charactersFloater != NULL)
+ {
+ charactersFloater->handleCharactersDataGetReply(pContent);
+ }
+}
+
+void CharactersGetResponder::error(U32 status, const std::string& reason)
+{
+ LLFloaterPathfindingCharacters *charactersFloater = mCharactersFloaterHandle.get();
+ if (charactersFloater != NULL)
+ {
+ charactersFloater->handleCharactersDataGetError(mCharactersDataGetURL, reason);
+ }
+}
diff --git a/indra/newview/llfloaterpathfindingcharacters.h b/indra/newview/llfloaterpathfindingcharacters.h new file mode 100644 index 0000000000..c381492784 --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.h @@ -0,0 +1,133 @@ +/**
+ * @file llfloaterpathfindingcharacters.h
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLFLOATERPATHFINDINGCHARACTERS_H
+#define LL_LLFLOATERPATHFINDINGCHARACTERS_H
+
+#include <string>
+#include <map>
+
+#include "llhandle.h"
+#include "llfloater.h"
+#include "llpathfindingcharacter.h"
+#include "llselectmgr.h"
+
+#include <boost/signals2.hpp>
+
+class LLSD;
+class LLTextBase;
+class LLScrollListCtrl;
+class LLCheckBoxCtrl;
+class LLRadioGroup;
+class LLButton;
+
+class LLFloaterPathfindingCharacters
+: public LLFloater
+{
+ friend class LLFloaterReg;
+ friend class CharactersGetResponder;
+
+public:
+ typedef enum
+ {
+ kMessagingInitial,
+ kMessagingFetchStarting,
+ kMessagingFetchRequestSent,
+ kMessagingFetchRequestSent_MultiRequested,
+ kMessagingFetchReceived,
+ kMessagingFetchError,
+ kMessagingComplete,
+ kMessagingServiceNotAvailable
+ } EMessagingState;
+
+ virtual BOOL postBuild();
+ virtual void onOpen(const LLSD& pKey);
+ virtual void onClose(bool app_quitting);
+ virtual void draw();
+
+ static void openCharactersViewer();
+
+ EMessagingState getMessagingState() const;
+ BOOL isMessagingInProgress() const;
+
+protected:
+
+private:
+ typedef std::map<std::string, LLPathfindingCharacter> PathfindingCharacterMap;
+
+ LLRootHandle<LLFloaterPathfindingCharacters> mSelfHandle;
+ PathfindingCharacterMap mPathfindingCharacters;
+ EMessagingState mMessagingState;
+ LLScrollListCtrl *mCharactersScrollList;
+ LLTextBase *mCharactersStatus;
+ LLTextBase *mLabelActions;
+ LLCheckBoxCtrl *mShowBeaconCheckBox;
+ LLButton *mTakeBtn;
+ LLButton *mTakeCopyBtn;
+ LLButton *mReturnBtn;
+ LLButton *mDeleteBtn;
+ LLButton *mTeleportBtn;
+ LLObjectSelectionHandle mCharacterSelection;
+ boost::signals2::connection mSelectionUpdateSlot;
+
+ // Does its own instance management, so clients not allowed
+ // to allocate or destroy.
+ LLFloaterPathfindingCharacters(const LLSD& pSeed);
+ virtual ~LLFloaterPathfindingCharacters();
+
+ void sendCharactersDataGetRequest();
+ void handleCharactersDataGetReply(const LLSD& pCharactersData);
+ void handleCharactersDataGetError(const std::string& pURL, const std::string& pErrorReason);
+
+ std::string getRegionName() const;
+ std::string getCapabilityURL() const;
+
+ void parseCharactersData(const LLSD &pCharactersData);
+
+ void setMessagingState(EMessagingState pMessagingState);
+
+ void onCharactersSelectionChange();
+ void onRefreshCharactersClicked();
+ void onSelectAllCharactersClicked();
+ void onSelectNoneCharactersClicked();
+ void onTakeCharactersClicked();
+ void onTakeCopyCharactersClicked();
+ void onReturnCharactersClicked();
+ void onDeleteCharactersClicked();
+ void onTeleportCharacterToMeClicked();
+
+ void updateCharactersList();
+ void selectAllCharacters();
+ void selectNoneCharacters();
+
+ void updateCharactersStatusMessage();
+
+ void updateActionFields();
+ void setEnableActionFields(BOOL pEnabled);
+};
+
+#endif // LL_LLFLOATERPATHFINDINGCHARACTERS_H
diff --git a/indra/newview/llfloaterpathfindingconsole.cpp b/indra/newview/llfloaterpathfindingconsole.cpp new file mode 100644 index 0000000000..405b089155 --- /dev/null +++ b/indra/newview/llfloaterpathfindingconsole.cpp @@ -0,0 +1,891 @@ +/**
+* @file llfloaterpathfindingconsole.cpp
+* @author William Todd Stinson
+* @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings.
+*
+* $LicenseInfo:firstyear=2002&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$
+*/
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloaterpathfindingconsole.h"
+#include "llfloaterpathfindinglinksets.h"
+#include "llfloaterpathfindingcharacters.h"
+
+#include "llsd.h"
+#include "llhandle.h"
+#include "llagent.h"
+#include "llpanel.h"
+#include "llbutton.h"
+#include "llradiogroup.h"
+#include "llsliderctrl.h"
+#include "lllineeditor.h"
+#include "lltextbase.h"
+#include "lltabcontainer.h"
+#include "llcombobox.h"
+#include "llfloaterreg.h"
+#include "llviewerregion.h"
+#include "llviewerwindow.h"
+#include "llviewercamera.h"
+#include "llviewercontrol.h"
+#include "llpathfindingnavmeshzone.h"
+#include "llpathfindingmanager.h"
+
+#include "LLPathingLib.h"
+
+#define XUI_RENDER_HEATMAP_NONE 0
+#define XUI_RENDER_HEATMAP_A 1
+#define XUI_RENDER_HEATMAP_B 2
+#define XUI_RENDER_HEATMAP_C 3
+#define XUI_RENDER_HEATMAP_D 4
+
+#define XUI_CHARACTER_TYPE_A 1
+#define XUI_CHARACTER_TYPE_B 2
+#define XUI_CHARACTER_TYPE_C 3
+#define XUI_CHARACTER_TYPE_D 4
+
+#define XUI_TEST_TAB_INDEX 1
+
+LLHandle<LLFloaterPathfindingConsole> LLFloaterPathfindingConsole::sInstanceHandle;
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingConsole
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingConsole::postBuild()
+{
+ mShowNavMeshCheckBox = findChild<LLCheckBoxCtrl>("show_navmesh");
+ llassert(mShowNavMeshCheckBox != NULL);
+
+ mShowNavMeshWalkabilityComboBox = findChild<LLComboBox>("show_heatmap_mode");
+ llassert(mShowNavMeshWalkabilityComboBox != NULL);
+ mShowNavMeshWalkabilityComboBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWalkabilitySet, this));
+
+ mShowWalkablesCheckBox = findChild<LLCheckBoxCtrl>("show_walkables");
+ llassert(mShowWalkablesCheckBox != NULL);
+
+ mShowStaticObstaclesCheckBox = findChild<LLCheckBoxCtrl>("show_static_obstacles");
+ llassert(mShowStaticObstaclesCheckBox != NULL);
+
+ mShowMaterialVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_material_volumes");
+ llassert(mShowMaterialVolumesCheckBox != NULL);
+
+ mShowExclusionVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_exclusion_volumes");
+ llassert(mShowExclusionVolumesCheckBox != NULL);
+
+ mShowWorldCheckBox = findChild<LLCheckBoxCtrl>("show_world");
+ llassert(mShowWorldCheckBox != NULL);
+ mShowWorldCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWorldToggle, this));
+
+ mViewCharactersButton = findChild<LLButton>("view_characters_floater");
+ llassert(mViewCharactersButton != NULL);
+ mViewCharactersButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onViewCharactersClicked, this));
+
+ mEditTestTabContainer = findChild<LLTabContainer>("edit_test_tab_container");
+ llassert(mEditTestTabContainer != NULL);
+
+ mEditTab = findChild<LLPanel>("edit_panel");
+ llassert(mEditTab != NULL);
+
+ mTestTab = findChild<LLPanel>("test_panel");
+ llassert(mTestTab != NULL);
+
+ mUnfreezeLabel = findChild<LLTextBase>("unfreeze_label");
+ llassert(mUnfreezeLabel != NULL);
+
+ mUnfreezeButton = findChild<LLButton>("enter_unfrozen_mode");
+ llassert(mUnfreezeButton != NULL);
+ mUnfreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onUnfreezeClicked, this));
+
+ mLinksetsLabel = findChild<LLTextBase>("edit_linksets_label");
+ llassert(mLinksetsLabel != NULL);
+
+ mLinksetsButton = findChild<LLButton>("view_and_edit_linksets");
+ llassert(mLinksetsButton != NULL);
+ mLinksetsButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onViewEditLinksetClicked, this));
+
+ mFreezeLabel = findChild<LLTextBase>("freeze_label");
+ llassert(mFreezeLabel != NULL);
+
+ mFreezeButton = findChild<LLButton>("enter_frozen_mode");
+ llassert(mFreezeButton != NULL);
+ mFreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onFreezeClicked, this));
+
+ mPathfindingStatus = findChild<LLTextBase>("pathfinding_status");
+ llassert(mPathfindingStatus != NULL);
+
+ mCharacterWidthSlider = findChild<LLSliderCtrl>("character_width");
+ llassert(mCharacterWidthSlider != NULL);
+ mCharacterWidthSlider->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterWidthSet, this));
+
+ mCharacterTypeRadioGroup = findChild<LLRadioGroup>("character_type");
+ llassert(mCharacterTypeRadioGroup != NULL);
+ mCharacterTypeRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterTypeSwitch, this));
+
+ mPathTestingStatus = findChild<LLTextBase>("path_test_status");
+ llassert(mPathTestingStatus != NULL);
+
+ mClearPathButton = findChild<LLButton>("clear_path");
+ llassert(mClearPathButton != NULL);
+ mClearPathButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onClearPathClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingConsole::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+ setHeartBeat( true );
+ //make sure we have a pathing system
+ if ( !LLPathingLib::getInstance() )
+ {
+ LLPathingLib::initSystem();
+ }
+ if ( LLPathingLib::getInstance() == NULL )
+ {
+ setConsoleState(kConsoleStateLibraryNotImplemented);
+ llwarns <<"Errror: cannot find pathing library implementation."<<llendl;
+ }
+ else
+ {
+ if (!mNavMeshZoneSlot.connected())
+ {
+ mNavMeshZoneSlot = mNavMeshZone.registerNavMeshZoneListener(boost::bind(&LLFloaterPathfindingConsole::onNavMeshZoneCB, this, _1));
+ }
+
+ mIsNavMeshUpdating = false;
+ mNavMeshZone.initialize();
+
+ mNavMeshZone.enable();
+ mNavMeshZone.refresh();
+ }
+
+ if (!mAgentStateSlot.connected())
+ {
+ mAgentStateSlot = LLPathfindingManager::getInstance()->registerAgentStateListener(boost::bind(&LLFloaterPathfindingConsole::onAgentStateCB, this, _1));
+ }
+
+ setAgentState(LLPathfindingManager::getInstance()->getAgentState());
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onClose(bool pIsAppQuitting)
+{
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+
+ if (mNavMeshZoneSlot.connected())
+ {
+ mNavMeshZoneSlot.disconnect();
+ }
+
+ if (LLPathingLib::getInstance() != NULL)
+ {
+ mNavMeshZone.disable();
+ }
+
+ LLFloater::onClose(pIsAppQuitting);
+ setHeartBeat( false );
+ setConsoleState(kConsoleStateUnknown);
+ //Reset all the checkboxes to default
+ mShowNavMeshCheckBox->set( false );
+ mShowWalkablesCheckBox->set( false );
+ mShowMaterialVolumesCheckBox->set( false );
+ mShowStaticObstaclesCheckBox->set( false );
+ mShowExclusionVolumesCheckBox->set( false );
+ mShowWorldCheckBox->set( false );
+}
+
+BOOL LLFloaterPathfindingConsole::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
+{
+ if (isGeneratePathMode(mask, clicktype, down))
+ {
+ LLVector3 dv = gViewerWindow->mouseDirectionGlobal(x, y);
+ LLVector3 mousePos = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 rayStart = mousePos;
+ LLVector3 rayEnd = mousePos + dv * 150;
+
+ if (mask & MASK_CONTROL)
+ {
+ mPathData.mStartPointA = rayStart;
+ mPathData.mEndPointA = rayEnd;
+ mHasStartPoint = true;
+ }
+ else if (mask & MASK_SHIFT)
+ {
+ mPathData.mStartPointB = rayStart;
+ mPathData.mEndPointB = rayEnd;
+ mHasEndPoint = true;
+ }
+ generatePath();
+ updatePathTestStatus();
+
+ return TRUE;
+ }
+ else
+ {
+ return LLFloater::handleAnyMouseClick(x, y, mask, clicktype, down);
+ }
+}
+
+BOOL LLFloaterPathfindingConsole::isGeneratePathMode(MASK mask, EClickType clicktype, BOOL down) const
+{
+ return (isShown() && (mEditTestTabContainer->getCurrentPanelIndex() == XUI_TEST_TAB_INDEX) &&
+ (clicktype == LLMouseHandler::CLICK_LEFT) && down &&
+ (((mask & MASK_CONTROL) && !(mask & (~MASK_CONTROL))) ||
+ ((mask & MASK_SHIFT) && !(mask & (~MASK_SHIFT)))));
+}
+
+LLHandle<LLFloaterPathfindingConsole> LLFloaterPathfindingConsole::getInstanceHandle()
+{
+ if (sInstanceHandle.isDead())
+ {
+ LLFloaterPathfindingConsole *floaterInstance = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console");
+ if (floaterInstance != NULL)
+ {
+ sInstanceHandle = floaterInstance->mSelfHandle;
+ }
+ }
+
+ return sInstanceHandle;
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderPath() const
+{
+ return (mHasStartPoint && mHasEndPoint);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderNavMesh() const
+{
+ return mShowNavMeshCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderNavMesh(BOOL pIsRenderNavMesh)
+{
+ mShowNavMeshCheckBox->set(pIsRenderNavMesh);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderWalkables() const
+{
+ return mShowWalkablesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderWalkables(BOOL pIsRenderWalkables)
+{
+ mShowWalkablesCheckBox->set(pIsRenderWalkables);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderStaticObstacles() const
+{
+ return mShowStaticObstaclesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderStaticObstacles(BOOL pIsRenderStaticObstacles)
+{
+ mShowStaticObstaclesCheckBox->set(pIsRenderStaticObstacles);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderMaterialVolumes() const
+{
+ return mShowMaterialVolumesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderMaterialVolumes(BOOL pIsRenderMaterialVolumes)
+{
+ mShowMaterialVolumesCheckBox->set(pIsRenderMaterialVolumes);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderExclusionVolumes() const
+{
+ return mShowExclusionVolumesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderExclusionVolumes(BOOL pIsRenderExclusionVolumes)
+{
+ mShowExclusionVolumesCheckBox->set(pIsRenderExclusionVolumes);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderWorld() const
+{
+ return mShowWorldCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderWorld(BOOL pIsRenderWorld)
+{
+ mShowWorldCheckBox->set(pIsRenderWorld);
+}
+
+LLFloaterPathfindingConsole::ERenderHeatmapType LLFloaterPathfindingConsole::getRenderHeatmapType() const
+{
+ ERenderHeatmapType renderHeatmapType;
+
+ switch (mShowNavMeshWalkabilityComboBox->getValue().asInteger())
+ {
+ case XUI_RENDER_HEATMAP_NONE :
+ renderHeatmapType = kRenderHeatmapNone;
+ break;
+ case XUI_RENDER_HEATMAP_A :
+ renderHeatmapType = kRenderHeatmapA;
+ break;
+ case XUI_RENDER_HEATMAP_B :
+ renderHeatmapType = kRenderHeatmapB;
+ break;
+ case XUI_RENDER_HEATMAP_C :
+ renderHeatmapType = kRenderHeatmapC;
+ break;
+ case XUI_RENDER_HEATMAP_D :
+ renderHeatmapType = kRenderHeatmapD;
+ break;
+ default :
+ renderHeatmapType = kRenderHeatmapNone;
+ llassert(0);
+ break;
+ }
+
+ return renderHeatmapType;
+}
+
+void LLFloaterPathfindingConsole::setRenderHeatmapType(ERenderHeatmapType pRenderHeatmapType)
+{
+ LLSD comboBoxValue;
+
+ switch (pRenderHeatmapType)
+ {
+ case kRenderHeatmapNone :
+ comboBoxValue = XUI_RENDER_HEATMAP_NONE;
+ break;
+ case kRenderHeatmapA :
+ comboBoxValue = XUI_RENDER_HEATMAP_A;
+ break;
+ case kRenderHeatmapB :
+ comboBoxValue = XUI_RENDER_HEATMAP_B;
+ break;
+ case kRenderHeatmapC :
+ comboBoxValue = XUI_RENDER_HEATMAP_C;
+ break;
+ case kRenderHeatmapD :
+ comboBoxValue = XUI_RENDER_HEATMAP_D;
+ break;
+ default :
+ comboBoxValue = XUI_RENDER_HEATMAP_NONE;
+ llassert(0);
+ break;
+ }
+
+ return mShowNavMeshWalkabilityComboBox->setValue(comboBoxValue);
+}
+
+F32 LLFloaterPathfindingConsole::getCharacterWidth() const
+{
+ return mCharacterWidthSlider->getValueF32();
+}
+
+void LLFloaterPathfindingConsole::setCharacterWidth(F32 pCharacterWidth)
+{
+ mCharacterWidthSlider->setValue(LLSD(pCharacterWidth));
+}
+
+LLFloaterPathfindingConsole::ECharacterType LLFloaterPathfindingConsole::getCharacterType() const
+{
+ ECharacterType characterType;
+
+ switch (mCharacterTypeRadioGroup->getValue().asInteger())
+ {
+ case XUI_CHARACTER_TYPE_A :
+ characterType = kCharacterTypeA;
+ break;
+ case XUI_CHARACTER_TYPE_B :
+ characterType = kCharacterTypeB;
+ break;
+ case XUI_CHARACTER_TYPE_C :
+ characterType = kCharacterTypeC;
+ break;
+ case XUI_CHARACTER_TYPE_D :
+ characterType = kCharacterTypeD;
+ break;
+ default :
+ characterType = kCharacterTypeA;
+ llassert(0);
+ break;
+ }
+
+ return characterType;
+}
+
+void LLFloaterPathfindingConsole::setCharacterType(ECharacterType pCharacterType)
+{
+ LLSD radioGroupValue;
+
+ switch (pCharacterType)
+ {
+ case kCharacterTypeA :
+ radioGroupValue = XUI_CHARACTER_TYPE_A;
+ break;
+ case kCharacterTypeB :
+ radioGroupValue = XUI_CHARACTER_TYPE_B;
+ break;
+ case kCharacterTypeC :
+ radioGroupValue = XUI_CHARACTER_TYPE_C;
+ break;
+ case kCharacterTypeD :
+ radioGroupValue = XUI_CHARACTER_TYPE_D;
+ break;
+ default :
+ radioGroupValue = XUI_CHARACTER_TYPE_A;
+ llassert(0);
+ break;
+ }
+
+ mCharacterTypeRadioGroup->setValue(radioGroupValue);
+}
+
+LLFloaterPathfindingConsole::LLFloaterPathfindingConsole(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mSelfHandle(),
+ mShowNavMeshCheckBox(NULL),
+ mShowNavMeshWalkabilityComboBox(NULL),
+ mShowWalkablesCheckBox(NULL),
+ mShowStaticObstaclesCheckBox(NULL),
+ mShowMaterialVolumesCheckBox(NULL),
+ mShowExclusionVolumesCheckBox(NULL),
+ mShowWorldCheckBox(NULL),
+ mPathfindingStatus(NULL),
+ mViewCharactersButton(NULL),
+ mEditTestTabContainer(NULL),
+ mEditTab(NULL),
+ mTestTab(NULL),
+ mUnfreezeLabel(NULL),
+ mUnfreezeButton(NULL),
+ mLinksetsLabel(NULL),
+ mLinksetsButton(NULL),
+ mFreezeLabel(NULL),
+ mFreezeButton(NULL),
+ mCharacterWidthSlider(NULL),
+ mCharacterTypeRadioGroup(NULL),
+ mPathTestingStatus(NULL),
+ mClearPathButton(NULL),
+ mNavMeshZoneSlot(),
+ mNavMeshZone(),
+ mIsNavMeshUpdating(false),
+ mAgentStateSlot(),
+ mConsoleState(kConsoleStateUnknown),
+ mPathData(),
+ mHasStartPoint(false),
+ mHasEndPoint(false),
+ mHeartBeat( false )
+{
+ mSelfHandle.bind(this);
+}
+
+LLFloaterPathfindingConsole::~LLFloaterPathfindingConsole()
+{
+}
+
+void LLFloaterPathfindingConsole::onShowWalkabilitySet()
+{
+ switch (getRenderHeatmapType())
+ {
+ case kRenderHeatmapNone :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapNone"
+ << llendl;
+ break;
+ case kRenderHeatmapA :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapA"
+ << llendl;
+ break;
+ case kRenderHeatmapB :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapB"
+ << llendl;
+ break;
+ case kRenderHeatmapC :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapC"
+ << llendl;
+ break;
+ case kRenderHeatmapD :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapD"
+ << llendl;
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::onShowWorldToggle()
+{
+ BOOL checkBoxValue = mShowWorldCheckBox->get();
+
+ LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance();
+ if (llPathingLibInstance != NULL)
+ {
+ llPathingLibInstance->setRenderWorld(checkBoxValue);
+ }
+ else
+ {
+ mShowWorldCheckBox->set(FALSE);
+ llwarns << "cannot find LLPathingLib instance" << llendl;
+ }
+}
+
+void LLFloaterPathfindingConsole::onCharacterWidthSet()
+{
+ generatePath();
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onCharacterTypeSwitch()
+{
+ switch (getCharacterType())
+ {
+ case kCharacterTypeA :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeA"
+ << llendl;
+ break;
+ case kCharacterTypeB :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeB"
+ << llendl;
+ break;
+ case kCharacterTypeC :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeC"
+ << llendl;
+ break;
+ case kCharacterTypeD :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeD"
+ << llendl;
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onViewCharactersClicked()
+{
+ LLFloaterPathfindingCharacters::openCharactersViewer();
+}
+
+void LLFloaterPathfindingConsole::onUnfreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateUnfrozen);
+}
+
+void LLFloaterPathfindingConsole::onFreezeClicked()
+{
+ mFreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateFrozen);
+}
+
+void LLFloaterPathfindingConsole::onViewEditLinksetClicked()
+{
+ LLFloaterPathfindingLinksets::openLinksetsEditor();
+}
+
+void LLFloaterPathfindingConsole::onClearPathClicked()
+{
+ mHasStartPoint = false;
+ mHasEndPoint = false;
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onNavMeshZoneCB(LLPathfindingNavMeshZone::ENavMeshZoneRequestStatus pNavMeshZoneRequestStatus)
+{
+ switch (pNavMeshZoneRequestStatus)
+ {
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestUnknown :
+ setConsoleState(kConsoleStateUnknown);
+ break;
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestNeedsUpdate :
+ mIsNavMeshUpdating = true;
+ mNavMeshZone.refresh();
+ break;
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestStarted :
+ setConsoleState(kConsoleStateDownloading);
+ break;
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestCompleted :
+ mIsNavMeshUpdating = false;
+ setConsoleState(kConsoleStateHasNavMesh);
+ break;
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestNotEnabled :
+ setConsoleState(kConsoleStateRegionNotEnabled);
+ break;
+ case LLPathfindingNavMeshZone::kNavMeshZoneRequestError :
+ setConsoleState(kConsoleStateError);
+ break;
+ default:
+ setConsoleState(kConsoleStateUnknown);
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ setAgentState(pAgentState);
+}
+
+void LLFloaterPathfindingConsole::setConsoleState(EConsoleState pConsoleState)
+{
+ mConsoleState = pConsoleState;
+ updateControlsOnConsoleState();
+ updateStatusOnConsoleState();
+}
+
+void LLFloaterPathfindingConsole::updateControlsOnConsoleState()
+{
+ switch (mConsoleState)
+ {
+ case kConsoleStateUnknown :
+ case kConsoleStateLibraryNotImplemented :
+ case kConsoleStateRegionNotEnabled :
+ mShowNavMeshCheckBox->setEnabled(FALSE);
+ mShowNavMeshWalkabilityComboBox->setEnabled(FALSE);
+ mShowWalkablesCheckBox->setEnabled(FALSE);
+ mShowStaticObstaclesCheckBox->setEnabled(FALSE);
+ mShowMaterialVolumesCheckBox->setEnabled(FALSE);
+ mShowExclusionVolumesCheckBox->setEnabled(FALSE);
+ mShowWorldCheckBox->setEnabled(FALSE);
+ mViewCharactersButton->setEnabled(FALSE);
+ mEditTestTabContainer->selectTab(0);
+ mTestTab->setEnabled(FALSE);
+ mCharacterWidthSlider->setEnabled(FALSE);
+ mCharacterTypeRadioGroup->setEnabled(FALSE);
+ mClearPathButton->setEnabled(FALSE);
+ mHasStartPoint = false;
+ mHasEndPoint = false;
+ break;
+ case kConsoleStateDownloading :
+ case kConsoleStateError :
+ mShowNavMeshCheckBox->setEnabled(FALSE);
+ mShowNavMeshWalkabilityComboBox->setEnabled(FALSE);
+ mShowWalkablesCheckBox->setEnabled(FALSE);
+ mShowStaticObstaclesCheckBox->setEnabled(FALSE);
+ mShowMaterialVolumesCheckBox->setEnabled(FALSE);
+ mShowExclusionVolumesCheckBox->setEnabled(FALSE);
+ mShowWorldCheckBox->setEnabled(FALSE);
+ mViewCharactersButton->setEnabled(TRUE);
+ mEditTestTabContainer->selectTab(0);
+ mTestTab->setEnabled(FALSE);
+ mCharacterWidthSlider->setEnabled(FALSE);
+ mCharacterTypeRadioGroup->setEnabled(FALSE);
+ mClearPathButton->setEnabled(FALSE);
+ mHasStartPoint = false;
+ mHasEndPoint = false;
+ break;
+ case kConsoleStateHasNavMesh :
+ mShowNavMeshCheckBox->setEnabled(TRUE);
+ mShowNavMeshWalkabilityComboBox->setEnabled(TRUE);
+ mShowWalkablesCheckBox->setEnabled(TRUE);
+ mShowStaticObstaclesCheckBox->setEnabled(TRUE);
+ mShowMaterialVolumesCheckBox->setEnabled(TRUE);
+ mShowExclusionVolumesCheckBox->setEnabled(TRUE);
+ mShowWorldCheckBox->setEnabled(TRUE);
+ mViewCharactersButton->setEnabled(TRUE);
+ mTestTab->setEnabled(TRUE);
+ mCharacterWidthSlider->setEnabled(TRUE);
+ mCharacterTypeRadioGroup->setEnabled(TRUE);
+ mClearPathButton->setEnabled(TRUE);
+ mTestTab->setEnabled(TRUE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::updateStatusOnConsoleState()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ switch (mConsoleState)
+ {
+ case kConsoleStateUnknown :
+ statusText = getString("navmesh_status_unknown");
+ break;
+ case kConsoleStateLibraryNotImplemented :
+ statusText = getString("navmesh_status_library_not_implemented");
+ styleParams.color = warningColor;
+ break;
+ case kConsoleStateRegionNotEnabled :
+ statusText = getString("navmesh_status_region_not_enabled");
+ styleParams.color = warningColor;
+ break;
+ case kConsoleStateDownloading :
+ if (mIsNavMeshUpdating)
+ {
+ statusText = getString("navmesh_status_updating");
+ }
+ else
+ {
+ statusText = getString("navmesh_status_downloading");
+ }
+ break;
+ case kConsoleStateHasNavMesh :
+ statusText = getString("navmesh_status_has_navmesh");
+ break;
+ case kConsoleStateError :
+ statusText = getString("navmesh_status_error");
+ styleParams.color = warningColor;
+ break;
+ default :
+ statusText = getString("navmesh_status_unknown");
+ llassert(0);
+ break;
+ }
+
+ mPathfindingStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+void LLFloaterPathfindingConsole::setAgentState(LLPathfindingManager::EAgentState pAgentState)
+{
+ switch (LLPathfindingManager::getInstance()->getLastKnownNonErrorAgentState())
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mEditTab->setEnabled(FALSE);
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mLinksetsLabel->setEnabled(FALSE);
+ mLinksetsButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateFrozen :
+ mEditTab->setEnabled(TRUE);
+ mUnfreezeLabel->setEnabled(TRUE);
+ mUnfreezeButton->setEnabled(TRUE);
+ mLinksetsLabel->setEnabled(FALSE);
+ mLinksetsButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateUnfrozen :
+ mEditTab->setEnabled(TRUE);
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mLinksetsLabel->setEnabled(TRUE);
+ mLinksetsButton->setEnabled(TRUE);
+ mFreezeLabel->setEnabled(TRUE);
+ mFreezeButton->setEnabled(TRUE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::generatePath()
+{
+ if (mHasStartPoint && mHasEndPoint)
+ {
+ mPathData.mCharacterWidth = getCharacterWidth();
+ LLPathingLib::getInstance()->generatePath(mPathData);
+ }
+}
+
+void LLFloaterPathfindingConsole::updatePathTestStatus()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ if (!mHasStartPoint && !mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_start_and_end_points");
+ styleParams.color = warningColor;
+ }
+ else if (!mHasStartPoint && mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_start_point");
+ styleParams.color = warningColor;
+ }
+ else if (mHasStartPoint && !mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_end_point");
+ styleParams.color = warningColor;
+ }
+ else
+ {
+ statusText = getString("pathing_path_valid");
+ }
+
+ mPathTestingStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+
+BOOL LLFloaterPathfindingConsole::isRenderAnyShapes() const
+{
+ if ( isRenderWalkables() || isRenderStaticObstacles() ||
+ isRenderMaterialVolumes() || isRenderExclusionVolumes() )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+U32 LLFloaterPathfindingConsole::getRenderShapeFlags()
+{
+ resetShapeRenderFlags();
+
+ if ( isRenderWalkables() )
+ {
+ setShapeRenderFlag( LLPathingLib::LLST_WalkableObjects );
+ }
+ if ( isRenderStaticObstacles() )
+ {
+ setShapeRenderFlag( LLPathingLib::LLST_ObstacleObjects );
+ }
+ if ( isRenderMaterialVolumes() )
+ {
+ setShapeRenderFlag( LLPathingLib::LLST_MaterialPhantoms );
+ }
+ if ( isRenderExclusionVolumes() )
+ {
+ setShapeRenderFlag( LLPathingLib::LLST_ExclusionPhantoms );
+ }
+ return mShapeRenderFlags;
+}
+
+void LLFloaterPathfindingConsole::regionCrossingOccured()
+{
+ std::string statusText("");
+ LLStyle::Params styleParams;
+ styleParams.color = LLUIColorTable::instance().getColor("DrYellow");
+ statusText = getString("navmesh_update_needed");
+ mPathfindingStatus->setText((LLStringExplicit)statusText, styleParams);
+}
\ No newline at end of file diff --git a/indra/newview/llfloaterpathfindingconsole.h b/indra/newview/llfloaterpathfindingconsole.h new file mode 100644 index 0000000000..0f9f859924 --- /dev/null +++ b/indra/newview/llfloaterpathfindingconsole.h @@ -0,0 +1,201 @@ +/** + * @file llfloaterpathfindingconsole.h + * @author William Todd Stinson + * @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings. + * + * $LicenseInfo:firstyear=2002&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_LLFLOATERPATHFINDINGCONSOLE_H +#define LL_LLFLOATERPATHFINDINGCONSOLE_H + +#include "llfloater.h" +#include "llhandle.h" +#include "LLPathingLib.h" +#include "llpathfindingmanager.h" +#include "llpathfindingnavmeshzone.h" + +class LLSD; +class LLPanel; +class LLRadioGroup; +class LLSliderCtrl; +class LLLineEditor; +class LLTextBase; +class LLCheckBoxCtrl; +class LLTabContainer; +class LLComboBox; +class LLButton; + +class LLFloaterPathfindingConsole +: public LLFloater +{ + friend class LLFloaterReg; + +public: + typedef enum + { + kRenderHeatmapNone, + kRenderHeatmapA, + kRenderHeatmapB, + kRenderHeatmapC, + kRenderHeatmapD + } ERenderHeatmapType; + + typedef enum + { + kCharacterTypeA = 0, + kCharacterTypeB = 1, + kCharacterTypeC = 2, + kCharacterTypeD = 3 + } ECharacterType; + + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& pKey); + virtual void onClose(bool pIsAppQuitting); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + + BOOL isGeneratePathMode(MASK mask, EClickType clicktype, BOOL down) const; + + static LLHandle<LLFloaterPathfindingConsole> getInstanceHandle(); + + BOOL isRenderPath() const; + + BOOL isRenderNavMesh() const; + void setRenderNavMesh(BOOL pIsRenderNavMesh); + + BOOL isRenderWalkables() const; + void setRenderWalkables(BOOL pIsRenderWalkables); + + BOOL isRenderStaticObstacles() const; + void setRenderStaticObstacles(BOOL pIsRenderStaticObstacles); + + BOOL isRenderMaterialVolumes() const; + void setRenderMaterialVolumes(BOOL pIsRenderMaterialVolumes); + + BOOL isRenderExclusionVolumes() const; + void setRenderExclusionVolumes(BOOL pIsRenderExclusionVolumes); + + BOOL isRenderWorld() const; + void setRenderWorld(BOOL pIsRenderWorld); + + BOOL isRenderAnyShapes() const; + U32 getRenderShapeFlags(); + + ERenderHeatmapType getRenderHeatmapType() const; + void setRenderHeatmapType(ERenderHeatmapType pRenderHeatmapType); + + F32 getCharacterWidth() const; + void setCharacterWidth(F32 pCharacterWidth); + + ECharacterType getCharacterType() const; + void setCharacterType(ECharacterType pCharacterType); + + bool getHeartBeat() const { return mHeartBeat;} + void setHeartBeat( bool state ) { mHeartBeat=state; } + void regionCrossingOccured(); + + +protected: + +private: + typedef enum + { + kConsoleStateUnknown, + kConsoleStateLibraryNotImplemented, + kConsoleStateRegionNotEnabled, + kConsoleStateDownloading, + kConsoleStateHasNavMesh, + kConsoleStateError + } EConsoleState; + + // Does its own instance management, so clients not allowed + // to allocate or destroy. + LLFloaterPathfindingConsole(const LLSD& pSeed); + virtual ~LLFloaterPathfindingConsole(); + + void onShowWalkabilitySet(); + void onShowWorldToggle(); + void onCharacterWidthSet(); + void onCharacterTypeSwitch(); + void onViewCharactersClicked(); + void onUnfreezeClicked(); + void onFreezeClicked(); + void onViewEditLinksetClicked(); + void onClearPathClicked(); + void onNavMeshZoneCB(LLPathfindingNavMeshZone::ENavMeshZoneRequestStatus pNavMeshZoneRequestStatus); + void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState); + + void setConsoleState(EConsoleState pConsoleState); + + void updateControlsOnConsoleState(); + void updateStatusOnConsoleState(); + + void setAgentState(LLPathfindingManager::EAgentState pAgentState); + + void generatePath(); + void updatePathTestStatus(); + void resetShapeRenderFlags() { mShapeRenderFlags = 0; } + void setShapeRenderFlag( LLPathingLib::LLShapeType type ) { mShapeRenderFlags |= (1<<type); } + + LLRootHandle<LLFloaterPathfindingConsole> mSelfHandle; + LLCheckBoxCtrl *mShowNavMeshCheckBox; + LLComboBox *mShowNavMeshWalkabilityComboBox; + LLCheckBoxCtrl *mShowWalkablesCheckBox; + LLCheckBoxCtrl *mShowStaticObstaclesCheckBox; + LLCheckBoxCtrl *mShowMaterialVolumesCheckBox; + LLCheckBoxCtrl *mShowExclusionVolumesCheckBox; + LLCheckBoxCtrl *mShowWorldCheckBox; + LLTextBase *mPathfindingStatus; + LLButton *mViewCharactersButton; + LLTabContainer *mEditTestTabContainer; + LLPanel *mEditTab; + LLPanel *mTestTab; + LLTextBase *mUnfreezeLabel; + LLButton *mUnfreezeButton; + LLTextBase *mLinksetsLabel; + LLButton *mLinksetsButton; + LLTextBase *mFreezeLabel; + LLButton *mFreezeButton; + LLSliderCtrl *mCharacterWidthSlider; + LLRadioGroup *mCharacterTypeRadioGroup; + LLTextBase *mPathTestingStatus; + LLButton *mClearPathButton; + + LLPathfindingNavMeshZone::navmesh_zone_slot_t mNavMeshZoneSlot; + LLPathfindingNavMeshZone mNavMeshZone; + bool mIsNavMeshUpdating; + + LLPathfindingManager::agent_state_slot_t mAgentStateSlot; + + EConsoleState mConsoleState; + + //Container that is populated and subsequently submitted to the LLPathingSystem for processing + LLPathingLib::PathingPacket mPathData; + bool mHasStartPoint; + bool mHasEndPoint; + U32 mShapeRenderFlags; + bool mHeartBeat; + + static LLHandle<LLFloaterPathfindingConsole> sInstanceHandle; +}; + +#endif // LL_LLFLOATERPATHFINDINGCONSOLE_H diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp new file mode 100644 index 0000000000..af2024021b --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -0,0 +1,1225 @@ +/**
+ * @file llfloaterpathfindinglinksets.cpp
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llfloaterpathfindinglinksets.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "v3math.h"
+#include "lltextvalidate.h"
+#include "llagent.h"
+#include "lltextbase.h"
+#include "lllineeditor.h"
+#include "llscrolllistitem.h"
+#include "llscrolllistctrl.h"
+#include "llcombobox.h"
+#include "llcheckboxctrl.h"
+#include "llbutton.h"
+#include "llresmgr.h"
+#include "llviewerregion.h"
+#include "llselectmgr.h"
+#include "llviewermenu.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+#include "llpathfindingmanager.h"
+#include "llnotificationsutil.h"
+
+#include <boost/bind.hpp>
+#include <boost/signals2.hpp>
+
+#define XUI_LINKSET_USE_NONE 0
+#define XUI_LINKSET_USE_WALKABLE 1
+#define XUI_LINKSET_USE_STATIC_OBSTACLE 2
+#define XUI_LINKSET_USE_DYNAMIC_OBSTACLE 3
+#define XUI_LINKSET_USE_MATERIAL_VOLUME 4
+#define XUI_LINKSET_USE_EXCLUSION_VOLUME 5
+#define XUI_LINKSET_USE_DYNAMIC_PHANTOM 6
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingLinksets
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingLinksets::postBuild()
+{
+ childSetAction("apply_filters", boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ childSetAction("clear_filters", boost::bind(&LLFloaterPathfindingLinksets::onClearFiltersClicked, this));
+
+ mFilterByName = findChild<LLLineEditor>("filter_by_name");
+ llassert(mFilterByName != NULL);
+ mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByName->setSelectAllonFocusReceived(true);
+ mFilterByName->setCommitOnFocusLost(true);
+
+ mFilterByDescription = findChild<LLLineEditor>("filter_by_description");
+ llassert(mFilterByDescription != NULL);
+ mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByDescription->setSelectAllonFocusReceived(true);
+ mFilterByDescription->setCommitOnFocusLost(true);
+
+ mFilterByLinksetUse = findChild<LLComboBox>("filter_by_linkset_use");
+ llassert(mFilterByLinksetUse != NULL);
+ mFilterByLinksetUse->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+
+ mLinksetsScrollList = findChild<LLScrollListCtrl>("pathfinding_linksets");
+ llassert(mLinksetsScrollList != NULL);
+ mLinksetsScrollList->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onLinksetsSelectionChange, this));
+ mLinksetsScrollList->sortByColumnIndex(0, true);
+
+ mLinksetsStatus = findChild<LLTextBase>("linksets_status");
+ llassert(mLinksetsStatus != NULL);
+
+ mRefreshListButton = findChild<LLButton>("refresh_linksets_list");
+ llassert(mRefreshListButton != NULL);
+ mRefreshListButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onRefreshLinksetsClicked, this));
+
+ mSelectAllButton = findChild<LLButton>("select_all_linksets");
+ llassert(mSelectAllButton != NULL);
+ mSelectAllButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onSelectAllLinksetsClicked, this));
+
+ mSelectNoneButton = findChild<LLButton>("select_none_linksets");
+ llassert(mSelectNoneButton != NULL);
+ mSelectNoneButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onSelectNoneLinksetsClicked, this));
+
+ mShowBeaconCheckBox = findChild<LLCheckBoxCtrl>("show_beacon");
+ llassert(mShowBeaconCheckBox != NULL);
+
+ mTakeButton = findChild<LLButton>("take_linksets");
+ llassert(mTakeButton != NULL);
+ mTakeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTakeClicked, this));
+
+ mTakeCopyButton = findChild<LLButton>("take_copy_linksets");
+ llassert(mTakeCopyButton != NULL);
+ mTakeCopyButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTakeCopyClicked, this));
+
+ mReturnButton = findChild<LLButton>("return_linksets");
+ llassert(mReturnButton != NULL);
+ mReturnButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onReturnClicked, this));
+
+ mDeleteButton = findChild<LLButton>("delete_linksets");
+ llassert(mDeleteButton != NULL);
+ mDeleteButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onDeleteClicked, this));
+
+ mTeleportButton = findChild<LLButton>("teleport_me_to_linkset");
+ llassert(mTeleportButton != NULL);
+ mTeleportButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTeleportClicked, this));
+
+ mEditLinksetUse = findChild<LLComboBox>("edit_linkset_use");
+ llassert(mEditLinksetUse != NULL);
+
+ mEditLinksetUse->clearRows();
+
+ mEditLinksetUseUnset = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getString("linkset_choose_use"), XUI_LINKSET_USE_NONE));
+ llassert(mEditLinksetUseUnset != NULL);
+
+ mEditLinksetUseWalkable = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kWalkable), XUI_LINKSET_USE_WALKABLE));
+ llassert(mEditLinksetUseWalkable != NULL);
+
+ mEditLinksetUseStaticObstacle = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kStaticObstacle), XUI_LINKSET_USE_STATIC_OBSTACLE));
+ llassert(mEditLinksetUseStaticObstacle != NULL);
+
+ mEditLinksetUseDynamicObstacle = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kDynamicObstacle), XUI_LINKSET_USE_DYNAMIC_OBSTACLE));
+ llassert(mEditLinksetUseDynamicObstacle != NULL);
+
+ mEditLinksetUseMaterialVolume = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kMaterialVolume), XUI_LINKSET_USE_MATERIAL_VOLUME));
+ llassert(mEditLinksetUseMaterialVolume != NULL);
+
+ mEditLinksetUseExclusionVolume = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kExclusionVolume), XUI_LINKSET_USE_EXCLUSION_VOLUME));
+ llassert(mEditLinksetUseExclusionVolume != NULL);
+
+ mEditLinksetUseDynamicPhantom = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kDynamicPhantom), XUI_LINKSET_USE_DYNAMIC_PHANTOM));
+ llassert(mEditLinksetUseDynamicPhantom != NULL);
+
+ mEditLinksetUse->selectFirstItem();
+
+ mLabelWalkabilityCoefficients = findChild<LLTextBase>("walkability_coefficients_label");
+ llassert(mLabelWalkabilityCoefficients != NULL);
+
+ mLabelEditA = findChild<LLTextBase>("edit_a_label");
+ llassert(mLabelEditA != NULL);
+
+ mEditA = findChild<LLLineEditor>("edit_a_value");
+ llassert(mEditA != NULL);
+ mEditA->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditA->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditB = findChild<LLTextBase>("edit_b_label");
+ llassert(mLabelEditB != NULL);
+
+ mEditB = findChild<LLLineEditor>("edit_b_value");
+ llassert(mEditB != NULL);
+ mEditB->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditB->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditC = findChild<LLTextBase>("edit_c_label");
+ llassert(mLabelEditC != NULL);
+
+ mEditC = findChild<LLLineEditor>("edit_c_value");
+ llassert(mEditC != NULL);
+ mEditC->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditC->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditD = findChild<LLTextBase>("edit_d_label");
+ llassert(mLabelEditD != NULL);
+
+ mEditD = findChild<LLLineEditor>("edit_d_value");
+ llassert(mEditD != NULL);
+ mEditD->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditD->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mApplyEditsButton = findChild<LLButton>("apply_edit_values");
+ llassert(mApplyEditsButton != NULL);
+ mApplyEditsButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyChangesClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingLinksets::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+
+ requestGetLinksets();
+ selectNoneLinksets();
+ mLinksetsScrollList->setCommitOnSelectionChange(true);
+
+ if (!mAgentStateSlot.connected())
+ {
+ mAgentStateSlot = LLPathfindingManager::getInstance()->registerAgentStateListener(boost::bind(&LLFloaterPathfindingLinksets::onAgentStateCB, this, _1));
+ }
+
+ if (!mSelectionUpdateSlot.connected())
+ {
+ mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect(boost::bind(&LLFloaterPathfindingLinksets::updateControls, this));
+ }
+}
+
+void LLFloaterPathfindingLinksets::onClose(bool pAppQuitting)
+{
+ if (mSelectionUpdateSlot.connected())
+ {
+ mSelectionUpdateSlot.disconnect();
+ }
+
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+
+ mLinksetsScrollList->setCommitOnSelectionChange(false);
+ selectNoneLinksets();
+ if (mLinksetsSelection.notNull())
+ {
+ mLinksetsSelection.clear();
+ }
+
+ LLFloater::onClose(pAppQuitting);
+}
+
+void LLFloaterPathfindingLinksets::draw()
+{
+ if (mShowBeaconCheckBox->get())
+ {
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ const std::string &objectName = selectedItem->getColumn(0)->getValue().asString();
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ gObjectList.addDebugBeacon(viewerObject->getPositionAgent(), objectName, LLColor4(0.f, 0.f, 1.f, 0.8f), LLColor4(1.f, 1.f, 1.f, 1.f), 6);
+ }
+ }
+ }
+ }
+
+ LLFloater::draw();
+}
+
+void LLFloaterPathfindingLinksets::openLinksetsEditor()
+{
+ LLFloaterReg::toggleInstanceOrBringToFront("pathfinding_linksets");
+}
+
+LLFloaterPathfindingLinksets::EMessagingState LLFloaterPathfindingLinksets::getMessagingState() const
+{
+ return mMessagingState;
+}
+
+bool LLFloaterPathfindingLinksets::isMessagingInProgress() const
+{
+ return ((mMessagingState == kMessagingGetRequestSent) || (mMessagingState == kMessagingSetRequestSent));
+}
+
+LLFloaterPathfindingLinksets::LLFloaterPathfindingLinksets(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mFilterByName(NULL),
+ mFilterByDescription(NULL),
+ mFilterByLinksetUse(NULL),
+ mLinksetsScrollList(NULL),
+ mLinksetsStatus(NULL),
+ mRefreshListButton(NULL),
+ mSelectAllButton(NULL),
+ mSelectNoneButton(NULL),
+ mShowBeaconCheckBox(NULL),
+ mTakeButton(NULL),
+ mTakeCopyButton(NULL),
+ mReturnButton(NULL),
+ mDeleteButton(NULL),
+ mTeleportButton(NULL),
+ mEditLinksetUse(NULL),
+ mLabelWalkabilityCoefficients(NULL),
+ mLabelEditA(NULL),
+ mEditA(NULL),
+ mLabelEditB(NULL),
+ mEditB(NULL),
+ mLabelEditC(NULL),
+ mEditC(NULL),
+ mLabelEditD(NULL),
+ mEditD(NULL),
+ mApplyEditsButton(NULL),
+ mMessagingState(kMessagingUnknown),
+ mLinksetsListPtr(),
+ mLinksetsSelection(),
+ mAgentStateSlot(),
+ mSelectionUpdateSlot()
+{
+}
+
+LLFloaterPathfindingLinksets::~LLFloaterPathfindingLinksets()
+{
+}
+
+void LLFloaterPathfindingLinksets::setMessagingState(EMessagingState pMessagingState)
+{
+ mMessagingState = pMessagingState;
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::requestGetLinksets()
+{
+ llassert(!isMessagingInProgress());
+ if (!isMessagingInProgress())
+ {
+ switch (LLPathfindingManager::getInstance()->requestGetLinksets(boost::bind(&LLFloaterPathfindingLinksets::handleNewLinksets, this, _1, _2)))
+ {
+ case LLPathfindingManager::kLinksetsRequestStarted :
+ setMessagingState(kMessagingGetRequestSent);
+ break;
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ clearLinksets();
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestNotEnabled :
+ clearLinksets();
+ setMessagingState(kMessagingNotEnabled);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingGetError);
+ break;
+ default :
+ setMessagingState(kMessagingGetError);
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD)
+{
+ llassert(!isMessagingInProgress());
+ if (!isMessagingInProgress())
+ {
+ switch (LLPathfindingManager::getInstance()->requestSetLinksets(pLinksetList, pLinksetUse, pA, pB, pC, pD, boost::bind(&LLFloaterPathfindingLinksets::handleUpdateLinksets, this, _1, _2)))
+ {
+ case LLPathfindingManager::kLinksetsRequestStarted :
+ setMessagingState(kMessagingSetRequestSent);
+ break;
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestNotEnabled :
+ clearLinksets();
+ setMessagingState(kMessagingNotEnabled);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingSetError);
+ break;
+ default :
+ setMessagingState(kMessagingSetError);
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleNewLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr)
+{
+ mLinksetsListPtr = pLinksetsListPtr;
+ updateScrollList();
+
+ switch (pLinksetsRequestStatus)
+ {
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingGetError);
+ break;
+ default :
+ setMessagingState(kMessagingGetError);
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleUpdateLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr)
+{
+ if (mLinksetsListPtr == NULL)
+ {
+ mLinksetsListPtr = pLinksetsListPtr;
+ }
+ else
+ {
+ mLinksetsListPtr->update(*pLinksetsListPtr);
+ }
+ updateScrollList();
+
+ switch (pLinksetsRequestStatus)
+ {
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingSetError);
+ break;
+ default :
+ setMessagingState(kMessagingSetError);
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::onApplyAllFilters()
+{
+ applyFilters();
+}
+
+void LLFloaterPathfindingLinksets::onClearFiltersClicked()
+{
+ clearFilters();
+}
+
+void LLFloaterPathfindingLinksets::onLinksetsSelectionChange()
+{
+ mLinksetsSelection.clear();
+ LLSelectMgr::getInstance()->deselectAll();
+
+ std::vector<LLScrollListItem *> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *>viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem *>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ viewerObjects.push_back(viewerObject);
+ }
+ }
+
+ if (!viewerObjects.empty())
+ {
+ mLinksetsSelection = LLSelectMgr::getInstance()->selectObjectAndFamily(viewerObjects);
+ }
+ }
+
+ updateEditFieldValues();
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::onRefreshLinksetsClicked()
+{
+ requestGetLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onSelectAllLinksetsClicked()
+{
+ selectAllLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onSelectNoneLinksetsClicked()
+{
+ selectNoneLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onTakeClicked()
+{
+ handle_take();
+}
+
+void LLFloaterPathfindingLinksets::onTakeCopyClicked()
+{
+ handle_take_copy();
+}
+
+void LLFloaterPathfindingLinksets::onReturnClicked()
+{
+ handle_object_return();
+}
+
+void LLFloaterPathfindingLinksets::onDeleteClicked()
+{
+ handle_object_delete();
+}
+
+void LLFloaterPathfindingLinksets::onTeleportClicked()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ llassert(selectedItems.size() == 1);
+ if (selectedItems.size() == 1)
+ {
+ std::vector<LLScrollListItem*>::const_reference selectedItemRef = selectedItems.front();
+ const LLScrollListItem *selectedItem = selectedItemRef;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ const LLVector3 &linksetLocation = linksetPtr->getLocation();
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ gAgent.teleportRequest(region->getHandle(), linksetLocation, true);
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl)
+{
+ LLLineEditor *pLineEditor = static_cast<LLLineEditor *>(pUICtrl);
+ llassert(pLineEditor != NULL);
+
+ const std::string &valueString = pLineEditor->getText();
+ S32 value = static_cast<S32>(atoi(valueString.c_str()));
+
+ if ((value < LLPathfindingLinkset::MIN_WALKABILITY_VALUE) || (value > LLPathfindingLinkset::MAX_WALKABILITY_VALUE))
+ {
+ value = llclamp(value, LLPathfindingLinkset::MIN_WALKABILITY_VALUE, LLPathfindingLinkset::MAX_WALKABILITY_VALUE);
+ pLineEditor->setValue(LLSD(value));
+ }
+}
+
+void LLFloaterPathfindingLinksets::onApplyChangesClicked()
+{
+ applyEdit();
+}
+
+void LLFloaterPathfindingLinksets::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::applyFilters()
+{
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::clearFilters()
+{
+ mFilterByName->clear();
+ mFilterByDescription->clear();
+ setFilterLinksetUse(LLPathfindingLinkset::kUnknown);
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::selectAllLinksets()
+{
+ mLinksetsScrollList->selectAll();
+}
+
+void LLFloaterPathfindingLinksets::selectNoneLinksets()
+{
+ mLinksetsScrollList->deselectAllItems();
+}
+
+void LLFloaterPathfindingLinksets::clearLinksets()
+{
+ if (mLinksetsListPtr != NULL)
+ {
+ mLinksetsListPtr->clear();
+ }
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::updateControls()
+{
+ updateStatusMessage();
+ updateEnableStateOnListActions();
+ updateEnableStateOnEditFields();
+}
+
+void LLFloaterPathfindingLinksets::updateEditFieldValues()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ if (numSelectedItems <= 0)
+ {
+ mEditLinksetUse->selectFirstItem();
+ mEditA->clear();
+ mEditB->clear();
+ mEditC->clear();
+ mEditD->clear();
+ }
+ else
+ {
+ LLScrollListItem *firstItem = selectedItems.front();
+
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(firstItem->getUUID().asString());
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+
+ setEditLinksetUse(linksetPtr->getLinksetUse());
+ mEditA->setValue(LLSD(linksetPtr->getWalkabilityCoefficientA()));
+ mEditB->setValue(LLSD(linksetPtr->getWalkabilityCoefficientB()));
+ mEditC->setValue(LLSD(linksetPtr->getWalkabilityCoefficientC()));
+ mEditD->setValue(LLSD(linksetPtr->getWalkabilityCoefficientD()));
+
+ switch (getAllowLinksetUse())
+ {
+ case kAllowLinksetUseAll :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(TRUE);
+ mEditLinksetUseDynamicObstacle->setEnabled(TRUE);
+ mEditLinksetUseMaterialVolume->setEnabled(TRUE);
+ mEditLinksetUseExclusionVolume->setEnabled(TRUE);
+ mEditLinksetUseDynamicPhantom->setEnabled(TRUE);
+ break;
+ case kAllowLinksetUseOnlyNonPhantom :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(TRUE);
+ mEditLinksetUseDynamicObstacle->setEnabled(TRUE);
+ mEditLinksetUseMaterialVolume->setEnabled(FALSE);
+ mEditLinksetUseExclusionVolume->setEnabled(FALSE);
+ mEditLinksetUseDynamicPhantom->setEnabled(FALSE);
+ break;
+ case kAllowLinksetUseOnlyPhantom :
+ mEditLinksetUseWalkable->setEnabled(FALSE);
+ mEditLinksetUseStaticObstacle->setEnabled(FALSE);
+ mEditLinksetUseDynamicObstacle->setEnabled(FALSE);
+ mEditLinksetUseMaterialVolume->setEnabled(TRUE);
+ mEditLinksetUseExclusionVolume->setEnabled(TRUE);
+ mEditLinksetUseDynamicPhantom->setEnabled(TRUE);
+ break;
+ case kAllowLinksetUseOnlyTerrain :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(FALSE);
+ mEditLinksetUseDynamicObstacle->setEnabled(FALSE);
+ mEditLinksetUseMaterialVolume->setEnabled(FALSE);
+ mEditLinksetUseExclusionVolume->setEnabled(FALSE);
+ mEditLinksetUseDynamicPhantom->setEnabled(FALSE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::updateScrollList()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ uuid_vec_t selectedUUIDs;
+ if (numSelectedItems > 0)
+ {
+ selectedUUIDs.reserve(selectedItems.size());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ selectedUUIDs.push_back(listItem->getUUID());
+ }
+ }
+
+ S32 origScrollPosition = mLinksetsScrollList->getScrollPos();
+ mLinksetsScrollList->deleteAllItems();
+
+ if (mLinksetsListPtr != NULL)
+ {
+ std::string nameFilter = mFilterByName->getText();
+ std::string descriptionFilter = mFilterByDescription->getText();
+ LLPathfindingLinkset::ELinksetUse linksetUseFilter = getFilterLinksetUse();
+ bool isFilteringName = !nameFilter.empty();
+ bool isFilteringDescription = !descriptionFilter.empty();
+ bool isFilteringLinksetUse = (linksetUseFilter != LLPathfindingLinkset::kUnknown);
+
+ const LLVector3& avatarPosition = gAgent.getPositionAgent();
+
+ if (isFilteringName || isFilteringDescription || isFilteringLinksetUse)
+ {
+ LLStringUtil::toUpper(nameFilter);
+ LLStringUtil::toUpper(descriptionFilter);
+ for (LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->begin();
+ linksetIter != mLinksetsListPtr->end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+ std::string linksetName = (linksetPtr->isTerrain() ? getString("linkset_terrain_name") : linksetPtr->getName());
+ std::string linksetDescription = linksetPtr->getDescription();
+ LLStringUtil::toUpper(linksetName);
+ LLStringUtil::toUpper(linksetDescription);
+ if ((!isFilteringName || (linksetName.find(nameFilter) != std::string::npos)) &&
+ (!isFilteringDescription || (linksetDescription.find(descriptionFilter) != std::string::npos)) &&
+ (!isFilteringLinksetUse || (linksetPtr->getLinksetUse() == linksetUseFilter)))
+ {
+ LLSD element = buildLinksetScrollListElement(linksetPtr, avatarPosition);
+ mLinksetsScrollList->addElement(element);
+ }
+ }
+ }
+ else
+ {
+ for (LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->begin();
+ linksetIter != mLinksetsListPtr->end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+ LLSD element = buildLinksetScrollListElement(linksetPtr, avatarPosition);
+ mLinksetsScrollList->addElement(element);
+ }
+ }
+ }
+
+ mLinksetsScrollList->selectMultiple(selectedUUIDs);
+ mLinksetsScrollList->setScrollPos(origScrollPosition);
+ updateEditFieldValues();
+ updateControls();
+}
+
+LLSD LLFloaterPathfindingLinksets::buildLinksetScrollListElement(const LLPathfindingLinksetPtr pLinksetPtr, const LLVector3 &pAvatarPosition) const
+{
+ LLSD columns;
+
+ if (pLinksetPtr->isTerrain())
+ {
+ columns[0]["column"] = "name";
+ columns[0]["value"] = getString("linkset_terrain_name");
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = getString("linkset_terrain_description");
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "land_impact";
+ columns[2]["value"] = getString("linkset_terrain_land_impact");
+ columns[2]["font"] = "SANSSERIF";
+
+ columns[3]["column"] = "dist_from_you";
+ columns[3]["value"] = getString("linkset_terrain_dist_from_you");
+ columns[3]["font"] = "SANSSERIF";
+ }
+ else
+ {
+ columns[0]["column"] = "name";
+ columns[0]["value"] = pLinksetPtr->getName();
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = pLinksetPtr->getDescription();
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "land_impact";
+ columns[2]["value"] = llformat("%1d", pLinksetPtr->getLandImpact());
+ columns[2]["font"] = "SANSSERIF";
+
+ columns[3]["column"] = "dist_from_you";
+ columns[3]["value"] = llformat("%1.0f m", dist_vec(pAvatarPosition, pLinksetPtr->getLocation()));
+ columns[3]["font"] = "SANSSERIF";
+ }
+
+ columns[4]["column"] = "linkset_use";
+ std::string linksetUse = getLinksetUseString(pLinksetPtr->getLinksetUse());
+ if (pLinksetPtr->isTerrain())
+ {
+ linksetUse += (" " + getString("linkset_is_terrain"));
+ }
+ else if (!pLinksetPtr->isModifiable())
+ {
+ linksetUse += (" " + getString("linkset_is_restricted_state"));
+ }
+ columns[4]["value"] = linksetUse;
+ columns[4]["font"] = "SANSSERIF";
+
+ columns[5]["column"] = "a_percent";
+ columns[5]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientA());
+ columns[5]["font"] = "SANSSERIF";
+
+ columns[6]["column"] = "b_percent";
+ columns[6]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientB());
+ columns[6]["font"] = "SANSSERIF";
+
+ columns[7]["column"] = "c_percent";
+ columns[7]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientC());
+ columns[7]["font"] = "SANSSERIF";
+
+ columns[8]["column"] = "d_percent";
+ columns[8]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientD());
+ columns[8]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["id"] = pLinksetPtr->getUUID().asString();
+ element["column"] = columns;
+
+ return element;
+}
+
+LLSD LLFloaterPathfindingLinksets::buildLinksetUseScrollListElement(const std::string &label, S32 value) const
+{
+ LLSD columns;
+
+ columns[0]["column"] = "name";
+ columns[0]["relwidth"] = static_cast<LLSD::Real>(100.0f);
+ columns[0]["value"] = label;
+ columns[0]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["value"] = value;
+ element["column"] = columns;
+
+ return element;
+}
+
+LLFloaterPathfindingLinksets::EAllowLinksetsUse LLFloaterPathfindingLinksets::getAllowLinksetUse() const
+{
+ EAllowLinksetsUse allowLinksetUse = kAllowLinksetUseAll;
+
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ bool isAllLocked = true;
+ bool isAllPhantom = true;
+ bool isAllNonPhantom = true;
+ bool isAllTerrain = true;
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ (isAllLocked || isAllPhantom || isAllNonPhantom) && (selectedItemIter != selectedItems.end()); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ llassert(linksetIter != mLinksetsListPtr->end());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (!linksetPtr->isTerrain())
+ {
+ isAllTerrain = false;
+ }
+ if (!linksetPtr->isModifiable())
+ {
+ if (linksetPtr->isPhantom())
+ {
+ isAllNonPhantom = false;
+ }
+ else
+ {
+ isAllPhantom = false;
+ }
+ }
+ else
+ {
+ isAllLocked = false;
+ }
+ }
+
+ if (isAllTerrain)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyTerrain;
+ }
+ else if (isAllLocked)
+ {
+ if (isAllPhantom && !isAllNonPhantom)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyPhantom;
+ }
+ else if (isAllNonPhantom && !isAllPhantom)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyNonPhantom;
+ }
+ }
+ }
+
+ return allowLinksetUse;
+}
+
+bool LLFloaterPathfindingLinksets::doShowLinksetUseSetWarning(LLPathfindingLinkset::ELinksetUse linksetUse) const
+{
+ bool showWarning = false;
+
+ if (linksetUse != LLPathfindingLinkset::kUnknown)
+ {
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ !showWarning && (selectedItemIter != selectedItems.end()); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ llassert(linksetIter != mLinksetsListPtr->end());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ showWarning = (!linksetPtr->isModifiable() && (linksetPtr->isPhantom() != LLPathfindingLinkset::isPhantom(linksetUse)));
+ }
+ }
+ }
+
+ return showWarning;
+}
+
+void LLFloaterPathfindingLinksets::updateStatusMessage()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ switch (getMessagingState())
+ {
+ case kMessagingUnknown:
+ statusText = getString("linksets_messaging_initial");
+ break;
+ case kMessagingGetRequestSent :
+ statusText = getString("linksets_messaging_get_inprogress");
+ break;
+ case kMessagingGetError :
+ statusText = getString("linksets_messaging_get_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingSetRequestSent :
+ statusText = getString("linksets_messaging_set_inprogress");
+ break;
+ case kMessagingSetError :
+ statusText = getString("linksets_messaging_set_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingComplete :
+ if (mLinksetsScrollList->isEmpty())
+ {
+ statusText = getString("linksets_messaging_complete_none_found");
+ }
+ else
+ {
+ S32 numItems = mLinksetsScrollList->getItemCount();
+ S32 numSelectedItems = mLinksetsScrollList->getNumSelected();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ std::string numItemsString;
+ LLResMgr::getInstance()->getIntegerString(numItemsString, numItems);
+
+ std::string numSelectedItemsString;
+ LLResMgr::getInstance()->getIntegerString(numSelectedItemsString, numSelectedItems);
+
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUM_SELECTED]"] = numSelectedItemsString;
+ string_args["[NUM_TOTAL]"] = numItemsString;
+ statusText = getString("linksets_messaging_complete_available", string_args);
+ }
+ break;
+ case kMessagingNotEnabled :
+ statusText = getString("linksets_messaging_not_enabled");
+ styleParams.color = warningColor;
+ break;
+ default:
+ statusText = getString("linksets_messaging_initial");
+ llassert(0);
+ break;
+ }
+
+ mLinksetsStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+void LLFloaterPathfindingLinksets::updateEnableStateOnListActions()
+{
+ switch (getMessagingState())
+ {
+ case kMessagingUnknown:
+ case kMessagingGetRequestSent :
+ case kMessagingSetRequestSent :
+ mRefreshListButton->setEnabled(FALSE);
+ mSelectAllButton->setEnabled(FALSE);
+ mSelectNoneButton->setEnabled(FALSE);
+ break;
+ case kMessagingGetError :
+ case kMessagingSetError :
+ case kMessagingNotEnabled :
+ mRefreshListButton->setEnabled(TRUE);
+ mSelectAllButton->setEnabled(FALSE);
+ mSelectNoneButton->setEnabled(FALSE);
+ break;
+ case kMessagingComplete :
+ {
+ int numItems = mLinksetsScrollList->getItemCount();
+ int numSelectedItems = mLinksetsScrollList->getNumSelected();
+ mRefreshListButton->setEnabled(TRUE);
+ mSelectAllButton->setEnabled(numSelectedItems < numItems);
+ mSelectNoneButton->setEnabled(numSelectedItems > 0);
+ }
+ break;
+ default:
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::updateEnableStateOnEditFields()
+{
+ int numSelectedItems = mLinksetsScrollList->getNumSelected();
+ bool isEditEnabled = ((numSelectedItems > 0) && LLPathfindingManager::getInstance()->isAllowAlterPermanent());
+
+ mShowBeaconCheckBox->setEnabled(numSelectedItems > 0);
+ mTakeButton->setEnabled(isEditEnabled && visible_take_object());
+ mTakeCopyButton->setEnabled(isEditEnabled && enable_object_take_copy());
+ mReturnButton->setEnabled(isEditEnabled && enable_object_return());
+ mDeleteButton->setEnabled(isEditEnabled && enable_object_delete());
+ mTeleportButton->setEnabled(numSelectedItems == 1);
+
+ mEditLinksetUse->setEnabled(isEditEnabled);
+
+ mLabelWalkabilityCoefficients->setEnabled(isEditEnabled);
+ mLabelEditA->setEnabled(isEditEnabled);
+ mLabelEditB->setEnabled(isEditEnabled);
+ mLabelEditC->setEnabled(isEditEnabled);
+ mLabelEditD->setEnabled(isEditEnabled);
+ mEditA->setEnabled(isEditEnabled);
+ mEditB->setEnabled(isEditEnabled);
+ mEditC->setEnabled(isEditEnabled);
+ mEditD->setEnabled(isEditEnabled);
+
+ mApplyEditsButton->setEnabled(isEditEnabled && (getMessagingState() == kMessagingComplete));
+}
+
+void LLFloaterPathfindingLinksets::applyEdit()
+{
+ LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse();
+
+ if (doShowLinksetUseSetWarning(linksetUse))
+ {
+ LLPathfindingLinkset::ELinksetUse restrictedLinksetUse = LLPathfindingLinkset::getLinksetUseWithToggledPhantom(linksetUse);
+ LLSD substitutions;
+ substitutions["REQUESTED_TYPE"] = getLinksetUseString(linksetUse);
+ substitutions["RESTRICTED_TYPE"] = getLinksetUseString(restrictedLinksetUse);
+ LLNotificationsUtil::add("PathfindingLinksets_SetLinksetUseMismatchOnRestricted", substitutions, LLSD(), boost::bind(&LLFloaterPathfindingLinksets::handleApplyEdit, this, _1, _2));
+ }
+ else
+ {
+ doApplyEdit();
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse)
+{
+ if (LLNotificationsUtil::getSelectedOption(pNotification, pResponse) == 0)
+ {
+ doApplyEdit();
+ }
+}
+
+void LLFloaterPathfindingLinksets::doApplyEdit()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse();
+ const std::string &aString = mEditA->getText();
+ const std::string &bString = mEditB->getText();
+ const std::string &cString = mEditC->getText();
+ const std::string &dString = mEditD->getText();
+ S32 aValue = static_cast<S32>(atoi(aString.c_str()));
+ S32 bValue = static_cast<S32>(atoi(bString.c_str()));
+ S32 cValue = static_cast<S32>(atoi(cString.c_str()));
+ S32 dValue = static_cast<S32>(atoi(dString.c_str()));
+
+ LLPathfindingLinksetListPtr editListPtr(new LLPathfindingLinksetList());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ LLUUID uuid = listItem->getUUID();
+ const std::string &uuidString = uuid.asString();
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::iterator linksetIter = mLinksetsListPtr->find(uuidString);
+ llassert(linksetIter != mLinksetsListPtr->end());
+ LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ editListPtr->insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuidString, linksetPtr));
+ }
+
+ requestSetLinksets(editListPtr, linksetUse, aValue, bValue, cValue, dValue);
+ }
+}
+
+std::string LLFloaterPathfindingLinksets::getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const
+{
+ std::string linksetUse;
+
+ switch (pLinksetUse)
+ {
+ case LLPathfindingLinkset::kWalkable :
+ linksetUse = getString("linkset_use_walkable");
+ break;
+ case LLPathfindingLinkset::kStaticObstacle :
+ linksetUse = getString("linkset_use_static_obstacle");
+ break;
+ case LLPathfindingLinkset::kDynamicObstacle :
+ linksetUse = getString("linkset_use_dynamic_obstacle");
+ break;
+ case LLPathfindingLinkset::kMaterialVolume :
+ linksetUse = getString("linkset_use_material_volume");
+ break;
+ case LLPathfindingLinkset::kExclusionVolume :
+ linksetUse = getString("linkset_use_exclusion_volume");
+ break;
+ case LLPathfindingLinkset::kDynamicPhantom :
+ linksetUse = getString("linkset_use_dynamic_phantom");
+ break;
+ case LLPathfindingLinkset::kUnknown :
+ default :
+ linksetUse = getString("linkset_use_dynamic_obstacle");
+ llassert(0);
+ break;
+ }
+
+ return linksetUse;
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getFilterLinksetUse() const
+{
+ return convertToLinksetUse(mFilterByLinksetUse->getValue());
+}
+
+void LLFloaterPathfindingLinksets::setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse)
+{
+ mFilterByLinksetUse->setValue(convertToXuiValue(pLinksetUse));
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getEditLinksetUse() const
+{
+ return convertToLinksetUse(mEditLinksetUse->getValue());
+}
+
+void LLFloaterPathfindingLinksets::setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse)
+{
+ mEditLinksetUse->setValue(convertToXuiValue(pLinksetUse));
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::convertToLinksetUse(LLSD pXuiValue) const
+{
+ LLPathfindingLinkset::ELinksetUse linkUse;
+
+ switch (pXuiValue.asInteger())
+ {
+ case XUI_LINKSET_USE_NONE :
+ linkUse = LLPathfindingLinkset::kUnknown;
+ break;
+ case XUI_LINKSET_USE_WALKABLE :
+ linkUse = LLPathfindingLinkset::kWalkable;
+ break;
+ case XUI_LINKSET_USE_STATIC_OBSTACLE :
+ linkUse = LLPathfindingLinkset::kStaticObstacle;
+ break;
+ case XUI_LINKSET_USE_DYNAMIC_OBSTACLE :
+ linkUse = LLPathfindingLinkset::kDynamicObstacle;
+ break;
+ case XUI_LINKSET_USE_MATERIAL_VOLUME :
+ linkUse = LLPathfindingLinkset::kMaterialVolume;
+ break;
+ case XUI_LINKSET_USE_EXCLUSION_VOLUME :
+ linkUse = LLPathfindingLinkset::kExclusionVolume;
+ break;
+ case XUI_LINKSET_USE_DYNAMIC_PHANTOM :
+ linkUse = LLPathfindingLinkset::kDynamicPhantom;
+ break;
+ default :
+ linkUse = LLPathfindingLinkset::kUnknown;
+ llassert(0);
+ break;
+ }
+
+ return linkUse;
+}
+
+LLSD LLFloaterPathfindingLinksets::convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const
+{
+ LLSD xuiValue;
+
+ switch (pLinksetUse)
+ {
+ case LLPathfindingLinkset::kUnknown :
+ xuiValue = XUI_LINKSET_USE_NONE;
+ break;
+ case LLPathfindingLinkset::kWalkable :
+ xuiValue = XUI_LINKSET_USE_WALKABLE;
+ break;
+ case LLPathfindingLinkset::kStaticObstacle :
+ xuiValue = XUI_LINKSET_USE_STATIC_OBSTACLE;
+ break;
+ case LLPathfindingLinkset::kDynamicObstacle :
+ xuiValue = XUI_LINKSET_USE_DYNAMIC_OBSTACLE;
+ break;
+ case LLPathfindingLinkset::kMaterialVolume :
+ xuiValue = XUI_LINKSET_USE_MATERIAL_VOLUME;
+ break;
+ case LLPathfindingLinkset::kExclusionVolume :
+ xuiValue = XUI_LINKSET_USE_EXCLUSION_VOLUME;
+ break;
+ case LLPathfindingLinkset::kDynamicPhantom :
+ xuiValue = XUI_LINKSET_USE_DYNAMIC_PHANTOM;
+ break;
+ default :
+ xuiValue = XUI_LINKSET_USE_NONE;
+ llassert(0);
+ break;
+ }
+
+ return xuiValue;
+}
diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h new file mode 100644 index 0000000000..d201ffe20b --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.h @@ -0,0 +1,189 @@ +/**
+ * @file llfloaterpathfindinglinksets.h
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLFLOATERPATHFINDINGLINKSETS_H
+#define LL_LLFLOATERPATHFINDINGLINKSETS_H
+
+#include "llfloater.h"
+#include "lluuid.h"
+#include "llselectmgr.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+#include "llpathfindingmanager.h"
+
+#include <boost/signals2.hpp> + +class LLSD;
+class LLUICtrl;
+class LLTextBase;
+class LLScrollListCtrl;
+class LLScrollListItem;
+class LLLineEditor;
+class LLComboBox;
+class LLCheckBoxCtrl;
+class LLButton;
+
+class LLFloaterPathfindingLinksets
+: public LLFloater
+{
+ friend class LLFloaterReg;
+
+public:
+ typedef enum
+ {
+ kMessagingUnknown,
+ kMessagingGetRequestSent,
+ kMessagingGetError,
+ kMessagingSetRequestSent,
+ kMessagingSetError,
+ kMessagingComplete,
+ kMessagingNotEnabled
+ } EMessagingState;
+
+ virtual BOOL postBuild();
+ virtual void onOpen(const LLSD& pKey);
+ virtual void onClose(bool pAppQuitting);
+ virtual void draw();
+
+ static void openLinksetsEditor();
+
+ EMessagingState getMessagingState() const;
+ bool isMessagingInProgress() const;
+
+protected:
+
+private:
+ typedef enum
+ {
+ kAllowLinksetUseAll,
+ kAllowLinksetUseOnlyNonPhantom,
+ kAllowLinksetUseOnlyPhantom,
+ kAllowLinksetUseOnlyTerrain
+ } EAllowLinksetsUse;
+
+ LLLineEditor *mFilterByName;
+ LLLineEditor *mFilterByDescription;
+ LLComboBox *mFilterByLinksetUse;
+ LLScrollListCtrl *mLinksetsScrollList;
+ LLTextBase *mLinksetsStatus;
+ LLButton *mRefreshListButton;
+ LLButton *mSelectAllButton;
+ LLButton *mSelectNoneButton;
+ LLCheckBoxCtrl *mShowBeaconCheckBox;
+ LLButton *mTakeButton;
+ LLButton *mTakeCopyButton;
+ LLButton *mReturnButton;
+ LLButton *mDeleteButton;
+ LLButton *mTeleportButton;
+ LLComboBox *mEditLinksetUse;
+ LLScrollListItem *mEditLinksetUseUnset;
+ LLScrollListItem *mEditLinksetUseWalkable;
+ LLScrollListItem *mEditLinksetUseStaticObstacle;
+ LLScrollListItem *mEditLinksetUseDynamicObstacle;
+ LLScrollListItem *mEditLinksetUseMaterialVolume;
+ LLScrollListItem *mEditLinksetUseExclusionVolume;
+ LLScrollListItem *mEditLinksetUseDynamicPhantom;
+ LLTextBase *mLabelWalkabilityCoefficients;
+ LLTextBase *mLabelEditA;
+ LLLineEditor *mEditA;
+ LLTextBase *mLabelEditB;
+ LLLineEditor *mEditB;
+ LLTextBase *mLabelEditC;
+ LLLineEditor *mEditC;
+ LLTextBase *mLabelEditD;
+ LLLineEditor *mEditD;
+ LLButton *mApplyEditsButton;
+
+ EMessagingState mMessagingState;
+ LLPathfindingLinksetListPtr mLinksetsListPtr;
+ LLObjectSelectionHandle mLinksetsSelection;
+ LLPathfindingManager::agent_state_slot_t mAgentStateSlot;
+ boost::signals2::connection mSelectionUpdateSlot; +
+ // Does its own instance management, so clients not allowed
+ // to allocate or destroy.
+ LLFloaterPathfindingLinksets(const LLSD& pSeed);
+ virtual ~LLFloaterPathfindingLinksets();
+
+ void setMessagingState(EMessagingState pMessagingState);
+ void requestGetLinksets();
+ void requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD);
+ void handleNewLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr);
+ void handleUpdateLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr);
+
+ void onApplyAllFilters();
+ void onClearFiltersClicked();
+ void onLinksetsSelectionChange();
+ void onRefreshLinksetsClicked();
+ void onSelectAllLinksetsClicked();
+ void onSelectNoneLinksetsClicked();
+ void onTakeClicked();
+ void onTakeCopyClicked();
+ void onReturnClicked();
+ void onDeleteClicked();
+ void onTeleportClicked();
+ void onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl);
+ void onApplyChangesClicked();
+ void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState);
+
+ void applyFilters();
+ void clearFilters();
+
+ void selectAllLinksets();
+ void selectNoneLinksets();
+ void clearLinksets();
+
+ void updateControls();
+ void updateEditFieldValues();
+ void updateScrollList();
+ LLSD buildLinksetScrollListElement(const LLPathfindingLinksetPtr pLinksetPtr, const LLVector3 &pAvatarPosition) const;
+ LLSD buildLinksetUseScrollListElement(const std::string &label, S32 value) const;
+
+ EAllowLinksetsUse getAllowLinksetUse() const;
+ bool doShowLinksetUseSetWarning(LLPathfindingLinkset::ELinksetUse linksetUse) const;
+
+ void updateStatusMessage();
+ void updateEnableStateOnListActions();
+ void updateEnableStateOnEditFields();
+
+ void applyEdit();
+ void handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse);
+ void doApplyEdit();
+
+ std::string getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const;
+
+ LLPathfindingLinkset::ELinksetUse getFilterLinksetUse() const;
+ void setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse);
+
+ LLPathfindingLinkset::ELinksetUse getEditLinksetUse() const;
+ void setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse);
+
+ LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const;
+ LLSD convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const;
+};
+
+#endif // LL_LLFLOATERPATHFINDINGLINKSETS_H
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index da81bb057b..4139b9725b 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -35,7 +35,7 @@ #define LLCONVEXDECOMPINTER_STATIC 1 -#include "llconvexdecomposition.h" +#include "LLConvexDecomposition.h" #include "lluploadfloaterobservers.h" class LLVOVolume; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 1f77e7a602..ee62a39f75 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -283,7 +283,6 @@ LLPanelObject::LLPanelObject() mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), - mCastShadows(TRUE), mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), mSculptTypeRevert(0) @@ -497,7 +496,7 @@ void LLPanelObject::getState( ) BOOL is_flexible = volobjp && volobjp->isFlexible(); // Physics checkbox - mIsPhysical = root_objectp->usePhysics(); + mIsPhysical = root_objectp->flagUsePhysics(); mCheckPhysics->set( mIsPhysical ); mCheckPhysics->setEnabled( roots_selected>0 && (editable || gAgent.isGodlike()) @@ -512,12 +511,6 @@ void LLPanelObject::getState( ) mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); -#if 0 // 1.9.2 - mCastShadows = root_objectp->flagCastShadows(); - mCheckCastShadows->set( mCastShadows ); - mCheckCastShadows->setEnabled( roots_selected==1 && editable ); -#endif - //---------------------------------------------------------------------------- S32 selected_item = MI_BOX; @@ -1214,22 +1207,6 @@ void LLPanelObject::sendIsPhantom() } } -void LLPanelObject::sendCastShadows() -{ - BOOL value = mCheckCastShadows->get(); - if( mCastShadows != value ) - { - LLSelectMgr::getInstance()->selectionUpdateCastShadows(value); - mCastShadows = value; - - llinfos << "update cast shadows sent" << llendl; - } - else - { - llinfos << "update cast shadows not changed" << llendl; - } -} - // static void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) { @@ -1886,10 +1863,6 @@ void LLPanelObject::clearCtrls() mCheckPhantom ->set(FALSE); mCheckPhantom ->setEnabled( FALSE ); -#if 0 // 1.9.2 - mCheckCastShadows->set(FALSE); - mCheckCastShadows->setEnabled( FALSE ); -#endif // Disable text labels mLabelPosition ->setEnabled( FALSE ); mLabelSize ->setEnabled( FALSE ); @@ -1977,14 +1950,6 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) self->sendIsPhantom(); } -// static -void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendCastShadows(); -} - - void LLPanelObject::onSelectSculpt(const LLSD& data) { LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 475dfdaedb..86b59d4ff9 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -64,7 +64,6 @@ public: static void onCommitRotation( LLUICtrl* ctrl, void* userdata); static void onCommitTemporary( LLUICtrl* ctrl, void* userdata); static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); - static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -87,7 +86,6 @@ protected: void sendIsTemporary(); void sendIsPhantom(); - void sendCastShadows(); void sendSculpt(); void getVolumeParams(LLVolumeParams& volume_params); @@ -153,7 +151,6 @@ protected: LLCheckBoxCtrl *mCheckPhysics; LLCheckBoxCtrl *mCheckTemporary; LLCheckBoxCtrl *mCheckPhantom; - LLCheckBoxCtrl *mCheckCastShadows; LLTextureCtrl *mCtrlSculptTexture; LLTextBox *mLabelSculptType; @@ -165,7 +162,6 @@ protected: BOOL mIsPhysical; // to avoid sending "physical" when not changed BOOL mIsTemporary; // to avoid sending "temporary" when not changed BOOL mIsPhantom; // to avoid sending "phantom" when not changed - BOOL mCastShadows; // to avoid sending "cast shadows" when not changed S32 mSelectedType; // So we know what selected type we last were LLUUID mSculptTextureRevert; // so we can revert the sculpt texture on cancel diff --git a/indra/newview/llpathfindingcharacter.cpp b/indra/newview/llpathfindingcharacter.cpp new file mode 100644 index 0000000000..afa07457bc --- /dev/null +++ b/indra/newview/llpathfindingcharacter.cpp @@ -0,0 +1,103 @@ +/**
+ * @file llpathfindingcharacter.cpp
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding character that contains various properties required for havok pathfinding.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llpathfindingcharacter.h"
+#include "llsd.h"
+#include "v3math.h"
+#include "lluuid.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+
+#define CHARACTER_NAME_FIELD "name"
+#define CHARACTER_DESCRIPTION_FIELD "description"
+#define CHARACTER_OWNER_FIELD "owner"
+#define CHARACTER_CPU_TIME_FIELD "cpu_time"
+#define CHARACTER_POSITION_FIELD "position"
+
+//---------------------------------------------------------------------------
+// LLPathfindingCharacter
+//---------------------------------------------------------------------------
+
+LLPathfindingCharacter::LLPathfindingCharacter(const std::string &pUUID, const LLSD& pCharacterItem)
+ : mUUID(pUUID),
+ mName(),
+ mDescription(),
+ mOwnerUUID(),
+ mOwnerName(),
+ mCPUTime(0U),
+ mLocation()
+{
+ llassert(pCharacterItem.has(CHARACTER_NAME_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_NAME_FIELD).isString());
+ mName = pCharacterItem.get(CHARACTER_NAME_FIELD).asString();
+
+ llassert(pCharacterItem.has(CHARACTER_DESCRIPTION_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_DESCRIPTION_FIELD).isString());
+ mDescription = pCharacterItem.get(CHARACTER_DESCRIPTION_FIELD).asString();
+
+ llassert(pCharacterItem.has(CHARACTER_OWNER_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_OWNER_FIELD).isUUID());
+ mOwnerUUID = pCharacterItem.get(CHARACTER_OWNER_FIELD).asUUID();
+ LLAvatarNameCache::get(mOwnerUUID, &mOwnerName);
+
+ llassert(pCharacterItem.has(CHARACTER_CPU_TIME_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_CPU_TIME_FIELD).isReal());
+ mCPUTime = pCharacterItem.get(CHARACTER_CPU_TIME_FIELD).asReal();
+
+ llassert(pCharacterItem.has(CHARACTER_POSITION_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_POSITION_FIELD).isArray());
+ mLocation.setValue(pCharacterItem.get(CHARACTER_POSITION_FIELD));
+}
+
+LLPathfindingCharacter::LLPathfindingCharacter(const LLPathfindingCharacter& pOther)
+ : mUUID(pOther.mUUID),
+ mName(pOther.mName),
+ mDescription(pOther.mDescription),
+ mOwnerUUID(pOther.mOwnerUUID),
+ mOwnerName(pOther.mOwnerName),
+ mCPUTime(pOther.mCPUTime),
+ mLocation(pOther.mLocation)
+{
+}
+
+LLPathfindingCharacter::~LLPathfindingCharacter()
+{
+}
+
+LLPathfindingCharacter& LLPathfindingCharacter::operator =(const LLPathfindingCharacter& pOther)
+{
+ mUUID = pOther.mUUID;
+ mName = pOther.mName;
+ mDescription = pOther.mDescription;
+ mOwnerUUID = pOther.mOwnerUUID;
+ mOwnerName = pOther.mOwnerName;
+ mCPUTime = pOther.mCPUTime;
+ mLocation = pOther.mLocation;
+
+ return *this;
+}
diff --git a/indra/newview/llpathfindingcharacter.h b/indra/newview/llpathfindingcharacter.h new file mode 100644 index 0000000000..9b0a7bae30 --- /dev/null +++ b/indra/newview/llpathfindingcharacter.h @@ -0,0 +1,66 @@ +/**
+ * @file llpathfindingcharacter.h
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding character that contains various properties required for havok pathfinding.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGCHARACTER_H
+#define LL_LLPATHFINDINGCHARACTER_H
+
+#include "v3math.h"
+#include "lluuid.h"
+#include "llavatarname.h"
+
+class LLSD;
+class LLAvatarName;
+
+class LLPathfindingCharacter
+{
+public:
+ LLPathfindingCharacter(const std::string &pUUID, const LLSD &pCharacterItem);
+ LLPathfindingCharacter(const LLPathfindingCharacter& pOther);
+ virtual ~LLPathfindingCharacter();
+
+ LLPathfindingCharacter& operator = (const LLPathfindingCharacter& pOther);
+
+ inline const LLUUID& getUUID() const {return mUUID;};
+ inline const std::string& getName() const {return mName;};
+ inline const std::string& getDescription() const {return mDescription;};
+ inline const std::string getOwnerName() const {return mOwnerName.getCompleteName();};
+ inline F32 getCPUTime() const {return mCPUTime;};
+ inline const LLVector3& getLocation() const {return mLocation;};
+
+protected:
+
+private:
+ LLUUID mUUID;
+ std::string mName;
+ std::string mDescription;
+ LLUUID mOwnerUUID;
+ LLAvatarName mOwnerName;
+ F32 mCPUTime;
+ LLVector3 mLocation;
+};
+
+#endif // LL_LLPATHFINDINGCHARACTER_H
diff --git a/indra/newview/llpathfindinglinkset.cpp b/indra/newview/llpathfindinglinkset.cpp new file mode 100644 index 0000000000..1300022e8b --- /dev/null +++ b/indra/newview/llpathfindinglinkset.cpp @@ -0,0 +1,499 @@ +/**
+ * @file llpathfindinglinksets.cpp
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding linkset that contains various properties required for havok pathfinding.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llpathfindinglinkset.h"
+#include "llsd.h"
+#include "v3math.h"
+#include "lluuid.h"
+
+#define LINKSET_NAME_FIELD "name"
+#define LINKSET_DESCRIPTION_FIELD "description"
+#define LINKSET_LAND_IMPACT_FIELD "landimpact"
+#define LINKSET_MODIFIABLE_FIELD "modifiable"
+#ifdef DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+#define DEPRECATED_LINKSET_PERMANENT_FIELD "permanent"
+#define DEPRECATED_LINKSET_WALKABLE_FIELD "walkable"
+#endif // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+#define LINKSET_CATEGORY_FIELD "navmesh_category"
+#define LINKSET_PHANTOM_FIELD "phantom"
+#define LINKSET_WALKABILITY_A_FIELD "A"
+#define LINKSET_WALKABILITY_B_FIELD "B"
+#define LINKSET_WALKABILITY_C_FIELD "C"
+#define LINKSET_WALKABILITY_D_FIELD "D"
+#define LINKSET_POSITION_FIELD "position"
+
+#define LINKSET_CATEGORY_VALUE_INCLUDE 0
+#define LINKSET_CATEGORY_VALUE_EXCLUDE 1
+#define LINKSET_CATEGORY_VALUE_IGNORE 2
+
+//---------------------------------------------------------------------------
+// LLPathfindingLinkset
+//---------------------------------------------------------------------------
+
+const S32 LLPathfindingLinkset::MIN_WALKABILITY_VALUE(0);
+const S32 LLPathfindingLinkset::MAX_WALKABILITY_VALUE(100);
+
+LLPathfindingLinkset::LLPathfindingLinkset(const LLSD& pTerrainLinksetItem)
+ : mUUID(),
+ mIsTerrain(true),
+ mName(),
+ mDescription(),
+ mLandImpact(0U),
+ mLocation(LLVector3::zero),
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ mHasModifiable(true),
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+ mIsModifiable(TRUE),
+ mLinksetUse(kUnknown),
+ mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
+{
+ parsePathfindingData(pTerrainLinksetItem);
+}
+
+LLPathfindingLinkset::LLPathfindingLinkset(const std::string &pUUID, const LLSD& pLinksetItem)
+ : mUUID(pUUID),
+ mIsTerrain(false),
+ mName(),
+ mDescription(),
+ mLandImpact(0U),
+ mLocation(LLVector3::zero),
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ mHasModifiable(false),
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+ mIsModifiable(TRUE),
+ mLinksetUse(kUnknown),
+ mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
+{
+ parseObjectData(pLinksetItem);
+ parsePathfindingData(pLinksetItem);
+}
+
+LLPathfindingLinkset::LLPathfindingLinkset(const LLPathfindingLinkset& pOther)
+ : mUUID(pOther.mUUID),
+ mName(pOther.mName),
+ mDescription(pOther.mDescription),
+ mLandImpact(pOther.mLandImpact),
+ mLocation(pOther.mLocation),
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ mHasModifiable(pOther.mHasModifiable),
+ mIsModifiable(pOther.mHasModifiable ? pOther.mIsModifiable : TRUE),
+#else // MISSING_MODIFIABLE_FIELD_WAR
+ mIsModifiable(pOther.mIsModifiable),
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+ mLinksetUse(pOther.mLinksetUse),
+ mWalkabilityCoefficientA(pOther.mWalkabilityCoefficientA),
+ mWalkabilityCoefficientB(pOther.mWalkabilityCoefficientB),
+ mWalkabilityCoefficientC(pOther.mWalkabilityCoefficientC),
+ mWalkabilityCoefficientD(pOther.mWalkabilityCoefficientD)
+{
+}
+
+LLPathfindingLinkset::~LLPathfindingLinkset()
+{
+}
+
+LLPathfindingLinkset& LLPathfindingLinkset::operator =(const LLPathfindingLinkset& pOther)
+{
+ mUUID = pOther.mUUID;
+ mName = pOther.mName;
+ mDescription = pOther.mDescription;
+ mLandImpact = pOther.mLandImpact;
+ mLocation = pOther.mLocation;
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ if (pOther.mHasModifiable)
+ {
+ mHasModifiable = pOther.mHasModifiable;
+ mIsModifiable = pOther.mIsModifiable;
+ }
+#else // MISSING_MODIFIABLE_FIELD_WAR
+ mIsModifiable = pOther.mIsModifiable;
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+ mLinksetUse = pOther.mLinksetUse;
+ mWalkabilityCoefficientA = pOther.mWalkabilityCoefficientA;
+ mWalkabilityCoefficientB = pOther.mWalkabilityCoefficientB;
+ mWalkabilityCoefficientC = pOther.mWalkabilityCoefficientC;
+ mWalkabilityCoefficientD = pOther.mWalkabilityCoefficientD;
+
+ return *this;
+}
+
+BOOL LLPathfindingLinkset::isPhantom() const
+{
+ return isPhantom(getLinksetUse());
+}
+
+BOOL LLPathfindingLinkset::isPhantom(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kStaticObstacle :
+ case kDynamicObstacle :
+ retVal = false;
+ break;
+ case kMaterialVolume :
+ case kExclusionVolume :
+ case kDynamicPhantom :
+ retVal = true;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
+
+LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUseWithToggledPhantom(ELinksetUse pLinksetUse)
+{
+ BOOL isPhantom = LLPathfindingLinkset::isPhantom(pLinksetUse);
+ ENavMeshGenerationCategory navMeshGenerationCategory = getNavMeshGenerationCategory(pLinksetUse);
+
+ return getLinksetUse(!isPhantom, navMeshGenerationCategory);
+}
+
+LLSD LLPathfindingLinkset::encodeAlteredFields(ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD itemData;
+
+ if (!isTerrain() && (pLinksetUse != kUnknown) && (mLinksetUse != pLinksetUse))
+ {
+ if (mIsModifiable)
+ {
+ itemData[LINKSET_PHANTOM_FIELD] = static_cast<bool>(LLPathfindingLinkset::isPhantom(pLinksetUse));
+ }
+#ifdef DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ itemData[DEPRECATED_LINKSET_PERMANENT_FIELD] = static_cast<bool>(LLPathfindingLinkset::isPermanent(pLinksetUse));
+ itemData[DEPRECATED_LINKSET_WALKABLE_FIELD] = static_cast<bool>(LLPathfindingLinkset::isWalkable(pLinksetUse));
+#endif // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ itemData[LINKSET_CATEGORY_FIELD] = convertCategoryToLLSD(getNavMeshGenerationCategory(pLinksetUse));
+ }
+
+ if (mWalkabilityCoefficientA != pA)
+ {
+ itemData[LINKSET_WALKABILITY_A_FIELD] = llclamp(pA, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientB != pB)
+ {
+ itemData[LINKSET_WALKABILITY_B_FIELD] = llclamp(pB, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientC != pC)
+ {
+ itemData[LINKSET_WALKABILITY_C_FIELD] = llclamp(pC, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientD != pD)
+ {
+ itemData[LINKSET_WALKABILITY_D_FIELD] = llclamp(pD, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ return itemData;
+}
+
+void LLPathfindingLinkset::parseObjectData(const LLSD &pLinksetItem)
+{
+ llassert(pLinksetItem.has(LINKSET_NAME_FIELD));
+ llassert(pLinksetItem.get(LINKSET_NAME_FIELD).isString());
+ mName = pLinksetItem.get(LINKSET_NAME_FIELD).asString();
+
+ llassert(pLinksetItem.has(LINKSET_DESCRIPTION_FIELD));
+ llassert(pLinksetItem.get(LINKSET_DESCRIPTION_FIELD).isString());
+ mDescription = pLinksetItem.get(LINKSET_DESCRIPTION_FIELD).asString();
+
+ llassert(pLinksetItem.has(LINKSET_LAND_IMPACT_FIELD));
+ llassert(pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).isInteger());
+ llassert(pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).asInteger() >= 0);
+ mLandImpact = pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).asInteger();
+
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ mHasModifiable = pLinksetItem.has(LINKSET_MODIFIABLE_FIELD);
+ if (mHasModifiable)
+ {
+ llassert(pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).isBoolean());
+ mIsModifiable = pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).asBoolean();
+ }
+#else // MISSING_MODIFIABLE_FIELD_WAR
+ llassert(pLinksetItem.has(LINKSET_MODIFIABLE_FIELD));
+ llassert(pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).isBoolean());
+ mIsModifiable = pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).asBoolean();
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+
+ llassert(pLinksetItem.has(LINKSET_POSITION_FIELD));
+ llassert(pLinksetItem.get(LINKSET_POSITION_FIELD).isArray());
+ mLocation.setValue(pLinksetItem.get(LINKSET_POSITION_FIELD));
+}
+
+void LLPathfindingLinkset::parsePathfindingData(const LLSD &pLinksetItem)
+{
+ bool isPhantom = false;
+ if (pLinksetItem.has(LINKSET_PHANTOM_FIELD))
+ {
+ llassert(pLinksetItem.get(LINKSET_PHANTOM_FIELD).isBoolean());
+ isPhantom = pLinksetItem.get(LINKSET_PHANTOM_FIELD).asBoolean();
+ }
+
+#ifdef DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ if (pLinksetItem.has(LINKSET_CATEGORY_FIELD))
+ {
+ mLinksetUse = getLinksetUse(isPhantom, convertCategoryFromLLSD(pLinksetItem.get(LINKSET_CATEGORY_FIELD)));
+ }
+ else
+ {
+ llassert(pLinksetItem.has(DEPRECATED_LINKSET_PERMANENT_FIELD));
+ llassert(pLinksetItem.get(DEPRECATED_LINKSET_PERMANENT_FIELD).isBoolean());
+ bool isPermanent = pLinksetItem.get(DEPRECATED_LINKSET_PERMANENT_FIELD).asBoolean();
+
+ llassert(pLinksetItem.has(DEPRECATED_LINKSET_WALKABLE_FIELD));
+ llassert(pLinksetItem.get(DEPRECATED_LINKSET_WALKABLE_FIELD).isBoolean());
+ bool isWalkable = pLinksetItem.get(DEPRECATED_LINKSET_WALKABLE_FIELD).asBoolean();
+
+ mLinksetUse = getLinksetUse(isPhantom, isPermanent, isWalkable);
+ }
+#else // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ llassert(pLinksetItem.has(LINKSET_CATEGORY_FIELD));
+ mLinksetUse = getLinksetUse(isPhantom, convertCategoryFromLLSD(pLinksetItem.get(LINKSET_CATEGORY_FIELD)));
+#endif // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_A_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_A_FIELD).isInteger());
+ mWalkabilityCoefficientA = pLinksetItem.get(LINKSET_WALKABILITY_A_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientA >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientA <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_B_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_B_FIELD).isInteger());
+ mWalkabilityCoefficientB = pLinksetItem.get(LINKSET_WALKABILITY_B_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientB >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientB <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_C_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_C_FIELD).isInteger());
+ mWalkabilityCoefficientC = pLinksetItem.get(LINKSET_WALKABILITY_C_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientC >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientC <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_D_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_D_FIELD).isInteger());
+ mWalkabilityCoefficientD = pLinksetItem.get(LINKSET_WALKABILITY_D_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientD >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientD <= MAX_WALKABILITY_VALUE);
+}
+
+#ifdef DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUse(bool pIsPhantom, bool pIsPermanent, bool pIsWalkable)
+{
+ return (pIsPhantom ? (pIsPermanent ? (pIsWalkable ? kMaterialVolume : kExclusionVolume) : kDynamicPhantom) :
+ (pIsPermanent ? (pIsWalkable ? kWalkable : kStaticObstacle) : kDynamicObstacle));
+}
+
+BOOL LLPathfindingLinkset::isPermanent(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kStaticObstacle :
+ case kMaterialVolume :
+ case kExclusionVolume :
+ retVal = true;
+ break;
+ case kDynamicObstacle :
+ case kDynamicPhantom :
+ retVal = false;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
+
+BOOL LLPathfindingLinkset::isWalkable(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kMaterialVolume :
+ retVal = true;
+ break;
+ case kStaticObstacle :
+ case kDynamicObstacle :
+ case kExclusionVolume :
+ case kDynamicPhantom :
+ retVal = false;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
+#endif // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+
+LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUse(bool pIsPhantom, ENavMeshGenerationCategory pNavMeshGenerationCategory)
+{
+ ELinksetUse linksetUse = kUnknown;
+
+ if (pIsPhantom)
+ {
+ switch (pNavMeshGenerationCategory)
+ {
+ case kNavMeshGenerationIgnore :
+ linksetUse = kDynamicPhantom;
+ break;
+ case kNavMeshGenerationInclude :
+ linksetUse = kMaterialVolume;
+ break;
+ case kNavMeshGenerationExclude :
+ linksetUse = kExclusionVolume;
+ break;
+ default :
+ linksetUse = kUnknown;
+ llassert(0);
+ break;
+ }
+ }
+ else
+ {
+ switch (pNavMeshGenerationCategory)
+ {
+ case kNavMeshGenerationIgnore :
+ linksetUse = kDynamicObstacle;
+ break;
+ case kNavMeshGenerationInclude :
+ linksetUse = kWalkable;
+ break;
+ case kNavMeshGenerationExclude :
+ linksetUse = kStaticObstacle;
+ break;
+ default :
+ linksetUse = kUnknown;
+ llassert(0);
+ break;
+ }
+ }
+
+ return linksetUse;
+}
+
+LLPathfindingLinkset::ENavMeshGenerationCategory LLPathfindingLinkset::getNavMeshGenerationCategory(ELinksetUse pLinksetUse)
+{
+ ENavMeshGenerationCategory navMeshGenerationCategory;
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kMaterialVolume :
+ navMeshGenerationCategory = kNavMeshGenerationInclude;
+ break;
+ case kStaticObstacle :
+ case kExclusionVolume :
+ navMeshGenerationCategory = kNavMeshGenerationExclude;
+ break;
+ case kDynamicObstacle :
+ case kDynamicPhantom :
+ navMeshGenerationCategory = kNavMeshGenerationIgnore;
+ break;
+ case kUnknown :
+ default :
+ navMeshGenerationCategory = kNavMeshGenerationIgnore;
+ llassert(0);
+ break;
+ }
+
+ return navMeshGenerationCategory;
+}
+
+LLSD LLPathfindingLinkset::convertCategoryToLLSD(ENavMeshGenerationCategory pNavMeshGenerationCategory)
+{
+ LLSD llsd;
+
+ switch (pNavMeshGenerationCategory)
+ {
+ case kNavMeshGenerationIgnore :
+ llsd = static_cast<S32>(LINKSET_CATEGORY_VALUE_IGNORE);
+ break;
+ case kNavMeshGenerationInclude :
+ llsd = static_cast<S32>(LINKSET_CATEGORY_VALUE_INCLUDE);
+ break;
+ case kNavMeshGenerationExclude :
+ llsd = static_cast<S32>(LINKSET_CATEGORY_VALUE_EXCLUDE);
+ break;
+ default :
+ llsd = static_cast<S32>(LINKSET_CATEGORY_VALUE_IGNORE);
+ llassert(0);
+ break;
+ }
+
+ return llsd;
+}
+
+LLPathfindingLinkset::ENavMeshGenerationCategory LLPathfindingLinkset::convertCategoryFromLLSD(const LLSD &llsd)
+{
+ ENavMeshGenerationCategory navMeshGenerationCategory;
+
+ llassert(llsd.isInteger());
+ switch (llsd.asInteger())
+ {
+ case LINKSET_CATEGORY_VALUE_IGNORE :
+ navMeshGenerationCategory = kNavMeshGenerationIgnore;
+ break;
+ case LINKSET_CATEGORY_VALUE_INCLUDE :
+ navMeshGenerationCategory = kNavMeshGenerationInclude;
+ break;
+ case LINKSET_CATEGORY_VALUE_EXCLUDE :
+ navMeshGenerationCategory = kNavMeshGenerationExclude;
+ break;
+ default :
+ navMeshGenerationCategory = kNavMeshGenerationIgnore;
+ llassert(0);
+ break;
+ }
+
+ return navMeshGenerationCategory;
+}
diff --git a/indra/newview/llpathfindinglinkset.h b/indra/newview/llpathfindinglinkset.h new file mode 100644 index 0000000000..49250dc748 --- /dev/null +++ b/indra/newview/llpathfindinglinkset.h @@ -0,0 +1,128 @@ +/**
+ * @file llpathfindinglinkset.h
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding linkset that contains various properties required for havok pathfinding.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGLINKSET_H
+#define LL_LLPATHFINDINGLINKSET_H
+
+#include "v3math.h"
+#include "lluuid.h"
+
+#include <boost/shared_ptr.hpp>
+
+class LLSD;
+class LLPathfindingLinkset;
+
+typedef boost::shared_ptr<LLPathfindingLinkset> LLPathfindingLinksetPtr;
+
+#define DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+#define MISSING_MODIFIABLE_FIELD_WAR
+
+class LLPathfindingLinkset
+{
+public:
+ typedef enum
+ {
+ kNavMeshGenerationIgnore,
+ kNavMeshGenerationInclude,
+ kNavMeshGenerationExclude
+ } ENavMeshGenerationCategory;
+
+ typedef enum
+ {
+ kUnknown,
+ kWalkable,
+ kStaticObstacle,
+ kDynamicObstacle,
+ kMaterialVolume,
+ kExclusionVolume,
+ kDynamicPhantom
+ } ELinksetUse;
+
+ LLPathfindingLinkset(const LLSD &pTerrainLinksetItem);
+ LLPathfindingLinkset(const std::string &pUUID, const LLSD &pLinksetItem);
+ LLPathfindingLinkset(const LLPathfindingLinkset& pOther);
+ virtual ~LLPathfindingLinkset();
+
+ LLPathfindingLinkset& operator = (const LLPathfindingLinkset& pOther);
+
+ inline bool isTerrain() const {return mIsTerrain;};
+ inline const LLUUID& getUUID() const {return mUUID;};
+ inline const std::string& getName() const {return mName;};
+ inline const std::string& getDescription() const {return mDescription;};
+ inline U32 getLandImpact() const {return mLandImpact;};
+ inline const LLVector3& getLocation() const {return mLocation;};
+ BOOL isModifiable() const {return mIsModifiable;};
+ BOOL isPhantom() const;
+ static BOOL isPhantom(ELinksetUse pLinksetUse);
+ static ELinksetUse getLinksetUseWithToggledPhantom(ELinksetUse pLinksetUse);
+
+ inline ELinksetUse getLinksetUse() const {return mLinksetUse;};
+
+ inline S32 getWalkabilityCoefficientA() const {return mWalkabilityCoefficientA;};
+ inline S32 getWalkabilityCoefficientB() const {return mWalkabilityCoefficientB;};
+ inline S32 getWalkabilityCoefficientC() const {return mWalkabilityCoefficientC;};
+ inline S32 getWalkabilityCoefficientD() const {return mWalkabilityCoefficientD;};
+
+ LLSD encodeAlteredFields(ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+
+ static const S32 MIN_WALKABILITY_VALUE;
+ static const S32 MAX_WALKABILITY_VALUE;
+
+protected:
+
+private:
+ void parseObjectData(const LLSD &pLinksetItem);
+ void parsePathfindingData(const LLSD &pLinksetItem);
+
+#ifdef DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ static ELinksetUse getLinksetUse(bool pIsPhantom, bool pIsPermanent, bool pIsWalkable);
+ static BOOL isPermanent(ELinksetUse pLinksetUse);
+ static BOOL isWalkable(ELinksetUse pLinksetUse);
+#endif // DEPRECATED_NAVMESH_PERMANENT_WALKABLE_FLAGS
+ static ELinksetUse getLinksetUse(bool pIsPhantom, ENavMeshGenerationCategory pNavMeshGenerationCategory);
+ static ENavMeshGenerationCategory getNavMeshGenerationCategory(ELinksetUse pLinksetUse);
+ static LLSD convertCategoryToLLSD(ENavMeshGenerationCategory pNavMeshGenerationCategory);
+ static ENavMeshGenerationCategory convertCategoryFromLLSD(const LLSD &llsd);
+
+ LLUUID mUUID;
+ bool mIsTerrain;
+ std::string mName;
+ std::string mDescription;
+ U32 mLandImpact;
+ LLVector3 mLocation;
+#ifdef MISSING_MODIFIABLE_FIELD_WAR
+ bool mHasModifiable;
+#endif // MISSING_MODIFIABLE_FIELD_WAR
+ BOOL mIsModifiable;
+ ELinksetUse mLinksetUse;
+ S32 mWalkabilityCoefficientA;
+ S32 mWalkabilityCoefficientB;
+ S32 mWalkabilityCoefficientC;
+ S32 mWalkabilityCoefficientD;
+};
+
+#endif // LL_LLPATHFINDINGLINKSET_H
diff --git a/indra/newview/llpathfindinglinksetlist.cpp b/indra/newview/llpathfindinglinksetlist.cpp new file mode 100644 index 0000000000..57febbf0f2 --- /dev/null +++ b/indra/newview/llpathfindinglinksetlist.cpp @@ -0,0 +1,122 @@ +/**
+ * @file llpathfindinglinksetlist.cpp
+ * @author William Todd Stinson
+ * @brief Class to implement the list of a set of pathfinding linksets
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include <string>
+#include <map>
+
+#include "llsd.h"
+#include "lluuid.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+
+//---------------------------------------------------------------------------
+// LLPathfindingLinksetList
+//---------------------------------------------------------------------------
+
+LLPathfindingLinksetList::LLPathfindingLinksetList()
+ : LLPathfindingLinksetMap()
+{
+}
+
+LLPathfindingLinksetList::LLPathfindingLinksetList(const LLSD& pLinksetItems)
+ : LLPathfindingLinksetMap()
+{
+ for (LLSD::map_const_iterator linksetItemIter = pLinksetItems.beginMap();
+ linksetItemIter != pLinksetItems.endMap(); ++linksetItemIter)
+ {
+ const std::string& uuid(linksetItemIter->first);
+ const LLSD& linksetData = linksetItemIter->second;
+ LLPathfindingLinksetPtr linkset(new LLPathfindingLinkset(uuid, linksetData));
+ insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuid, linkset));
+ }
+}
+
+LLPathfindingLinksetList::~LLPathfindingLinksetList()
+{
+ clear();
+}
+
+void LLPathfindingLinksetList::update(const LLPathfindingLinksetList &pUpdateLinksetList)
+{
+ for (LLPathfindingLinksetList::const_iterator updateLinksetIter = pUpdateLinksetList.begin();
+ updateLinksetIter != pUpdateLinksetList.end(); ++updateLinksetIter)
+ {
+ const std::string &uuid = updateLinksetIter->first;
+ const LLPathfindingLinksetPtr updateLinksetPtr = updateLinksetIter->second;
+
+ LLPathfindingLinksetList::iterator linksetIter = find(uuid);
+ if (linksetIter == end())
+ {
+ insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuid, updateLinksetPtr));
+ }
+ else
+ {
+ LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ *linksetPtr = *updateLinksetPtr;
+ }
+ }
+}
+
+LLSD LLPathfindingLinksetList::encodeObjectFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD listData;
+
+ for (LLPathfindingLinksetMap::const_iterator linksetIter = begin(); linksetIter != end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (!linksetPtr->isTerrain())
+ {
+ LLSD linksetData = linksetPtr->encodeAlteredFields(pLinksetUse, pA, pB, pC, pD);
+ if (!linksetData.isUndefined())
+ {
+ const std::string& uuid(linksetIter->first);
+ listData[uuid] = linksetData;
+ }
+ }
+ }
+
+ return listData;
+}
+
+LLSD LLPathfindingLinksetList::encodeTerrainFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD terrainData;
+
+ for (LLPathfindingLinksetMap::const_iterator linksetIter = begin(); linksetIter != end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (linksetPtr->isTerrain())
+ {
+ terrainData = linksetPtr->encodeAlteredFields(pLinksetUse, pA, pB, pC, pD);
+ break;
+ }
+ }
+
+ return terrainData;
+}
diff --git a/indra/newview/llpathfindinglinksetlist.h b/indra/newview/llpathfindinglinksetlist.h new file mode 100644 index 0000000000..813c4ec46c --- /dev/null +++ b/indra/newview/llpathfindinglinksetlist.h @@ -0,0 +1,61 @@ +/**
+ * @file llpathfindinglinksetlist.h
+ * @author William Todd Stinson
+ * @brief Class to implement the list of a set of pathfinding linksets
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGLINKSETLIST_H
+#define LL_LLPATHFINDINGLINKSETLIST_H
+
+#include <string>
+#include <map>
+#include "llpathfindinglinkset.h"
+
+#include <boost/shared_ptr.hpp>
+
+class LLSD;
+class LLPathfindingLinksetList;
+
+typedef boost::shared_ptr<LLPathfindingLinksetList> LLPathfindingLinksetListPtr;
+typedef std::map<std::string, LLPathfindingLinksetPtr> LLPathfindingLinksetMap;
+
+class LLPathfindingLinksetList : public LLPathfindingLinksetMap
+{
+public:
+ LLPathfindingLinksetList();
+ LLPathfindingLinksetList(const LLSD& pLinksetItems);
+ virtual ~LLPathfindingLinksetList();
+
+ void update(const LLPathfindingLinksetList &pUpdateLinksetList);
+
+ LLSD encodeObjectFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+ LLSD encodeTerrainFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+
+protected:
+
+private:
+
+};
+
+#endif // LL_LLPATHFINDINGLINKSETLIST_H
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp new file mode 100644 index 0000000000..ebefebbb64 --- /dev/null +++ b/indra/newview/llpathfindingmanager.cpp @@ -0,0 +1,730 @@ +/**
+ * @file llpathfindingmanager.cpp
+ * @author William Todd Stinson
+ * @brief A state manager for the various pathfinding states.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include <string>
+#include <vector>
+
+#include "llviewerprecompiledheaders.h"
+#include "llsd.h"
+#include "llpathfindingmanager.h"
+#include "llsingleton.h"
+#include "llhttpclient.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llpathfindingnavmesh.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+#include "llhttpnode.h"
+
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+#define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc"
+
+#define CAP_SERVICE_AGENT_STATE "AgentPreferences"
+#define ALTER_NAVMESH_OBJECTS_FIELD "alter_navmesh_objects"
+#define DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD "alter_permanent_objects"
+
+#define CAP_SERVICE_OBJECT_LINKSETS "ObjectNavMeshProperties"
+#define CAP_SERVICE_TERRAIN_LINKSETS "TerrainNavMeshProperties"
+
+#define SIM_MESSAGE_NAVMESH_STATUS_UPDATE "/message/NavmeshStatusUpdate"
+
+//---------------------------------------------------------------------------
+// LLNavMeshSimStateChangeNode
+//---------------------------------------------------------------------------
+
+class LLNavMeshSimStateChangeNode : public LLHTTPNode
+{
+public:
+ virtual void post(ResponsePtr pResponse, const LLSD &pContext, const LLSD &pInput) const;
+};
+
+LLHTTPRegistration<LLNavMeshSimStateChangeNode> gHTTPRegistrationNavMeshSimStateChangeNode(SIM_MESSAGE_NAVMESH_STATUS_UPDATE);
+
+//---------------------------------------------------------------------------
+// NavMeshResponder
+//---------------------------------------------------------------------------
+
+class NavMeshResponder : public LLHTTPClient::Responder
+{
+public:
+ NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);
+ virtual ~NavMeshResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string& pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ U32 mNavMeshVersion;
+ LLPathfindingNavMeshPtr mNavMeshPtr;
+};
+
+//---------------------------------------------------------------------------
+// AgentStateResponder
+//---------------------------------------------------------------------------
+
+class AgentStateResponder : public LLHTTPClient::Responder
+{
+public:
+ AgentStateResponder(const std::string &pCapabilityURL, LLPathfindingManager::EAgentState pRequestedAgentState = LLPathfindingManager::kAgentStateUnknown);
+ virtual ~AgentStateResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string& pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LLPathfindingManager::EAgentState mRequestedAgentState;
+};
+
+//---------------------------------------------------------------------------
+// LinksetsResponder
+//---------------------------------------------------------------------------
+
+class LinksetsResponder
+{
+public:
+ LinksetsResponder(LLPathfindingManager::linksets_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested);
+ virtual ~LinksetsResponder();
+
+ void handleObjectLinksetsResult(const LLSD &pContent);
+ void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+ void handleTerrainLinksetsResult(const LLSD &pContent);
+ void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+
+protected:
+
+private:
+ void sendCallback();
+
+ typedef enum
+ {
+ kNotRequested,
+ kWaiting,
+ kReceivedGood,
+ kReceivedError
+ } EMessagingState;
+
+ LLPathfindingManager::linksets_callback_t mLinksetsCallback;
+
+ EMessagingState mObjectMessagingState;
+ EMessagingState mTerrainMessagingState;
+
+ LLPathfindingLinksetListPtr mObjectLinksetListPtr;
+ LLPathfindingLinksetPtr mTerrainLinksetPtr;
+};
+
+typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;
+
+//---------------------------------------------------------------------------
+// ObjectLinksetsResponder
+//---------------------------------------------------------------------------
+
+class ObjectLinksetsResponder : public LLHTTPClient::Responder
+{
+public:
+ ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+ virtual ~ObjectLinksetsResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string &pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LinksetsResponderPtr mLinksetsResponsderPtr;
+};
+
+//---------------------------------------------------------------------------
+// TerrainLinksetsResponder
+//---------------------------------------------------------------------------
+
+class TerrainLinksetsResponder : public LLHTTPClient::Responder
+{
+public:
+ TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+ virtual ~TerrainLinksetsResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string &pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LinksetsResponderPtr mLinksetsResponsderPtr;
+};
+
+//---------------------------------------------------------------------------
+// LLPathfindingManager
+//---------------------------------------------------------------------------
+
+LLPathfindingManager::LLPathfindingManager()
+ : LLSingleton<LLPathfindingManager>(),
+ mNavMeshMap(),
+ mNavMeshVersionXXX(0),
+ mAgentStateSignal(),
+ mAgentState(kAgentStateUnknown),
+ mLastKnownNonErrorAgentState(kAgentStateUnknown)
+{
+}
+
+LLPathfindingManager::~LLPathfindingManager()
+{
+}
+
+bool LLPathfindingManager::isPathfindingEnabledForCurrentRegion() const
+{
+ std::string retrieveNavMeshURL = getRetrieveNavMeshURLForCurrentRegion();
+ return !retrieveNavMeshURL.empty();
+}
+
+bool LLPathfindingManager::isAllowAlterPermanent()
+{
+ return (!isPathfindingEnabledForCurrentRegion() || (getAgentState() == kAgentStateUnfrozen));
+}
+
+bool LLPathfindingManager::isAllowViewTerrainProperties() const
+{
+ LLViewerRegion* region = getCurrentRegion();
+ return (gAgent.isGodlike() || ((region != NULL) && region->canManageEstate()));
+}
+
+LLPathfindingNavMesh::navmesh_slot_t LLPathfindingManager::registerNavMeshListenerForRegion(LLViewerRegion *pRegion, LLPathfindingNavMesh::navmesh_callback_t pNavMeshCallback)
+{
+ LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pRegion);
+ return navMeshPtr->registerNavMeshListener(pNavMeshCallback);
+}
+
+void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion)
+{
+ LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pRegion);
+
+ if (navMeshPtr->hasNavMeshVersion(mNavMeshVersionXXX))
+ {
+ navMeshPtr->handleRefresh();
+ }
+ else
+ {
+ if (pRegion == NULL)
+ {
+ navMeshPtr->handleNavMeshNotEnabled();
+ }
+ else
+ {
+ std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion);
+ if (navMeshURL.empty())
+ {
+ navMeshPtr->handleNavMeshNotEnabled();
+ }
+ else
+ {
+ navMeshPtr->handleNavMeshStart(mNavMeshVersionXXX);
+ LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, mNavMeshVersionXXX, navMeshPtr);
+
+ LLSD postData;
+ LLHTTPClient::post(navMeshURL, postData, responder);
+ }
+ }
+ }
+}
+
+void LLPathfindingManager::handleNavMeshUpdate(const LLUUID &pRegionUUID, U32 pNavMeshVersion)
+{
+ LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pRegionUUID);
+ navMeshPtr->handleNavMeshNewVersion(++mNavMeshVersionXXX);
+}
+
+LLPathfindingManager::agent_state_slot_t LLPathfindingManager::registerAgentStateListener(agent_state_callback_t pAgentStateCallback)
+{
+ return mAgentStateSignal.connect(pAgentStateCallback);
+}
+
+LLPathfindingManager::EAgentState LLPathfindingManager::getAgentState()
+{
+ if (!isPathfindingEnabledForCurrentRegion())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ if (!isValidAgentState(mAgentState))
+ {
+ requestGetAgentState();
+ }
+ }
+
+ return mAgentState;
+}
+
+LLPathfindingManager::EAgentState LLPathfindingManager::getLastKnownNonErrorAgentState() const
+{
+ return mLastKnownNonErrorAgentState;
+}
+
+void LLPathfindingManager::requestSetAgentState(EAgentState pRequestedAgentState)
+{
+ llassert(isValidAgentState(pRequestedAgentState));
+ std::string agentStateURL = getAgentStateURLForCurrentRegion();
+
+ if (agentStateURL.empty())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ LLSD request;
+ request[ALTER_NAVMESH_OBJECTS_FIELD] = static_cast<LLSD::Boolean>(pRequestedAgentState == kAgentStateUnfrozen);
+#ifdef DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD
+ request[DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD] = static_cast<LLSD::Boolean>(pRequestedAgentState == kAgentStateUnfrozen);
+#endif // DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD
+
+ LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL, pRequestedAgentState);
+ LLHTTPClient::post(agentStateURL, request, responder);
+ }
+}
+
+LLPathfindingManager::ELinksetsRequestStatus LLPathfindingManager::requestGetLinksets(linksets_callback_t pLinksetsCallback) const
+{
+ ELinksetsRequestStatus status;
+
+ std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+ std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
+ if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
+ {
+ status = kLinksetsRequestNotEnabled;
+ }
+ else
+ {
+ bool doRequestTerrain = isAllowViewTerrainProperties();
+ LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pLinksetsCallback, true, doRequestTerrain));
+
+ LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);
+
+ if (doRequestTerrain)
+ {
+ LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);
+ }
+
+ status = kLinksetsRequestStarted;
+ }
+
+ return status;
+}
+
+LLPathfindingManager::ELinksetsRequestStatus LLPathfindingManager::requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD, linksets_callback_t pLinksetsCallback) const
+{
+ ELinksetsRequestStatus status = kLinksetsRequestNotEnabled;
+
+ std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+ std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
+ if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
+ {
+ status = kLinksetsRequestNotEnabled;
+ }
+ else
+ {
+ LLSD objectPostData = pLinksetList->encodeObjectFields(pLinksetUse, pA, pB, pC, pD);
+ LLSD terrainPostData;
+ if (isAllowViewTerrainProperties())
+ {
+ terrainPostData = pLinksetList->encodeTerrainFields(pLinksetUse, pA, pB, pC, pD);
+ }
+
+ if (objectPostData.isUndefined() && terrainPostData.isUndefined())
+ {
+ status = kLinksetsRequestCompleted;
+ }
+ else
+ {
+ LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined()));
+
+ if (!objectPostData.isUndefined())
+ {
+ LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);
+ }
+
+ if (!terrainPostData.isUndefined())
+ {
+ LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);
+ }
+
+ status = kLinksetsRequestStarted;
+ }
+ }
+
+ return status;
+}
+
+LLPathfindingNavMeshPtr LLPathfindingManager::getNavMeshForRegion(const LLUUID &pRegionUUID)
+{
+ LLPathfindingNavMeshPtr navMeshPtr;
+ NavMeshMap::iterator navMeshIter = mNavMeshMap.find(pRegionUUID);
+ if (navMeshIter == mNavMeshMap.end())
+ {
+ navMeshPtr = LLPathfindingNavMeshPtr(new LLPathfindingNavMesh(pRegionUUID));
+ mNavMeshMap.insert(std::pair<LLUUID, LLPathfindingNavMeshPtr>(pRegionUUID, navMeshPtr));
+ }
+ else
+ {
+ navMeshPtr = navMeshIter->second;
+ }
+
+ return navMeshPtr;
+}
+
+LLPathfindingNavMeshPtr LLPathfindingManager::getNavMeshForRegion(LLViewerRegion *pRegion)
+{
+ LLUUID regionUUID;
+ if (pRegion != NULL)
+ {
+ regionUUID = pRegion->getRegionID();
+ }
+
+ return getNavMeshForRegion(regionUUID);
+}
+
+bool LLPathfindingManager::isValidAgentState(EAgentState pAgentState)
+{
+ return ((pAgentState == kAgentStateFrozen) || (pAgentState == kAgentStateUnfrozen));
+}
+
+void LLPathfindingManager::requestGetAgentState()
+{
+ std::string agentStateURL = getAgentStateURLForCurrentRegion();
+
+ if (agentStateURL.empty())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL);
+ LLHTTPClient::get(agentStateURL, responder);
+ }
+}
+
+void LLPathfindingManager::setAgentState(EAgentState pAgentState)
+{
+ mAgentState = pAgentState;
+
+ if (mAgentState != kAgentStateError)
+ {
+ mLastKnownNonErrorAgentState = mAgentState;
+ }
+
+ mAgentStateSignal(mAgentState);
+}
+
+void LLPathfindingManager::handleAgentStateResult(const LLSD &pContent, EAgentState pRequestedAgentState)
+{
+#ifndef DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD
+ llassert(pContent.has(ALTER_NAVMESH_OBJECTS_FIELD));
+ llassert(pContent.get(ALTER_NAVMESH_OBJECTS_FIELD).isBoolean());
+ EAgentState agentState = (pContent.get(ALTER_NAVMESH_OBJECTS_FIELD).asBoolean() ? kAgentStateUnfrozen : kAgentStateFrozen);
+#else // DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD
+ EAgentState agentState = kAgentStateUnknown;
+ if (pContent.has(ALTER_NAVMESH_OBJECTS_FIELD))
+ {
+ llassert(pContent.get(ALTER_NAVMESH_OBJECTS_FIELD).isBoolean());
+ agentState = (pContent.get(ALTER_NAVMESH_OBJECTS_FIELD).asBoolean() ? kAgentStateUnfrozen : kAgentStateFrozen);
+ }
+ else
+ {
+ llassert(pContent.has(DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD));
+ llassert(pContent.get(DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD).isBoolean());
+ agentState = (pContent.get(DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD).asBoolean() ? kAgentStateUnfrozen : kAgentStateFrozen);
+ }
+#endif // DEPRECATED_ALTER_NAVMESH_OBJECTS_FIELD
+
+ if (isValidAgentState(pRequestedAgentState) && (agentState != pRequestedAgentState))
+ {
+ agentState = kAgentStateError;
+ llassert(0);
+ }
+
+ setAgentState(agentState);
+}
+
+void LLPathfindingManager::handleAgentStateError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+ setAgentState(kAgentStateError);
+}
+
+std::string LLPathfindingManager::getRetrieveNavMeshURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_RETRIEVE_NAVMESH);
+}
+
+std::string LLPathfindingManager::getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const
+{
+ return getCapabilityURLForRegion(pRegion, CAP_SERVICE_RETRIEVE_NAVMESH);
+}
+
+std::string LLPathfindingManager::getAgentStateURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_AGENT_STATE);
+}
+
+std::string LLPathfindingManager::getObjectLinksetsURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_OBJECT_LINKSETS);
+}
+
+std::string LLPathfindingManager::getTerrainLinksetsURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_TERRAIN_LINKSETS);
+}
+
+std::string LLPathfindingManager::getCapabilityURLForCurrentRegion(const std::string &pCapabilityName) const
+{
+ return getCapabilityURLForRegion(getCurrentRegion(), pCapabilityName);
+}
+
+std::string LLPathfindingManager::getCapabilityURLForRegion(LLViewerRegion *pRegion, const std::string &pCapabilityName) const
+{
+ std::string capabilityURL("");
+
+ if (pRegion != NULL)
+ {
+ capabilityURL = pRegion->getCapability(pCapabilityName);
+ }
+
+ if (capabilityURL.empty())
+ {
+ llwarns << "cannot find capability '" << pCapabilityName << "' for current region '"
+ << ((pRegion != NULL) ? pRegion->getName() : "<null>") << "'" << llendl;
+ }
+
+ return capabilityURL;
+}
+
+LLViewerRegion *LLPathfindingManager::getCurrentRegion() const
+{
+ return gAgent.getRegion();
+}
+
+//---------------------------------------------------------------------------
+// LLNavMeshSimStateChangeNode
+//---------------------------------------------------------------------------
+
+void LLNavMeshSimStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, const LLSD &pInput) const
+{
+ LLViewerRegion *region = gAgent.getRegion();
+ U32 navMeshVersion = 0U;
+ LLPathfindingManager::getInstance()->handleNavMeshUpdate(region->getRegionID(), navMeshVersion);
+}
+
+//---------------------------------------------------------------------------
+// NavMeshResponder
+//---------------------------------------------------------------------------
+
+NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)
+ : mCapabilityURL(pCapabilityURL),
+ mNavMeshVersion(pNavMeshVersion),
+ mNavMeshPtr(pNavMeshPtr)
+{
+}
+
+NavMeshResponder::~NavMeshResponder()
+{
+}
+
+void NavMeshResponder::result(const LLSD &pContent)
+{
+ mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion);
+}
+
+void NavMeshResponder::error(U32 pStatus, const std::string& pReason)
+{
+ mNavMeshPtr->handleNavMeshError(pStatus, pReason, mCapabilityURL, mNavMeshVersion);
+}
+
+//---------------------------------------------------------------------------
+// AgentStateResponder
+//---------------------------------------------------------------------------
+
+AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL, LLPathfindingManager::EAgentState pRequestedAgentState)
+ : LLHTTPClient::Responder(),
+ mCapabilityURL(pCapabilityURL),
+ mRequestedAgentState(pRequestedAgentState)
+{
+}
+
+AgentStateResponder::~AgentStateResponder()
+{
+}
+
+void AgentStateResponder::result(const LLSD &pContent)
+{
+ LLPathfindingManager::getInstance()->handleAgentStateResult(pContent, mRequestedAgentState);
+}
+
+void AgentStateResponder::error(U32 pStatus, const std::string &pReason)
+{
+ LLPathfindingManager::getInstance()->handleAgentStateError(pStatus, pReason, mCapabilityURL);
+}
+
+//---------------------------------------------------------------------------
+// LinksetsResponder
+//---------------------------------------------------------------------------
+
+LinksetsResponder::LinksetsResponder(LLPathfindingManager::linksets_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested)
+ : mLinksetsCallback(pLinksetsCallback),
+ mObjectMessagingState(pIsObjectRequested ? kWaiting : kNotRequested),
+ mTerrainMessagingState(pIsTerrainRequested ? kWaiting : kNotRequested),
+ mObjectLinksetListPtr(),
+ mTerrainLinksetPtr()
+{
+}
+
+LinksetsResponder::~LinksetsResponder()
+{
+}
+
+void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent)
+{
+ mObjectLinksetListPtr = LLPathfindingLinksetListPtr(new LLPathfindingLinksetList(pContent));
+
+ mObjectMessagingState = kReceivedGood;
+ if (mTerrainMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+ mObjectMessagingState = kReceivedError;
+ if (mTerrainMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent)
+{
+ mTerrainLinksetPtr = LLPathfindingLinksetPtr(new LLPathfindingLinkset(pContent));
+
+ mTerrainMessagingState = kReceivedGood;
+ if (mObjectMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ mTerrainMessagingState = kReceivedError;
+ if (mObjectMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::sendCallback()
+{
+ llassert(mObjectMessagingState != kWaiting);
+ llassert(mTerrainMessagingState != kWaiting);
+ LLPathfindingManager::ELinksetsRequestStatus requestStatus =
+ ((((mObjectMessagingState == kReceivedGood) || (mObjectMessagingState == kNotRequested)) &&
+ ((mTerrainMessagingState == kReceivedGood) || (mTerrainMessagingState == kNotRequested))) ?
+ LLPathfindingManager::kLinksetsRequestCompleted : LLPathfindingManager::kLinksetsRequestError);
+
+ if (mObjectMessagingState != kReceivedGood)
+ {
+ mObjectLinksetListPtr = LLPathfindingLinksetListPtr(new LLPathfindingLinksetList());
+ }
+
+ if (mTerrainMessagingState == kReceivedGood)
+ {
+ mObjectLinksetListPtr->insert(std::pair<std::string, LLPathfindingLinksetPtr>(mTerrainLinksetPtr->getUUID().asString(), mTerrainLinksetPtr));
+ }
+
+ mLinksetsCallback(requestStatus, mObjectLinksetListPtr);
+}
+
+//---------------------------------------------------------------------------
+// ObjectLinksetsResponder
+//---------------------------------------------------------------------------
+
+ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+ : mCapabilityURL(pCapabilityURL),
+ mLinksetsResponsderPtr(pLinksetsResponsderPtr)
+{
+}
+
+ObjectLinksetsResponder::~ObjectLinksetsResponder()
+{
+}
+
+void ObjectLinksetsResponder::result(const LLSD &pContent)
+{
+ mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent);
+}
+
+void ObjectLinksetsResponder::error(U32 pStatus, const std::string &pReason)
+{
+ mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, mCapabilityURL);
+}
+
+//---------------------------------------------------------------------------
+// TerrainLinksetsResponder
+//---------------------------------------------------------------------------
+
+TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+: mCapabilityURL(pCapabilityURL),
+mLinksetsResponsderPtr(pLinksetsResponsderPtr)
+{
+}
+
+TerrainLinksetsResponder::~TerrainLinksetsResponder()
+{
+}
+
+void TerrainLinksetsResponder::result(const LLSD &pContent)
+{
+ mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent);
+}
+
+void TerrainLinksetsResponder::error(U32 pStatus, const std::string &pReason)
+{
+ mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, mCapabilityURL);
+}
diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h new file mode 100644 index 0000000000..3e85cb1291 --- /dev/null +++ b/indra/newview/llpathfindingmanager.h @@ -0,0 +1,124 @@ +/**
+ * @file llpathfindingmanager.h
+ * @author William Todd Stinson
+ * @brief A state manager for the various pathfinding states.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGMANAGER_H
+#define LL_LLPATHFINDINGMANAGER_H
+
+#include "llsingleton.h"
+#include "lluuid.h"
+#include "llpathfindingnavmesh.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+
+#include <string>
+#include <map>
+
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+class LLFloater;
+class LLViewerRegion;
+
+class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
+{
+ friend class AgentStateResponder;
+public:
+ typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap;
+
+ typedef enum {
+ kAgentStateUnknown,
+ kAgentStateFrozen,
+ kAgentStateUnfrozen,
+ kAgentStateNotEnabled,
+ kAgentStateError
+ } EAgentState;
+
+ typedef boost::function<void (EAgentState)> agent_state_callback_t;
+ typedef boost::signals2::signal<void (EAgentState)> agent_state_signal_t;
+ typedef boost::signals2::connection agent_state_slot_t;
+
+ typedef enum {
+ kLinksetsRequestStarted,
+ kLinksetsRequestCompleted,
+ kLinksetsRequestNotEnabled,
+ kLinksetsRequestError
+ } ELinksetsRequestStatus;
+
+ typedef boost::function<void (ELinksetsRequestStatus, LLPathfindingLinksetListPtr)> linksets_callback_t;
+
+ LLPathfindingManager();
+ virtual ~LLPathfindingManager();
+
+ bool isPathfindingEnabledForCurrentRegion() const;
+
+ bool isAllowAlterPermanent();
+ bool isAllowViewTerrainProperties() const;
+
+ LLPathfindingNavMesh::navmesh_slot_t registerNavMeshListenerForRegion(LLViewerRegion *pRegion, LLPathfindingNavMesh::navmesh_callback_t pNavMeshCallback);
+ void requestGetNavMeshForRegion(LLViewerRegion *pRegion);
+ void handleNavMeshUpdate(const LLUUID &pRegionUUID, U32 pNavMeshVersion);
+
+ agent_state_slot_t registerAgentStateListener(agent_state_callback_t pAgentStateCallback);
+ EAgentState getAgentState();
+ EAgentState getLastKnownNonErrorAgentState() const;
+ void requestSetAgentState(EAgentState pAgentState);
+
+ ELinksetsRequestStatus requestGetLinksets(linksets_callback_t pLinksetsCallback) const;
+ ELinksetsRequestStatus requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD, linksets_callback_t pLinksetsCallback) const;
+
+protected:
+
+private:
+ LLPathfindingNavMeshPtr getNavMeshForRegion(const LLUUID &pRegionUUID);
+ LLPathfindingNavMeshPtr getNavMeshForRegion(LLViewerRegion *pRegion);
+
+ static bool isValidAgentState(EAgentState pAgentState);
+
+ void requestGetAgentState();
+ void setAgentState(EAgentState pAgentState);
+ void handleAgentStateResult(const LLSD &pContent, EAgentState pRequestedAgentState);
+ void handleAgentStateError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+
+ std::string getRetrieveNavMeshURLForCurrentRegion() const;
+ std::string getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const;
+ std::string getAgentStateURLForCurrentRegion() const;
+ std::string getObjectLinksetsURLForCurrentRegion() const;
+ std::string getTerrainLinksetsURLForCurrentRegion() const;
+
+ std::string getCapabilityURLForCurrentRegion(const std::string &pCapabilityName) const;
+ std::string getCapabilityURLForRegion(LLViewerRegion *pRegion, const std::string &pCapabilityName) const;
+ LLViewerRegion *getCurrentRegion() const;
+
+ NavMeshMap mNavMeshMap;
+ U32 mNavMeshVersionXXX; // XXX stinson 03/02/2012 : a hacky way of doing versions for now
+
+ agent_state_signal_t mAgentStateSignal;
+ EAgentState mAgentState;
+ EAgentState mLastKnownNonErrorAgentState;
+};
+
+#endif // LL_LLPATHFINDINGMANAGER_H
diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp new file mode 100644 index 0000000000..84343cf31e --- /dev/null +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -0,0 +1,138 @@ +/**
+ * @file llpathfindingnavmesh.cpp
+ * @author William Todd Stinson
+ * @brief A class for representing the navmesh of a pathfinding region.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "lluuid.h"
+#include "llpathfindingnavmesh.h"
+#include "llsdserialize.h"
+
+#include <string>
+
+//---------------------------------------------------------------------------
+// LLPathfindingNavMesh
+//---------------------------------------------------------------------------
+
+LLPathfindingNavMesh::LLPathfindingNavMesh(const LLUUID &pRegionUUID)
+ : mRegionUUID(pRegionUUID),
+ mNavMeshRequestStatus(kNavMeshRequestUnknown),
+ mNavMeshSignal(),
+ mNavMeshData(),
+ mNavMeshVersion(0U)
+{
+}
+
+LLPathfindingNavMesh::~LLPathfindingNavMesh()
+{
+}
+
+LLPathfindingNavMesh::navmesh_slot_t LLPathfindingNavMesh::registerNavMeshListener(navmesh_callback_t pNavMeshCallback)
+{
+ return mNavMeshSignal.connect(pNavMeshCallback);
+}
+
+bool LLPathfindingNavMesh::hasNavMeshVersion(U32 pNavMeshVersion) const
+{
+ return (((mNavMeshRequestStatus == kNavMeshRequestStarted) || (mNavMeshRequestStatus == kNavMeshRequestCompleted)) && (mNavMeshVersion == pNavMeshVersion));
+}
+
+void LLPathfindingNavMesh::handleRefresh()
+{
+ mNavMeshSignal(mNavMeshRequestStatus, mRegionUUID, mNavMeshVersion, mNavMeshData);
+}
+
+void LLPathfindingNavMesh::handleNavMeshNewVersion(U32 pNavMeshVersion)
+{
+ mNavMeshData.clear();
+ mNavMeshVersion = pNavMeshVersion;
+ setRequestStatus(kNavMeshRequestNeedsUpdate);
+}
+
+void LLPathfindingNavMesh::handleNavMeshStart(U32 pNavMeshVersion)
+{
+ mNavMeshVersion = pNavMeshVersion;
+ setRequestStatus(kNavMeshRequestStarted);
+}
+
+void LLPathfindingNavMesh::handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion)
+{
+ if (mNavMeshVersion == pNavMeshVersion)
+ {
+ if ( pContent.has("navmesh_data") )
+ {
+ const LLSD::Binary &value = pContent["navmesh_data"].asBinary();
+ unsigned int binSize = value.size();
+ std::string newStr(reinterpret_cast<const char *>(&value[0]), binSize);
+ std::istringstream streamdecomp( newStr );
+ unsigned int decompBinSize = 0;
+ bool valid = false;
+ U8* pUncompressedNavMeshContainer = unzip_llsdNavMesh( valid, decompBinSize, streamdecomp, binSize ) ;
+ if ( !valid )
+ {
+ llwarns << "Unable to decompress the navmesh llsd." << llendl;
+ setRequestStatus(kNavMeshRequestError);
+ }
+ else
+ {
+ llassert(pUncompressedNavMeshContainer);
+ mNavMeshData.resize( decompBinSize );
+ memcpy( &mNavMeshData[0], &pUncompressedNavMeshContainer[0], decompBinSize );
+ setRequestStatus(kNavMeshRequestCompleted);
+ }
+ if ( pUncompressedNavMeshContainer )
+ {
+ free( pUncompressedNavMeshContainer );
+ }
+ }
+ else
+ {
+ llwarns << "No mesh data received" << llendl;
+ setRequestStatus(kNavMeshRequestError);
+ }
+ }
+}
+
+void LLPathfindingNavMesh::handleNavMeshNotEnabled()
+{
+ mNavMeshData.clear();
+ setRequestStatus(kNavMeshRequestNotEnabled);
+}
+
+void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion)
+{
+ llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+ if (mNavMeshVersion == pNavMeshVersion)
+ {
+ mNavMeshData.clear();
+ setRequestStatus(kNavMeshRequestError);
+ }
+}
+
+void LLPathfindingNavMesh::setRequestStatus(ENavMeshRequestStatus pNavMeshRequestStatus)
+{
+ mNavMeshRequestStatus = pNavMeshRequestStatus;
+ mNavMeshSignal(mNavMeshRequestStatus, mRegionUUID, mNavMeshVersion, mNavMeshData);
+}
diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h new file mode 100644 index 0000000000..eb9ef9683d --- /dev/null +++ b/indra/newview/llpathfindingnavmesh.h @@ -0,0 +1,87 @@ +/**
+ * @file llpathfindingnavmesh.h
+ * @author William Todd Stinson
+ * @brief A class for representing the navmesh of a pathfinding region.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGNAVMESH_H
+#define LL_LLPATHFINDINGNAVMESH_H
+
+#include "llsd.h"
+#include "lluuid.h"
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+class LLSD;
+class LLPathfindingNavMesh;
+
+typedef boost::shared_ptr<LLPathfindingNavMesh> LLPathfindingNavMeshPtr;
+
+class LLPathfindingNavMesh
+{
+public:
+ typedef enum {
+ kNavMeshRequestUnknown,
+ kNavMeshRequestNeedsUpdate,
+ kNavMeshRequestStarted,
+ kNavMeshRequestCompleted,
+ kNavMeshRequestNotEnabled,
+ kNavMeshRequestError
+ } ENavMeshRequestStatus;
+
+ typedef boost::function<void (ENavMeshRequestStatus, const LLUUID &, U32, const LLSD::Binary &)> navmesh_callback_t;
+ typedef boost::signals2::signal<void (ENavMeshRequestStatus, const LLUUID &, U32, const LLSD::Binary &)> navmesh_signal_t;
+ typedef boost::signals2::connection navmesh_slot_t;
+
+ LLPathfindingNavMesh(const LLUUID &pRegionUUID);
+ virtual ~LLPathfindingNavMesh();
+
+ navmesh_slot_t registerNavMeshListener(navmesh_callback_t pNavMeshCallback);
+
+ bool hasNavMeshVersion(U32 pNavMeshVersion) const;
+
+ void handleRefresh();
+ void handleNavMeshNewVersion(U32 pNavMeshVersion);
+ void handleNavMeshStart(U32 pNavMeshVersion);
+ void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion);
+ void handleNavMeshNotEnabled();
+ void handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion);
+
+protected:
+
+private:
+ void setRequestStatus(ENavMeshRequestStatus pNavMeshRequestStatus);
+
+ LLUUID mRegionUUID;
+ ENavMeshRequestStatus mNavMeshRequestStatus;
+ navmesh_signal_t mNavMeshSignal;
+ LLSD::Binary mNavMeshData;
+ U32 mNavMeshVersion;
+};
+
+#endif // LL_LLPATHFINDINGNAVMESH_H
diff --git a/indra/newview/llpathfindingnavmeshzone.cpp b/indra/newview/llpathfindingnavmeshzone.cpp new file mode 100644 index 0000000000..3767834655 --- /dev/null +++ b/indra/newview/llpathfindingnavmeshzone.cpp @@ -0,0 +1,367 @@ +/**
+ * @file llpathfindingnavmeshzone.cpp
+ * @author William Todd Stinson
+ * @brief A class for representing the zone of navmeshes containing and possible surrounding the current region.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llpathfindingnavmesh.h"
+#include "llpathfindingnavmeshzone.h"
+#include "llpathfindingmanager.h"
+#include "llviewercontrol.h"
+
+#include "LLPathingLib.h"
+
+#include <string>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+#define CENTER_REGION 99
+
+//---------------------------------------------------------------------------
+// LLPathfindingNavMeshZone
+//---------------------------------------------------------------------------
+
+LLPathfindingNavMeshZone::LLPathfindingNavMeshZone()
+ : mNavMeshLocationPtrs(),
+ mNavMeshZoneSignal()
+{
+}
+
+LLPathfindingNavMeshZone::~LLPathfindingNavMeshZone()
+{
+}
+
+LLPathfindingNavMeshZone::navmesh_zone_slot_t LLPathfindingNavMeshZone::registerNavMeshZoneListener(navmesh_zone_callback_t pNavMeshZoneCallback)
+{
+ return mNavMeshZoneSignal.connect(pNavMeshZoneCallback);
+}
+
+void LLPathfindingNavMeshZone::initialize()
+{
+ mNavMeshLocationPtrs.clear();
+
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ LLViewerRegion *currentRegion = gAgent.getRegion();
+ if (currentRegion != NULL)
+ {
+ llinfos << "STINSON DEBUG: currentRegion: '" << currentRegion->getName() << "' (" << currentRegion->getRegionID().asString() << ")" << llendl;
+ std::vector<S32> availableRegions;
+ currentRegion->getNeighboringRegionsStatus( availableRegions );
+ std::vector<LLViewerRegion*> neighborRegionsPtrs;
+ currentRegion->getNeighboringRegions( neighborRegionsPtrs );
+ for (std::vector<S32>::const_iterator statusIter = availableRegions.begin();
+ statusIter != availableRegions.end(); ++statusIter)
+ {
+ LLViewerRegion *region = neighborRegionsPtrs[statusIter - availableRegions.begin()];
+ llinfos << "STINSON DEBUG: region #" << *statusIter << ": '" << region->getName() << "' (" << region->getRegionID().asString() << ")" << llendl;
+ }
+ }
+
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ NavMeshLocationPtr centerNavMeshPtr(new NavMeshLocation(CENTER_REGION, boost::bind(&LLPathfindingNavMeshZone::handleNavMeshLocation, this)));
+ mNavMeshLocationPtrs.push_back(centerNavMeshPtr);
+
+ U32 neighborRegionDir = gSavedSettings.getU32("RetrieveNeighboringRegion");
+ if (neighborRegionDir != CENTER_REGION)
+ {
+ NavMeshLocationPtr neighborNavMeshPtr(new NavMeshLocation(neighborRegionDir, boost::bind(&LLPathfindingNavMeshZone::handleNavMeshLocation, this)));
+ mNavMeshLocationPtrs.push_back(neighborNavMeshPtr);
+ }
+}
+
+void LLPathfindingNavMeshZone::enable()
+{
+ for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
+ navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
+ {
+ NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
+ navMeshLocationPtr->enable();
+ }
+}
+
+void LLPathfindingNavMeshZone::disable()
+{
+ for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
+ navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
+ {
+ NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
+ navMeshLocationPtr->disable();
+ }
+}
+
+void LLPathfindingNavMeshZone::refresh()
+{
+ llassert(LLPathingLib::getInstance() != NULL);
+ if (LLPathingLib::getInstance() != NULL)
+ {
+ LLPathingLib::getInstance()->cleanupResidual();
+ }
+
+ for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
+ navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
+ {
+ NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
+ navMeshLocationPtr->refresh();
+ }
+}
+
+void LLPathfindingNavMeshZone::handleNavMeshLocation()
+{
+ updateStatus();
+}
+
+void LLPathfindingNavMeshZone::updateStatus()
+{
+ bool hasRequestUnknown = false;
+ bool hasRequestNeedsUpdate = false;
+ bool hasRequestStarted = false;
+ bool hasRequestCompleted = false;
+ bool hasRequestNotEnabled = false;
+ bool hasRequestError = false;
+
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update BEGIN" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ for (NavMeshLocationPtrs::iterator navMeshLocationPtrIter = mNavMeshLocationPtrs.begin();
+ navMeshLocationPtrIter != mNavMeshLocationPtrs.end(); ++navMeshLocationPtrIter)
+ {
+ NavMeshLocationPtr navMeshLocationPtr = *navMeshLocationPtrIter;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: region #" << navMeshLocationPtr->getDirection() << ": region(" << navMeshLocationPtr->getRegionUUID().asString() << ") status:" << navMeshLocationPtr->getRequestStatus() << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ switch (navMeshLocationPtr->getRequestStatus())
+ {
+ case LLPathfindingNavMesh::kNavMeshRequestUnknown :
+ hasRequestUnknown = true;
+ break;
+ case LLPathfindingNavMesh::kNavMeshRequestNeedsUpdate :
+ hasRequestNeedsUpdate = true;
+ break;
+ case LLPathfindingNavMesh::kNavMeshRequestStarted :
+ hasRequestStarted = true;
+ break;
+ case LLPathfindingNavMesh::kNavMeshRequestCompleted :
+ hasRequestCompleted = true;
+ break;
+ case LLPathfindingNavMesh::kNavMeshRequestNotEnabled :
+ hasRequestNotEnabled = true;
+ break;
+ case LLPathfindingNavMesh::kNavMeshRequestError :
+ hasRequestError = true;
+ break;
+ default :
+ hasRequestError = true;
+ llassert(0);
+ break;
+ }
+ }
+
+ ENavMeshZoneRequestStatus zoneRequestStatus = kNavMeshZoneRequestUnknown;
+ if (hasRequestNeedsUpdate)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestNeedsUpdate;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is NEEDS UPDATE" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else if (hasRequestStarted)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestStarted;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is STARTED" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else if (hasRequestError)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestError;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is ERROR" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else if (hasRequestUnknown)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestUnknown;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is UNKNOWN" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else if (hasRequestCompleted)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestCompleted;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is stitching" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llassert(LLPathingLib::getInstance() != NULL);
+ if (LLPathingLib::getInstance() != NULL)
+ {
+ LLPathingLib::getInstance()->stitchNavMeshes( gSavedSettings.getBOOL("EnableVBOForNavMeshVisualization") );
+ }
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is COMPLETED" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else if (hasRequestNotEnabled)
+ {
+ zoneRequestStatus = kNavMeshZoneRequestNotEnabled;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is NOT ENABLED" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ }
+ else
+ {
+ zoneRequestStatus = kNavMeshZoneRequestError;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llinfos << "STINSON DEBUG: Navmesh zone update is BAD ERROR" << llendl;
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+ llassert(0);
+ }
+
+ mNavMeshZoneSignal(zoneRequestStatus);
+}
+
+//---------------------------------------------------------------------------
+// LLPathfindingNavMeshZone::NavMeshLocation
+//---------------------------------------------------------------------------
+
+LLPathfindingNavMeshZone::NavMeshLocation::NavMeshLocation(S32 pDirection, navmesh_location_callback_t pLocationCallback)
+ : mDirection(pDirection),
+ mRegionUUID(),
+ mHasNavMesh(false),
+ mNavMeshVersion(0U),
+ mLocationCallback(pLocationCallback),
+ mRequestStatus(LLPathfindingNavMesh::kNavMeshRequestUnknown),
+ mNavMeshSlot()
+{
+}
+
+LLPathfindingNavMeshZone::NavMeshLocation::~NavMeshLocation()
+{
+}
+
+void LLPathfindingNavMeshZone::NavMeshLocation::enable()
+{
+ clear();
+
+ LLViewerRegion *region = getRegion();
+ if (region == NULL)
+ {
+ mRegionUUID.setNull();
+ }
+ else
+ {
+ mRegionUUID = region->getRegionID();
+ mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(region, boost::bind(&LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh, this, _1, _2, _3, _4));
+ }
+}
+
+void LLPathfindingNavMeshZone::NavMeshLocation::refresh()
+{
+ LLViewerRegion *region = getRegion();
+
+ if (region == NULL)
+ {
+ llassert(mRegionUUID.isNull());
+ LLSD::Binary nullData;
+ handleNavMesh(LLPathfindingNavMesh::kNavMeshRequestNotEnabled, mRegionUUID, 0U, nullData);
+ }
+ else
+ {
+ llassert(mRegionUUID == region->getRegionID());
+ LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(region);
+ }
+}
+
+void LLPathfindingNavMeshZone::NavMeshLocation::disable()
+{
+ clear();
+}
+
+LLPathfindingNavMesh::ENavMeshRequestStatus LLPathfindingNavMeshZone::NavMeshLocation::getRequestStatus() const
+{
+ return mRequestStatus;
+}
+
+void LLPathfindingNavMeshZone::NavMeshLocation::handleNavMesh(LLPathfindingNavMesh::ENavMeshRequestStatus pNavMeshRequestStatus, const LLUUID &pRegionUUID, U32 pNavMeshVersion, const LLSD::Binary &pNavMeshData)
+{
+ llassert(mRegionUUID == pRegionUUID);
+ mRequestStatus = pNavMeshRequestStatus;
+ if ((pNavMeshRequestStatus == LLPathfindingNavMesh::kNavMeshRequestCompleted) && (!mHasNavMesh || (mNavMeshVersion != pNavMeshVersion)))
+ {
+ llassert(!pNavMeshData.empty());
+ mHasNavMesh = true;
+ mNavMeshVersion = pNavMeshVersion;
+ llassert(LLPathingLib::getInstance() != NULL);
+ if (LLPathingLib::getInstance() != NULL)
+ {
+ LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD(pNavMeshData, mDirection);
+ }
+ }
+ mLocationCallback();
+}
+
+void LLPathfindingNavMeshZone::NavMeshLocation::clear()
+{
+ mHasNavMesh = false;
+ mRequestStatus = LLPathfindingNavMesh::kNavMeshRequestUnknown;
+ if (mNavMeshSlot.connected())
+ {
+ mNavMeshSlot.disconnect();
+ }
+}
+
+LLViewerRegion *LLPathfindingNavMeshZone::NavMeshLocation::getRegion() const
+{
+ LLViewerRegion *region = NULL;
+
+ LLViewerRegion *currentRegion = gAgent.getRegion();
+ if (currentRegion != NULL)
+ {
+ if (mDirection == CENTER_REGION)
+ {
+ region = currentRegion;
+ }
+ else
+ {
+ //User wants to pull in a neighboring region
+ std::vector<S32> availableRegions;
+ currentRegion->getNeighboringRegionsStatus( availableRegions );
+ //Is the desired region in the available list
+ std::vector<S32>::iterator foundElem = std::find(availableRegions.begin(),availableRegions.end(),mDirection);
+ if ( foundElem != availableRegions.end() )
+ {
+ std::vector<LLViewerRegion*> neighborRegionsPtrs;
+ currentRegion->getNeighboringRegions( neighborRegionsPtrs );
+ region = neighborRegionsPtrs[foundElem - availableRegions.begin()];
+ }
+ }
+ }
+
+ return region;
+}
diff --git a/indra/newview/llpathfindingnavmeshzone.h b/indra/newview/llpathfindingnavmeshzone.h new file mode 100644 index 0000000000..833f3ebb05 --- /dev/null +++ b/indra/newview/llpathfindingnavmeshzone.h @@ -0,0 +1,116 @@ +/**
+ * @file llpathfindingnavmeshzone.h
+ * @author William Todd Stinson
+ * @brief A class for representing the zone of navmeshes containing and possible surrounding the current region.
+ *
+ * $LicenseInfo:firstyear=2002&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_LLPATHFINDINGNAVMESHZONE_H
+#define LL_LLPATHFINDINGNAVMESHZONE_H
+
+#include "llsd.h"
+#include "lluuid.h"
+#include "llpathfindingnavmesh.h"
+
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+//#define XXX_STINSON_DEBUG_NAVMESH_ZONE
+
+class LLPathfindingNavMeshZone
+{
+public:
+ typedef enum {
+ kNavMeshZoneRequestUnknown,
+ kNavMeshZoneRequestNeedsUpdate,
+ kNavMeshZoneRequestStarted,
+ kNavMeshZoneRequestCompleted,
+ kNavMeshZoneRequestNotEnabled,
+ kNavMeshZoneRequestError
+ } ENavMeshZoneRequestStatus;
+
+ typedef boost::function<void (ENavMeshZoneRequestStatus)> navmesh_zone_callback_t;
+ typedef boost::signals2::signal<void (ENavMeshZoneRequestStatus)> navmesh_zone_signal_t;
+ typedef boost::signals2::connection navmesh_zone_slot_t;
+
+ LLPathfindingNavMeshZone();
+ virtual ~LLPathfindingNavMeshZone();
+
+ navmesh_zone_slot_t registerNavMeshZoneListener(navmesh_zone_callback_t pNavMeshZoneCallback);
+ void initialize();
+
+ void enable();
+ void disable();
+ void refresh();
+
+protected:
+
+private:
+ typedef boost::function<void (void)> navmesh_location_callback_t;
+ class NavMeshLocation
+ {
+ public:
+ NavMeshLocation(S32 pDirection, navmesh_location_callback_t pLocationCallback);
+ virtual ~NavMeshLocation();
+
+ void enable();
+ void refresh();
+ void disable();
+
+ LLPathfindingNavMesh::ENavMeshRequestStatus getRequestStatus() const;
+#ifdef XXX_STINSON_DEBUG_NAVMESH_ZONE
+ const LLUUID &getRegionUUID() const {return mRegionUUID;};
+ S32 getDirection() const {return mDirection;};
+#endif // XXX_STINSON_DEBUG_NAVMESH_ZONE
+
+ protected:
+
+ private:
+ void handleNavMesh(LLPathfindingNavMesh::ENavMeshRequestStatus pNavMeshRequestStatus, const LLUUID &pRegionUUID, U32 pNavMeshVersion, const LLSD::Binary &pNavMeshData);
+
+ void clear();
+ LLViewerRegion *getRegion() const;
+
+ S32 mDirection;
+ LLUUID mRegionUUID;
+ bool mHasNavMesh;
+ U32 mNavMeshVersion;
+ navmesh_location_callback_t mLocationCallback;
+ LLPathfindingNavMesh::ENavMeshRequestStatus mRequestStatus;
+ LLPathfindingNavMesh::navmesh_slot_t mNavMeshSlot;
+ };
+
+ typedef boost::shared_ptr<NavMeshLocation> NavMeshLocationPtr;
+ typedef std::vector<NavMeshLocationPtr> NavMeshLocationPtrs;
+
+ void handleNavMeshLocation();
+ void updateStatus();
+
+ NavMeshLocationPtrs mNavMeshLocationPtrs;
+ navmesh_zone_signal_t mNavMeshZoneSignal;
+};
+
+#endif // LL_LLPATHFINDINGNAVMESHZONE_H
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 6111255a66..9cfcf3de79 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -4144,12 +4144,6 @@ void LLSelectMgr::selectionUpdatePhantom(BOOL is_phantom) getSelection()->applyToObjects(&func); } -void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows) -{ - LLSelectMgrApplyFlags func( FLAGS_CAST_SHADOWS, cast_shadows); - getSelection()->applyToObjects(&func); -} - //---------------------------------------------------------------------- // Helpful packing functions for sendObjectMessage() //---------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 87ada5ac6b..c2816fe78a 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -501,7 +501,6 @@ public: void selectionUpdatePhysics(BOOL use_physics); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); - void selectionUpdateCastShadows(BOOL cast_shadows); void selectionDump(); BOOL selectionAllPCode(LLPCode code); // all objects have this PCode diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 5d196a465f..746320f887 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1,4795 +1,4797 @@ -/** - * @file llspatialpartition.cpp - * @brief LLSpatialGroup class implementation and supporting functions - * - * $LicenseInfo:firstyear=2003&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llspatialpartition.h" - -#include "llappviewer.h" -#include "lltexturecache.h" -#include "lltexturefetch.h" -#include "llimageworker.h" -#include "llviewerwindow.h" -#include "llviewerobjectlist.h" -#include "llvovolume.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llviewercamera.h" -#include "llface.h" -#include "llfloatertools.h" -#include "llviewercontrol.h" -#include "llviewerregion.h" -#include "llcamera.h" -#include "pipeline.h" -#include "llmeshrepository.h" -#include "llrender.h" -#include "lloctree.h" -#include "llphysicsshapebuilderutil.h" -#include "llvoavatar.h" -#include "llvolumemgr.h" -#include "lltextureatlas.h" -#include "llglslshader.h" -#include "llviewershadermgr.h" - -static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); -static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); - -const F32 SG_OCCLUSION_FUDGE = 0.25f; -#define SG_DISCARD_TOLERANCE 0.01f - -#if LL_OCTREE_PARANOIA_CHECK -#define assert_octree_valid(x) x->validate() -#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates() -#else -#define assert_octree_valid(x) -#define assert_states_valid(x) -#endif - - -static U32 sZombieGroups = 0; -U32 LLSpatialGroup::sNodeCount = 0; - -#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 - -std::set<GLuint> LLSpatialGroup::sPendingQueries; - -U32 gOctreeMaxCapacity; - -BOOL LLSpatialGroup::sNoDelete = FALSE; - -static F32 sLastMaxTexPriority = 1.f; -static F32 sCurMaxTexPriority = 1.f; - -class LLOcclusionQueryPool : public LLGLNamePool -{ -protected: - virtual GLuint allocateName() - { - GLuint name; - glGenQueriesARB(1, &name); - return name; - } - - virtual void releaseName(GLuint name) - { -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - LLSpatialGroup::sPendingQueries.erase(name); -#endif - glDeleteQueriesARB(1, &name); - } -}; - -static LLOcclusionQueryPool sQueryPool; - -//static counter for frame to switch LOD on - -void sg_assert(BOOL expr) -{ -#if LL_OCTREE_PARANOIA_CHECK - if (!expr) - { - llerrs << "Octree invalid!" << llendl; - } -#endif -} - -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - if ((min-origin).magVecSquared() < r && - (max-origin).magVecSquared() < r) - { - return 2; - } - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min.mV[i]) - { - t = min.mV[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max.mV[i]) - { - t = origin.mV[i] - max.mV[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - LLVector4a origina; - origina.load3(origin.mV); - - LLVector4a v; - v.setSub(min, origina); - - if (v.dot3(v) < r) - { - v.setSub(max, origina); - if (v.dot3(v) < r) - { - return 2; - } - } - - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min[i]) - { - t = min[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max[i]) - { - t = origin.mV[i] - max[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -typedef enum -{ - b000 = 0x00, - b001 = 0x01, - b010 = 0x02, - b011 = 0x03, - b100 = 0x04, - b101 = 0x05, - b110 = 0x06, - b111 = 0x07, -} eLoveTheBits; - -//contact Runitai Linden for a copy of the SL object used to write this table -//basically, you give the table a bitmask of the look-at vector to a node and it -//gives you a triangle fan index array -static U16 sOcclusionIndices[] = -{ - //000 - b111, b110, b010, b011, b001, b101, b100, b110, - //001 - b011, b010, b000, b001, b101, b111, b110, b010, - //010 - b101, b100, b110, b111, b011, b001, b000, b100, - //011 - b001, b000, b100, b101, b111, b011, b010, b000, - //100 - b110, b000, b010, b011, b111, b101, b100, b000, - //101 - b010, b100, b000, b001, b011, b111, b110, b100, - //110 - b100, b010, b110, b111, b101, b001, b000, b010, - //111 - b000, b110, b100, b101, b001, b011, b010, b110, -}; - -U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return cypher*8; -} - -U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return (U8*) (sOcclusionIndices+cypher*8); -} - - -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); - -void LLSpatialGroup::buildOcclusion() -{ - //if (mOcclusionVerts.isNull()) - { - mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, - LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. - mOcclusionVerts->allocateBuffer(8, 64, true); - - LLStrider<U16> idx; - mOcclusionVerts->getIndexStrider(idx); - for (U32 i = 0; i < 64; i++) - { - *idx++ = sOcclusionIndices[i]; - } - } - - LLVector4a fudge; - fudge.splat(SG_OCCLUSION_FUDGE); - - LLVector4a r; - r.setAdd(mBounds[1], fudge); - - LLStrider<LLVector3> pos; - - { - LLFastTimer t(FTM_BUILD_OCCLUSION); - mOcclusionVerts->getVertexStrider(pos); - } - - { - LLVector4a* v = (LLVector4a*) pos.get(); - - const LLVector4a& c = mBounds[0]; - const LLVector4a& s = r; - - static const LLVector4a octant[] = - { - LLVector4a(-1.f, -1.f, -1.f), - LLVector4a(-1.f, -1.f, 1.f), - LLVector4a(-1.f, 1.f, -1.f), - LLVector4a(-1.f, 1.f, 1.f), - - LLVector4a(1.f, -1.f, -1.f), - LLVector4a(1.f, -1.f, 1.f), - LLVector4a(1.f, 1.f, -1.f), - LLVector4a(1.f, 1.f, 1.f), - }; - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - - for (S32 i = 0; i < 8; ++i) - { - LLVector4a p; - p.setMul(s, octant[i]); - p.add(c); - v[i] = p; - } - } - - { - mOcclusionVerts->flush(); - LLVertexBuffer::unbind(); - } - - clearState(LLSpatialGroup::OCCLUSION_DIRTY); -} - - -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); - -//returns: -// 0 if sphere and AABB are not intersecting -// 1 if they are -// 2 if AABB is entirely inside sphere - -S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad) -{ - S32 ret = 2; - - LLVector3 min = center - size; - LLVector3 max = center + size; - for (U32 i = 0; i < 3; i++) - { - if (min.mV[i] > pos.mV[i] + rad || - max.mV[i] < pos.mV[i] - rad) - { //totally outside - return 0; - } - - if (min.mV[i] < pos.mV[i] - rad || - max.mV[i] > pos.mV[i] + rad) - { //intersecting - ret = 1; - } - } - - return ret; -} - -LLSpatialGroup::~LLSpatialGroup() -{ - /*if (sNoDelete) - { - llerrs << "Illegal deletion of LLSpatialGroup!" << llendl; - }*/ - - if (gDebugGL) - { - gPipeline.checkReferences(this); - } - - if (isState(DEAD)) - { - sZombieGroups--; - } - - sNodeCount--; - - if (gGLManager.mHasOcclusionQuery) - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - } - } - } - - mOcclusionVerts = NULL; - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - clearDrawMap(); - clearAtlasList() ; -} - -BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp) -{ - S8 type = atlasp->getComponents() - 1 ; - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(atlasp == *iter) - { - return TRUE ; - } - } - return FALSE ; -} - -void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) -{ - if(!hasAtlas(atlasp)) - { - mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ; - atlasp->addSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->addAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) -{ - mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ; - if(remove_group) - { - atlasp->removeSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->removeAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::clearAtlasList() -{ - std::list<LLTextureAtlas*>::iterator iter ; - for(S8 i = 0 ; i < 4 ; i++) - { - if(mAtlasList[i].size() > 0) - { - for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter) - { - ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ; - } - mAtlasList[i].clear() ; - } - } -} - -LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level) -{ - S8 type = ncomponents - 1 ; - if(mAtlasList[type].size() > 0) - { - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved)) - { - return *iter ; - } - } - } - - --recursive_level; - if(recursive_level) - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ; - } - } - return NULL ; -} - -void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) -{ - mCurUpdatingSlotp = slotp; - - //if(!hasAtlas(mCurUpdatingSlotp->getAtlas())) - //{ - // addAtlas(mCurUpdatingSlotp->getAtlas()) ; - //} -} - -LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) -{ - if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep) - { - return mCurUpdatingSlotp ; - } - - //--recursive_level ; - //if(recursive_level) - //{ - // LLSpatialGroup* parent = getParent() ; - // if(parent) - // { - // return parent->getCurUpdatingSlot(imagep, recursive_level) ; - // } - //} - return NULL ; -} - -void LLSpatialGroup::clearDrawMap() -{ - mDrawMap.clear(); -} - -BOOL LLSpatialGroup::isHUDGroup() -{ - return mSpatialPartition && mSpatialPartition->isHUDPartition() ; -} - -BOOL LLSpatialGroup::isRecentlyVisible() const -{ - return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; -} - -BOOL LLSpatialGroup::isVisible() const -{ - return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; -} - -void LLSpatialGroup::setVisible() -{ - mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame(); -} - -void LLSpatialGroup::validate() -{ -#if LL_OCTREE_PARANOIA_CHECK - - sg_assert(!isState(DIRTY)); - sg_assert(!isDead()); - - LLVector4a myMin; - myMin.setSub(mBounds[0], mBounds[1]); - LLVector4a myMax; - myMax.setAdd(mBounds[0], mBounds[1]); - - validateDrawMap(); - - for (element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - sg_assert(drawable->getSpatialGroup() == this); - if (drawable->getSpatialBridge()) - { - sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge()); - } - - /*if (drawable->isSpatialBridge()) - { - LLSpatialPartition* part = drawable->asPartition(); - if (!part) - { - llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl; - } - LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - group->validate(); - }*/ - } - - for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i) - { - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); - - group->validate(); - - //ensure all children are enclosed in this node - LLVector4a center = group->mBounds[0]; - LLVector4a size = group->mBounds[1]; - - LLVector4a min; - min.setSub(center, size); - LLVector4a max; - max.setAdd(center, size); - - for (U32 j = 0; j < 3; j++) - { - sg_assert(min[j] >= myMin[j]-0.02f); - sg_assert(max[j] <= myMax[j]+0.02f); - } - } - -#endif -} - -void LLSpatialGroup::checkStates() -{ -#if LL_OCTREE_PARANOIA_CHECK - //LLOctreeStateCheck checker; - //checker.traverse(mOctreeNode); -#endif -} - -void LLSpatialGroup::validateDrawMap() -{ -#if LL_OCTREE_PARANOIA_CHECK - for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo& params = **j; - - params.validate(); - } - } -#endif -} - -BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->updateSpatialExtents(); - - OctreeNode* parent = mOctreeNode->getOctParent(); - - if (mOctreeNode->isInside(drawablep->getPositionGroup()) && - (mOctreeNode->contains(drawablep) || - (drawablep->getBinRadius() > mOctreeNode->getSize()[0] && - parent && parent->getElementCount() >= gOctreeMaxCapacity))) - { - unbound(); - setState(OBJECT_DIRTY); - //setState(GEOM_DIRTY); - return TRUE; - } - - return FALSE; -} - - -BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (!from_octree) - { - mOctreeNode->insert(drawablep); - } - else - { - drawablep->setSpatialGroup(this); - setState(OBJECT_DIRTY | GEOM_DIRTY); - setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); - gPipeline.markRebuild(this, TRUE); - if (drawablep->isSpatialBridge()) - { - mBridgeList.push_back((LLSpatialBridge*) drawablep); - } - if (drawablep->getRadius() > 1.f) - { - setState(IMAGE_DIRTY); - } - } - - return TRUE; -} - -void LLSpatialGroup::rebuildGeom() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (!isDead()) - { - mSpatialPartition->rebuildGeom(this); - } -} - -void LLSpatialGroup::rebuildMesh() -{ - if (!isDead()) - { - mSpatialPartition->rebuildMesh(this); - } -} - -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); - -void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) -{ - if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) - { - return; - } - - if (group->changeLOD()) - { - group->mLastUpdateDistance = group->mDistance; - group->mLastUpdateViewAngle = group->mViewAngle; - } - - LLFastTimer ftm(FTM_REBUILD_VBO); - - group->clearDrawMap(); - - //get geometry count - U32 index_count = 0; - U32 vertex_count = 0; - - addGeometryCount(group, vertex_count, index_count); - - if (vertex_count > 0 && index_count > 0) - { //create vertex buffer containing volume geometry for this node - group->mBuilt = 1.f; - if (group->mVertexBuffer.isNull() || - !group->mVertexBuffer->isWriteable() || - (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) - { - group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); - group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); - stop_glerror(); - } - else - { - group->mVertexBuffer->resizeBuffer(vertex_count, index_count); - stop_glerror(); - } - - getGeometry(group); - } - else - { - group->mVertexBuffer = NULL; - group->mBufferMap.clear(); - } - - group->mLastUpdateTime = gFrameTimeSeconds; - group->clearState(LLSpatialGroup::GEOM_DIRTY); -} - - -void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) -{ - -} - -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) -{ - const OctreeNode* node = mOctreeNode; - - if (node->getData().empty()) - { //don't do anything if there are no objects - if (empty && mOctreeNode->getParent()) - { //only root is allowed to be empty - OCT_ERRS << "Empty leaf found in octree." << llendl; - } - return FALSE; - } - - LLVector4a& newMin = mObjectExtents[0]; - LLVector4a& newMax = mObjectExtents[1]; - - if (isState(OBJECT_DIRTY)) - { //calculate new bounding box - clearState(OBJECT_DIRTY); - - //initialize bounding box to first element - OctreeNode::const_element_iter i = node->getData().begin(); - LLDrawable* drawablep = *i; - const LLVector4a* minMax = drawablep->getSpatialExtents(); - - newMin = minMax[0]; - newMax = minMax[1]; - - for (++i; i != node->getData().end(); ++i) - { - drawablep = *i; - minMax = drawablep->getSpatialExtents(); - - update_min_max(newMin, newMax, minMax[0]); - update_min_max(newMin, newMax, minMax[1]); - - //bin up the object - /*for (U32 i = 0; i < 3; i++) - { - if (minMax[0].mV[i] < newMin.mV[i]) - { - newMin.mV[i] = minMax[0].mV[i]; - } - if (minMax[1].mV[i] > newMax.mV[i]) - { - newMax.mV[i] = minMax[1].mV[i]; - } - }*/ - } - - mObjectBounds[0].setAdd(newMin, newMax); - mObjectBounds[0].mul(0.5f); - mObjectBounds[1].setSub(newMax, newMin); - mObjectBounds[1].mul(0.5f); - } - - if (empty) - { - minOut = newMin; - maxOut = newMax; - } - else - { - minOut.setMin(minOut, newMin); - maxOut.setMax(maxOut, newMax); - } - - return TRUE; -} - -void LLSpatialGroup::unbound() -{ - if (isState(DIRTY)) - { - return; - } - - setState(DIRTY); - - //all the parent nodes need to rebound this child - if (mOctreeNode) - { - OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); - while (parent != NULL) - { - LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0); - if (group->isState(DIRTY)) - { - return; - } - - group->setState(DIRTY); - parent = (OctreeNode*) parent->getParent(); - } - } -} - -LLSpatialGroup* LLSpatialGroup::getParent() -{ - if (isDead()) - { - return NULL; - } - - if(!mOctreeNode) - { - return NULL; - } - OctreeNode* parent = mOctreeNode->getOctParent(); - - if (parent) - { - return (LLSpatialGroup*) parent->getListener(0); - } - - return NULL; -} - -BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - unbound(); - if (mOctreeNode && !from_octree) - { - if (!mOctreeNode->remove(drawablep)) - { - OCT_ERRS << "Could not remove drawable from spatial group" << llendl; - } - } - else - { - drawablep->setSpatialGroup(NULL); - setState(GEOM_DIRTY); - gPipeline.markRebuild(this, TRUE); - - if (drawablep->isSpatialBridge()) - { - for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i) - { - if (*i == drawablep) - { - mBridgeList.erase(i); - break; - } - } - } - - if (getElementCount() == 0) - { //delete draw map on last element removal since a rebuild might never happen - clearDrawMap(); - } - } - return TRUE; -} - -void LLSpatialGroup::shift(const LLVector4a &offset) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLVector4a t = mOctreeNode->getCenter(); - t.add(offset); - mOctreeNode->setCenter(t); - mOctreeNode->updateMinMax(); - mBounds[0].add(offset); - mExtents[0].add(offset); - mExtents[1].add(offset); - mObjectBounds[0].add(offset); - mObjectExtents[0].add(offset); - mObjectExtents[1].add(offset); - - //if (!mSpatialPartition->mRenderByGroup) - { - setState(GEOM_DIRTY); - gPipeline.markRebuild(this, TRUE); - } - - if (mOcclusionVerts.notNull()) - { - setState(OCCLUSION_DIRTY); - } -} - -class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialSetState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); } -}; - -class LLSpatialSetStateDiff : public LLSpatialSetState -{ -public: - LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (!group->isState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::setState(U32 state) -{ - mState |= state; - - llassert(state <= LLSpatialGroup::STATE_MASK); -} - -void LLSpatialGroup::setState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - llassert(state <= LLSpatialGroup::STATE_MASK); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else - { - LLSpatialSetState setter(state); - setter.traverse(mOctreeNode); - } - } - else - { - mState |= state; - } -} - -class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialClearState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } -}; - -class LLSpatialClearStateDiff : public LLSpatialClearState -{ -public: - LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (group->isState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::clearState(U32 state) -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - mState &= ~state; -} - -void LLSpatialGroup::clearState(U32 state, S32 mode) -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - LLSpatialClearState clearer(state); - clearer.traverse(mOctreeNode); - } - } - else - { - mState &= ~state; - } -} - -BOOL LLSpatialGroup::isState(U32 state) const -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - return mState & state ? TRUE : FALSE; -} - -//===================================== -// Occlusion State Set/Clear -//===================================== -class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialSetOcclusionState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); } -}; - -class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState -{ -public: - LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (!group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - - -void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetOcclusionStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialSetOcclusionState setter(state); - setter.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] |= state; - - if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] |= state; - if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - } -} - -class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - - LLSpatialClearOcclusionState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); } -}; - -class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState -{ -public: - LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearOcclusionStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialClearOcclusionState clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] &= ~state; - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; - } -} -//====================================== -// Octree Listener Implementation -//====================================== - -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : - mState(0), - mGeometryBytes(0), - mSurfaceArea(0.f), - mBuilt(0.f), - mOctreeNode(node), - mSpatialPartition(part), - mVertexBuffer(NULL), - mBufferUsage(part->mBufferUsage), - mDistance(0.f), - mDepth(0.f), - mLastUpdateDistance(-1.f), - mLastUpdateTime(gFrameTimeSeconds), - mAtlasList(4), - mCurUpdatingTime(0), - mCurUpdatingSlotp(NULL), - mCurUpdatingTexture (NULL) -{ - sNodeCount++; - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - mViewAngle.splat(0.f); - mLastUpdateViewAngle.splat(-1.f); - mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = - mObjectExtents[0] = mObjectExtents[1] = mViewAngle; - - sg_assert(mOctreeNode->getListenerCount() == 0); - mOctreeNode->addListener(this); - setState(SG_INITIAL_STATE_MASK); - gPipeline.markRebuild(this, TRUE); - - mBounds[0] = node->getCenter(); - mBounds[1] = node->getSize(); - - part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; - mLODHash = part->mLODSeed; - - OctreeNode* oct_parent = node->getOctParent(); - - LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL; - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionQuery[i] = 0; - mOcclusionIssued[i] = 0; - mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; - mVisible[i] = 0; - } - - mOcclusionVerts = NULL; - - mRadius = 1; - mPixelArea = 1024.f; -} - -void LLSpatialGroup::updateDistance(LLCamera &camera) -{ - if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) - { - llwarns << "Attempted to update distance for camera other than world camera!" << llendl; - return; - } - -#if !LL_RELEASE_FOR_DOWNLOAD - if (isState(LLSpatialGroup::OBJECT_DIRTY)) - { - llerrs << "Spatial group dirty on distance update." << llendl; - } -#endif - if (!getData().empty()) - { - mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : - (F32) mOctreeNode->getSize().getLength3().getF32(); - mDistance = mSpatialPartition->calcDistance(this, camera); - mPixelArea = mSpatialPartition->calcPixelArea(this, camera); - } -} - -F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) -{ - LLVector4a eye; - LLVector4a origin; - origin.load3(camera.getOrigin().mV); - - eye.setSub(group->mObjectBounds[0], origin); - - F32 dist = 0.f; - - if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end()) - { - LLVector4a v = eye; - - dist = eye.getLength3().getF32(); - eye.normalize3fast(); - - if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) - { - if (!group->mSpatialPartition->isBridge()) - { - LLVector4a view_angle = eye; - - LLVector4a diff; - diff.setSub(view_angle, group->mLastUpdateViewAngle); - - if (diff.getLength3().getF32() > 0.64f) - { - group->mViewAngle = view_angle; - group->mLastUpdateViewAngle = view_angle; - //for occasional alpha sorting within the group - //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order, - //not setting this node to dirty would be a very good thing - group->setState(LLSpatialGroup::ALPHA_DIRTY); - gPipeline.markRebuild(group, FALSE); - } - } - } - - //calculate depth of node for alpha sorting - - LLVector3 at = camera.getAtAxis(); - - LLVector4a ata; - ata.load3(at.mV); - - LLVector4a t = ata; - //front of bounding box - t.mul(0.25f); - t.mul(group->mObjectBounds[1]); - v.sub(t); - - group->mDepth = v.dot3(ata).getF32(); - } - else - { - dist = eye.getLength3().getF32(); - } - - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - return dist; -} - -F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) -{ - return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera); -} - -F32 LLSpatialGroup::getUpdateUrgency() const -{ - if (!isVisible()) - { - return 0.f; - } - else - { - F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f; - return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance; - } -} - -BOOL LLSpatialGroup::needsUpdate() -{ - return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE; -} - -BOOL LLSpatialGroup::changeLOD() -{ - if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) - { ///a rebuild is going to happen, update distance and LoD - return TRUE; - } - - if (mSpatialPartition->mSlopRatio > 0.f) - { - F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); - - if (fabsf(ratio) >= mSpatialPartition->mSlopRatio) - { - return TRUE; - } - - if (mDistance > mRadius*2.f) - { - return FALSE; - } - } - - if (needsUpdate()) - { - return TRUE; - } - - return FALSE; -} - -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - addObject(drawablep, FALSE, TRUE); - unbound(); - setState(OBJECT_DIRTY); -} - -void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - removeObject(drawable, TRUE); - setState(OBJECT_DIRTY); -} - -void LLSpatialGroup::handleDestruction(const TreeNode* node) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - setState(DEAD); - - for (element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (drawable->getSpatialGroup() == this) - { - drawable->setSpatialGroup(NULL); - } - } - - //clean up avatar attachment stats - LLSpatialBridge* bridge = mSpatialPartition->asBridge(); - if (bridge) - { - if (bridge->mAvatar.notNull()) - { - bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; - bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; - } - } - - clearDrawMap(); - mVertexBuffer = NULL; - mBufferMap.clear(); - sZombieGroups++; - mOctreeNode = NULL; -} - -void LLSpatialGroup::handleStateChange(const TreeNode* node) -{ - //drop bounding box upon state change - if (mOctreeNode != node) - { - mOctreeNode = (OctreeNode*) node; - } - unbound(); -} - -void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (child->getListenerCount() == 0) - { - new LLSpatialGroup(child, mSpatialPartition); - } - else - { - OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl; - } - - unbound(); - - assert_states_valid(this); -} - -void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) -{ - unbound(); -} - -void LLSpatialGroup::destroyGL() -{ - setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); - gPipeline.markRebuild(this, TRUE); - - mLastUpdateTime = gFrameTimeSeconds; - mVertexBuffer = NULL; - mBufferMap.clear(); - - clearDrawMap(); - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - - mOcclusionVerts = NULL; - - for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* facep = drawable->getFace(j); - facep->clearVertexBuffer(); - } - } -} - -BOOL LLSpatialGroup::rebound() -{ - if (!isState(DIRTY)) - { //return TRUE if we're not empty - return TRUE; - } - - if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) - { - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->rebound(); - - //copy single child's bounding box - mBounds[0] = group->mBounds[0]; - mBounds[1] = group->mBounds[1]; - mExtents[0] = group->mExtents[0]; - mExtents[1] = group->mExtents[1]; - - group->setState(SKIP_FRUSTUM_CHECK); - } - else if (mOctreeNode->isLeaf()) - { //copy object bounding box if this is a leaf - boundObjects(TRUE, mExtents[0], mExtents[1]); - mBounds[0] = mObjectBounds[0]; - mBounds[1] = mObjectBounds[1]; - } - else - { - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - //initialize to first child - newMin = group->mExtents[0]; - newMax = group->mExtents[1]; - - //first, rebound children - for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) - { - group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - const LLVector4a& max = group->mExtents[1]; - const LLVector4a& min = group->mExtents[0]; - - newMax.setMax(newMax, max); - newMin.setMin(newMin, min); - } - - boundObjects(FALSE, newMin, newMax); - - mBounds[0].setAdd(newMin, newMax); - mBounds[0].mul(0.5f); - mBounds[1].setSub(newMax, newMin); - mBounds[1].mul(0.5f); - } - - setState(OCCLUSION_DIRTY); - - clearState(DIRTY); - - return TRUE; -} - -static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); - -void LLSpatialGroup::checkOcclusion() -{ - if (LLPipeline::sUseOcclusion > 1) - { - LLFastTimer t(FTM_OCCLUSION_READBACK); - LLSpatialGroup* parent = getParent(); - if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //if the parent has been marked as occluded, the child is implicitly occluded - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - else if (isOcclusionState(QUERY_PENDING)) - { //otherwise, if a query is pending, read it back - - GLuint available = 0; - if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - - if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) - { //query was issued last frame, wait until it's available - S32 max_loop = 1024; - LLFastTimer t(FTM_OCCLUSION_WAIT); - while (!available && max_loop-- > 0) - { - F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); - //do some usefu work while we wait - LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread - LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread - LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread - - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - } - } - } - else - { - available = 1; - } - - if (available) - { //result is available, read it back, otherwise wait until next frame - GLuint res = 1; - if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - } - else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { //delete the query to avoid holding onto hundreds of pending queries - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - - if (isOcclusionState(DISCARD_QUERY)) - { - res = 2; - } - - if (res > 0) - { - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - assert_states_valid(this); - setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - } - else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //check occlusion has been issued for occluded node that has not had a query issued - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - } -} - -static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); -static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); - - - -void LLSpatialGroup::doOcclusion(LLCamera* camera) -{ - if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) - { - // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension - if (earlyFail(camera, this)) - { - LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); - setOcclusionState(LLSpatialGroup::DISCARD_QUERY); - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) - { - { //no query pending, or previous query to be discarded - LLFastTimer t(FTM_RENDER_OCCLUSION); - - if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - LLFastTimer t(FTM_OCCLUSION_ALLOCATE); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); - } - - if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) - { - LLFastTimer t(FTM_OCCLUSION_BUILD); - buildOcclusion(); - } - - // Depth clamp all water to avoid it being culled as a result of being - // behind the far clip plane, and in the case of edge water to avoid - // it being culled while still visible. - bool const use_depth_clamp = gGLManager.mHasDepthClamp && - (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || - mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); - - LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0); - -#if !LL_DARWIN - U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; -#else - U32 mode = GL_SAMPLES_PASSED_ARB; -#endif - -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - - { - LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); - - //store which frame this query was issued on - mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; - - { - LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY); - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - } - - { - LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - } - - if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) - { - LLFastTimer t(FTM_OCCLUSION_DRAW_WATER); - - LLGLSquashToFarClip squash(glh_get_current_projection(), 1); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); - } - else - { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - else - { - LLFastTimer t(FTM_OCCLUSION_DRAW); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); - } - else - { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - - - { - LLFastTimer t(FTM_OCCLUSION_END_QUERY); - glEndQueryARB(mode); - } - } - } - - { - LLFastTimer t(FTM_SET_OCCLUSION_STATE); - setOcclusionState(LLSpatialGroup::QUERY_PENDING); - clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); - } - } - } - } -} - -//============================================== - -LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage) -: mRenderByGroup(render_by_group), mBridge(NULL) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - mOcclusionEnabled = TRUE; - mDrawableType = 0; - mPartitionType = LLViewerRegion::PARTITION_NONE; - mLODSeed = 0; - mLODPeriod = 1; - mVertexDataMask = data_mask; - mBufferUsage = buffer_usage; - mDepthMask = FALSE; - mSlopRatio = 0.25f; - mInfiniteFarClip = FALSE; - - LLVector4a center, size; - center.splat(0.f); - size.splat(1.f); - - mOctree = new LLSpatialGroup::OctreeRoot(center,size, - NULL); - new LLSpatialGroup(mOctree, this); -} - - -LLSpatialPartition::~LLSpatialPartition() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - delete mOctree; - mOctree = NULL; -} - - -LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->updateSpatialExtents(); - - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - - assert_octree_valid(mOctree); - mOctree->insert(drawablep); - assert_octree_valid(mOctree); - - LLSpatialGroup* group = drawablep->getSpatialGroup(); - - if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) - { - group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); - } - - return group; -} - -BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->setSpatialGroup(NULL); - - if (!curp->removeObject(drawablep)) - { - OCT_ERRS << "Failed to remove drawable from octree!" << llendl; - } - - assert_octree_valid(mOctree); - - return TRUE; -} - -void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - // sanity check submitted by open source user bushing Spatula - // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne) - if (!drawablep) - { - OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl; - return; - } - - BOOL was_visible = curp ? curp->isVisible() : FALSE; - - if (curp && curp->mSpatialPartition != this) - { - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - if (curp->mSpatialPartition->remove(drawablep, curp)) - { - put(drawablep, was_visible); - return; - } - else - { - OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl; - } - } - - if (curp && curp->updateInGroup(drawablep, immediate)) - { - // Already updated, don't need to do anything - assert_octree_valid(mOctree); - return; - } - - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - if (curp && !remove(drawablep, curp)) - { - OCT_ERRS << "Move couldn't find existing spatial group!" << llendl; - } - - put(drawablep, was_visible); -} - -class LLSpatialShift : public LLSpatialGroup::OctreeTraveler -{ -public: - const LLVector4a& mOffset; - - LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); - } -}; - -void LLSpatialPartition::shift(const LLVector4a &offset) -{ //shift octree node bounding boxes by offset - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLSpatialShift shifter(offset); - shifter.traverse(mOctree); -} - -class LLOctreeCull : public LLSpatialGroup::OctreeTraveler -{ -public: - LLOctreeCull(LLCamera* camera) - : mCamera(camera), mRes(0) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - group->checkOcclusion(); - - if (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - gPipeline.markOccluder(group); - return true; - } - - return false; - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (earlyFail(group)) - { - return; - } - - if (mRes == 2 || - (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) - { //fully in, just add everything - LLSpatialGroup::OctreeTraveler::traverse(n); - } - else - { - mRes = frustumCheck(group); - - if (mRes) - { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); - } - - mRes = 0; - } - } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); - if (res != 0) - { - res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); - } - return res; - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); - if (res != 0) - { - res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); - } - return res; - } - - virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group) - { - if (branch->getElementCount() == 0) //no elements - { - return false; - } - else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box - { - return true; - } - else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum - { - return false; - } - - return true; - } - - virtual void preprocess(LLSpatialGroup* group) - { - - } - - virtual void processGroup(LLSpatialGroup* group) - { - if (group->needsUpdate() || - group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1) - { - group->doOcclusion(mCamera); - } - gPipeline.markNotCulled(group, *mCamera); - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - preprocess(group); - - if (checkObjects(branch, group)) - { - processGroup(group); - } - } - - LLCamera *mCamera; - S32 mRes; -}; - -class LLOctreeCullNoFarClip : public LLOctreeCull -{ -public: - LLOctreeCullNoFarClip(LLCamera* camera) - : LLOctreeCull(camera) { } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); - return res; - } -}; - -class LLOctreeCullShadow : public LLOctreeCull -{ -public: - LLOctreeCullShadow(LLCamera* camera) - : LLOctreeCull(camera) { } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); - } -}; - -class LLOctreeCullVisExtents: public LLOctreeCullShadow -{ -public: - LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max) - : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - if (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - return true; - } - - return false; - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (earlyFail(group)) - { - return; - } - - if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) || - mRes == 2) - { //don't need to do frustum check - LLSpatialGroup::OctreeTraveler::traverse(n); - } - else - { - mRes = frustumCheck(group); - - if (mRes) - { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); - } - - mRes = 0; - } - } - - virtual void processGroup(LLSpatialGroup* group) - { - llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty()) - - if (mRes < 2) - { - if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0) - { - mEmpty = FALSE; - update_min_max(mMin, mMax, group->mObjectExtents[0]); - update_min_max(mMin, mMax, group->mObjectExtents[1]); - } - } - else - { - mEmpty = FALSE; - update_min_max(mMin, mMax, group->mExtents[0]); - update_min_max(mMin, mMax, group->mExtents[1]); - } - } - - BOOL mEmpty; - LLVector4a& mMin; - LLVector4a& mMax; -}; - -class LLOctreeCullDetectVisible: public LLOctreeCullShadow -{ -public: - LLOctreeCullDetectVisible(LLCamera* camera) - : LLOctreeCullShadow(camera), mResult(FALSE) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - if (mResult || //already found a node, don't check any more - (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED))) - { - return true; - } - - return false; - } - - virtual void processGroup(LLSpatialGroup* group) - { - if (group->isVisible()) - { - mResult = TRUE; - } - } - - BOOL mResult; -}; - -class LLOctreeSelect : public LLOctreeCull -{ -public: - LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results) - : LLOctreeCull(camera), mResults(results) { } - - virtual bool earlyFail(LLSpatialGroup* group) { return false; } - virtual void preprocess(LLSpatialGroup* group) { } - - virtual void processGroup(LLSpatialGroup* group) - { - LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - if (!drawable->isDead()) - { - if (drawable->isSpatialBridge()) - { - drawable->setVisible(*mCamera, mResults, TRUE); - } - else - { - mResults->push_back(drawable); - } - } - } - } - - std::vector<LLDrawable*>* mResults; -}; - -void drawBox(const LLVector3& c, const LLVector3& r) -{ - LLVertexBuffer::unbind(); - - gGL.begin(LLRender::TRIANGLE_STRIP); - //left front - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - //right front - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); - //right back - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); - //left back - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); - //left front - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - gGL.end(); - - //bottom - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); - gGL.end(); - - //top - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); - gGL.end(); -} - -void drawBox(const LLVector4a& c, const LLVector4a& r) -{ - drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r)); -} - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size) -{ - LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); - LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); - LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); - LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); - - gGL.begin(LLRender::LINES); - - //top - gGL.vertex3fv((pos+v1).mV); - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos+v1).mV); - - //bottom - gGL.vertex3fv((pos-v1).mV); - gGL.vertex3fv((pos-v2).mV); - gGL.vertex3fv((pos-v2).mV); - gGL.vertex3fv((pos-v3).mV); - gGL.vertex3fv((pos-v3).mV); - gGL.vertex3fv((pos-v4).mV); - gGL.vertex3fv((pos-v4).mV); - gGL.vertex3fv((pos-v1).mV); - - //right - gGL.vertex3fv((pos+v1).mV); - gGL.vertex3fv((pos-v3).mV); - - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos-v2).mV); - - //left - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos-v4).mV); - - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos-v1).mV); - - gGL.end(); -} - -void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size) -{ - drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size)); -} - -class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> -{ -public: - virtual void visit(const LLOctreeNode<LLDrawable>* state) - { - LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); - group->destroyGL(); - - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup) - { - gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); - } - } - - for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) - { - LLSpatialBridge* bridge = *i; - traverse(bridge->mOctree); - } - } -}; - -void LLSpatialPartition::restoreGL() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); -} - -void LLSpatialPartition::resetVertexBuffers() -{ - LLOctreeDirty dirty; - dirty.traverse(mOctree); -} - -BOOL LLSpatialPartition::isOcclusionEnabled() -{ - return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2; -} - -BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) -{ - LLVector4a visMina, visMaxa; - visMina.load3(visMin.mV); - visMaxa.load3(visMax.mV); - - { - LLFastTimer ftm(FTM_CULL_REBOUND); - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - } - - LLOctreeCullVisExtents vis(&camera, visMina, visMaxa); - vis.traverse(mOctree); - - visMin.set(visMina.getF32ptr()); - visMax.set(visMaxa.getF32ptr()); - return vis.mEmpty; -} - -BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera) -{ - LLOctreeCullDetectVisible vis(&camera); - vis.traverse(mOctree); - return vis.mResult; -} - -S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); -#if LL_OCTREE_PARANOIA_CHECK - ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); -#endif - { - LLFastTimer ftm(FTM_CULL_REBOUND); - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - } - -#if LL_OCTREE_PARANOIA_CHECK - ((LLSpatialGroup*)mOctree->getListener(0))->validate(); -#endif - - - if (for_select) - { - LLOctreeSelect selecter(&camera, results); - selecter.traverse(mOctree); - } - else if (LLPipeline::sShadowRender) - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCullShadow culler(&camera); - culler.traverse(mOctree); - } - else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCullNoFarClip culler(&camera); - culler.traverse(mOctree); - } - else - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCull culler(&camera); - culler.traverse(mOctree); - } - - return 0; -} - -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) -{ - if (camera->getOrigin().isExactlyZero()) - { - return FALSE; - } - - const F32 vel = SG_OCCLUSION_FUDGE*2.f; - LLVector4a fudge; - fudge.splat(vel); - - const LLVector4a& c = group->mBounds[0]; - LLVector4a r; - r.setAdd(group->mBounds[1], fudge); - - /*if (r.magVecSquared() > 1024.0*1024.0) - { - return TRUE; - }*/ - - LLVector4a e; - e.load3(camera->getOrigin().mV); - - LLVector4a min; - min.setSub(c,r); - LLVector4a max; - max.setAdd(c,r); - - S32 lt = e.lessThan(min).getGatheredBits() & 0x7; - if (lt) - { - return FALSE; - } - - S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; - if (gt) - { - return FALSE; - } - - return TRUE; -} - - -void pushVerts(LLDrawInfo* params, U32 mask) -{ - LLRenderPass::applyModelMatrix(*params); - params->mVertexBuffer->setBuffer(mask); - params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, - params->mStart, params->mEnd, params->mCount, params->mOffset); -} - -void pushVerts(LLSpatialGroup* group, U32 mask) -{ - LLDrawInfo* params = NULL; - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - params = *j; - pushVerts(params, mask); - } - } -} - -void pushVerts(LLFace* face, U32 mask) -{ - llassert(face->verify()); - - LLVertexBuffer* buffer = face->getVertexBuffer(); - - if (buffer && (face->getGeomCount() >= 3)) - { - buffer->setBuffer(mask); - U16 start = face->getGeomStart(); - U16 end = start + face->getGeomCount()-1; - U32 count = face->getIndicesCount(); - U16 offset = face->getIndicesStart(); - buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); - } -} - -void pushVerts(LLDrawable* drawable, U32 mask) -{ - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - pushVerts(drawable->getFace(i), mask); - } -} - -void pushVerts(LLVolume* volume) -{ - LLVertexBuffer::unbind(); - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); - } -} - -void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) -{ - if (buffer) - { - buffer->setBuffer(mask); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - } -} - -void pushBufferVerts(LLSpatialGroup* group, U32 mask) -{ - if (group->mSpatialPartition->mRenderByGroup) - { - if (!group->mDrawMap.empty()) - { - LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin()); - LLRenderPass::applyModelMatrix(*params); - - pushBufferVerts(group->mVertexBuffer, mask); - - for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i) - { - for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k) - { - pushBufferVerts(*k, mask); - } - } - } - } - } - else - { - drawBox(group->mBounds[0], group->mBounds[1]); - } -} - -void pushVertsColorCoded(LLSpatialGroup* group, U32 mask) -{ - LLDrawInfo* params = NULL; - - LLColor4 colors[] = { - LLColor4::green, - LLColor4::green1, - LLColor4::green2, - LLColor4::green3, - LLColor4::green4, - LLColor4::green5, - LLColor4::green6 - }; - - static const U32 col_count = LL_ARRAY_SIZE(colors); - - U32 col = 0; - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - params = *j; - LLRenderPass::applyModelMatrix(*params); - gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f); - params->mVertexBuffer->setBuffer(mask); - params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, - params->mStart, params->mEnd, params->mCount, params->mOffset); - col = (col+1)%col_count; - } - } -} - -void renderOctree(LLSpatialGroup* group) -{ - //render solid object bounding box, color - //coded by buffer usage and activity - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - LLVector4 col; - if (group->mBuilt > 0.f) - { - group->mBuilt -= 2.f * gFrameIntervalSeconds; - if (group->mBufferUsage == GL_STATIC_DRAW_ARB) - { - col.setVec(1.0f, 0, 0, group->mBuilt*0.5f); - } - else - { - col.setVec(0.1f,0.1f,1,0.1f); - //col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f); - } - - if (group->mBufferUsage != GL_STATIC_DRAW_ARB) - { - LLGLDepthTest gl_depth(FALSE, FALSE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4f(1,0,0,group->mBuilt); - gGL.flush(); - glLineWidth(5.f); - drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - gGL.flush(); - glLineWidth(1.f); - gGL.flush(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (!group->mSpatialPartition->isBridge()) - { - gGL.pushMatrix(); - LLVector3 trans = drawable->getRegion()->getOriginAgent(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - } - - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* face = drawable->getFace(j); - if (face->getVertexBuffer()) - { - if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) - { - gGL.diffuseColor4f(0, 1, 0, group->mBuilt); - } - else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f) - { - gGL.diffuseColor4f(1, 0, 0, group->mBuilt); - } - else - { - continue; - } - - face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX); - //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, - // (face->mExtents[1]-face->mExtents[0])*0.5f); - face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); - } - } - - if (!group->mSpatialPartition->isBridge()) - { - gGL.popMatrix(); - } - } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - gGL.diffuseColor4f(1,1,1,1); - } - } - else - { - if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() - && group->mSpatialPartition->mRenderByGroup) - { - col.setVec(0.8f, 0.4f, 0.1f, 0.1f); - } - else - { - col.setVec(0.1f, 0.1f, 1.f, 0.1f); - } - } - - gGL.diffuseColor4fv(col.mV); - LLVector4a fudge; - fudge.splat(0.001f); - LLVector4a size = group->mObjectBounds[1]; - size.mul(1.01f); - size.add(fudge); - - //{ - // LLGLDepthTest depth(GL_TRUE, GL_FALSE); - // drawBox(group->mObjectBounds[0], fudge); - //} - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - //if (group->mBuilt <= 0.f) - { - //draw opaque outline - //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f); - //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - - gGL.diffuseColor4f(0,1,1,1); - drawBoxOutline(group->mBounds[0],group->mBounds[1]); - - //draw bounding box for draw info - /*if (group->mSpatialPartition->mRenderByGroup) - { - gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f); - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - LLDrawInfo* draw_info = *j; - LLVector4a center; - center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]); - size.mul(0.5f); - drawBoxOutline(center, size); - } - } - }*/ - } - -// LLSpatialGroup::OctreeNode* node = group->mOctreeNode; -// gGL.diffuseColor4f(0,1,0,1); -// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); -} - -void renderVisibility(LLSpatialGroup* group, LLCamera* camera) -{ - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLGLEnable cull(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() && - !group->getData().empty(); - - if (render_objects) - { - LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); - gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); - gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); - pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); - } - - { - LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL); - - if (render_objects) - { - gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f); - gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f); - pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); - } - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - if (render_objects) - { - gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f); - gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f); - pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); - } - /*else if (camera && group->mOcclusionVerts.notNull()) - { - LLVertexBuffer::unbind(); - group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - - gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f); - group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f); - group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - }*/ - } -} - -void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color) -{ - gGL.diffuseColor4fv(color.mV); - gGL.begin(LLRender::LINES); - { - gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV); - gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV); - gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV); - gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV); - gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV); - gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV); - } - gGL.end(); -} - -void renderUpdateType(LLDrawable* drawablep) -{ - LLViewerObject* vobj = drawablep->getVObj(); - if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType()) - { - return; - } - LLGLEnable blend(GL_BLEND); - switch (vobj->getLastUpdateType()) - { - case OUT_FULL: - gGL.diffuseColor4f(0,1,0,0.5f); - break; - case OUT_TERSE_IMPROVED: - gGL.diffuseColor4f(0,1,1,0.5f); - break; - case OUT_FULL_COMPRESSED: - if (vobj->getLastUpdateCached()) - { - gGL.diffuseColor4f(1,0,0,0.5f); - } - else - { - gGL.diffuseColor4f(1,1,0,0.5f); - } - break; - case OUT_FULL_CACHED: - gGL.diffuseColor4f(0,0,1,0.5f); - break; - default: - llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; - break; - }; - S32 num_faces = drawablep->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } -} - -void renderComplexityDisplay(LLDrawable* drawablep) -{ - LLViewerObject* vobj = drawablep->getVObj(); - if (!vobj) - { - return; - } - - LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj); - - if (!voVol) - { - return; - } - - if (!voVol->isRoot()) - { - return; - } - - LLVOVolume::texture_cost_t textures; - F32 cost = (F32) voVol->getRenderCost(textures); - - // add any child volumes - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child); - if (child_volume) - { - cost += child_volume->getRenderCost(textures); - } - } - - // add texture cost - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - - F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax(); - - - - // allow user to set a static color scale - if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0) - { - cost_max = gSavedSettings.getS32("RenderComplexityStaticMax"); - } - - F32 cost_ratio = cost / cost_max; - - // cap cost ratio at 1.0f in case cost_max is at a low threshold - cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; - - LLGLEnable blend(GL_BLEND); - - LLColor4 color; - const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); - const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid"); - const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax"); - - if (cost_ratio < 0.5f) - { - color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2); - } - else - { - color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2); - } - - LLSD color_val = color.getValue(); - - // don't highlight objects below the threshold - if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) - { - glColor4f(color[0],color[1],color[2],0.5f); - - - S32 num_faces = drawablep->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - if (child) - { - num_faces = child->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } - } - } - } - - voVol->setDebugText(llformat("%4.0f", cost)); -} - -void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) -{ - if (set_color) - { - if (drawable->isSpatialBridge()) - { - gGL.diffuseColor4f(1,0.5f,0,1); - } - else if (drawable->getVOVolume()) - { - if (drawable->isRoot()) - { - gGL.diffuseColor4f(1,1,0,1); - } - else - { - gGL.diffuseColor4f(0,1,0,1); - } - } - else if (drawable->getVObj()) - { - switch (drawable->getVObj()->getPCode()) - { - case LLViewerObject::LL_VO_SURFACE_PATCH: - gGL.diffuseColor4f(0,1,1,1); - break; - case LLViewerObject::LL_VO_CLOUDS: - // no longer used - break; - case LLViewerObject::LL_VO_PART_GROUP: - case LLViewerObject::LL_VO_HUD_PART_GROUP: - gGL.diffuseColor4f(0,0,1,1); - break; - case LLViewerObject::LL_VO_VOID_WATER: - case LLViewerObject::LL_VO_WATER: - gGL.diffuseColor4f(0,0.5f,1,1); - break; - case LL_PCODE_LEGACY_TREE: - gGL.diffuseColor4f(0,0.5f,0,1); - break; - default: - gGL.diffuseColor4f(1,0,1,1); - break; - } - } - else - { - gGL.diffuseColor4f(1,0,0,1); - } - } - - const LLVector4a* ext; - LLVector4a pos, size; - - //render face bounding boxes - for (S32 i = 0; i < drawable->getNumFaces(); i++) - { - LLFace* facep = drawable->getFace(i); - - ext = facep->mExtents; - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - drawBoxOutline(pos,size); - } - - //render drawable bounding box - ext = drawable->getSpatialExtents(); - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - LLViewerObject* vobj = drawable->getVObj(); - if (vobj && vobj->onActiveList()) - { - gGL.flush(); - glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f)); - //glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f)); - stop_glerror(); - drawBoxOutline(pos,size); - gGL.flush(); - glLineWidth(1.f); - } - else - { - drawBoxOutline(pos,size); - } -} - -void renderNormals(LLDrawable* drawablep) -{ - LLVertexBuffer::unbind(); - - LLVOVolume* vol = drawablep->getVOVolume(); - if (vol) - { - LLVolume* volume = vol->getVolume(); - gGL.pushMatrix(); - gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale")); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - - for (S32 j = 0; j < face.mNumVertices; ++j) - { - gGL.begin(LLRender::LINES); - LLVector4a n,p; - - n.setMul(face.mNormals[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(1,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - - if (face.mBinormals) - { - n.setMul(face.mBinormals[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(0,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - } - gGL.end(); - } - } - - gGL.popMatrix(); - } -} - -S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale) -{ - const S32 DEFAULT_DETAIL = 1; - const F32 LARGE_THRESHOLD = 5.f; - const F32 MEGA_THRESHOLD = 25.f; - - S32 detail = DEFAULT_DETAIL; - F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f; - - if (avg_scale > LARGE_THRESHOLD) - { - detail += 1; - if (avg_scale > MEGA_THRESHOLD) - { - detail += 1; - } - } - - return detail; -} - -void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color) -{ - LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); - LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); - - const LLVector3 center(0,0,0); - const LLVector3 size(0.25f,0.25f,0.25f); - - if (decomp) - { - if (!decomp->mBaseHullMesh.empty()) - { - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals); - } - else - { - gMeshRepo.buildPhysicsMesh(*decomp); - gGL.diffuseColor4f(0,1,1,1); - drawBoxOutline(center, size); - } - - } - else - { - gGL.diffuseColor3f(1,0,1); - drawBoxOutline(center, size); - } -} - -void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color) -{ - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - LLGLEnable offset(GL_POLYGON_OFFSET_LINE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glPolygonOffset(3.f, 3.f); - glLineWidth(3.f); - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - glLineWidth(1.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -} - -void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) -{ - U8 physics_type = volume->getPhysicsShapeType(); - - if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible()) - { - return; - } - - //not allowed to return at this point without rendering *something* - - F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold"); - F32 cost = volume->getObjectCost(); - - LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor"); - LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor"); - LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor"); - - F32 normalizedCost = 1.f - exp( -(cost / threshold) ); - - LLColor4 color; - if ( normalizedCost <= 0.5f ) - { - color = lerp( low, mid, 2.f * normalizedCost ); - } - else - { - color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) ); - } - - LLColor4 line_color = color*0.5f; - - U32 data_mask = LLVertexBuffer::MAP_VERTEX; - - LLVolumeParams volume_params = volume->getVolume()->getParams(); - - LLPhysicsVolumeParams physics_params(volume_params, - physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); - - LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec; - LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec); - - U32 type = physics_spec.getType(); - - LLVector3 center(0,0,0); - LLVector3 size(0.25f,0.25f,0.25f); - - gGL.pushMatrix(); - gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); - - if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH) - { - LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); - LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); - - if (decomp) - { //render a physics based mesh - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (!decomp->mHull.empty()) - { //decomposition exists, use that - - if (decomp->mMesh.empty()) - { - gMeshRepo.buildPhysicsMesh(*decomp); - } - - for (U32 i = 0; i < decomp->mMesh.size(); ++i) - { - render_hull(decomp->mMesh[i], color, line_color); - } - } - else if (!decomp->mPhysicsShapeMesh.empty()) - { - //decomp has physics mesh, render that mesh - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else - { //no mesh or decomposition, render base hull - renderMeshBaseHull(volume, data_mask, color, line_color); - - if (decomp->mPhysicsShapeMesh.empty()) - { - //attempt to fetch physics shape mesh if available - gMeshRepo.fetchPhysicsShape(mesh_id); - } - } - } - else - { - gGL.diffuseColor3f(1,1,0); - drawBoxOutline(center, size); - } - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX || - type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) - { - if (volume->isMesh()) - { - renderMeshBaseHull(volume, data_mask, color, line_color); - } - else - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - - if (!phys_volume->mHullPoints) - { //build convex hull - std::vector<LLVector3> pos; - std::vector<U16> index; - - S32 index_offset = 0; - - for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = phys_volume->getVolumeFace(i); - if (index_offset + face.mNumVertices > 65535) - { - continue; - } - - for (S32 j = 0; j < face.mNumVertices; ++j) - { - pos.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (S32 j = 0; j < face.mNumIndices; ++j) - { - index.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - - if (!pos.empty() && !index.empty()) - { - LLCDMeshData mesh; - mesh.mIndexBase = &index[0]; - mesh.mVertexBase = pos[0].mV; - mesh.mNumVertices = pos.size(); - mesh.mVertexStrideBytes = 12; - mesh.mIndexStrideBytes = 6; - mesh.mIndexType = LLCDMeshData::INT_16; - - mesh.mNumTriangles = index.size()/3; - - LLCDMeshData res; - - LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res ); - - //copy res into phys_volume - phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices); - phys_volume->mNumHullPoints = res.mNumVertices; - - S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF; - phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size); - phys_volume->mNumHullIndices = res.mNumTriangles*3; - - const F32* v = res.mVertexBase; - - for (S32 i = 0; i < res.mNumVertices; ++i) - { - F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes); - phys_volume->mHullPoints[i].load3(p); - } - - if (res.mIndexType == LLCDMeshData::INT_16) - { - for (S32 i = 0; i < res.mNumTriangles; ++i) - { - U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); - - phys_volume->mHullIndices[i*3+0] = idx[0]; - phys_volume->mHullIndices[i*3+1] = idx[1]; - phys_volume->mHullIndices[i*3+2] = idx[2]; - } - } - else - { - for (S32 i = 0; i < res.mNumTriangles; ++i) - { - U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); - - phys_volume->mHullIndices[i*3+0] = (U16) idx[0]; - phys_volume->mHullIndices[i*3+1] = (U16) idx[1]; - phys_volume->mHullIndices[i*3+2] = (U16) idx[2]; - } - } - } - } - - if (phys_volume->mHullPoints) - { - //render hull - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::unbind(); - - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); - - } - else - { - gGL.diffuseColor4f(1,0,1,1); - drawBoxOutline(center, size); - } - - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX) - { - LLVector3 center = physics_spec.getCenter(); - LLVector3 scale = physics_spec.getScale(); - LLVector3 vscale = volume->getScale()*2.f; - scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]); - - gGL.diffuseColor4fv(color.mV); - drawBox(center, scale); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE) - { - /*LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); - - gGL.diffuseColor4fv(color.mV); - pushVerts(sphere); - LLPrimitive::sVolumeManager->unrefVolume(sphere);*/ - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER) - { - LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); - - gGL.diffuseColor4fv(color.mV); - pushVerts(cylinder); - LLPrimitive::sVolumeManager->unrefVolume(cylinder); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH) - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4fv(line_color.mV); - pushVerts(phys_volume); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - pushVerts(phys_volume); - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - - if (phys_volume->mHullPoints && phys_volume->mHullIndices) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - LLVertexBuffer::unbind(); - glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints); - gGL.diffuseColor4fv(line_color.mV); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); - } - else - { - gGL.diffuseColor3f(1,0,1); - drawBoxOutline(center, size); - gMeshRepo.buildHull(volume_params, detail); - } - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT) - { - //TODO: implement sculpted prim physics display - } - else - { - llerrs << "Unhandled type" << llendl; - } - - gGL.popMatrix(); -} - -void renderPhysicsShapes(LLSpatialGroup* group) -{ - for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE ) - { - if (!group->mSpatialPartition->isBridge()) - { - gGL.pushMatrix(); - LLVector3 trans = drawable->getRegion()->getOriginAgent(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - renderPhysicsShape(drawable, volume); - gGL.popMatrix(); - } - else - { - renderPhysicsShape(drawable, volume); - } - } - else - { - LLViewerObject* object = drawable->getVObj(); - if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) - { - //push face vertices for terrain - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* face = drawable->getFace(i); - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - - gGL.diffuseColor3f(0.2f, 1.f, 0.3f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - } - } - } - } - } -} - -void renderTexturePriority(LLDrawable* drawable) -{ - for (int face=0; face<drawable->getNumFaces(); ++face) - { - LLFace *facep = drawable->getFace(face); - - LLVector4 cold(0,0,0.25f); - LLVector4 hot(1,0.25f,0.25f); - - LLVector4 boost_cold(0,0,0,0); - LLVector4 boost_hot(0,1,0,1); - - LLGLDisable blend(GL_BLEND); - - //LLViewerTexture* imagep = facep->getTexture(); - //if (imagep) - { - - //F32 vsize = imagep->mMaxVirtualSize; - F32 vsize = facep->getPixelArea(); - - if (vsize > sCurMaxTexPriority) - { - sCurMaxTexPriority = vsize; - } - - F32 t = vsize/sLastMaxTexPriority; - - LLVector4 col = lerp(cold, hot, t); - gGL.diffuseColor4fv(col.mV); - } - //else - //{ - // gGL.diffuseColor4f(1,0,1,1); - //} - - LLVector4a center; - center.setAdd(facep->mExtents[1],facep->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(facep->mExtents[1],facep->mExtents[0]); - size.mul(0.5f); - size.add(LLVector4a(0.01f)); - drawBox(center, size); - - /*S32 boost = imagep->getBoostLevel(); - if (boost>LLViewerTexture::BOOST_NONE) - { - F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1); - LLVector4 col = lerp(boost_cold, boost_hot, t); - LLGLEnable blend_on(GL_BLEND); - gGL.blendFunc(GL_SRC_ALPHA, GL_ONE); - gGL.diffuseColor4fv(col.mV); - drawBox(center, size); - gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - }*/ - } -} - -void renderPoints(LLDrawable* drawablep) -{ - LLGLDepthTest depth(GL_FALSE, GL_FALSE); - if (drawablep->getNumFaces()) - { - gGL.begin(LLRender::POINTS); - gGL.diffuseColor3f(1,1,1); - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); - } - gGL.end(); - } -} - -void renderTextureAnim(LLDrawInfo* params) -{ - if (!params->mTextureMatrix) - { - return; - } - - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(1,1,0,0.5f); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); -} - -void renderBatchSize(LLDrawInfo* params) -{ - LLGLEnable offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f, 1.f); - gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor)); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); -} - -void renderShadowFrusta(LLDrawInfo* params) -{ - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ADD); - - LLVector4a center; - center.setAdd(params->mExtents[1], params->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(params->mExtents[1],params->mExtents[0]); - size.mul(0.5f); - - if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(1,0,0); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(0,1,0); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(0,0,1); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(1,0,1); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); -} - - -void renderLights(LLDrawable* drawablep) -{ - if (!drawablep->isLight()) - { - return; - } - - if (drawablep->getNumFaces()) - { - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(0,1,1,0.5f); - - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - - const LLVector4a* ext = drawablep->getSpatialExtents(); - - LLVector4a pos; - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - { - LLGLDepthTest depth(GL_FALSE, GL_TRUE); - gGL.diffuseColor4f(1,1,1,1); - drawBoxOutline(pos, size); - } - - gGL.diffuseColor4f(1,1,0,1); - F32 rad = drawablep->getVOVolume()->getLightRadius(); - drawBoxOutline(pos, LLVector4a(rad)); - } -} - -class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect -{ -public: - - - LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t) - : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL) - { - - } - - void visit(const LLOctreeNode<LLVolumeTriangle>* branch) - { - LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0); - - LLVector3 center, size; - - if (branch->getData().empty()) - { - gGL.diffuseColor3f(1.f,0.2f,0.f); - center.set(branch->getCenter().getF32ptr()); - size.set(branch->getSize().getF32ptr()); - } - else - { - gGL.diffuseColor3f(0.75f, 1.f, 0.f); - center.set(vl->mBounds[0].getF32ptr()); - size.set(vl->mBounds[1].getF32ptr()); - } - - drawBoxOutline(center, size); - - for (U32 i = 0; i < 2; i++) - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER); - - if (i == 1) - { - gGL.diffuseColor4f(0,1,1,0.5f); - } - else - { - gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f); - drawBoxOutline(center, size); - } - - if (i == 1) - { - gGL.flush(); - glLineWidth(3.f); - } - - gGL.begin(LLRender::TRIANGLES); - for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); - iter != branch->getData().end(); - ++iter) - { - const LLVolumeTriangle* tri = *iter; - - gGL.vertex3fv(tri->mV[0]->getF32ptr()); - gGL.vertex3fv(tri->mV[1]->getF32ptr()); - gGL.vertex3fv(tri->mV[2]->getF32ptr()); - } - gGL.end(); - - if (i == 1) - { - gGL.flush(); - glLineWidth(1.f); - } - } - } -}; - -void renderRaycast(LLDrawable* drawablep) -{ - if (drawablep->getNumFaces()) - { - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(0,1,1,0.5f); - - if (drawablep->getVOVolume()) - { - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - LLVOVolume* vobj = drawablep->getVOVolume(); - LLVolume* volume = vobj->getVolume(); - - bool transform = true; - if (drawablep->isState(LLDrawable::RIGGED)) - { - volume = vobj->getRiggedVolume(); - transform = false; - } - - if (volume) - { - LLVector3 trans = drawablep->getRegion()->getOriginAgent(); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - - gGL.pushMatrix(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); - - LLVector3 start, end; - if (transform) - { - start = vobj->agentPositionToVolume(gDebugRaycastStart); - end = vobj->agentPositionToVolume(gDebugRaycastEnd); - } - else - { - start = gDebugRaycastStart; - end = gDebugRaycastEnd; - } - - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - LLVector4a dir; - dir.setSub(enda, starta); - - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - { - //render face positions - LLVertexBuffer::unbind(); - gGL.diffuseColor4f(0,1,1,0.5f); - glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); - } - - if (!volume->isUnique()) - { - F32 t = 1.f; - - if (!face.mOctree) - { - ((LLVolumeFace*) &face)->createOctree(); - } - - LLRenderOctreeRaycast render(starta, dir, &t); - - render.traverse(face.mOctree); - } - - gGL.popMatrix(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - } - } - else if (drawablep->isAvatar()) - { - if (drawablep->getVObj() == gDebugRaycastObject) - { - LLGLDepthTest depth(GL_FALSE); - LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get(); - av->renderCollisionVolumes(); - } - } - - if (drawablep->getVObj() == gDebugRaycastObject) - { - // draw intersection point - gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); - LLVector3 translate = gDebugRaycastIntersection; - gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]); - LLCoordFrame orient; - orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal); - LLMatrix4 rotation; - orient.getRotMatrixToParent(rotation); - gGL.multMatrix((float*)rotation.mMatrix); - - gGL.diffuseColor4f(1,0,0,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f)); - gGL.diffuseColor4f(0,1,0,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f)); - gGL.diffuseColor4f(0,0,1,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f)); - gGL.popMatrix(); - - // draw bounding box of prim - const LLVector4a* ext = drawablep->getSpatialExtents(); - - LLVector4a pos; - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - LLGLDepthTest depth(GL_FALSE, GL_TRUE); - gGL.diffuseColor4f(0,0.5f,0.5f,1); - drawBoxOutline(pos, size); - } - } -} - - -void renderAvatarCollisionVolumes(LLVOAvatar* avatar) -{ - avatar->renderCollisionVolumes(); -} - -void renderAgentTarget(LLVOAvatar* avatar) -{ - // render these for self only (why, i don't know) - if (avatar->isSelf()) - { - renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); - renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); - renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f)); - renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f)); - } -} - -class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - stop_glerror(); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - stop_glerror(); - } - - //draw tight fit bounding boxes for spatial group - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) - { - group->rebuildGeom(); - group->rebuildMesh(); - - renderOctree(group); - stop_glerror(); - } - - //render visibility wireframe - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) - { - group->rebuildGeom(); - group->rebuildMesh(); - - gGL.flush(); - gGL.pushMatrix(); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - renderVisibility(group, mCamera); - stop_glerror(); - gGLLastMatrix = NULL; - gGL.popMatrix(); - gGL.diffuseColor4f(1,1,1,1); - } - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) - { - return; - } - - LLVector4a nodeCenter = group->mBounds[0]; - LLVector4a octCenter = group->mOctreeNode->getCenter(); - - group->rebuildGeom(); - group->rebuildMesh(); - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) - { - if (!group->getData().empty()) - { - gGL.diffuseColor3f(0,0,1); - drawBoxOutline(group->mObjectBounds[0], - group->mObjectBounds[1]); - } - } - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) - { - renderBoundingBox(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS)) - { - renderNormals(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE)) - { - if (drawable->isState(LLDrawable::IN_REBUILD_Q2)) - { - gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f); - const LLVector4a* ext = drawable->getSpatialExtents(); - LLVector4a center; - center.setAdd(ext[0], ext[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - drawBoxOutline(center, size); - } - } - - if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - renderTexturePriority(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS)) - { - renderPoints(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS)) - { - renderLights(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) - { - renderRaycast(drawable); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE)) - { - renderUpdateType(drawable); - } - if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) - { - renderComplexityDisplay(drawable); - } - - LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get()); - - if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)) - { - renderAvatarCollisionVolumes(avatar); - } - - if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET)) - { - renderAgentTarget(avatar); - } - - if (gDebugGL) - { - for (U32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* facep = drawable->getFace(i); - U8 index = facep->getTextureIndex(); - if (facep->mDrawInfo) - { - if (index < 255) - { - if (facep->mDrawInfo->mTextureList.size() <= index) - { - llerrs << "Face texture index out of bounds." << llendl; - } - else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) - { - llerrs << "Face texture index incorrect." << llendl; - } - } - } - } - } - } - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo* draw_info = *j; - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)) - { - renderTextureAnim(draw_info); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE)) - { - renderBatchSize(draw_info); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - renderShadowFrusta(draw_info); - } - } - } - } -}; - - -class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - stop_glerror(); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - stop_glerror(); - } - - group->rebuildGeom(); - group->rebuildMesh(); - - renderPhysicsShapes(group); - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - - } -}; - -class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) - { - return; - } - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - renderBoundingBox(drawable, FALSE); - } - } -}; - -void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera) -{ - LLOctreePushBBoxVerts pusher(camera); - pusher.traverse(mOctree); -} - -class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable> -{ -public: - U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS]; - - LLOctreeStateCheck() - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mInheritedMask[i] = 0; - } - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - node->accept(this); - - - U32 temp[LLViewerCamera::NUM_CAMERAS]; - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - temp[i] = mInheritedMask[i]; - mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; - } - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mInheritedMask[i] = temp[i]; - } - } - - - virtual void visit(const LLOctreeNode<LLDrawable>* state) - { - LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i])) - { - llerrs << "Spatial group failed inherited mask test." << llendl; - } - } - - if (group->isState(LLSpatialGroup::DIRTY)) - { - assert_parent_state(group, LLSpatialGroup::DIRTY); - } - } - - void assert_parent_state(LLSpatialGroup* group, U32 state) - { - LLSpatialGroup* parent = group->getParent(); - while (parent) - { - if (!parent->isState(state)) - { - llerrs << "Spatial group failed parent state check." << llendl; - } - parent = parent->getParent(); - } - } -}; - - -void LLSpatialPartition::renderPhysicsShapes() -{ - LLSpatialBridge* bridge = asBridge(); - LLCamera* camera = LLViewerCamera::getInstance(); - - if (bridge) - { - camera = NULL; - } - - gGL.flush(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glLineWidth(3.f); - LLOctreeRenderPhysicsShapes render_physics(camera); - render_physics.traverse(mOctree); - gGL.flush(); - glLineWidth(1.f); -} - -void LLSpatialPartition::renderDebug() -{ - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE | - LLPipeline::RENDER_DEBUG_OCCLUSION | - LLPipeline::RENDER_DEBUG_LIGHTS | - LLPipeline::RENDER_DEBUG_BATCH_SIZE | - LLPipeline::RENDER_DEBUG_UPDATE_TYPE | - LLPipeline::RENDER_DEBUG_BBOXES | - LLPipeline::RENDER_DEBUG_NORMALS | - LLPipeline::RENDER_DEBUG_POINTS | - LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY | - LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | - LLPipeline::RENDER_DEBUG_RAYCAST | - LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | - LLPipeline::RENDER_DEBUG_AGENT_TARGET | - //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | - LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | - LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) - { - return; - } - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds); - sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea(); - sCurMaxTexPriority = 0.f; - } - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - LLGLDisable cullface(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gPipeline.disableLights(); - - LLSpatialBridge* bridge = asBridge(); - LLCamera* camera = LLViewerCamera::getInstance(); - - if (bridge) - { - camera = NULL; - } - - LLOctreeStateCheck checker; - checker.traverse(mOctree); - - LLOctreeRenderNonOccluded render_debug(camera); - render_debug.traverse(mOctree); - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } -} - -void LLSpatialGroup::drawObjectBox(LLColor4 col) -{ - gGL.diffuseColor4fv(col.mV); - LLVector4a size; - size = mObjectBounds[1]; - size.mul(1.01f); - size.add(LLVector4a(0.001f)); - drawBox(mObjectBounds[0], size); -} - -bool LLSpatialPartition::isHUDPartition() -{ - return mPartitionType == LLViewerRegion::PARTITION_HUD ; -} - -BOOL LLSpatialPartition::isVisible(const LLVector3& v) -{ - if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f)) - { - return FALSE; - } - - return TRUE; -} - -class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler -{ -public: - LLVector3 mStart; - LLVector3 mEnd; - S32 *mFaceHit; - LLVector3 *mIntersection; - LLVector2 *mTexCoord; - LLVector3 *mNormal; - LLVector3 *mBinormal; - LLDrawable* mHit; - BOOL mPickTransparent; - - LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent, - S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal) - : mStart(start), - mEnd(end), - mFaceHit(face_hit), - mIntersection(intersection), - mTexCoord(tex_coord), - mNormal(normal), - mBinormal(binormal), - mHit(NULL), - mPickTransparent(pick_transparent) - { - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - check(*i); - } - } - - virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node) - { - node->accept(this); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - const LLSpatialGroup::OctreeNode* child = node->getChild(i); - LLVector3 res; - - LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); - - LLVector4a size; - LLVector4a center; - - size = group->mBounds[1]; - center = group->mBounds[0]; - - LLVector3 local_start = mStart; - LLVector3 local_end = mEnd; - - if (group->mSpatialPartition->isBridge()) - { - LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix(); - local_matrix.invert(); - - local_start = mStart * local_matrix; - local_end = mEnd * local_matrix; - } - - LLVector4a start, end; - start.load3(local_start.mV); - end.load3(local_end.mV); - - if (LLLineSegmentBoxIntersect(start, end, center, size)) - { - check(child); - } - } - - return mHit; - } - - virtual bool check(LLDrawable* drawable) - { - LLVector3 local_start = mStart; - LLVector3 local_end = mEnd; - - if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible()) - { - return false; - } - - if (drawable->isSpatialBridge()) - { - LLSpatialPartition *part = drawable->asPartition(); - LLSpatialBridge* bridge = part->asBridge(); - if (bridge && gPipeline.hasRenderType(bridge->mDrawableType)) - { - check(part->mOctree); - } - } - else - { - LLViewerObject* vobj = drawable->getVObj(); - - if (vobj) - { - LLVector3 intersection; - bool skip_check = false; - if (vobj->isAvatar()) - { - LLVOAvatar* avatar = (LLVOAvatar*) vobj; - if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools)) - { - LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal); - if (hit) - { - mEnd = intersection; - if (mIntersection) - { - *mIntersection = intersection; - } - - mHit = hit->mDrawable; - skip_check = true; - } - - } - } - - if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal)) - { - mEnd = intersection; // shorten ray so we only find CLOSER hits - if (mIntersection) - { - *mIntersection = intersection; - } - - mHit = vobj->mDrawable; - } - } - } - - return false; - } -}; - -LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - BOOL pick_transparent, - S32* face_hit, // return the face hit - LLVector3* intersection, // return the intersection point - LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point - ) - -{ - LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); - LLDrawable* drawable = intersect.check(mOctree); - - return drawable; -} - -LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, - LLViewerTexture* texture, LLVertexBuffer* buffer, - BOOL fullbright, U8 bump, BOOL particle, F32 part_size) -: - mVertexBuffer(buffer), - mTexture(texture), - mTextureMatrix(NULL), - mModelMatrix(NULL), - mStart(start), - mEnd(end), - mCount(count), - mOffset(offset), - mFullbright(fullbright), - mBump(bump), - mParticle(particle), - mPartSize(part_size), - mVSize(0.f), - mGroup(NULL), - mFace(NULL), - mDistance(0.f), - mDrawMode(LLRender::TRIANGLES) -{ - mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); - - mDebugColor = (rand() << 16) + rand(); -} - -LLDrawInfo::~LLDrawInfo() -{ - /*if (LLSpatialGroup::sNoDelete) - { - llerrs << "LLDrawInfo deleted illegally!" << llendl; - }*/ - - if (mFace) - { - mFace->setDrawInfo(NULL); - } - - if (gDebugGL) - { - gPipeline.checkReferences(this); - } -} - -void LLDrawInfo::validate() -{ - mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); -} - -LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) -{ - return new LLVertexBuffer(type_mask, usage); -} - -LLCullResult::LLCullResult() -{ - clear(); -} - -void LLCullResult::clear() -{ - mVisibleGroupsSize = 0; - mVisibleGroupsEnd = mVisibleGroups.begin(); - - mAlphaGroupsSize = 0; - mAlphaGroupsEnd = mAlphaGroups.begin(); - - mOcclusionGroupsSize = 0; - mOcclusionGroupsEnd = mOcclusionGroups.begin(); - - mDrawableGroupsSize = 0; - mDrawableGroupsEnd = mDrawableGroups.begin(); - - mVisibleListSize = 0; - mVisibleListEnd = mVisibleList.begin(); - - mVisibleBridgeSize = 0; - mVisibleBridgeEnd = mVisibleBridge.begin(); - - - for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) - { - for (U32 j = 0; j < mRenderMapSize[i]; j++) - { - mRenderMap[i][j] = 0; - } - mRenderMapSize[i] = 0; - mRenderMapEnd[i] = mRenderMap[i].begin(); - } -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups() -{ - return mVisibleGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups() -{ - return mVisibleGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups() -{ - return mAlphaGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups() -{ - return mAlphaGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups() -{ - return mOcclusionGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups() -{ - return mOcclusionGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups() -{ - return mDrawableGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups() -{ - return mDrawableGroupsEnd; -} - -LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList() -{ - return mVisibleList.begin(); -} - -LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList() -{ - return mVisibleListEnd; -} - -LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge() -{ - return mVisibleBridge.begin(); -} - -LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge() -{ - return mVisibleBridgeEnd; -} - -LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type) -{ - return mRenderMap[type].begin(); -} - -LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type) -{ - return mRenderMapEnd[type]; -} - -void LLCullResult::pushVisibleGroup(LLSpatialGroup* group) -{ - if (mVisibleGroupsSize < mVisibleGroups.size()) - { - mVisibleGroups[mVisibleGroupsSize] = group; - } - else - { - mVisibleGroups.push_back(group); - } - ++mVisibleGroupsSize; - mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize; -} - -void LLCullResult::pushAlphaGroup(LLSpatialGroup* group) -{ - if (mAlphaGroupsSize < mAlphaGroups.size()) - { - mAlphaGroups[mAlphaGroupsSize] = group; - } - else - { - mAlphaGroups.push_back(group); - } - ++mAlphaGroupsSize; - mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize; -} - -void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) -{ - if (mOcclusionGroupsSize < mOcclusionGroups.size()) - { - mOcclusionGroups[mOcclusionGroupsSize] = group; - } - else - { - mOcclusionGroups.push_back(group); - } - ++mOcclusionGroupsSize; - mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize; -} - -void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) -{ - if (mDrawableGroupsSize < mDrawableGroups.size()) - { - mDrawableGroups[mDrawableGroupsSize] = group; - } - else - { - mDrawableGroups.push_back(group); - } - ++mDrawableGroupsSize; - mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize; -} - -void LLCullResult::pushDrawable(LLDrawable* drawable) -{ - if (mVisibleListSize < mVisibleList.size()) - { - mVisibleList[mVisibleListSize] = drawable; - } - else - { - mVisibleList.push_back(drawable); - } - ++mVisibleListSize; - mVisibleListEnd = mVisibleList.begin()+mVisibleListSize; -} - -void LLCullResult::pushBridge(LLSpatialBridge* bridge) -{ - if (mVisibleBridgeSize < mVisibleBridge.size()) - { - mVisibleBridge[mVisibleBridgeSize] = bridge; - } - else - { - mVisibleBridge.push_back(bridge); - } - ++mVisibleBridgeSize; - mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize; -} - -void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info) -{ - if (mRenderMapSize[type] < mRenderMap[type].size()) - { - mRenderMap[type][mRenderMapSize[type]] = draw_info; - } - else - { - mRenderMap[type].push_back(draw_info); - } - ++mRenderMapSize[type]; - mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type]; -} - - -void LLCullResult::assertDrawMapsEmpty() -{ - for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) - { - if (mRenderMapSize[i] != 0) - { - llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl; - } - } -} - - - +/**
+ * @file llspatialpartition.cpp
+ * @brief LLSpatialGroup class implementation and supporting functions
+ *
+ * $LicenseInfo:firstyear=2003&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llspatialpartition.h"
+
+#include "llappviewer.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "llimageworker.h"
+#include "llviewerwindow.h"
+#include "llviewerobjectlist.h"
+#include "llvovolume.h"
+#include "llvolume.h"
+#include "llvolumeoctree.h"
+#include "llviewercamera.h"
+#include "llface.h"
+#include "llfloatertools.h"
+#include "llviewercontrol.h"
+#include "llviewerregion.h"
+#include "llcamera.h"
+#include "pipeline.h"
+#include "llmeshrepository.h"
+#include "llrender.h"
+#include "lloctree.h"
+#include "llphysicsshapebuilderutil.h"
+#include "llvoavatar.h"
+#include "llvolumemgr.h"
+#include "lltextureatlas.h"
+#include "llglslshader.h"
+#include "llagent.h"
+#include "llviewershadermgr.h"
+
+static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
+static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
+
+const F32 SG_OCCLUSION_FUDGE = 0.25f;
+#define SG_DISCARD_TOLERANCE 0.01f
+
+#if LL_OCTREE_PARANOIA_CHECK
+#define assert_octree_valid(x) x->validate()
+#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
+#else
+#define assert_octree_valid(x)
+#define assert_states_valid(x)
+#endif
+
+
+static U32 sZombieGroups = 0;
+U32 LLSpatialGroup::sNodeCount = 0;
+
+#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
+
+std::set<GLuint> LLSpatialGroup::sPendingQueries;
+
+U32 gOctreeMaxCapacity;
+
+BOOL LLSpatialGroup::sNoDelete = FALSE;
+
+static F32 sLastMaxTexPriority = 1.f;
+static F32 sCurMaxTexPriority = 1.f;
+
+class LLOcclusionQueryPool : public LLGLNamePool
+{
+protected:
+ virtual GLuint allocateName()
+ {
+ GLuint name;
+ glGenQueriesARB(1, &name);
+ return name;
+ }
+
+ virtual void releaseName(GLuint name)
+ {
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ LLSpatialGroup::sPendingQueries.erase(name);
+#endif
+ glDeleteQueriesARB(1, &name);
+ }
+};
+
+static LLOcclusionQueryPool sQueryPool;
+
+//static counter for frame to switch LOD on
+
+void sg_assert(BOOL expr)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ if (!expr)
+ {
+ llerrs << "Octree invalid!" << llendl;
+ }
+#endif
+}
+
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ if ((min-origin).magVecSquared() < r &&
+ (max-origin).magVecSquared() < r)
+ {
+ return 2;
+ }
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min.mV[i])
+ {
+ t = min.mV[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max.mV[i])
+ {
+ t = origin.mV[i] - max.mV[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ LLVector4a origina;
+ origina.load3(origin.mV);
+
+ LLVector4a v;
+ v.setSub(min, origina);
+
+ if (v.dot3(v) < r)
+ {
+ v.setSub(max, origina);
+ if (v.dot3(v) < r)
+ {
+ return 2;
+ }
+ }
+
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min[i])
+ {
+ t = min[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max[i])
+ {
+ t = origin.mV[i] - max[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+typedef enum
+{
+ b000 = 0x00,
+ b001 = 0x01,
+ b010 = 0x02,
+ b011 = 0x03,
+ b100 = 0x04,
+ b101 = 0x05,
+ b110 = 0x06,
+ b111 = 0x07,
+} eLoveTheBits;
+
+//contact Runitai Linden for a copy of the SL object used to write this table
+//basically, you give the table a bitmask of the look-at vector to a node and it
+//gives you a triangle fan index array
+static U16 sOcclusionIndices[] =
+{
+ //000
+ b111, b110, b010, b011, b001, b101, b100, b110,
+ //001
+ b011, b010, b000, b001, b101, b111, b110, b010,
+ //010
+ b101, b100, b110, b111, b011, b001, b000, b100,
+ //011
+ b001, b000, b100, b101, b111, b011, b010, b000,
+ //100
+ b110, b000, b010, b011, b111, b101, b100, b000,
+ //101
+ b010, b100, b000, b001, b011, b111, b110, b100,
+ //110
+ b100, b010, b110, b111, b101, b001, b000, b010,
+ //111
+ b000, b110, b100, b101, b001, b011, b010, b110,
+};
+
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return cypher*8;
+}
+
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return (U8*) (sOcclusionIndices+cypher*8);
+}
+
+
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
+
+void LLSpatialGroup::buildOcclusion()
+{
+ //if (mOcclusionVerts.isNull())
+ {
+ mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX,
+ LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
+ mOcclusionVerts->allocateBuffer(8, 64, true);
+
+ LLStrider<U16> idx;
+ mOcclusionVerts->getIndexStrider(idx);
+ for (U32 i = 0; i < 64; i++)
+ {
+ *idx++ = sOcclusionIndices[i];
+ }
+ }
+
+ LLVector4a fudge;
+ fudge.splat(SG_OCCLUSION_FUDGE);
+
+ LLVector4a r;
+ r.setAdd(mBounds[1], fudge);
+
+ LLStrider<LLVector3> pos;
+
+ {
+ LLFastTimer t(FTM_BUILD_OCCLUSION);
+ mOcclusionVerts->getVertexStrider(pos);
+ }
+
+ {
+ LLVector4a* v = (LLVector4a*) pos.get();
+
+ const LLVector4a& c = mBounds[0];
+ const LLVector4a& s = r;
+
+ static const LLVector4a octant[] =
+ {
+ LLVector4a(-1.f, -1.f, -1.f),
+ LLVector4a(-1.f, -1.f, 1.f),
+ LLVector4a(-1.f, 1.f, -1.f),
+ LLVector4a(-1.f, 1.f, 1.f),
+
+ LLVector4a(1.f, -1.f, -1.f),
+ LLVector4a(1.f, -1.f, 1.f),
+ LLVector4a(1.f, 1.f, -1.f),
+ LLVector4a(1.f, 1.f, 1.f),
+ };
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ LLVector4a p;
+ p.setMul(s, octant[i]);
+ p.add(c);
+ v[i] = p;
+ }
+ }
+
+ {
+ mOcclusionVerts->flush();
+ LLVertexBuffer::unbind();
+ }
+
+ clearState(LLSpatialGroup::OCCLUSION_DIRTY);
+}
+
+
+BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
+
+//returns:
+// 0 if sphere and AABB are not intersecting
+// 1 if they are
+// 2 if AABB is entirely inside sphere
+
+S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
+{
+ S32 ret = 2;
+
+ LLVector3 min = center - size;
+ LLVector3 max = center + size;
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (min.mV[i] > pos.mV[i] + rad ||
+ max.mV[i] < pos.mV[i] - rad)
+ { //totally outside
+ return 0;
+ }
+
+ if (min.mV[i] < pos.mV[i] - rad ||
+ max.mV[i] > pos.mV[i] + rad)
+ { //intersecting
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+LLSpatialGroup::~LLSpatialGroup()
+{
+ /*if (sNoDelete)
+ {
+ llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
+ }*/
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
+ if (isState(DEAD))
+ {
+ sZombieGroups--;
+ }
+
+ sNodeCount--;
+
+ if (gGLManager.mHasOcclusionQuery)
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ }
+ }
+ }
+
+ mOcclusionVerts = NULL;
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ clearDrawMap();
+ clearAtlasList() ;
+}
+
+BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
+{
+ S8 type = atlasp->getComponents() - 1 ;
+ for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+ {
+ if(atlasp == *iter)
+ {
+ return TRUE ;
+ }
+ }
+ return FALSE ;
+}
+
+void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level)
+{
+ if(!hasAtlas(atlasp))
+ {
+ mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
+ atlasp->addSpatialGroup(this) ;
+ }
+
+ --recursive_level;
+ if(recursive_level)//levels propagating up.
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ parent->addAtlas(atlasp, recursive_level) ;
+ }
+ }
+}
+
+void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level)
+{
+ mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
+ if(remove_group)
+ {
+ atlasp->removeSpatialGroup(this) ;
+ }
+
+ --recursive_level;
+ if(recursive_level)//levels propagating up.
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ parent->removeAtlas(atlasp, recursive_level) ;
+ }
+ }
+}
+
+void LLSpatialGroup::clearAtlasList()
+{
+ std::list<LLTextureAtlas*>::iterator iter ;
+ for(S8 i = 0 ; i < 4 ; i++)
+ {
+ if(mAtlasList[i].size() > 0)
+ {
+ for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
+ {
+ ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;
+ }
+ mAtlasList[i].clear() ;
+ }
+ }
+}
+
+LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
+{
+ S8 type = ncomponents - 1 ;
+ if(mAtlasList[type].size() > 0)
+ {
+ for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+ {
+ if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
+ {
+ return *iter ;
+ }
+ }
+ }
+
+ --recursive_level;
+ if(recursive_level)
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
+ }
+ }
+ return NULL ;
+}
+
+void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp)
+{
+ mCurUpdatingSlotp = slotp;
+
+ //if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
+ //{
+ // addAtlas(mCurUpdatingSlotp->getAtlas()) ;
+ //}
+}
+
+LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level)
+{
+ if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
+ {
+ return mCurUpdatingSlotp ;
+ }
+
+ //--recursive_level ;
+ //if(recursive_level)
+ //{
+ // LLSpatialGroup* parent = getParent() ;
+ // if(parent)
+ // {
+ // return parent->getCurUpdatingSlot(imagep, recursive_level) ;
+ // }
+ //}
+ return NULL ;
+}
+
+void LLSpatialGroup::clearDrawMap()
+{
+ mDrawMap.clear();
+}
+
+BOOL LLSpatialGroup::isHUDGroup()
+{
+ return mSpatialPartition && mSpatialPartition->isHUDPartition() ;
+}
+
+BOOL LLSpatialGroup::isRecentlyVisible() const
+{
+ return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
+}
+
+BOOL LLSpatialGroup::isVisible() const
+{
+ return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+}
+
+void LLSpatialGroup::setVisible()
+{
+ mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
+}
+
+void LLSpatialGroup::validate()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+
+ sg_assert(!isState(DIRTY));
+ sg_assert(!isDead());
+
+ LLVector4a myMin;
+ myMin.setSub(mBounds[0], mBounds[1]);
+ LLVector4a myMax;
+ myMax.setAdd(mBounds[0], mBounds[1]);
+
+ validateDrawMap();
+
+ for (element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ sg_assert(drawable->getSpatialGroup() == this);
+ if (drawable->getSpatialBridge())
+ {
+ sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
+ }
+
+ /*if (drawable->isSpatialBridge())
+ {
+ LLSpatialPartition* part = drawable->asPartition();
+ if (!part)
+ {
+ llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl;
+ }
+ LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+ group->validate();
+ }*/
+ }
+
+ for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
+
+ group->validate();
+
+ //ensure all children are enclosed in this node
+ LLVector4a center = group->mBounds[0];
+ LLVector4a size = group->mBounds[1];
+
+ LLVector4a min;
+ min.setSub(center, size);
+ LLVector4a max;
+ max.setAdd(center, size);
+
+ for (U32 j = 0; j < 3; j++)
+ {
+ sg_assert(min[j] >= myMin[j]-0.02f);
+ sg_assert(max[j] <= myMax[j]+0.02f);
+ }
+ }
+
+#endif
+}
+
+void LLSpatialGroup::checkStates()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ //LLOctreeStateCheck checker;
+ //checker.traverse(mOctreeNode);
+#endif
+}
+
+void LLSpatialGroup::validateDrawMap()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo& params = **j;
+
+ params.validate();
+ }
+ }
+#endif
+}
+
+BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->updateSpatialExtents();
+
+ OctreeNode* parent = mOctreeNode->getOctParent();
+
+ if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&
+ (mOctreeNode->contains(drawablep) ||
+ (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
+ parent && parent->getElementCount() >= gOctreeMaxCapacity)))
+ {
+ unbound();
+ setState(OBJECT_DIRTY);
+ //setState(GEOM_DIRTY);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (!from_octree)
+ {
+ mOctreeNode->insert(drawablep);
+ }
+ else
+ {
+ drawablep->setSpatialGroup(this);
+ setState(OBJECT_DIRTY | GEOM_DIRTY);
+ setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+ gPipeline.markRebuild(this, TRUE);
+ if (drawablep->isSpatialBridge())
+ {
+ mBridgeList.push_back((LLSpatialBridge*) drawablep);
+ }
+ if (drawablep->getRadius() > 1.f)
+ {
+ setState(IMAGE_DIRTY);
+ }
+ }
+
+ return TRUE;
+}
+
+void LLSpatialGroup::rebuildGeom()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (!isDead())
+ {
+ mSpatialPartition->rebuildGeom(this);
+ }
+}
+
+void LLSpatialGroup::rebuildMesh()
+{
+ if (!isDead())
+ {
+ mSpatialPartition->rebuildMesh(this);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+
+void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
+{
+ if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
+ {
+ return;
+ }
+
+ if (group->changeLOD())
+ {
+ group->mLastUpdateDistance = group->mDistance;
+ group->mLastUpdateViewAngle = group->mViewAngle;
+ }
+
+ LLFastTimer ftm(FTM_REBUILD_VBO);
+
+ group->clearDrawMap();
+
+ //get geometry count
+ U32 index_count = 0;
+ U32 vertex_count = 0;
+
+ addGeometryCount(group, vertex_count, index_count);
+
+ if (vertex_count > 0 && index_count > 0)
+ { //create vertex buffer containing volume geometry for this node
+ group->mBuilt = 1.f;
+ if (group->mVertexBuffer.isNull() ||
+ !group->mVertexBuffer->isWriteable() ||
+ (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
+ {
+ group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
+ group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
+ stop_glerror();
+ }
+ else
+ {
+ group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
+ stop_glerror();
+ }
+
+ getGeometry(group);
+ }
+ else
+ {
+ group->mVertexBuffer = NULL;
+ group->mBufferMap.clear();
+ }
+
+ group->mLastUpdateTime = gFrameTimeSeconds;
+ group->clearState(LLSpatialGroup::GEOM_DIRTY);
+}
+
+
+void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
+{
+
+}
+
+BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
+{
+ const OctreeNode* node = mOctreeNode;
+
+ if (node->getData().empty())
+ { //don't do anything if there are no objects
+ if (empty && mOctreeNode->getParent())
+ { //only root is allowed to be empty
+ OCT_ERRS << "Empty leaf found in octree." << llendl;
+ }
+ return FALSE;
+ }
+
+ LLVector4a& newMin = mObjectExtents[0];
+ LLVector4a& newMax = mObjectExtents[1];
+
+ if (isState(OBJECT_DIRTY))
+ { //calculate new bounding box
+ clearState(OBJECT_DIRTY);
+
+ //initialize bounding box to first element
+ OctreeNode::const_element_iter i = node->getData().begin();
+ LLDrawable* drawablep = *i;
+ const LLVector4a* minMax = drawablep->getSpatialExtents();
+
+ newMin = minMax[0];
+ newMax = minMax[1];
+
+ for (++i; i != node->getData().end(); ++i)
+ {
+ drawablep = *i;
+ minMax = drawablep->getSpatialExtents();
+
+ update_min_max(newMin, newMax, minMax[0]);
+ update_min_max(newMin, newMax, minMax[1]);
+
+ //bin up the object
+ /*for (U32 i = 0; i < 3; i++)
+ {
+ if (minMax[0].mV[i] < newMin.mV[i])
+ {
+ newMin.mV[i] = minMax[0].mV[i];
+ }
+ if (minMax[1].mV[i] > newMax.mV[i])
+ {
+ newMax.mV[i] = minMax[1].mV[i];
+ }
+ }*/
+ }
+
+ mObjectBounds[0].setAdd(newMin, newMax);
+ mObjectBounds[0].mul(0.5f);
+ mObjectBounds[1].setSub(newMax, newMin);
+ mObjectBounds[1].mul(0.5f);
+ }
+
+ if (empty)
+ {
+ minOut = newMin;
+ maxOut = newMax;
+ }
+ else
+ {
+ minOut.setMin(minOut, newMin);
+ maxOut.setMax(maxOut, newMax);
+ }
+
+ return TRUE;
+}
+
+void LLSpatialGroup::unbound()
+{
+ if (isState(DIRTY))
+ {
+ return;
+ }
+
+ setState(DIRTY);
+
+ //all the parent nodes need to rebound this child
+ if (mOctreeNode)
+ {
+ OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
+ while (parent != NULL)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
+ if (group->isState(DIRTY))
+ {
+ return;
+ }
+
+ group->setState(DIRTY);
+ parent = (OctreeNode*) parent->getParent();
+ }
+ }
+}
+
+LLSpatialGroup* LLSpatialGroup::getParent()
+{
+ if (isDead())
+ {
+ return NULL;
+ }
+
+ if(!mOctreeNode)
+ {
+ return NULL;
+ }
+ OctreeNode* parent = mOctreeNode->getOctParent();
+
+ if (parent)
+ {
+ return (LLSpatialGroup*) parent->getListener(0);
+ }
+
+ return NULL;
+}
+
+BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ unbound();
+ if (mOctreeNode && !from_octree)
+ {
+ if (!mOctreeNode->remove(drawablep))
+ {
+ OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
+ }
+ }
+ else
+ {
+ drawablep->setSpatialGroup(NULL);
+ setState(GEOM_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+
+ if (drawablep->isSpatialBridge())
+ {
+ for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
+ {
+ if (*i == drawablep)
+ {
+ mBridgeList.erase(i);
+ break;
+ }
+ }
+ }
+
+ if (getElementCount() == 0)
+ { //delete draw map on last element removal since a rebuild might never happen
+ clearDrawMap();
+ }
+ }
+ return TRUE;
+}
+
+void LLSpatialGroup::shift(const LLVector4a &offset)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ LLVector4a t = mOctreeNode->getCenter();
+ t.add(offset);
+ mOctreeNode->setCenter(t);
+ mOctreeNode->updateMinMax();
+ mBounds[0].add(offset);
+ mExtents[0].add(offset);
+ mExtents[1].add(offset);
+ mObjectBounds[0].add(offset);
+ mObjectExtents[0].add(offset);
+ mObjectExtents[1].add(offset);
+
+ //if (!mSpatialPartition->mRenderByGroup)
+ {
+ setState(GEOM_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+ }
+
+ if (mOcclusionVerts.notNull())
+ {
+ setState(OCCLUSION_DIRTY);
+ }
+}
+
+class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialSetState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }
+};
+
+class LLSpatialSetStateDiff : public LLSpatialSetState
+{
+public:
+ LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (!group->isState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::setState(U32 state)
+{
+ mState |= state;
+
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+}
+
+void LLSpatialGroup::setState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialSetStateDiff setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else
+ {
+ LLSpatialSetState setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ }
+ else
+ {
+ mState |= state;
+ }
+}
+
+class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialClearState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
+};
+
+class LLSpatialClearStateDiff : public LLSpatialClearState
+{
+public:
+ LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (group->isState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::clearState(U32 state)
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ mState &= ~state;
+}
+
+void LLSpatialGroup::clearState(U32 state, S32 mode)
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialClearStateDiff clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else
+ {
+ LLSpatialClearState clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ }
+ else
+ {
+ mState &= ~state;
+ }
+}
+
+BOOL LLSpatialGroup::isState(U32 state) const
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ return mState & state ? TRUE : FALSE;
+}
+
+//=====================================
+// Occlusion State Set/Clear
+//=====================================
+class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialSetOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }
+};
+
+class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
+{
+public:
+ LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (!group->isOcclusionState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+
+void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialSetOcclusionStateDiff setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else if (mode == STATE_MODE_BRANCH)
+ {
+ LLSpatialSetOcclusionState setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionState[i] |= state;
+
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+ }
+}
+
+class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+
+ LLSpatialClearOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
+};
+
+class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
+{
+public:
+ LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (group->isOcclusionState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialClearOcclusionStateDiff clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else if (mode == STATE_MODE_BRANCH)
+ {
+ LLSpatialClearOcclusionState clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionState[i] &= ~state;
+ }
+ }
+ }
+ else
+ {
+ mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
+ }
+}
+//======================================
+// Octree Listener Implementation
+//======================================
+
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
+ mState(0),
+ mGeometryBytes(0),
+ mSurfaceArea(0.f),
+ mBuilt(0.f),
+ mOctreeNode(node),
+ mSpatialPartition(part),
+ mVertexBuffer(NULL),
+ mBufferUsage(part->mBufferUsage),
+ mDistance(0.f),
+ mDepth(0.f),
+ mLastUpdateDistance(-1.f),
+ mLastUpdateTime(gFrameTimeSeconds),
+ mAtlasList(4),
+ mCurUpdatingTime(0),
+ mCurUpdatingSlotp(NULL),
+ mCurUpdatingTexture (NULL)
+{
+ sNodeCount++;
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ mViewAngle.splat(0.f);
+ mLastUpdateViewAngle.splat(-1.f);
+ mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
+ mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
+
+ sg_assert(mOctreeNode->getListenerCount() == 0);
+ mOctreeNode->addListener(this);
+ setState(SG_INITIAL_STATE_MASK);
+ gPipeline.markRebuild(this, TRUE);
+
+ mBounds[0] = node->getCenter();
+ mBounds[1] = node->getSize();
+
+ part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
+ mLODHash = part->mLODSeed;
+
+ OctreeNode* oct_parent = node->getOctParent();
+
+ LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL;
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionQuery[i] = 0;
+ mOcclusionIssued[i] = 0;
+ mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0;
+ mVisible[i] = 0;
+ }
+
+ mOcclusionVerts = NULL;
+
+ mRadius = 1;
+ mPixelArea = 1024.f;
+}
+
+void LLSpatialGroup::updateDistance(LLCamera &camera)
+{
+ if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+ {
+ llwarns << "Attempted to update distance for camera other than world camera!" << llendl;
+ return;
+ }
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+ if (isState(LLSpatialGroup::OBJECT_DIRTY))
+ {
+ llerrs << "Spatial group dirty on distance update." << llendl;
+ }
+#endif
+ if (!getData().empty())
+ {
+ mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+ (F32) mOctreeNode->getSize().getLength3().getF32();
+ mDistance = mSpatialPartition->calcDistance(this, camera);
+ mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
+ }
+}
+
+F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
+{
+ LLVector4a eye;
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ eye.setSub(group->mObjectBounds[0], origin);
+
+ F32 dist = 0.f;
+
+ if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
+ {
+ LLVector4a v = eye;
+
+ dist = eye.getLength3().getF32();
+ eye.normalize3fast();
+
+ if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ LLVector4a view_angle = eye;
+
+ LLVector4a diff;
+ diff.setSub(view_angle, group->mLastUpdateViewAngle);
+
+ if (diff.getLength3().getF32() > 0.64f)
+ {
+ group->mViewAngle = view_angle;
+ group->mLastUpdateViewAngle = view_angle;
+ //for occasional alpha sorting within the group
+ //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
+ //not setting this node to dirty would be a very good thing
+ group->setState(LLSpatialGroup::ALPHA_DIRTY);
+ gPipeline.markRebuild(group, FALSE);
+ }
+ }
+ }
+
+ //calculate depth of node for alpha sorting
+
+ LLVector3 at = camera.getAtAxis();
+
+ LLVector4a ata;
+ ata.load3(at.mV);
+
+ LLVector4a t = ata;
+ //front of bounding box
+ t.mul(0.25f);
+ t.mul(group->mObjectBounds[1]);
+ v.sub(t);
+
+ group->mDepth = v.dot3(ata).getF32();
+ }
+ else
+ {
+ dist = eye.getLength3().getF32();
+ }
+
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ return dist;
+}
+
+F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
+{
+ return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
+}
+
+F32 LLSpatialGroup::getUpdateUrgency() const
+{
+ if (!isVisible())
+ {
+ return 0.f;
+ }
+ else
+ {
+ F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
+ return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
+ }
+}
+
+BOOL LLSpatialGroup::needsUpdate()
+{
+ return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
+}
+
+BOOL LLSpatialGroup::changeLOD()
+{
+ if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
+ { ///a rebuild is going to happen, update distance and LoD
+ return TRUE;
+ }
+
+ if (mSpatialPartition->mSlopRatio > 0.f)
+ {
+ F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
+
+ if (fabsf(ratio) >= mSpatialPartition->mSlopRatio)
+ {
+ return TRUE;
+ }
+
+ if (mDistance > mRadius*2.f)
+ {
+ return FALSE;
+ }
+ }
+
+ if (needsUpdate())
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ addObject(drawablep, FALSE, TRUE);
+ unbound();
+ setState(OBJECT_DIRTY);
+}
+
+void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ removeObject(drawable, TRUE);
+ setState(OBJECT_DIRTY);
+}
+
+void LLSpatialGroup::handleDestruction(const TreeNode* node)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ setState(DEAD);
+
+ for (element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (drawable->getSpatialGroup() == this)
+ {
+ drawable->setSpatialGroup(NULL);
+ }
+ }
+
+ //clean up avatar attachment stats
+ LLSpatialBridge* bridge = mSpatialPartition->asBridge();
+ if (bridge)
+ {
+ if (bridge->mAvatar.notNull())
+ {
+ bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
+ bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
+ }
+ }
+
+ clearDrawMap();
+ mVertexBuffer = NULL;
+ mBufferMap.clear();
+ sZombieGroups++;
+ mOctreeNode = NULL;
+}
+
+void LLSpatialGroup::handleStateChange(const TreeNode* node)
+{
+ //drop bounding box upon state change
+ if (mOctreeNode != node)
+ {
+ mOctreeNode = (OctreeNode*) node;
+ }
+ unbound();
+}
+
+void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (child->getListenerCount() == 0)
+ {
+ new LLSpatialGroup(child, mSpatialPartition);
+ }
+ else
+ {
+ OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
+ }
+
+ unbound();
+
+ assert_states_valid(this);
+}
+
+void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
+{
+ unbound();
+}
+
+void LLSpatialGroup::destroyGL()
+{
+ setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+
+ mLastUpdateTime = gFrameTimeSeconds;
+ mVertexBuffer = NULL;
+ mBufferMap.clear();
+
+ clearDrawMap();
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+
+ mOcclusionVerts = NULL;
+
+ for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ for (S32 j = 0; j < drawable->getNumFaces(); j++)
+ {
+ LLFace* facep = drawable->getFace(j);
+ facep->clearVertexBuffer();
+ }
+ }
+}
+
+BOOL LLSpatialGroup::rebound()
+{
+ if (!isState(DIRTY))
+ { //return TRUE if we're not empty
+ return TRUE;
+ }
+
+ if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
+ group->rebound();
+
+ //copy single child's bounding box
+ mBounds[0] = group->mBounds[0];
+ mBounds[1] = group->mBounds[1];
+ mExtents[0] = group->mExtents[0];
+ mExtents[1] = group->mExtents[1];
+
+ group->setState(SKIP_FRUSTUM_CHECK);
+ }
+ else if (mOctreeNode->isLeaf())
+ { //copy object bounding box if this is a leaf
+ boundObjects(TRUE, mExtents[0], mExtents[1]);
+ mBounds[0] = mObjectBounds[0];
+ mBounds[1] = mObjectBounds[1];
+ }
+ else
+ {
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
+ group->clearState(SKIP_FRUSTUM_CHECK);
+ group->rebound();
+ //initialize to first child
+ newMin = group->mExtents[0];
+ newMax = group->mExtents[1];
+
+ //first, rebound children
+ for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
+ {
+ group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
+ group->clearState(SKIP_FRUSTUM_CHECK);
+ group->rebound();
+ const LLVector4a& max = group->mExtents[1];
+ const LLVector4a& min = group->mExtents[0];
+
+ newMax.setMax(newMax, max);
+ newMin.setMin(newMin, min);
+ }
+
+ boundObjects(FALSE, newMin, newMax);
+
+ mBounds[0].setAdd(newMin, newMax);
+ mBounds[0].mul(0.5f);
+ mBounds[1].setSub(newMax, newMin);
+ mBounds[1].mul(0.5f);
+ }
+
+ setState(OCCLUSION_DIRTY);
+
+ clearState(DIRTY);
+
+ return TRUE;
+}
+
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait");
+
+void LLSpatialGroup::checkOcclusion()
+{
+ if (LLPipeline::sUseOcclusion > 1)
+ {
+ LLFastTimer t(FTM_OCCLUSION_READBACK);
+ LLSpatialGroup* parent = getParent();
+ if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //if the parent has been marked as occluded, the child is implicitly occluded
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
+ else if (isOcclusionState(QUERY_PENDING))
+ { //otherwise, if a query is pending, read it back
+
+ GLuint available = 0;
+ if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+
+ if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
+ { //query was issued last frame, wait until it's available
+ S32 max_loop = 1024;
+ LLFastTimer t(FTM_OCCLUSION_WAIT);
+ while (!available && max_loop-- > 0)
+ {
+ F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
+ //do some usefu work while we wait
+ LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
+ LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
+ LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
+
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+ }
+ }
+ }
+ else
+ {
+ available = 1;
+ }
+
+ if (available)
+ { //result is available, read it back, otherwise wait until next frame
+ GLuint res = 1;
+ if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+ }
+ else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ { //delete the query to avoid holding onto hundreds of pending queries
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+
+ if (isOcclusionState(DISCARD_QUERY))
+ {
+ res = 2;
+ }
+
+ if (res > 0)
+ {
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ assert_states_valid(this);
+ setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
+ }
+ else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //check occlusion has been issued for occluded node that has not had a query issued
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
+static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw");
+
+
+
+void LLSpatialGroup::doOcclusion(LLCamera* camera)
+{
+ if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
+ {
+ // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
+ if (earlyFail(camera, this))
+ {
+ LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
+ setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
+ {
+ { //no query pending, or previous query to be discarded
+ LLFastTimer t(FTM_RENDER_OCCLUSION);
+
+ if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
+ }
+
+ if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
+ {
+ LLFastTimer t(FTM_OCCLUSION_BUILD);
+ buildOcclusion();
+ }
+
+ // Depth clamp all water to avoid it being culled as a result of being
+ // behind the far clip plane, and in the case of edge water to avoid
+ // it being culled while still visible.
+ bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
+ (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||
+ mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
+
+ LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);
+
+#if !LL_DARWIN
+ U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
+#else
+ U32 mode = GL_SAMPLES_PASSED_ARB;
+#endif
+
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+
+ {
+ LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
+
+ //store which frame this query was issued on
+ mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY);
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ }
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_SET_BUFFER);
+ mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ }
+
+ if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+ {
+ LLFastTimer t(FTM_OCCLUSION_DRAW_WATER);
+
+ LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+ else
+ {
+ LLFastTimer t(FTM_OCCLUSION_DRAW);
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_END_QUERY);
+ glEndQueryARB(mode);
+ }
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_SET_OCCLUSION_STATE);
+ setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+ clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+ }
+ }
+ }
+ }
+}
+
+//==============================================
+
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
+: mRenderByGroup(render_by_group), mBridge(NULL)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ mOcclusionEnabled = TRUE;
+ mDrawableType = 0;
+ mPartitionType = LLViewerRegion::PARTITION_NONE;
+ mLODSeed = 0;
+ mLODPeriod = 1;
+ mVertexDataMask = data_mask;
+ mBufferUsage = buffer_usage;
+ mDepthMask = FALSE;
+ mSlopRatio = 0.25f;
+ mInfiniteFarClip = FALSE;
+
+ LLVector4a center, size;
+ center.splat(0.f);
+ size.splat(1.f);
+
+ mOctree = new LLSpatialGroup::OctreeRoot(center,size,
+ NULL);
+ new LLSpatialGroup(mOctree, this);
+}
+
+
+LLSpatialPartition::~LLSpatialPartition()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ delete mOctree;
+ mOctree = NULL;
+}
+
+
+LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->updateSpatialExtents();
+
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+
+ assert_octree_valid(mOctree);
+ mOctree->insert(drawablep);
+ assert_octree_valid(mOctree);
+
+ LLSpatialGroup* group = drawablep->getSpatialGroup();
+
+ if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
+ {
+ group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+ }
+
+ return group;
+}
+
+BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->setSpatialGroup(NULL);
+
+ if (!curp->removeObject(drawablep))
+ {
+ OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
+ }
+
+ assert_octree_valid(mOctree);
+
+ return TRUE;
+}
+
+void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ // sanity check submitted by open source user bushing Spatula
+ // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
+ if (!drawablep)
+ {
+ OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl;
+ return;
+ }
+
+ BOOL was_visible = curp ? curp->isVisible() : FALSE;
+
+ if (curp && curp->mSpatialPartition != this)
+ {
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+ if (curp->mSpatialPartition->remove(drawablep, curp))
+ {
+ put(drawablep, was_visible);
+ return;
+ }
+ else
+ {
+ OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl;
+ }
+ }
+
+ if (curp && curp->updateInGroup(drawablep, immediate))
+ {
+ // Already updated, don't need to do anything
+ assert_octree_valid(mOctree);
+ return;
+ }
+
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+ if (curp && !remove(drawablep, curp))
+ {
+ OCT_ERRS << "Move couldn't find existing spatial group!" << llendl;
+ }
+
+ put(drawablep, was_visible);
+}
+
+class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ const LLVector4a& mOffset;
+
+ LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
+ }
+};
+
+void LLSpatialPartition::shift(const LLVector4a &offset)
+{ //shift octree node bounding boxes by offset
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ LLSpatialShift shifter(offset);
+ shifter.traverse(mOctree);
+}
+
+class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ LLOctreeCull(LLCamera* camera)
+ : mCamera(camera), mRes(0) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ group->checkOcclusion();
+
+ if (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ gPipeline.markOccluder(group);
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (earlyFail(group))
+ {
+ return;
+ }
+
+ if (mRes == 2 ||
+ (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
+ { //fully in, just add everything
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ else
+ {
+ mRes = frustumCheck(group);
+
+ if (mRes)
+ { //at least partially in, run on down
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+
+ mRes = 0;
+ }
+ }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+ if (res != 0)
+ {
+ res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+ }
+ return res;
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+ if (res != 0)
+ {
+ res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+ }
+ return res;
+ }
+
+ virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
+ {
+ if (branch->getElementCount() == 0) //no elements
+ {
+ return false;
+ }
+ else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
+ {
+ return true;
+ }
+ else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual void preprocess(LLSpatialGroup* group)
+ {
+
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ if (group->needsUpdate() ||
+ group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
+ {
+ group->doOcclusion(mCamera);
+ }
+ gPipeline.markNotCulled(group, *mCamera);
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ preprocess(group);
+
+ if (checkObjects(branch, group))
+ {
+ processGroup(group);
+ }
+ }
+
+ LLCamera *mCamera;
+ S32 mRes;
+};
+
+class LLOctreeCullNoFarClip : public LLOctreeCull
+{
+public:
+ LLOctreeCullNoFarClip(LLCamera* camera)
+ : LLOctreeCull(camera) { }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+ return res;
+ }
+};
+
+class LLOctreeCullShadow : public LLOctreeCull
+{
+public:
+ LLOctreeCullShadow(LLCamera* camera)
+ : LLOctreeCull(camera) { }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+ }
+};
+
+class LLOctreeCullVisExtents: public LLOctreeCullShadow
+{
+public:
+ LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
+ : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ if (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (earlyFail(group))
+ {
+ return;
+ }
+
+ if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
+ mRes == 2)
+ { //don't need to do frustum check
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ else
+ {
+ mRes = frustumCheck(group);
+
+ if (mRes)
+ { //at least partially in, run on down
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+
+ mRes = 0;
+ }
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty())
+
+ if (mRes < 2)
+ {
+ if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0)
+ {
+ mEmpty = FALSE;
+ update_min_max(mMin, mMax, group->mObjectExtents[0]);
+ update_min_max(mMin, mMax, group->mObjectExtents[1]);
+ }
+ }
+ else
+ {
+ mEmpty = FALSE;
+ update_min_max(mMin, mMax, group->mExtents[0]);
+ update_min_max(mMin, mMax, group->mExtents[1]);
+ }
+ }
+
+ BOOL mEmpty;
+ LLVector4a& mMin;
+ LLVector4a& mMax;
+};
+
+class LLOctreeCullDetectVisible: public LLOctreeCullShadow
+{
+public:
+ LLOctreeCullDetectVisible(LLCamera* camera)
+ : LLOctreeCullShadow(camera), mResult(FALSE) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ if (mResult || //already found a node, don't check any more
+ (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ if (group->isVisible())
+ {
+ mResult = TRUE;
+ }
+ }
+
+ BOOL mResult;
+};
+
+class LLOctreeSelect : public LLOctreeCull
+{
+public:
+ LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
+ : LLOctreeCull(camera), mResults(results) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group) { return false; }
+ virtual void preprocess(LLSpatialGroup* group) { }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ if (!drawable->isDead())
+ {
+ if (drawable->isSpatialBridge())
+ {
+ drawable->setVisible(*mCamera, mResults, TRUE);
+ }
+ else
+ {
+ mResults->push_back(drawable);
+ }
+ }
+ }
+ }
+
+ std::vector<LLDrawable*>* mResults;
+};
+
+void drawBox(const LLVector3& c, const LLVector3& r)
+{
+ LLVertexBuffer::unbind();
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ //left front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ //right front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+ //right back
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+ //left back
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+ //left front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ gGL.end();
+
+ //bottom
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+ gGL.end();
+
+ //top
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+ gGL.end();
+}
+
+void drawBox(const LLVector4a& c, const LLVector4a& r)
+{
+ drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
+}
+
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
+{
+ LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
+ LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
+ LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
+ LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
+
+ gGL.begin(LLRender::LINES);
+
+ //top
+ gGL.vertex3fv((pos+v1).mV);
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos+v1).mV);
+
+ //bottom
+ gGL.vertex3fv((pos-v1).mV);
+ gGL.vertex3fv((pos-v2).mV);
+ gGL.vertex3fv((pos-v2).mV);
+ gGL.vertex3fv((pos-v3).mV);
+ gGL.vertex3fv((pos-v3).mV);
+ gGL.vertex3fv((pos-v4).mV);
+ gGL.vertex3fv((pos-v4).mV);
+ gGL.vertex3fv((pos-v1).mV);
+
+ //right
+ gGL.vertex3fv((pos+v1).mV);
+ gGL.vertex3fv((pos-v3).mV);
+
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos-v2).mV);
+
+ //left
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos-v4).mV);
+
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos-v1).mV);
+
+ gGL.end();
+}
+
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+ drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
+class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ virtual void visit(const LLOctreeNode<LLDrawable>* state)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+ group->destroyGL();
+
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
+ {
+ gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
+ }
+ }
+
+ for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ traverse(bridge->mOctree);
+ }
+ }
+};
+
+void LLSpatialPartition::restoreGL()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+}
+
+void LLSpatialPartition::resetVertexBuffers()
+{
+ LLOctreeDirty dirty;
+ dirty.traverse(mOctree);
+}
+
+BOOL LLSpatialPartition::isOcclusionEnabled()
+{
+ return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
+}
+
+BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
+{
+ LLVector4a visMina, visMaxa;
+ visMina.load3(visMin.mV);
+ visMaxa.load3(visMax.mV);
+
+ {
+ LLFastTimer ftm(FTM_CULL_REBOUND);
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+ group->rebound();
+ }
+
+ LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
+ vis.traverse(mOctree);
+
+ visMin.set(visMina.getF32ptr());
+ visMax.set(visMaxa.getF32ptr());
+ return vis.mEmpty;
+}
+
+BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
+{
+ LLOctreeCullDetectVisible vis(&camera);
+ vis.traverse(mOctree);
+ return vis.mResult;
+}
+
+S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+#if LL_OCTREE_PARANOIA_CHECK
+ ((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
+ {
+ LLFastTimer ftm(FTM_CULL_REBOUND);
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+ group->rebound();
+ }
+
+#if LL_OCTREE_PARANOIA_CHECK
+ ((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+
+ if (for_select)
+ {
+ LLOctreeSelect selecter(&camera, results);
+ selecter.traverse(mOctree);
+ }
+ else if (LLPipeline::sShadowRender)
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCullShadow culler(&camera);
+ culler.traverse(mOctree);
+ }
+ else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCullNoFarClip culler(&camera);
+ culler.traverse(mOctree);
+ }
+ else
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCull culler(&camera);
+ culler.traverse(mOctree);
+ }
+
+ return 0;
+}
+
+BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
+{
+ if (camera->getOrigin().isExactlyZero())
+ {
+ return FALSE;
+ }
+
+ const F32 vel = SG_OCCLUSION_FUDGE*2.f;
+ LLVector4a fudge;
+ fudge.splat(vel);
+
+ const LLVector4a& c = group->mBounds[0];
+ LLVector4a r;
+ r.setAdd(group->mBounds[1], fudge);
+
+ /*if (r.magVecSquared() > 1024.0*1024.0)
+ {
+ return TRUE;
+ }*/
+
+ LLVector4a e;
+ e.load3(camera->getOrigin().mV);
+
+ LLVector4a min;
+ min.setSub(c,r);
+ LLVector4a max;
+ max.setAdd(c,r);
+
+ S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
+ if (lt)
+ {
+ return FALSE;
+ }
+
+ S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
+ if (gt)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void pushVerts(LLDrawInfo* params, U32 mask)
+{
+ LLRenderPass::applyModelMatrix(*params);
+ params->mVertexBuffer->setBuffer(mask);
+ params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+ params->mStart, params->mEnd, params->mCount, params->mOffset);
+}
+
+void pushVerts(LLSpatialGroup* group, U32 mask)
+{
+ LLDrawInfo* params = NULL;
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ params = *j;
+ pushVerts(params, mask);
+ }
+ }
+}
+
+void pushVerts(LLFace* face, U32 mask)
+{
+ llassert(face->verify());
+
+ LLVertexBuffer* buffer = face->getVertexBuffer();
+
+ if (buffer && (face->getGeomCount() >= 3))
+ {
+ buffer->setBuffer(mask);
+ U16 start = face->getGeomStart();
+ U16 end = start + face->getGeomCount()-1;
+ U32 count = face->getIndicesCount();
+ U16 offset = face->getIndicesStart();
+ buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+ }
+}
+
+void pushVerts(LLDrawable* drawable, U32 mask)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ pushVerts(drawable->getFace(i), mask);
+ }
+}
+
+void pushVerts(LLVolume* volume)
+{
+ LLVertexBuffer::unbind();
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
+ }
+}
+
+void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
+{
+ if (buffer)
+ {
+ buffer->setBuffer(mask);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ }
+}
+
+void pushBufferVerts(LLSpatialGroup* group, U32 mask)
+{
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ if (!group->mDrawMap.empty())
+ {
+ LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
+ LLRenderPass::applyModelMatrix(*params);
+
+ pushBufferVerts(group->mVertexBuffer, mask);
+
+ for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+ {
+ for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k)
+ {
+ pushBufferVerts(*k, mask);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ drawBox(group->mBounds[0], group->mBounds[1]);
+ }
+}
+
+void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
+{
+ LLDrawInfo* params = NULL;
+
+ LLColor4 colors[] = {
+ LLColor4::green,
+ LLColor4::green1,
+ LLColor4::green2,
+ LLColor4::green3,
+ LLColor4::green4,
+ LLColor4::green5,
+ LLColor4::green6
+ };
+
+ static const U32 col_count = LL_ARRAY_SIZE(colors);
+
+ U32 col = 0;
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ params = *j;
+ LLRenderPass::applyModelMatrix(*params);
+ gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
+ params->mVertexBuffer->setBuffer(mask);
+ params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+ params->mStart, params->mEnd, params->mCount, params->mOffset);
+ col = (col+1)%col_count;
+ }
+ }
+}
+
+void renderOctree(LLSpatialGroup* group)
+{
+ //render solid object bounding box, color
+ //coded by buffer usage and activity
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+ LLVector4 col;
+ if (group->mBuilt > 0.f)
+ {
+ group->mBuilt -= 2.f * gFrameIntervalSeconds;
+ if (group->mBufferUsage == GL_STATIC_DRAW_ARB)
+ {
+ col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
+ }
+ else
+ {
+ col.setVec(0.1f,0.1f,1,0.1f);
+ //col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
+ }
+
+ if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
+ {
+ LLGLDepthTest gl_depth(FALSE, FALSE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4f(1,0,0,group->mBuilt);
+ gGL.flush();
+ glLineWidth(5.f);
+ drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+ gGL.flush();
+ glLineWidth(1.f);
+ gGL.flush();
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ }
+
+ for (S32 j = 0; j < drawable->getNumFaces(); j++)
+ {
+ LLFace* face = drawable->getFace(j);
+ if (face->getVertexBuffer())
+ {
+ if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
+ {
+ gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
+ }
+ else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
+ {
+ gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
+ }
+ else
+ {
+ continue;
+ }
+
+ face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
+ // (face->mExtents[1]-face->mExtents[0])*0.5f);
+ face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
+ }
+ }
+
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.popMatrix();
+ }
+ }
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ gGL.diffuseColor4f(1,1,1,1);
+ }
+ }
+ else
+ {
+ if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty()
+ && group->mSpatialPartition->mRenderByGroup)
+ {
+ col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
+ }
+ else
+ {
+ col.setVec(0.1f, 0.1f, 1.f, 0.1f);
+ }
+ }
+
+ gGL.diffuseColor4fv(col.mV);
+ LLVector4a fudge;
+ fudge.splat(0.001f);
+ LLVector4a size = group->mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(fudge);
+
+ //{
+ // LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ // drawBox(group->mObjectBounds[0], fudge);
+ //}
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ //if (group->mBuilt <= 0.f)
+ {
+ //draw opaque outline
+ //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
+ //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+
+ gGL.diffuseColor4f(0,1,1,1);
+ drawBoxOutline(group->mBounds[0],group->mBounds[1]);
+
+ //draw bounding box for draw info
+ /*if (group->mSpatialPartition->mRenderByGroup)
+ {
+ gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ LLDrawInfo* draw_info = *j;
+ LLVector4a center;
+ center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
+ }
+ }
+ }*/
+ }
+
+// LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
+// gGL.diffuseColor4f(0,1,0,1);
+// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
+}
+
+void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
+{
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ LLGLEnable cull(GL_CULL_FACE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+ !group->getData().empty();
+
+ if (render_objects)
+ {
+ LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+ gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
+ gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
+ pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ {
+ LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
+
+ if (render_objects)
+ {
+ gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f);
+ gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
+ pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ if (render_objects)
+ {
+ gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
+ gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f);
+ pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+ }
+ /*else if (camera && group->mOcclusionVerts.notNull())
+ {
+ LLVertexBuffer::unbind();
+ group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f);
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f);
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }*/
+ }
+}
+
+void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
+{
+ gGL.diffuseColor4fv(color.mV);
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV);
+ gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV);
+ gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV);
+ gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV);
+ gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV);
+ gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV);
+ }
+ gGL.end();
+}
+
+void renderUpdateType(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+ {
+ return;
+ }
+ LLGLEnable blend(GL_BLEND);
+ switch (vobj->getLastUpdateType())
+ {
+ case OUT_FULL:
+ gGL.diffuseColor4f(0,1,0,0.5f);
+ break;
+ case OUT_TERSE_IMPROVED:
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ break;
+ case OUT_FULL_COMPRESSED:
+ if (vobj->getLastUpdateCached())
+ {
+ gGL.diffuseColor4f(1,0,0,0.5f);
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,1,0,0.5f);
+ }
+ break;
+ case OUT_FULL_CACHED:
+ gGL.diffuseColor4f(0,0,1,0.5f);
+ break;
+ default:
+ llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+ break;
+ };
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
+void renderComplexityDisplay(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj)
+ {
+ return;
+ }
+
+ LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj);
+
+ if (!voVol)
+ {
+ return;
+ }
+
+ if (!voVol->isRoot())
+ {
+ return;
+ }
+
+ LLVOVolume::texture_cost_t textures;
+ F32 cost = (F32) voVol->getRenderCost(textures);
+
+ // add any child volumes
+ LLViewerObject::const_child_list_t children = voVol->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ const LLViewerObject *child = *iter;
+ const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
+ if (child_volume)
+ {
+ cost += child_volume->getRenderCost(textures);
+ }
+ }
+
+ // add texture cost
+ for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+ {
+ // add the cost of each individual texture in the linkset
+ cost += iter->second;
+ }
+
+ F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
+
+
+
+ // allow user to set a static color scale
+ if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
+ {
+ cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
+ }
+
+ F32 cost_ratio = cost / cost_max;
+
+ // cap cost ratio at 1.0f in case cost_max is at a low threshold
+ cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
+
+ LLGLEnable blend(GL_BLEND);
+
+ LLColor4 color;
+ const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
+ const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
+ const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
+
+ if (cost_ratio < 0.5f)
+ {
+ color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
+ }
+ else
+ {
+ color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
+ }
+
+ LLSD color_val = color.getValue();
+
+ // don't highlight objects below the threshold
+ if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
+ {
+ glColor4f(color[0],color[1],color[2],0.5f);
+
+
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+ LLViewerObject::const_child_list_t children = voVol->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ const LLViewerObject *child = *iter;
+ if (child)
+ {
+ num_faces = child->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+ }
+ }
+ }
+
+ voVol->setDebugText(llformat("%4.0f", cost));
+}
+
+void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
+{
+ if (set_color)
+ {
+ if (drawable->isSpatialBridge())
+ {
+ gGL.diffuseColor4f(1,0.5f,0,1);
+ }
+ else if (drawable->getVOVolume())
+ {
+ if (drawable->isRoot())
+ {
+ gGL.diffuseColor4f(1,1,0,1);
+ }
+ else
+ {
+ gGL.diffuseColor4f(0,1,0,1);
+ }
+ }
+ else if (drawable->getVObj())
+ {
+ switch (drawable->getVObj()->getPCode())
+ {
+ case LLViewerObject::LL_VO_SURFACE_PATCH:
+ gGL.diffuseColor4f(0,1,1,1);
+ break;
+ case LLViewerObject::LL_VO_CLOUDS:
+ // no longer used
+ break;
+ case LLViewerObject::LL_VO_PART_GROUP:
+ case LLViewerObject::LL_VO_HUD_PART_GROUP:
+ gGL.diffuseColor4f(0,0,1,1);
+ break;
+ case LLViewerObject::LL_VO_VOID_WATER:
+ case LLViewerObject::LL_VO_WATER:
+ gGL.diffuseColor4f(0,0.5f,1,1);
+ break;
+ case LL_PCODE_LEGACY_TREE:
+ gGL.diffuseColor4f(0,0.5f,0,1);
+ break;
+ default:
+ gGL.diffuseColor4f(1,0,1,1);
+ break;
+ }
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,0,0,1);
+ }
+ }
+
+ const LLVector4a* ext;
+ LLVector4a pos, size;
+
+ //render face bounding boxes
+ for (S32 i = 0; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+
+ ext = facep->mExtents;
+
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ drawBoxOutline(pos,size);
+ }
+
+ //render drawable bounding box
+ ext = drawable->getSpatialExtents();
+
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ LLViewerObject* vobj = drawable->getVObj();
+ if (vobj && vobj->onActiveList())
+ {
+ gGL.flush();
+ glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
+ //glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
+ stop_glerror();
+ drawBoxOutline(pos,size);
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ else
+ {
+ drawBoxOutline(pos,size);
+ }
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+ LLVertexBuffer::unbind();
+
+ LLVOVolume* vol = drawablep->getVOVolume();
+ if (vol)
+ {
+ LLVolume* volume = vol->getVolume();
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ gGL.begin(LLRender::LINES);
+ LLVector4a n,p;
+
+ n.setMul(face.mNormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.diffuseColor4f(1,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+
+ if (face.mBinormals)
+ {
+ n.setMul(face.mBinormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.diffuseColor4f(0,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+ }
+ gGL.end();
+ }
+ }
+
+ gGL.popMatrix();
+ }
+}
+
+S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
+{
+ const S32 DEFAULT_DETAIL = 1;
+ const F32 LARGE_THRESHOLD = 5.f;
+ const F32 MEGA_THRESHOLD = 25.f;
+
+ S32 detail = DEFAULT_DETAIL;
+ F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
+
+ if (avg_scale > LARGE_THRESHOLD)
+ {
+ detail += 1;
+ if (avg_scale > MEGA_THRESHOLD)
+ {
+ detail += 1;
+ }
+ }
+
+ return detail;
+}
+
+void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
+{
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ const LLVector3 center(0,0,0);
+ const LLVector3 size(0.25f,0.25f,0.25f);
+
+ if (decomp)
+ {
+ if (!decomp->mBaseHullMesh.empty())
+ {
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+ }
+ else
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ gGL.diffuseColor4f(0,1,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+}
+
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
+{
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonOffset(3.f, 3.f);
+ glLineWidth(3.f);
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
+{
+ U8 physics_type = volume->getPhysicsShapeType();
+
+ if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
+ {
+ return;
+ }
+
+ //not allowed to return at this point without rendering *something*
+
+ F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
+ F32 cost = volume->getObjectCost();
+
+ LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
+ LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
+ LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
+
+ F32 normalizedCost = 1.f - exp( -(cost / threshold) );
+
+ LLColor4 color;
+ if ( normalizedCost <= 0.5f )
+ {
+ color = lerp( low, mid, 2.f * normalizedCost );
+ }
+ else
+ {
+ color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
+ }
+
+ LLColor4 line_color = color*0.5f;
+
+ U32 data_mask = LLVertexBuffer::MAP_VERTEX;
+
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+
+ LLPhysicsVolumeParams physics_params(volume_params,
+ physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+
+ LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
+ LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
+
+ U32 type = physics_spec.getType();
+
+ LLVector3 center(0,0,0);
+ LLVector3 size(0.25f,0.25f,0.25f);
+
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
+
+ if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
+ {
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ if (decomp)
+ { //render a physics based mesh
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (!decomp->mHull.empty())
+ { //decomposition exists, use that
+
+ if (decomp->mMesh.empty())
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ }
+
+ for (U32 i = 0; i < decomp->mMesh.size(); ++i)
+ {
+ render_hull(decomp->mMesh[i], color, line_color);
+ }
+ }
+ else if (!decomp->mPhysicsShapeMesh.empty())
+ {
+ //decomp has physics mesh, render that mesh
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else
+ { //no mesh or decomposition, render base hull
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+
+ if (decomp->mPhysicsShapeMesh.empty())
+ {
+ //attempt to fetch physics shape mesh if available
+ gMeshRepo.fetchPhysicsShape(mesh_id);
+ }
+ }
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,1,0);
+ drawBoxOutline(center, size);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
+ type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ if (volume->isMesh())
+ {
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+ }
+ else
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (!phys_volume->mHullPoints)
+ { //build convex hull
+ std::vector<LLVector3> pos;
+ std::vector<U16> index;
+
+ S32 index_offset = 0;
+
+ for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = phys_volume->getVolumeFace(i);
+ if (index_offset + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (S32 j = 0; j < face.mNumIndices; ++j)
+ {
+ index.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+
+ if (!pos.empty() && !index.empty())
+ {
+ LLCDMeshData mesh;
+ mesh.mIndexBase = &index[0];
+ mesh.mVertexBase = pos[0].mV;
+ mesh.mNumVertices = pos.size();
+ mesh.mVertexStrideBytes = 12;
+ mesh.mIndexStrideBytes = 6;
+ mesh.mIndexType = LLCDMeshData::INT_16;
+
+ mesh.mNumTriangles = index.size()/3;
+
+ LLCDMeshData res;
+
+ LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
+
+ //copy res into phys_volume
+ phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
+ phys_volume->mNumHullPoints = res.mNumVertices;
+
+ S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
+ phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
+ phys_volume->mNumHullIndices = res.mNumTriangles*3;
+
+ const F32* v = res.mVertexBase;
+
+ for (S32 i = 0; i < res.mNumVertices; ++i)
+ {
+ F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
+ phys_volume->mHullPoints[i].load3(p);
+ }
+
+ if (res.mIndexType == LLCDMeshData::INT_16)
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = idx[0];
+ phys_volume->mHullIndices[i*3+1] = idx[1];
+ phys_volume->mHullIndices[i*3+2] = idx[2];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
+ phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
+ phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
+ }
+ }
+ }
+ }
+
+ if (phys_volume->mHullPoints)
+ {
+ //render hull
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::unbind();
+
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,0,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
+ {
+ LLVector3 center = physics_spec.getCenter();
+ LLVector3 scale = physics_spec.getScale();
+ LLVector3 vscale = volume->getScale()*2.f;
+ scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
+
+ gGL.diffuseColor4fv(color.mV);
+ drawBox(center, scale);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
+ {
+ /*LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ gGL.diffuseColor4fv(color.mV);
+ pushVerts(sphere);
+ LLPrimitive::sVolumeManager->unrefVolume(sphere);*/
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ gGL.diffuseColor4fv(color.mV);
+ pushVerts(cylinder);
+ LLPrimitive::sVolumeManager->unrefVolume(cylinder);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4fv(line_color.mV);
+ pushVerts(phys_volume);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(phys_volume);
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (phys_volume->mHullPoints && phys_volume->mHullIndices)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ gGL.diffuseColor4fv(line_color.mV);
+ gGL.syncMatrices();
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,0,1);
+ drawBoxOutline(center, size);
+ gMeshRepo.buildHull(volume_params, detail);
+ }
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
+ {
+ //TODO: implement sculpted prim physics display
+ }
+ else
+ {
+ llerrs << "Unhandled type" << llendl;
+ }
+
+ gGL.popMatrix();
+}
+
+void renderPhysicsShapes(LLSpatialGroup* group)
+{
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ LLVOVolume* volume = drawable->getVOVolume();
+ if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ renderPhysicsShape(drawable, volume);
+ gGL.popMatrix();
+ }
+ else
+ {
+ renderPhysicsShape(drawable, volume);
+ }
+ }
+ else
+ {
+ LLViewerObject* object = drawable->getVObj();
+ if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
+ {
+ //push face vertices for terrain
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (buff)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
+ buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+
+ gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+void renderTexturePriority(LLDrawable* drawable)
+{
+ for (int face=0; face<drawable->getNumFaces(); ++face)
+ {
+ LLFace *facep = drawable->getFace(face);
+
+ LLVector4 cold(0,0,0.25f);
+ LLVector4 hot(1,0.25f,0.25f);
+
+ LLVector4 boost_cold(0,0,0,0);
+ LLVector4 boost_hot(0,1,0,1);
+
+ LLGLDisable blend(GL_BLEND);
+
+ //LLViewerTexture* imagep = facep->getTexture();
+ //if (imagep)
+ {
+
+ //F32 vsize = imagep->mMaxVirtualSize;
+ F32 vsize = facep->getPixelArea();
+
+ if (vsize > sCurMaxTexPriority)
+ {
+ sCurMaxTexPriority = vsize;
+ }
+
+ F32 t = vsize/sLastMaxTexPriority;
+
+ LLVector4 col = lerp(cold, hot, t);
+ gGL.diffuseColor4fv(col.mV);
+ }
+ //else
+ //{
+ // gGL.diffuseColor4f(1,0,1,1);
+ //}
+
+ LLVector4a center;
+ center.setAdd(facep->mExtents[1],facep->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(facep->mExtents[1],facep->mExtents[0]);
+ size.mul(0.5f);
+ size.add(LLVector4a(0.01f));
+ drawBox(center, size);
+
+ /*S32 boost = imagep->getBoostLevel();
+ if (boost>LLViewerTexture::BOOST_NONE)
+ {
+ F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1);
+ LLVector4 col = lerp(boost_cold, boost_hot, t);
+ LLGLEnable blend_on(GL_BLEND);
+ gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
+ gGL.diffuseColor4fv(col.mV);
+ drawBox(center, size);
+ gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }*/
+ }
+}
+
+void renderPoints(LLDrawable* drawablep)
+{
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+ if (drawablep->getNumFaces())
+ {
+ gGL.begin(LLRender::POINTS);
+ gGL.diffuseColor3f(1,1,1);
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
+ }
+ gGL.end();
+ }
+}
+
+void renderTextureAnim(LLDrawInfo* params)
+{
+ if (!params->mTextureMatrix)
+ {
+ return;
+ }
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(1,1,0,0.5f);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderBatchSize(LLDrawInfo* params)
+{
+ LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.f, 1.f);
+ gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor));
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderShadowFrusta(LLDrawInfo* params)
+{
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+ LLVector4a center;
+ center.setAdd(params->mExtents[1], params->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(params->mExtents[1],params->mExtents[0]);
+ size.mul(0.5f);
+
+ if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(1,0,0);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(0,1,0);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(0,0,1);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(1,0,1);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+}
+
+
+void renderLights(LLDrawable* drawablep)
+{
+ if (!drawablep->isLight())
+ {
+ return;
+ }
+
+ if (drawablep->getNumFaces())
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(0,1,1,0.5f);
+
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ {
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.diffuseColor4f(1,1,1,1);
+ drawBoxOutline(pos, size);
+ }
+
+ gGL.diffuseColor4f(1,1,0,1);
+ F32 rad = drawablep->getVOVolume()->getLightRadius();
+ drawBoxOutline(pos, LLVector4a(rad));
+ }
+}
+
+class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
+{
+public:
+
+
+ LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+ : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
+ {
+
+ }
+
+ void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ {
+ LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector3 center, size;
+
+ if (branch->getData().empty())
+ {
+ gGL.diffuseColor3f(1.f,0.2f,0.f);
+ center.set(branch->getCenter().getF32ptr());
+ size.set(branch->getSize().getF32ptr());
+ }
+ else
+ {
+ gGL.diffuseColor3f(0.75f, 1.f, 0.f);
+ center.set(vl->mBounds[0].getF32ptr());
+ size.set(vl->mBounds[1].getF32ptr());
+ }
+
+ drawBoxOutline(center, size);
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
+
+ if (i == 1)
+ {
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ }
+ else
+ {
+ gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f);
+ drawBoxOutline(center, size);
+ }
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(3.f);
+ }
+
+ gGL.begin(LLRender::TRIANGLES);
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end();
+ ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ gGL.vertex3fv(tri->mV[0]->getF32ptr());
+ gGL.vertex3fv(tri->mV[1]->getF32ptr());
+ gGL.vertex3fv(tri->mV[2]->getF32ptr());
+ }
+ gGL.end();
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ }
+ }
+};
+
+void renderRaycast(LLDrawable* drawablep)
+{
+ if (drawablep->getNumFaces())
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(0,1,1,0.5f);
+
+ if (drawablep->getVOVolume())
+ {
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ LLVolume* volume = vobj->getVolume();
+
+ bool transform = true;
+ if (drawablep->isState(LLDrawable::RIGGED))
+ {
+ volume = vobj->getRiggedVolume();
+ transform = false;
+ }
+
+ if (volume)
+ {
+ LLVector3 trans = drawablep->getRegion()->getOriginAgent();
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ gGL.pushMatrix();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
+
+ LLVector3 start, end;
+ if (transform)
+ {
+ start = vobj->agentPositionToVolume(gDebugRaycastStart);
+ end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+ }
+ else
+ {
+ start = gDebugRaycastStart;
+ end = gDebugRaycastEnd;
+ }
+
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+ LLVector4a dir;
+ dir.setSub(enda, starta);
+
+ gGL.flush();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ {
+ //render face positions
+ LLVertexBuffer::unbind();
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
+ gGL.syncMatrices();
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+
+ if (!volume->isUnique())
+ {
+ F32 t = 1.f;
+
+ if (!face.mOctree)
+ {
+ ((LLVolumeFace*) &face)->createOctree();
+ }
+
+ LLRenderOctreeRaycast render(starta, dir, &t);
+
+ render.traverse(face.mOctree);
+ }
+
+ gGL.popMatrix();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ }
+ }
+ else if (drawablep->isAvatar())
+ {
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
+ av->renderCollisionVolumes();
+ }
+ }
+
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ // draw intersection point
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLModelView);
+ LLVector3 translate = gDebugRaycastIntersection;
+ gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
+ LLCoordFrame orient;
+ orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
+ LLMatrix4 rotation;
+ orient.getRotMatrixToParent(rotation);
+ gGL.multMatrix((float*)rotation.mMatrix);
+
+ gGL.diffuseColor4f(1,0,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
+ gGL.diffuseColor4f(0,1,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
+ gGL.diffuseColor4f(0,0,1,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
+ gGL.popMatrix();
+
+ // draw bounding box of prim
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.diffuseColor4f(0,0.5f,0.5f,1);
+ drawBoxOutline(pos, size);
+ }
+ }
+}
+
+
+void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
+{
+ avatar->renderCollisionVolumes();
+}
+
+void renderAgentTarget(LLVOAvatar* avatar)
+{
+ // render these for self only (why, i don't know)
+ if (avatar->isSelf())
+ {
+ renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
+ renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
+ renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
+ renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
+ }
+}
+
+class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ //draw tight fit bounding boxes for spatial group
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
+ {
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderOctree(group);
+ stop_glerror();
+ }
+
+ //render visibility wireframe
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ {
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ gGL.flush();
+ gGL.pushMatrix();
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ renderVisibility(group, mCamera);
+ stop_glerror();
+ gGLLastMatrix = NULL;
+ gGL.popMatrix();
+ gGL.diffuseColor4f(1,1,1,1);
+ }
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+ {
+ return;
+ }
+
+ LLVector4a nodeCenter = group->mBounds[0];
+ LLVector4a octCenter = group->mOctreeNode->getCenter();
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+ {
+ if (!group->getData().empty())
+ {
+ gGL.diffuseColor3f(0,0,1);
+ drawBoxOutline(group->mObjectBounds[0],
+ group->mObjectBounds[1]);
+ }
+ }
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+ {
+ renderBoundingBox(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
+ {
+ renderNormals(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
+ {
+ if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f);
+ const LLVector4a* ext = drawable->getSpatialExtents();
+ LLVector4a center;
+ center.setAdd(ext[0], ext[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
+ }
+ }
+
+ if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ renderTexturePriority(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
+ {
+ renderPoints(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
+ {
+ renderLights(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ renderRaycast(drawable);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+ {
+ renderUpdateType(drawable);
+ }
+ if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
+ {
+ renderComplexityDisplay(drawable);
+ }
+
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
+
+ if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME))
+ {
+ renderAvatarCollisionVolumes(avatar);
+ }
+
+ if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
+ {
+ renderAgentTarget(avatar);
+ }
+
+
+ if (gDebugGL)
+ {
+ for (U32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* facep = drawable->getFace(i);
+ U8 index = facep->getTextureIndex();
+ if (facep->mDrawInfo)
+ {
+ if (index < 255)
+ {
+ if (facep->mDrawInfo->mTextureList.size() <= index)
+ {
+ llerrs << "Face texture index out of bounds." << llendl;
+ }
+ else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
+ {
+ llerrs << "Face texture index incorrect." << llendl;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo* draw_info = *j;
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM))
+ {
+ renderTextureAnim(draw_info);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
+ {
+ renderBatchSize(draw_info);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ renderShadowFrusta(draw_info);
+ }
+ }
+ }
+ }
+};
+
+
+class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderPhysicsShapes(group);
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+
+ }
+};
+
+class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+ {
+ return;
+ }
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ renderBoundingBox(drawable, FALSE);
+ }
+ }
+};
+
+void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
+{
+ LLOctreePushBBoxVerts pusher(camera);
+ pusher.traverse(mOctree);
+}
+
+class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
+
+ LLOctreeStateCheck()
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mInheritedMask[i] = 0;
+ }
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ node->accept(this);
+
+
+ U32 temp[LLViewerCamera::NUM_CAMERAS];
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ temp[i] = mInheritedMask[i];
+ mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED;
+ }
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mInheritedMask[i] = temp[i];
+ }
+ }
+
+
+ virtual void visit(const LLOctreeNode<LLDrawable>* state)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
+ {
+ llerrs << "Spatial group failed inherited mask test." << llendl;
+ }
+ }
+
+ if (group->isState(LLSpatialGroup::DIRTY))
+ {
+ assert_parent_state(group, LLSpatialGroup::DIRTY);
+ }
+ }
+
+ void assert_parent_state(LLSpatialGroup* group, U32 state)
+ {
+ LLSpatialGroup* parent = group->getParent();
+ while (parent)
+ {
+ if (!parent->isState(state))
+ {
+ llerrs << "Spatial group failed parent state check." << llendl;
+ }
+ parent = parent->getParent();
+ }
+ }
+};
+
+
+void LLSpatialPartition::renderPhysicsShapes()
+{
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ gGL.flush();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glLineWidth(3.f);
+ LLOctreeRenderPhysicsShapes render_physics(camera);
+ render_physics.traverse(mOctree);
+ gGL.flush();
+ glLineWidth(1.f);
+}
+
+void LLSpatialPartition::renderDebug()
+{
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
+ LLPipeline::RENDER_DEBUG_OCCLUSION |
+ LLPipeline::RENDER_DEBUG_LIGHTS |
+ LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+ LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
+ LLPipeline::RENDER_DEBUG_BBOXES |
+ LLPipeline::RENDER_DEBUG_NORMALS |
+ LLPipeline::RENDER_DEBUG_POINTS |
+ LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
+ LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
+ LLPipeline::RENDER_DEBUG_RAYCAST |
+ LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
+ LLPipeline::RENDER_DEBUG_AGENT_TARGET |
+ //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+ LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
+ LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
+ {
+ return;
+ }
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.bind();
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
+ sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
+ sCurMaxTexPriority = 0.f;
+ }
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ LLGLDisable cullface(GL_CULL_FACE);
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gPipeline.disableLights();
+
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ LLOctreeStateCheck checker;
+ checker.traverse(mOctree);
+
+ LLOctreeRenderNonOccluded render_debug(camera);
+ render_debug.traverse(mOctree);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.unbind();
+ }
+}
+
+void LLSpatialGroup::drawObjectBox(LLColor4 col)
+{
+ gGL.diffuseColor4fv(col.mV);
+ LLVector4a size;
+ size = mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(LLVector4a(0.001f));
+ drawBox(mObjectBounds[0], size);
+}
+
+bool LLSpatialPartition::isHUDPartition()
+{
+ return mPartitionType == LLViewerRegion::PARTITION_HUD ;
+}
+
+BOOL LLSpatialPartition::isVisible(const LLVector3& v)
+{
+ if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ LLVector3 mStart;
+ LLVector3 mEnd;
+ S32 *mFaceHit;
+ LLVector3 *mIntersection;
+ LLVector2 *mTexCoord;
+ LLVector3 *mNormal;
+ LLVector3 *mBinormal;
+ LLDrawable* mHit;
+ BOOL mPickTransparent;
+
+ LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent,
+ S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal)
+ : mStart(start),
+ mEnd(end),
+ mFaceHit(face_hit),
+ mIntersection(intersection),
+ mTexCoord(tex_coord),
+ mNormal(normal),
+ mBinormal(binormal),
+ mHit(NULL),
+ mPickTransparent(pick_transparent)
+ {
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ check(*i);
+ }
+ }
+
+ virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
+ {
+ node->accept(this);
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ const LLSpatialGroup::OctreeNode* child = node->getChild(i);
+ LLVector3 res;
+
+ LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
+
+ LLVector4a size;
+ LLVector4a center;
+
+ size = group->mBounds[1];
+ center = group->mBounds[0];
+
+ LLVector3 local_start = mStart;
+ LLVector3 local_end = mEnd;
+
+ if (group->mSpatialPartition->isBridge())
+ {
+ LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix();
+ local_matrix.invert();
+
+ local_start = mStart * local_matrix;
+ local_end = mEnd * local_matrix;
+ }
+
+ LLVector4a start, end;
+ start.load3(local_start.mV);
+ end.load3(local_end.mV);
+
+ if (LLLineSegmentBoxIntersect(start, end, center, size))
+ {
+ check(child);
+ }
+ }
+
+ return mHit;
+ }
+
+ virtual bool check(LLDrawable* drawable)
+ {
+ LLVector3 local_start = mStart;
+ LLVector3 local_end = mEnd;
+
+ if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible())
+ {
+ return false;
+ }
+
+ if (drawable->isSpatialBridge())
+ {
+ LLSpatialPartition *part = drawable->asPartition();
+ LLSpatialBridge* bridge = part->asBridge();
+ if (bridge && gPipeline.hasRenderType(bridge->mDrawableType))
+ {
+ check(part->mOctree);
+ }
+ }
+ else
+ {
+ LLViewerObject* vobj = drawable->getVObj();
+
+ if (vobj)
+ {
+ LLVector3 intersection;
+ bool skip_check = false;
+ if (vobj->isAvatar())
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*) vobj;
+ if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools))
+ {
+ LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal);
+ if (hit)
+ {
+ mEnd = intersection;
+ if (mIntersection)
+ {
+ *mIntersection = intersection;
+ }
+
+ mHit = hit->mDrawable;
+ skip_check = true;
+ }
+
+ }
+ }
+
+ if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal))
+ {
+ mEnd = intersection; // shorten ray so we only find CLOSER hits
+ if (mIntersection)
+ {
+ *mIntersection = intersection;
+ }
+
+ mHit = vobj->mDrawable;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
+LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit, // return the face hit
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+
+{
+ LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+ LLDrawable* drawable = intersect.check(mOctree);
+
+ return drawable;
+}
+
+LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
+ LLViewerTexture* texture, LLVertexBuffer* buffer,
+ BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
+:
+ mVertexBuffer(buffer),
+ mTexture(texture),
+ mTextureMatrix(NULL),
+ mModelMatrix(NULL),
+ mStart(start),
+ mEnd(end),
+ mCount(count),
+ mOffset(offset),
+ mFullbright(fullbright),
+ mBump(bump),
+ mParticle(particle),
+ mPartSize(part_size),
+ mVSize(0.f),
+ mGroup(NULL),
+ mFace(NULL),
+ mDistance(0.f),
+ mDrawMode(LLRender::TRIANGLES)
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+
+ mDebugColor = (rand() << 16) + rand();
+}
+
+LLDrawInfo::~LLDrawInfo()
+{
+ /*if (LLSpatialGroup::sNoDelete)
+ {
+ llerrs << "LLDrawInfo deleted illegally!" << llendl;
+ }*/
+
+ if (mFace)
+ {
+ mFace->setDrawInfo(NULL);
+ }
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+}
+
+void LLDrawInfo::validate()
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+}
+
+LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
+{
+ return new LLVertexBuffer(type_mask, usage);
+}
+
+LLCullResult::LLCullResult()
+{
+ clear();
+}
+
+void LLCullResult::clear()
+{
+ mVisibleGroupsSize = 0;
+ mVisibleGroupsEnd = mVisibleGroups.begin();
+
+ mAlphaGroupsSize = 0;
+ mAlphaGroupsEnd = mAlphaGroups.begin();
+
+ mOcclusionGroupsSize = 0;
+ mOcclusionGroupsEnd = mOcclusionGroups.begin();
+
+ mDrawableGroupsSize = 0;
+ mDrawableGroupsEnd = mDrawableGroups.begin();
+
+ mVisibleListSize = 0;
+ mVisibleListEnd = mVisibleList.begin();
+
+ mVisibleBridgeSize = 0;
+ mVisibleBridgeEnd = mVisibleBridge.begin();
+
+
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+ {
+ for (U32 j = 0; j < mRenderMapSize[i]; j++)
+ {
+ mRenderMap[i][j] = 0;
+ }
+ mRenderMapSize[i] = 0;
+ mRenderMapEnd[i] = mRenderMap[i].begin();
+ }
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
+{
+ return mVisibleGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
+{
+ return mVisibleGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
+{
+ return mAlphaGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
+{
+ return mAlphaGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
+{
+ return mOcclusionGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
+{
+ return mOcclusionGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
+{
+ return mDrawableGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
+{
+ return mDrawableGroupsEnd;
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
+{
+ return mVisibleList.begin();
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
+{
+ return mVisibleListEnd;
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
+{
+ return mVisibleBridge.begin();
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
+{
+ return mVisibleBridgeEnd;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
+{
+ return mRenderMap[type].begin();
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
+{
+ return mRenderMapEnd[type];
+}
+
+void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
+{
+ if (mVisibleGroupsSize < mVisibleGroups.size())
+ {
+ mVisibleGroups[mVisibleGroupsSize] = group;
+ }
+ else
+ {
+ mVisibleGroups.push_back(group);
+ }
+ ++mVisibleGroupsSize;
+ mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
+}
+
+void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
+{
+ if (mAlphaGroupsSize < mAlphaGroups.size())
+ {
+ mAlphaGroups[mAlphaGroupsSize] = group;
+ }
+ else
+ {
+ mAlphaGroups.push_back(group);
+ }
+ ++mAlphaGroupsSize;
+ mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
+}
+
+void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
+{
+ if (mOcclusionGroupsSize < mOcclusionGroups.size())
+ {
+ mOcclusionGroups[mOcclusionGroupsSize] = group;
+ }
+ else
+ {
+ mOcclusionGroups.push_back(group);
+ }
+ ++mOcclusionGroupsSize;
+ mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
+}
+
+void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
+{
+ if (mDrawableGroupsSize < mDrawableGroups.size())
+ {
+ mDrawableGroups[mDrawableGroupsSize] = group;
+ }
+ else
+ {
+ mDrawableGroups.push_back(group);
+ }
+ ++mDrawableGroupsSize;
+ mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
+}
+
+void LLCullResult::pushDrawable(LLDrawable* drawable)
+{
+ if (mVisibleListSize < mVisibleList.size())
+ {
+ mVisibleList[mVisibleListSize] = drawable;
+ }
+ else
+ {
+ mVisibleList.push_back(drawable);
+ }
+ ++mVisibleListSize;
+ mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
+}
+
+void LLCullResult::pushBridge(LLSpatialBridge* bridge)
+{
+ if (mVisibleBridgeSize < mVisibleBridge.size())
+ {
+ mVisibleBridge[mVisibleBridgeSize] = bridge;
+ }
+ else
+ {
+ mVisibleBridge.push_back(bridge);
+ }
+ ++mVisibleBridgeSize;
+ mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize;
+}
+
+void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
+{
+ if (mRenderMapSize[type] < mRenderMap[type].size())
+ {
+ mRenderMap[type][mRenderMapSize[type]] = draw_info;
+ }
+ else
+ {
+ mRenderMap[type].push_back(draw_info);
+ }
+ ++mRenderMapSize[type];
+ mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type];
+}
+
+
+void LLCullResult::assertDrawMapsEmpty()
+{
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+ {
+ if (mRenderMapSize[i] != 0)
+ {
+ llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl;
+ }
+ }
+}
+
+
+
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 66df7dae3e..65393cc168 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -346,6 +346,19 @@ void LLSurface::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegio } } + +void LLSurface::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + S32 i; + for (i = 0; i < 8; i++) + { + if ( mNeighbors[i] != NULL ) + { + regions.push_back( i ); + } + } +} + void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) { S32 i; diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index a4ef4fe2de..8052fb0d18 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -142,6 +142,7 @@ public: friend std::ostream& operator<<(std::ostream &s, const LLSurface &S); void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ); + void getNeighboringRegionsStatus( std::vector<S32>& regions ); public: // Number of grid points on one side of a region, including +1 buffer for diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 319e2508e0..61ff59c53a 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -205,9 +205,9 @@ BOOL LLToolGrab::handleObjectHit(const LLPickInfo& info) // Clicks on scripted or physical objects are temporary grabs, so // not "Build mode" - mHideBuildHighlight = script_touch || objectp->usePhysics(); + mHideBuildHighlight = script_touch || objectp->flagUsePhysics(); - if (!objectp->usePhysics()) + if (!objectp->flagUsePhysics()) { if (script_touch) { diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index b0d9bd5d70..3cd761b73b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -312,7 +312,7 @@ BOOL LLToolPie::handleLeftClickPick() // Switch to grab tool if physical or triggerable if (object && !object->isAvatar() && - ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) + ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) ) { gGrabTransientTool = this; @@ -596,8 +596,8 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } - else if ((object && !object->isAvatar() && object->usePhysics()) - || (parent && !parent->isAvatar() && parent->usePhysics())) + else if ((object && !object->isAvatar() && object->flagUsePhysics()) + || (parent && !parent->isAvatar() && parent->flagUsePhysics())) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 0adb187dd2..42309349b0 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1,1563 +1,1568 @@ -/** - * @file llviewerdisplay.cpp - * @brief LLViewerDisplay class implementation - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerdisplay.h" - -#include "llgl.h" -#include "llrender.h" -#include "llglheaders.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llviewercontrol.h" -#include "llcoord.h" -#include "llcriticaldamp.h" -#include "lldir.h" -#include "lldynamictexture.h" -#include "lldrawpoolalpha.h" -#include "llfeaturemanager.h" -//#include "llfirstuse.h" -#include "llhudmanager.h" -#include "llimagebmp.h" -#include "llmemory.h" -#include "llselectmgr.h" -#include "llsky.h" -#include "llstartup.h" -#include "lltoolfocus.h" -#include "lltoolmgr.h" -#include "lltooldraganddrop.h" -#include "lltoolpie.h" -#include "lltracker.h" -#include "lltrans.h" -#include "llui.h" -#include "llviewercamera.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llvograss.h" -#include "llworld.h" -#include "pipeline.h" -#include "llspatialpartition.h" -#include "llappviewer.h" -#include "llstartup.h" -#include "llviewershadermgr.h" -#include "llfasttimer.h" -#include "llfloatertools.h" -#include "llviewertexturelist.h" -#include "llfocusmgr.h" -#include "llcubemap.h" -#include "llviewerregion.h" -#include "lldrawpoolwater.h" -#include "lldrawpoolbump.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" -#include "llpostprocess.h" - -extern LLPointer<LLViewerTexture> gStartTexture; - -LLPointer<LLViewerTexture> gDisconnectedImagep = NULL; - -// used to toggle renderer back on after teleport -const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain -const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. -const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport. -BOOL gTeleportDisplay = FALSE; -LLFrameTimer gTeleportDisplayTimer; -LLFrameTimer gTeleportArrivalTimer; -const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain - -BOOL gForceRenderLandFence = FALSE; -BOOL gDisplaySwapBuffers = FALSE; -BOOL gDepthDirty = FALSE; -BOOL gResizeScreenTexture = FALSE; -BOOL gWindowResized = FALSE; -BOOL gSnapshot = FALSE; - -U32 gRecentFrameCount = 0; // number of 'recent' frames -LLFrameTimer gRecentFPSTime; -LLFrameTimer gRecentMemoryTime; - -// Rendering stuff -void pre_show_depth_buffer(); -void post_show_depth_buffer(); -void render_ui(F32 zoom_factor = 1.f, int subfield = 0); -void render_hud_attachments(); -void render_ui_3d(); -void render_ui_2d(); -void render_disconnected_background(); - -void display_startup() -{ - if ( !gViewerWindow->getActive() - || !gViewerWindow->getWindow()->getVisible() - || gViewerWindow->getWindow()->getMinimized() ) - { - return; - } - - gPipeline.updateGL(); - - // Update images? - //gImageList.updateImages(0.01f); - LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); - - LLGLSDefault gls_default; - - // Required for HTML update in login screen - static S32 frame_count = 0; - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - if (frame_count++ > 1) // make sure we have rendered a frame first - { - LLViewerDynamicTexture::updateAllInstances(); - } - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - LLGLSUIDefault gls_ui; - gPipeline.disableLights(); - - gViewerWindow->setup2DRender(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - - gGL.color4f(1,1,1,1); - gViewerWindow->draw(); - gGL.flush(); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - gViewerWindow->getWindow()->swapBuffers(); - glClear(GL_DEPTH_BUFFER_BIT); -} - -void display_update_camera() -{ - LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA); - // TODO: cut draw distance down if customizing avatar? - // TODO: cut draw distance on per-parcel basis? - - // Cut draw distance in half when customizing avatar, - // but on the viewer only. - F32 final_far = gAgentCamera.mDrawDistance; - if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) - { - final_far *= 0.5f; - } - LLViewerCamera::getInstance()->setFar(final_far); - gViewerWindow->setup3DRender(); - - // update all the sky/atmospheric/water settings - LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance()); - LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance()); - - // Update land visibility too - LLWorld::getInstance()->setLandFarClip(final_far); -} - -// Write some stats to llinfos -void display_stats() -{ - F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency"); - if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) - { - F32 fps = gRecentFrameCount / fps_log_freq; - llinfos << llformat("FPS: %.02f", fps) << llendl; - gRecentFrameCount = 0; - gRecentFPSTime.reset(); - } - F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); - if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) - { - gMemoryAllocated = LLMemory::getCurrentRSS(); - U32 memory = (U32)(gMemoryAllocated / (1024*1024)); - llinfos << llformat("MEMORY: %d MB", memory) << llendl; - LLMemory::logMemoryInfo(TRUE) ; - gRecentMemoryTime.reset(); - } -} - -static LLFastTimer::DeclareTimer FTM_PICK("Picking"); -static LLFastTimer::DeclareTimer FTM_RENDER("Render", true); -static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky"); -static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete"); - -// Paint the display! -void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) -{ - LLMemType mt_render(LLMemType::MTYPE_RENDER); - LLFastTimer t(FTM_RENDER); - - if (gWindowResized) - { //skip render on frames where window has been resized - gGL.flush(); - glClear(GL_COLOR_BUFFER_BIT); - gViewerWindow->getWindow()->swapBuffers(); - LLPipeline::refreshCachedSettings(); - gPipeline.resizeScreenTexture(); - gResizeScreenTexture = FALSE; - gWindowResized = FALSE; - return; - } - - if (LLPipeline::sRenderDeferred) - { //hack to make sky show up in deferred snapshots - for_snapshot = FALSE; - } - - if (LLPipeline::sRenderFrameTest) - { - send_agent_pause(); - } - - gSnapshot = for_snapshot; - - LLGLSDefault gls_default; - LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - stop_glerror(); - - gPipeline.disableLights(); - - //reset vertex buffers if needed - gPipeline.doResetVertexBuffers(); - - stop_glerror(); - - // Don't draw if the window is hidden or minimized. - // In fact, must explicitly check the minimized state before drawing. - // Attempting to draw into a minimized window causes a GL error. JC - if ( !gViewerWindow->getActive() - || !gViewerWindow->getWindow()->getVisible() - || gViewerWindow->getWindow()->getMinimized() ) - { - // Clean up memory the pools may have allocated - if (rebuild) - { - stop_glerror(); - gPipeline.rebuildPools(); - stop_glerror(); - } - - stop_glerror(); - gViewerWindow->returnEmptyPicks(); - stop_glerror(); - return; - } - - gViewerWindow->checkSettings(); - - { - LLFastTimer ftm(FTM_PICK); - LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); - gViewerWindow->performPick(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates"); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - ////////////////////////////////////////////////////////// - // - // Logic for forcing window updates if we're in drone mode. - // - - // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18 - if (gHeadlessClient) - { -#if LL_WINDOWS - static F32 last_update_time = 0.f; - if ((gFrameTimeSeconds - last_update_time) > 1.f) - { - InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE); - last_update_time = gFrameTimeSeconds; - } -#elif LL_DARWIN - // MBW -- Do something clever here. -#endif - // Not actually rendering, don't bother. - return; - } - - - // - // Bail out if we're in the startup state and don't want to try to - // render the world. - // - if (LLStartUp::getStartupState() < STATE_STARTED) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:Startup"); - display_startup(); - return; - } - - //LLGLState::verify(FALSE); - - ///////////////////////////////////////////////// - // - // Update GL Texture statistics (used for discard logic?) - // - - LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats"); - stop_glerror(); - - LLImageGL::updateStats(gFrameTimeSeconds); - - LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); - LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode")); - - gPipeline.mBackfaceCull = TRUE; - gFrameCount++; - gRecentFrameCount++; - if (gFocusMgr.getAppHasFocus()) - { - gForegroundFrameCount++; - } - - ////////////////////////////////////////////////////////// - // - // Display start screen if we're teleporting, and skip render - // - - if (gTeleportDisplay) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport"); - const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. - - S32 attach_count = 0; - if (isAgentAvatarValid()) - { - attach_count = gAgentAvatarp->getAttachmentCount(); - } - F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count; - F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32(); - F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time); - if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) ) - { - // Give up. Don't keep the UI locked forever. - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - gAgent.setTeleportMessage(std::string()); - } - - const std::string& message = gAgent.getTeleportMessage(); - switch( gAgent.getTeleportState() ) - { - case LLAgent::TELEPORT_START: - // Transition to REQUESTED. Viewer has sent some kind - // of TeleportRequest to the source simulator - gTeleportDisplayTimer.reset(); - gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressPercent(0); - gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); - gAgent.setTeleportMessage( - LLAgent::sTeleportProgressMessages["requesting"]); - break; - - case LLAgent::TELEPORT_REQUESTED: - // Waiting for source simulator to respond - gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) ); - gViewerWindow->setProgressString(message); - break; - - case LLAgent::TELEPORT_MOVING: - // Viewer has received destination location from source simulator - gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) ); - gViewerWindow->setProgressString(message); - break; - - case LLAgent::TELEPORT_START_ARRIVAL: - // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator - gTeleportArrivalTimer.reset(); - gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); - gViewerWindow->setProgressPercent(75.f); - gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING ); - gAgent.setTeleportMessage( - LLAgent::sTeleportProgressMessages["arriving"]); - gTextureList.mForceResetTextureStats = TRUE; - gAgentCamera.resetView(TRUE, TRUE); - break; - - case LLAgent::TELEPORT_ARRIVING: - // Make the user wait while content "pre-caches" - { - F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY); - if( arrival_fraction > 1.f ) - { - arrival_fraction = 1.f; - //LLFirstUse::useTeleport(); - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); - gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f); - gViewerWindow->setProgressString(message); - } - break; - - case LLAgent::TELEPORT_LOCAL: - // Short delay when teleporting in the same sim (progress screen active but not shown - did not - // fall-through from TELEPORT_START) - { - if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY ) - { - //LLFirstUse::useTeleport(); - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - } - break; - - case LLAgent::TELEPORT_NONE: - // No teleport in progress - gViewerWindow->setShowProgress(FALSE); - gTeleportDisplay = FALSE; - break; - } - } - else if(LLAppViewer::instance()->logoutRequestSent()) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:Logout"); - F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime; - if (percent_done > 100.f) - { - percent_done = 100.f; - } - - if( LLApp::isExiting() ) - { - percent_done = 100.f; - } - - gViewerWindow->setProgressPercent( percent_done ); - } - else - if (gRestoreGL) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL"); - F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME; - if( percent_done > 100.f ) - { - gViewerWindow->setShowProgress(FALSE); - gRestoreGL = FALSE; - } - else - { - - if( LLApp::isExiting() ) - { - percent_done = 100.f; - } - - gViewerWindow->setProgressPercent( percent_done ); - } - } - - ////////////////////////// - // - // Prepare for the next frame - // - - ///////////////////////////// - // - // Update the camera - // - // - - LLAppViewer::instance()->pingMainloopTimeout("Display:Camera"); - LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield); - LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); - - ////////////////////////// - // - // clear the next buffer - // (must follow dynamic texture writing since that uses the frame buffer) - // - - if (gDisconnected) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected"); - render_ui(); - } - - ////////////////////////// - // - // Set rendering options - // - // - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup"); - stop_glerror(); - - /////////////////////////////////////// - // - // Slam lighting parameters back to our defaults. - // Note that these are not the same as GL defaults... - - stop_glerror(); - gGL.setAmbientLightColor(LLColor4::white); - stop_glerror(); - - ///////////////////////////////////// - // - // Render - // - // Actually push all of our triangles to the screen. - // - - // do render-to-texture stuff here - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) - { - LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); - LLFastTimer t(FTM_UPDATE_TEXTURES); - if (LLViewerDynamicTexture::updateAllInstances()) - { - gGL.setColorMask(true, true); - glClear(GL_DEPTH_BUFFER_BIT); - } - } - - gViewerWindow->setup3DViewport(); - - gPipeline.resetFrameStats(); // Reset per-frame statistics. - - if (!gDisconnected) - { - LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE); - LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { //don't draw hud objects in this frame - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES)) - { //don't draw hud particles in this frame - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); - } - - //upkeep gl name pools - LLGLNamePool::upkeepPools(); - - stop_glerror(); - display_update_camera(); - stop_glerror(); - - // *TODO: merge these two methods - { - LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD); - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - stop_glerror(); - } - - { - LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM); - const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time - gPipeline.createObjects(max_geom_update_time); - gPipeline.processPartitionQ(); - gPipeline.updateGeom(max_geom_update_time); - stop_glerror(); - } - - gPipeline.updateGL(); - stop_glerror(); - - S32 water_clip = 0; - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && - (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || - gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER))) - { - if (LLViewerCamera::getInstance()->cameraUnderWater()) - { - water_clip = -1; - } - else - { - water_clip = 1; - } - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:Cull"); - - //Increment drawable frame counter - LLDrawable::incrementVisible(); - - LLSpatialGroup::sNoDelete = TRUE; - LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); - - /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) - { //force occlusion on for all render types if doing deferred render (tighter shadow frustum) - LLPipeline::sUseOcclusion = 3; - }*/ - - S32 occlusion = LLPipeline::sUseOcclusion; - if (gDepthDirty) - { //depth buffer is invalid, don't overwrite occlusion state - LLPipeline::sUseOcclusion = llmin(occlusion, 1); - } - gDepthDirty = FALSE; - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - static LLCullResult result; - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip); - stop_glerror(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - BOOL to_texture = gPipeline.canUseVertexShaders() && - LLPipeline::sRenderGlow; - - LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); - - { - LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP); - - if (gResizeScreenTexture) - { - gResizeScreenTexture = FALSE; - gPipeline.resizeScreenTexture(); - } - - gGL.setColorMask(true, true); - glClearColor(0,0,0,0); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - if (!for_snapshot) - { - if (gFrameCount > 1) - { //for some reason, ATI 4800 series will error out if you - //try to generate a shadow before the first frame is through - gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); - } - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - glh::matrix4f proj = glh_get_current_projection(); - glh::matrix4f mod = glh_get_current_modelview(); - glViewport(0,0,512,512); - LLVOAvatar::updateFreezeCounter() ; - - if(!LLPipeline::sMemAllocationThrottled) - { - LLVOAvatar::updateImpostors(); - } - - glh_set_current_projection(proj); - glh_set_current_modelview(mod); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj.m); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(mod.m); - gViewerWindow->setup3DViewport(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - } - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - LLGLState::checkStates(); - LLGLState::checkClientArrays(); - - //if (!for_snapshot) - { - LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION); - LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); - gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); - gPipeline.generateHighlight(*LLViewerCamera::getInstance()); - gPipeline.renderPhysicsDisplay(); - } - - LLGLState::checkStates(); - LLGLState::checkClientArrays(); - - ////////////////////////////////////// - // - // Update images, using the image stats generated during object update/culling - // - // Can put objects onto the retextured list. - // - // Doing this here gives hardware occlusion queries extra time to complete - LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); - - { - LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE); - LLFastTimer t(FTM_IMAGE_UPDATE); - - { - LLFastTimer t(FTM_IMAGE_UPDATE_CLASS); - LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), - LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); - } - - - { - LLFastTimer t(FTM_IMAGE_UPDATE_BUMP); - gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. - } - - { - LLFastTimer t(FTM_IMAGE_UPDATE_LIST); - F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time - max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) - gTextureList.updateImages(max_image_decode_time); - } - - { - LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); - //remove dead textures from GL - LLImageGL::deleteDeadTextures(); - stop_glerror(); - } - } - - LLGLState::checkStates(); - LLGLState::checkClientArrays(); - - /////////////////////////////////// - // - // StateSort - // - // Responsible for taking visible objects, and adding them to the appropriate draw orders. - // In the case of alpha objects, z-sorts them first. - // Also creates special lists for outlines and selected face rendering. - // - LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); - { - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT); - gPipeline.stateSort(*LLViewerCamera::getInstance(), result); - stop_glerror(); - - if (rebuild) - { - ////////////////////////////////////// - // - // rebuildPools - // - // - gPipeline.rebuildPools(); - stop_glerror(); - } - } - - LLGLState::checkStates(); - LLGLState::checkClientArrays(); - - LLPipeline::sUseOcclusion = occlusion; - - { - LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY); - LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); - LLFastTimer t(FTM_UPDATE_SKY); - gSky.updateSky(); - } - - if(gUseWireframe) - { - glClearColor(0.5f, 0.5f, 0.5f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); - - //// render frontmost floater opaque for occlusion culling purposes - //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost(); - //// assumes frontmost floater with focus is opaque - //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp)) - //{ - // gGL.matrixMode(LLRender::MM_MODELVIEW); - // gGL.pushMatrix(); - // { - // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - // gGL.loadIdentity(); - - // LLRect floater_rect = frontmost_floaterp->calcScreenRect(); - // // deflate by one pixel so rounding errors don't occlude outside of floater extents - // floater_rect.stretch(-1); - // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(), - // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(), - // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(), - // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled()); - // floater_3d_rect.translate(-0.5f, -0.5f); - // gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear()); - // gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f); - // gGL.color4fv(LLColor4::white.mV); - // gGL.begin(LLVertexBuffer::QUADS); - // { - // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f); - // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f); - // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f); - // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f); - // } - // gGL.end(); - // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - // } - // gGL.popMatrix(); - //} - - LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; - - LLGLState::checkStates(); - LLGLState::checkClientArrays(); - - stop_glerror(); - - if (to_texture) - { - gGL.setColorMask(true, true); - - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) - { - gPipeline.mDeferredScreen.bindTarget(); - glClearColor(1,0,1,1); - gPipeline.mDeferredScreen.clear(); - } - else - { - gPipeline.mScreen.bindTarget(); - if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) - { - const LLColor4 &col = LLDrawPoolWater::sWaterFogColor; - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - } - gPipeline.mScreen.clear(); - } - - gGL.setColorMask(true, false); - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); - - if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) - && !gRestoreGL) - { - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM); - gGL.setColorMask(true, false); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) - { - gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); - } - else - { - gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE); - } - - gGL.setColorMask(true, true); - - //store this frame's modelview matrix for use - //when rendering next frame's occlusion queries - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = gGLModelView[i]; - gGLLastProjection[i] = gGLProjection[i]; - } - stop_glerror(); - } - - for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++) - { //dummy cleanup of any currently bound textures - if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE) - { - gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType()); - gGL.getTexUnit(i)->disable(); - } - } - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); - - if (to_texture) - { - LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) - { - gPipeline.mDeferredScreen.flush(); - if(LLRenderTarget::sUseFBO) - { - LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), - gPipeline.mDeferredScreen.getHeight(), 0, 0, - gPipeline.mDeferredScreen.getWidth(), - gPipeline.mDeferredScreen.getHeight(), - GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - } - else - { - gPipeline.mScreen.flush(); - if(LLRenderTarget::sUseFBO) - { - LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), - gPipeline.mScreen.getHeight(), 0, 0, - gPipeline.mScreen.getWidth(), - gPipeline.mScreen.getHeight(), - GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - } - } - - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) - { - gPipeline.renderDeferredLighting(); - } - - LLPipeline::sUnderWaterRender = FALSE; - - LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); - if (!for_snapshot) - { - LLFastTimer t(FTM_RENDER_UI); - render_ui(); - } - - - LLSpatialGroup::sNoDelete = FALSE; - gPipeline.clearReferences(); - - gPipeline.rebuildGroups(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); - - stop_glerror(); - - if (LLPipeline::sRenderFrameTest) - { - send_agent_resume(); - LLPipeline::sRenderFrameTest = FALSE; - } - - display_stats(); - - LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); -} - -void render_hud_attachments() -{ - LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - - glh::matrix4f current_proj = glh_get_current_projection(); - glh::matrix4f current_mod = glh_get_current_modelview(); - - // clamp target zoom level to reasonable values - gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); - // smoothly interpolate current zoom level - gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); - - if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) - { - LLCamera hud_cam = *LLViewerCamera::getInstance(); - LLVector3 origin = hud_cam.getOrigin(); - hud_cam.setOrigin(-1.f,0,0); - hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); - LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); - - bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles"); - - //only render hud objects - gPipeline.pushRenderTypeMask(); - - // turn off everything - gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES); - // turn on HUD - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - // turn on HUD particles - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); - - // if particles are off, turn off hud-particles as well - if (!render_particles) - { - // turn back off HUD particles - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); - } - - bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); - if (has_ui) - { - gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - S32 use_occlusion = LLPipeline::sUseOcclusion; - LLPipeline::sUseOcclusion = 0; - - //cull, sort, and render hud objects - static LLCullResult result; - LLSpatialGroup::sNoDelete = TRUE; - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - gPipeline.updateCull(hud_cam, result); - - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY); - - gPipeline.stateSort(hud_cam, result); - - gPipeline.renderGeom(hud_cam); - - LLSpatialGroup::sNoDelete = FALSE; - //gPipeline.clearReferences(); - - render_hud_elements(); - - //restore type mask - gPipeline.popRenderTypeMask(); - - if (has_ui) - { - gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - LLPipeline::sUseOcclusion = use_occlusion; - } - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - glh_set_current_projection(current_proj); - glh_set_current_modelview(current_mod); -} - -LLRect get_whole_screen_region() -{ - LLRect whole_screen = gViewerWindow->getWorldViewRectScaled(); - - // apply camera zoom transform (for high res screenshots) - F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); - S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); - if (zoom_factor > 1.f) - { - S32 num_horizontal_tiles = llceil(zoom_factor); - S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor); - S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor); - int tile_y = sub_region / num_horizontal_tiles; - int tile_x = sub_region - (tile_y * num_horizontal_tiles); - - whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height); - } - return whole_screen; -} - -bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model) -{ - if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment()) - { - F32 zoom_level = gAgentCamera.mHUDCurZoom; - LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); - - F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); - proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); - proj.element(2,2) = -0.01f; - - F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect(); - - glh::matrix4f mat; - F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth(); - F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight(); - mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f)); - mat.set_translate( - glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio), - clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y), - 0.f)); - proj *= mat; - - glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION); - - mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level)); - mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f)); - - tmp_model *= mat; - model = tmp_model; - return TRUE; - } - else - { - return FALSE; - } -} - -bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model) -{ - LLRect whole_screen = get_whole_screen_region(); - return get_hud_matrices(whole_screen, proj, model); -} - -BOOL setup_hud_matrices() -{ - LLRect whole_screen = get_whole_screen_region(); - return setup_hud_matrices(whole_screen); -} - -BOOL setup_hud_matrices(const LLRect& screen_region) -{ - glh::matrix4f proj, model; - bool result = get_hud_matrices(screen_region, proj, model); - if (!result) return result; - - // set up transform to keep HUD objects in front of camera - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj.m); - glh_set_current_projection(proj); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(model.m); - glh_set_current_modelview(model); - return TRUE; -} - -static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); - -void render_ui(F32 zoom_factor, int subfield) -{ - LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI); - LLGLState::checkStates(); - - glh::matrix4f saved_view = glh_get_current_modelview(); - - if (!gSnapshot) - { - gGL.pushMatrix(); - gGL.loadMatrix(gGLLastModelView); - glh_set_current_modelview(glh_copy_matrix(gGLLastModelView)); - } - - { - BOOL to_texture = gPipeline.canUseVertexShaders() && - LLPipeline::sRenderGlow; - - if (to_texture) - { - gPipeline.renderBloom(gSnapshot, zoom_factor, subfield); - } - - render_hud_elements(); - render_hud_attachments(); - } - - LLGLSDefault gls_default; - LLGLSUIDefault gls_ui; - { - gPipeline.disableLights(); - } - - { - gGL.color4f(1,1,1,1); - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLFastTimer t(FTM_RENDER_UI); - - if (!gDisconnected) - { - render_ui_3d(); - LLGLState::checkStates(); - } - else - { - render_disconnected_background(); - } - - render_ui_2d(); - LLGLState::checkStates(); - } - gGL.flush(); - - { - gViewerWindow->setup2DRender(); - gViewerWindow->updateDebugText(); - gViewerWindow->drawDebugText(); - } - - LLVertexBuffer::unbind(); - } - - if (!gSnapshot) - { - glh_set_current_modelview(saved_view); - gGL.popMatrix(); - } - - if (gDisplaySwapBuffers) - { - LLFastTimer t(FTM_SWAP); - gViewerWindow->getWindow()->swapBuffers(); - } - gDisplaySwapBuffers = TRUE; -} - -void renderCoordinateAxes() -{ - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::LINES); - gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(2.0f, 0.0f, 0.0f); - gGL.vertex3f(3.0f, 0.0f, 0.0f); - gGL.vertex3f(5.0f, 0.0f, 0.0f); - gGL.vertex3f(6.0f, 0.0f, 0.0f); - gGL.vertex3f(8.0f, 0.0f, 0.0f); - // Make an X - gGL.vertex3f(11.0f, 1.0f, 1.0f); - gGL.vertex3f(11.0f, -1.0f, -1.0f); - gGL.vertex3f(11.0f, 1.0f, -1.0f); - gGL.vertex3f(11.0f, -1.0f, 1.0f); - - gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(0.0f, 2.0f, 0.0f); - gGL.vertex3f(0.0f, 3.0f, 0.0f); - gGL.vertex3f(0.0f, 5.0f, 0.0f); - gGL.vertex3f(0.0f, 6.0f, 0.0f); - gGL.vertex3f(0.0f, 8.0f, 0.0f); - // Make a Y - gGL.vertex3f(1.0f, 11.0f, 1.0f); - gGL.vertex3f(0.0f, 11.0f, 0.0f); - gGL.vertex3f(-1.0f, 11.0f, 1.0f); - gGL.vertex3f(0.0f, 11.0f, 0.0f); - gGL.vertex3f(0.0f, 11.0f, 0.0f); - gGL.vertex3f(0.0f, 11.0f, -1.0f); - - gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(0.0f, 0.0f, 2.0f); - gGL.vertex3f(0.0f, 0.0f, 3.0f); - gGL.vertex3f(0.0f, 0.0f, 5.0f); - gGL.vertex3f(0.0f, 0.0f, 6.0f); - gGL.vertex3f(0.0f, 0.0f, 8.0f); - // Make a Z - gGL.vertex3f(-1.0f, 1.0f, 11.0f); - gGL.vertex3f(1.0f, 1.0f, 11.0f); - gGL.vertex3f(1.0f, 1.0f, 11.0f); - gGL.vertex3f(-1.0f, -1.0f, 11.0f); - gGL.vertex3f(-1.0f, -1.0f, 11.0f); - gGL.vertex3f(1.0f, -1.0f, 11.0f); - gGL.end(); -} - - -void draw_axes() -{ - LLGLSUIDefault gls_ui; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - // A vertical white line at origin - LLVector3 v = gAgent.getPositionAgent(); - gGL.begin(LLRender::LINES); - gGL.color3f(1.0f, 1.0f, 1.0f); - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(0.0f, 0.0f, 40.0f); - gGL.end(); - // Some coordinate axes - gGL.pushMatrix(); - gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] ); - renderCoordinateAxes(); - gGL.popMatrix(); -} - -void render_ui_3d() -{ - LLGLSPipeline gls_pipeline; - - ////////////////////////////////////// - // - // Render 3D UI elements - // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD, - // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD - // - - ///////////////////////////////////////////////////////////// - // - // Render 2.5D elements (2D elements in the world) - // Stuff without z writes - // - - // Debugging stuff goes before the UI. - - stop_glerror(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - // Coordinate axes - if (gSavedSettings.getBOOL("ShowAxes")) - { - draw_axes(); - } - - gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements - stop_glerror(); -} - -void render_ui_2d() -{ - LLGLSUIDefault gls_ui; - - ///////////////////////////////////////////////////////////// - // - // Render 2D UI elements that overlay the world (no z compare) - - // Disable wireframe mode below here, as this is HUD/menus - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - // Menu overlays, HUD, etc - gViewerWindow->setup2DRender(); - - F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); - S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); - - if (zoom_factor > 1.f) - { - //decompose subregion number to x and y values - int pos_y = sub_region / llceil(zoom_factor); - int pos_x = sub_region - (pos_y*llceil(zoom_factor)); - // offset for this tile - LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor); - LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor); - } - - stop_glerror(); - //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - - // render outline for HUD - if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f) - { - gGL.pushMatrix(); - S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2); - S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2); - gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f); - gGL.translatef((F32)half_width, (F32)half_height, 0.f); - F32 zoom = gAgentCamera.mHUDCurZoom; - gGL.scalef(zoom,zoom,1.f); - gGL.color4fv(LLColor4::white.mV); - gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE); - gGL.popMatrix(); - stop_glerror(); - } - - - if (gSavedSettings.getBOOL("RenderUIBuffer")) - { - if (LLUI::sDirty) - { - LLUI::sDirty = FALSE; - LLRect t_rect; - - gPipeline.mUIScreen.bindTarget(); - gGL.setColorMask(true, true); - { - static const S32 pad = 8; - - LLUI::sDirtyRect.mLeft -= pad; - LLUI::sDirtyRect.mRight += pad; - LLUI::sDirtyRect.mBottom -= pad; - LLUI::sDirtyRect.mTop += pad; - - LLGLEnable scissor(GL_SCISSOR_TEST); - static LLRect last_rect = LLUI::sDirtyRect; - - //union with last rect to avoid mouse poop - last_rect.unionWith(LLUI::sDirtyRect); - - t_rect = LLUI::sDirtyRect; - LLUI::sDirtyRect = last_rect; - last_rect = t_rect; - - last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]); - last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]); - last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]); - last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]); - - LLRect clip_rect(last_rect); - - glClear(GL_COLOR_BUFFER_BIT); - - gViewerWindow->draw(); - } - - gPipeline.mUIScreen.flush(); - gGL.setColorMask(true, false); - - LLUI::sDirtyRect = t_rect; - } - - LLGLDisable cull(GL_CULL_FACE); - LLGLDisable blend(GL_BLEND); - S32 width = gViewerWindow->getWindowWidthScaled(); - S32 height = gViewerWindow->getWindowHeightScaled(); - gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.color4f(1,1,1,1); - gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0); - gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0); - gGL.texCoord2f(0, height); gGL.vertex2i(0, height); - gGL.texCoord2f(width, height); gGL.vertex2i(width, height); - gGL.end(); - } - else - { - gViewerWindow->draw(); - } - - - - // reset current origin for font rendering, in case of tiling render - LLFontGL::sCurOrigin.set(0, 0); -} - -void render_disconnected_background() -{ - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - gGL.color4f(1,1,1,1); - if (!gDisconnectedImagep && gDisconnected) - { - llinfos << "Loading last bitmap..." << llendl; - - std::string temp_str; - temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME; - - LLPointer<LLImageBMP> image_bmp = new LLImageBMP; - if( !image_bmp->load(temp_str) ) - { - //llinfos << "Bitmap load failed" << llendl; - return; - } - - LLPointer<LLImageRaw> raw = new LLImageRaw; - if (!image_bmp->decode(raw, 0.0f)) - { - llinfos << "Bitmap decode failed" << llendl; - gDisconnectedImagep = NULL; - return; - } - - U8 *rawp = raw->getData(); - S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight(); - for (S32 i = 0; i < npixels; i++) - { - S32 sum = 0; - sum = *rawp + *(rawp+1) + *(rawp+2); - sum /= 3; - *rawp = ((S32)sum*6 + *rawp)/7; - rawp++; - *rawp = ((S32)sum*6 + *rawp)/7; - rawp++; - *rawp = ((S32)sum*6 + *rawp)/7; - rawp++; - } - - - raw->expandToPowerOfTwo(); - gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE ); - gStartTexture = gDisconnectedImagep; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - - // Make sure the progress view always fills the entire window. - S32 width = gViewerWindow->getWindowWidthScaled(); - S32 height = gViewerWindow->getWindowHeightScaled(); - - if (gDisconnectedImagep) - { - LLGLSUIDefault gls_ui; - gViewerWindow->setup2DRender(); - gGL.pushMatrix(); - { - // scale ui to reflect UIScaleFactor - // this can't be done in setup2DRender because it requires a - // pushMatrix/popMatrix pair - const LLVector2& display_scale = gViewerWindow->getDisplayScale(); - gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); - - gGL.getTexUnit(0)->bind(gDisconnectedImagep); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - gl_rect_2d_simple_tex(width, height); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - gGL.popMatrix(); - } - gGL.flush(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - -} - -void display_cleanup() -{ - gDisconnectedImagep = NULL; -} +/**
+ * @file llviewerdisplay.cpp
+ * @brief LLViewerDisplay class implementation
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerdisplay.h"
+
+#include "llgl.h"
+#include "llrender.h"
+#include "llglheaders.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llviewercontrol.h"
+#include "llcoord.h"
+#include "llcriticaldamp.h"
+#include "lldir.h"
+#include "lldynamictexture.h"
+#include "lldrawpoolalpha.h"
+#include "llfeaturemanager.h"
+//#include "llfirstuse.h"
+#include "llhudmanager.h"
+#include "llimagebmp.h"
+#include "llmemory.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "llstartup.h"
+#include "lltoolfocus.h"
+#include "lltoolmgr.h"
+#include "lltooldraganddrop.h"
+#include "lltoolpie.h"
+#include "lltracker.h"
+#include "lltrans.h"
+#include "llui.h"
+#include "llviewercamera.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llvograss.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "llspatialpartition.h"
+#include "llappviewer.h"
+#include "llstartup.h"
+#include "llviewershadermgr.h"
+#include "llfasttimer.h"
+#include "llfloatertools.h"
+#include "llviewertexturelist.h"
+#include "llfocusmgr.h"
+#include "llcubemap.h"
+#include "llviewerregion.h"
+#include "lldrawpoolwater.h"
+#include "lldrawpoolbump.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llpostprocess.h"
+#include "LLPathingLib.h"
+#include "llfloaterpathfindingconsole.h"
+#include "llfloaterreg.h"
+
+extern LLPointer<LLViewerTexture> gStartTexture;
+
+LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
+
+// used to toggle renderer back on after teleport
+const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain
+const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
+const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport.
+BOOL gTeleportDisplay = FALSE;
+LLFrameTimer gTeleportDisplayTimer;
+LLFrameTimer gTeleportArrivalTimer;
+const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
+
+BOOL gForceRenderLandFence = FALSE;
+BOOL gDisplaySwapBuffers = FALSE;
+BOOL gDepthDirty = FALSE;
+BOOL gResizeScreenTexture = FALSE;
+BOOL gWindowResized = FALSE;
+BOOL gSnapshot = FALSE;
+
+U32 gRecentFrameCount = 0; // number of 'recent' frames
+LLFrameTimer gRecentFPSTime;
+LLFrameTimer gRecentMemoryTime;
+
+// Rendering stuff
+void pre_show_depth_buffer();
+void post_show_depth_buffer();
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+void render_hud_attachments();
+void render_ui_3d();
+void render_ui_2d();
+void render_disconnected_background();
+
+void display_startup()
+{
+ if ( !gViewerWindow->getActive()
+ || !gViewerWindow->getWindow()->getVisible()
+ || gViewerWindow->getWindow()->getMinimized() )
+ {
+ return;
+ }
+
+ gPipeline.updateGL();
+
+ // Update images?
+ //gImageList.updateImages(0.01f);
+ LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
+
+ LLGLSDefault gls_default;
+
+ // Required for HTML update in login screen
+ static S32 frame_count = 0;
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ if (frame_count++ > 1) // make sure we have rendered a frame first
+ {
+ LLViewerDynamicTexture::updateAllInstances();
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ LLGLSUIDefault gls_ui;
+ gPipeline.disableLights();
+
+ gViewerWindow->setup2DRender();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ gGL.color4f(1,1,1,1);
+ gViewerWindow->draw();
+ gGL.flush();
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ gViewerWindow->getWindow()->swapBuffers();
+ glClear(GL_DEPTH_BUFFER_BIT);
+}
+
+void display_update_camera()
+{
+ LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
+ // TODO: cut draw distance down if customizing avatar?
+ // TODO: cut draw distance on per-parcel basis?
+
+ // Cut draw distance in half when customizing avatar,
+ // but on the viewer only.
+ F32 final_far = gAgentCamera.mDrawDistance;
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
+ {
+ final_far *= 0.5f;
+ }
+ LLViewerCamera::getInstance()->setFar(final_far);
+ gViewerWindow->setup3DRender();
+
+ // update all the sky/atmospheric/water settings
+ LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance());
+ LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance());
+
+ // Update land visibility too
+ LLWorld::getInstance()->setLandFarClip(final_far);
+}
+
+// Write some stats to llinfos
+void display_stats()
+{
+ F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
+ if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
+ {
+ F32 fps = gRecentFrameCount / fps_log_freq;
+ llinfos << llformat("FPS: %.02f", fps) << llendl;
+ gRecentFrameCount = 0;
+ gRecentFPSTime.reset();
+ }
+ F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
+ if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
+ {
+ gMemoryAllocated = LLMemory::getCurrentRSS();
+ U32 memory = (U32)(gMemoryAllocated / (1024*1024));
+ llinfos << llformat("MEMORY: %d MB", memory) << llendl;
+ LLMemory::logMemoryInfo(TRUE) ;
+ gRecentMemoryTime.reset();
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_PICK("Picking");
+static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
+static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
+static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
+
+// Paint the display!
+void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
+{
+ LLMemType mt_render(LLMemType::MTYPE_RENDER);
+ LLFastTimer t(FTM_RENDER);
+
+ if (gWindowResized)
+ { //skip render on frames where window has been resized
+ gGL.flush();
+ glClear(GL_COLOR_BUFFER_BIT);
+ gViewerWindow->getWindow()->swapBuffers();
+ LLPipeline::refreshCachedSettings();
+ gPipeline.resizeScreenTexture();
+ gResizeScreenTexture = FALSE;
+ gWindowResized = FALSE;
+ return;
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ { //hack to make sky show up in deferred snapshots
+ for_snapshot = FALSE;
+ }
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ send_agent_pause();
+ }
+
+ gSnapshot = for_snapshot;
+
+ LLGLSDefault gls_default;
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ stop_glerror();
+
+ gPipeline.disableLights();
+
+ //reset vertex buffers if needed
+ gPipeline.doResetVertexBuffers();
+
+ stop_glerror();
+
+ // Don't draw if the window is hidden or minimized.
+ // In fact, must explicitly check the minimized state before drawing.
+ // Attempting to draw into a minimized window causes a GL error. JC
+ if ( !gViewerWindow->getActive()
+ || !gViewerWindow->getWindow()->getVisible()
+ || gViewerWindow->getWindow()->getMinimized() )
+ {
+ // Clean up memory the pools may have allocated
+ if (rebuild)
+ {
+ stop_glerror();
+ gPipeline.rebuildPools();
+ stop_glerror();
+ }
+
+ stop_glerror();
+ gViewerWindow->returnEmptyPicks();
+ stop_glerror();
+ return;
+ }
+
+ gViewerWindow->checkSettings();
+
+ {
+ LLFastTimer ftm(FTM_PICK);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Pick");
+ gViewerWindow->performPick();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ //////////////////////////////////////////////////////////
+ //
+ // Logic for forcing window updates if we're in drone mode.
+ //
+
+ // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18
+ if (gHeadlessClient)
+ {
+#if LL_WINDOWS
+ static F32 last_update_time = 0.f;
+ if ((gFrameTimeSeconds - last_update_time) > 1.f)
+ {
+ InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE);
+ last_update_time = gFrameTimeSeconds;
+ }
+#elif LL_DARWIN
+ // MBW -- Do something clever here.
+#endif
+ // Not actually rendering, don't bother.
+ return;
+ }
+
+
+ //
+ // Bail out if we're in the startup state and don't want to try to
+ // render the world.
+ //
+ if (LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
+ display_startup();
+ return;
+ }
+
+ //LLGLState::verify(FALSE);
+
+ /////////////////////////////////////////////////
+ //
+ // Update GL Texture statistics (used for discard logic?)
+ //
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
+ stop_glerror();
+
+ LLImageGL::updateStats(gFrameTimeSeconds);
+
+ LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
+ LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
+
+ gPipeline.mBackfaceCull = TRUE;
+ gFrameCount++;
+ gRecentFrameCount++;
+ if (gFocusMgr.getAppHasFocus())
+ {
+ gForegroundFrameCount++;
+ }
+
+ //////////////////////////////////////////////////////////
+ //
+ // Display start screen if we're teleporting, and skip render
+ //
+
+ if (gTeleportDisplay)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
+ const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
+
+ S32 attach_count = 0;
+ if (isAgentAvatarValid())
+ {
+ attach_count = gAgentAvatarp->getAttachmentCount();
+ }
+ F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
+ F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
+ F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
+ if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) )
+ {
+ // Give up. Don't keep the UI locked forever.
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ gAgent.setTeleportMessage(std::string());
+ }
+
+ const std::string& message = gAgent.getTeleportMessage();
+ switch( gAgent.getTeleportState() )
+ {
+ case LLAgent::TELEPORT_START:
+ // Transition to REQUESTED. Viewer has sent some kind
+ // of TeleportRequest to the source simulator
+ gTeleportDisplayTimer.reset();
+ gViewerWindow->setShowProgress(TRUE);
+ gViewerWindow->setProgressPercent(0);
+ gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED );
+ gAgent.setTeleportMessage(
+ LLAgent::sTeleportProgressMessages["requesting"]);
+ break;
+
+ case LLAgent::TELEPORT_REQUESTED:
+ // Waiting for source simulator to respond
+ gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) );
+ gViewerWindow->setProgressString(message);
+ break;
+
+ case LLAgent::TELEPORT_MOVING:
+ // Viewer has received destination location from source simulator
+ gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) );
+ gViewerWindow->setProgressString(message);
+ break;
+
+ case LLAgent::TELEPORT_START_ARRIVAL:
+ // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator
+ gTeleportArrivalTimer.reset();
+ gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
+ gViewerWindow->setProgressPercent(75.f);
+ gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING );
+ gAgent.setTeleportMessage(
+ LLAgent::sTeleportProgressMessages["arriving"]);
+ gTextureList.mForceResetTextureStats = TRUE;
+ gAgentCamera.resetView(TRUE, TRUE);
+ break;
+
+ case LLAgent::TELEPORT_ARRIVING:
+ // Make the user wait while content "pre-caches"
+ {
+ F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY);
+ if( arrival_fraction > 1.f )
+ {
+ arrival_fraction = 1.f;
+ //LLFirstUse::useTeleport();
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
+ gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f);
+ gViewerWindow->setProgressString(message);
+ }
+ break;
+
+ case LLAgent::TELEPORT_LOCAL:
+ // Short delay when teleporting in the same sim (progress screen active but not shown - did not
+ // fall-through from TELEPORT_START)
+ {
+ if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY )
+ {
+ //LLFirstUse::useTeleport();
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ }
+ break;
+
+ case LLAgent::TELEPORT_NONE:
+ // No teleport in progress
+ gViewerWindow->setShowProgress(FALSE);
+ gTeleportDisplay = FALSE;
+ break;
+ }
+ }
+ else if(LLAppViewer::instance()->logoutRequestSent())
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
+ F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
+ if (percent_done > 100.f)
+ {
+ percent_done = 100.f;
+ }
+
+ if( LLApp::isExiting() )
+ {
+ percent_done = 100.f;
+ }
+
+ gViewerWindow->setProgressPercent( percent_done );
+ }
+ else
+ if (gRestoreGL)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
+ F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
+ if( percent_done > 100.f )
+ {
+ gViewerWindow->setShowProgress(FALSE);
+ gRestoreGL = FALSE;
+ }
+ else
+ {
+
+ if( LLApp::isExiting() )
+ {
+ percent_done = 100.f;
+ }
+
+ gViewerWindow->setProgressPercent( percent_done );
+ }
+ }
+
+ //////////////////////////
+ //
+ // Prepare for the next frame
+ //
+
+ /////////////////////////////
+ //
+ // Update the camera
+ //
+ //
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
+ LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
+ LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+
+ //////////////////////////
+ //
+ // clear the next buffer
+ // (must follow dynamic texture writing since that uses the frame buffer)
+ //
+
+ if (gDisconnected)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
+ render_ui();
+ }
+
+ //////////////////////////
+ //
+ // Set rendering options
+ //
+ //
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
+ stop_glerror();
+
+ ///////////////////////////////////////
+ //
+ // Slam lighting parameters back to our defaults.
+ // Note that these are not the same as GL defaults...
+
+ stop_glerror();
+ gGL.setAmbientLightColor(LLColor4::white);
+ stop_glerror();
+
+ /////////////////////////////////////
+ //
+ // Render
+ //
+ // Actually push all of our triangles to the screen.
+ //
+
+ // do render-to-texture stuff here
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
+ LLFastTimer t(FTM_UPDATE_TEXTURES);
+ if (LLViewerDynamicTexture::updateAllInstances())
+ {
+ gGL.setColorMask(true, true);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ }
+
+ gViewerWindow->setup3DViewport();
+
+ gPipeline.resetFrameStats(); // Reset per-frame statistics.
+
+ if (!gDisconnected)
+ {
+ LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ { //don't draw hud objects in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
+ { //don't draw hud particles in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ }
+
+ //upkeep gl name pools
+ LLGLNamePool::upkeepPools();
+
+ stop_glerror();
+ display_update_camera();
+ stop_glerror();
+
+ // *TODO: merge these two methods
+ {
+ LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
+ LLHUDManager::getInstance()->updateEffects();
+ LLHUDObject::updateAll();
+ stop_glerror();
+ }
+
+ {
+ LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
+ const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
+ gPipeline.createObjects(max_geom_update_time);
+ gPipeline.processPartitionQ();
+ gPipeline.updateGeom(max_geom_update_time);
+ stop_glerror();
+ }
+
+ gPipeline.updateGL();
+ stop_glerror();
+
+ S32 water_clip = 0;
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
+ (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
+ gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
+ {
+ if (LLViewerCamera::getInstance()->cameraUnderWater())
+ {
+ water_clip = -1;
+ }
+ else
+ {
+ water_clip = 1;
+ }
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
+
+ //Increment drawable frame counter
+ LLDrawable::incrementVisible();
+
+ LLSpatialGroup::sNoDelete = TRUE;
+ LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
+
+ /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
+ { //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
+ LLPipeline::sUseOcclusion = 3;
+ }*/
+
+ S32 occlusion = LLPipeline::sUseOcclusion;
+ if (gDepthDirty)
+ { //depth buffer is invalid, don't overwrite occlusion state
+ LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+ }
+ gDepthDirty = FALSE;
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ static LLCullResult result;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
+ stop_glerror();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ BOOL to_texture = gPipeline.canUseVertexShaders() &&
+ LLPipeline::sRenderGlow;
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
+
+ {
+ LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP);
+
+ if (gResizeScreenTexture)
+ {
+ gResizeScreenTexture = FALSE;
+ gPipeline.resizeScreenTexture();
+ }
+
+ gGL.setColorMask(true, true);
+ glClearColor(0,0,0,0);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ if (!for_snapshot)
+ {
+ if (gFrameCount > 1)
+ {
+ //for some reason, ATI 4800 series will error out if you
+ //try to generate a shadow before the first frame is through
+ gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ glh::matrix4f proj = glh_get_current_projection();
+ glh::matrix4f mod = glh_get_current_modelview();
+ glViewport(0,0,512,512);
+ LLVOAvatar::updateFreezeCounter() ;
+
+ if(!LLPipeline::sMemAllocationThrottled)
+ {
+ LLVOAvatar::updateImpostors();
+ }
+
+ glh_set_current_projection(proj);
+ glh_set_current_modelview(mod);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.loadMatrix(proj.m);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(mod.m);
+ gViewerWindow->setup3DViewport();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ }
+ glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkClientArrays();
+
+ //if (!for_snapshot)
+ {
+ LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
+ gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
+ gPipeline.generateHighlight(*LLViewerCamera::getInstance());
+ gPipeline.renderPhysicsDisplay();
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkClientArrays();
+
+ //////////////////////////////////////
+ //
+ // Update images, using the image stats generated during object update/culling
+ //
+ // Can put objects onto the retextured list.
+ //
+ // Doing this here gives hardware occlusion queries extra time to complete
+ LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
+
+ {
+ LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
+ LLFastTimer t(FTM_IMAGE_UPDATE);
+
+ {
+ LLFastTimer t(FTM_IMAGE_UPDATE_CLASS);
+ LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(),
+ LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean());
+ }
+
+
+ {
+ LLFastTimer t(FTM_IMAGE_UPDATE_BUMP);
+ gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
+ }
+
+ {
+ LLFastTimer t(FTM_IMAGE_UPDATE_LIST);
+ F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
+ max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
+ gTextureList.updateImages(max_image_decode_time);
+ }
+
+ {
+ LLFastTimer t(FTM_IMAGE_UPDATE_DELETE);
+ //remove dead textures from GL
+ LLImageGL::deleteDeadTextures();
+ stop_glerror();
+ }
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkClientArrays();
+
+ ///////////////////////////////////
+ //
+ // StateSort
+ //
+ // Responsible for taking visible objects, and adding them to the appropriate draw orders.
+ // In the case of alpha objects, z-sorts them first.
+ // Also creates special lists for outlines and selected face rendering.
+ //
+ LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
+ {
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
+ gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
+ stop_glerror();
+
+ if (rebuild)
+ {
+ //////////////////////////////////////
+ //
+ // rebuildPools
+ //
+ //
+ gPipeline.rebuildPools();
+ stop_glerror();
+ }
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkClientArrays();
+
+ LLPipeline::sUseOcclusion = occlusion;
+
+ {
+ LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
+ LLFastTimer t(FTM_UPDATE_SKY);
+ gSky.updateSky();
+ }
+
+ if(gUseWireframe)
+ {
+ glClearColor(0.5f, 0.5f, 0.5f, 0.f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
+
+ //// render frontmost floater opaque for occlusion culling purposes
+ //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
+ //// assumes frontmost floater with focus is opaque
+ //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
+ //{
+ // gGL.matrixMode(LLRender::MM_MODELVIEW);
+ // gGL.pushMatrix();
+ // {
+ // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+ // gGL.loadIdentity();
+
+ // LLRect floater_rect = frontmost_floaterp->calcScreenRect();
+ // // deflate by one pixel so rounding errors don't occlude outside of floater extents
+ // floater_rect.stretch(-1);
+ // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),
+ // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
+ // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
+ // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
+ // floater_3d_rect.translate(-0.5f, -0.5f);
+ // gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
+ // gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
+ // gGL.color4fv(LLColor4::white.mV);
+ // gGL.begin(LLVertexBuffer::QUADS);
+ // {
+ // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
+ // }
+ // gGL.end();
+ // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ // }
+ // gGL.popMatrix();
+ //}
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
+
+ LLGLState::checkStates();
+ LLGLState::checkClientArrays();
+
+ stop_glerror();
+
+
+ if (to_texture)
+ {
+ gGL.setColorMask(true, true);
+
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.mDeferredScreen.bindTarget();
+ glClearColor(1,0,1,1);
+ gPipeline.mDeferredScreen.clear();
+ }
+ else
+ {
+ gPipeline.mScreen.bindTarget();
+ if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
+ {
+ const LLColor4 &col = LLDrawPoolWater::sWaterFogColor;
+ glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+ }
+ gPipeline.mScreen.clear();
+ }
+
+ gGL.setColorMask(true, false);
+ }
+
+ if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
+ && !gRestoreGL)
+ {
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
+ gGL.setColorMask(true, false);
+
+
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
+ }
+ else
+ {
+ gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
+ }
+
+ gGL.setColorMask(true, true);
+
+ //store this frame's modelview matrix for use
+ //when rendering next frame's occlusion queries
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = gGLModelView[i];
+ gGLLastProjection[i] = gGLProjection[i];
+ }
+ stop_glerror();
+ }
+
+ for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
+ { //dummy cleanup of any currently bound textures
+ if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+ {
+ gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+ gGL.getTexUnit(i)->disable();
+ }
+ }
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
+
+ if (to_texture)
+ {
+ LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH);
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.mDeferredScreen.flush();
+ if(LLRenderTarget::sUseFBO)
+ {
+ LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),
+ gPipeline.mDeferredScreen.getHeight(), 0, 0,
+ gPipeline.mDeferredScreen.getWidth(),
+ gPipeline.mDeferredScreen.getHeight(),
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+ else
+ {
+ gPipeline.mScreen.flush();
+ if(LLRenderTarget::sUseFBO)
+ {
+ LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),
+ gPipeline.mScreen.getHeight(), 0, 0,
+ gPipeline.mScreen.getWidth(),
+ gPipeline.mScreen.getHeight(),
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+ }
+
+
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender )
+ {
+ gPipeline.renderDeferredLighting();
+ }
+
+ LLPipeline::sUnderWaterRender = FALSE;
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
+ if (!for_snapshot)
+ {
+ LLFastTimer t(FTM_RENDER_UI);
+ render_ui();
+ }
+
+
+ LLSpatialGroup::sNoDelete = FALSE;
+ gPipeline.clearReferences();
+
+ gPipeline.rebuildGroups();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
+
+ stop_glerror();
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ send_agent_resume();
+ LLPipeline::sRenderFrameTest = FALSE;
+ }
+
+ display_stats();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
+}
+
+void render_hud_attachments()
+{
+ LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+
+ glh::matrix4f current_proj = glh_get_current_projection();
+ glh::matrix4f current_mod = glh_get_current_modelview();
+
+ // clamp target zoom level to reasonable values
+ gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+ // smoothly interpolate current zoom level
+ gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
+
+ if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
+ {
+ LLCamera hud_cam = *LLViewerCamera::getInstance();
+ LLVector3 origin = hud_cam.getOrigin();
+ hud_cam.setOrigin(-1.f,0,0);
+ hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
+ LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
+
+ bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
+
+ //only render hud objects
+ gPipeline.pushRenderTypeMask();
+
+ // turn off everything
+ gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
+ // turn on HUD
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ // turn on HUD particles
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+
+ // if particles are off, turn off hud-particles as well
+ if (!render_particles)
+ {
+ // turn back off HUD particles
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ }
+
+ bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ if (has_ui)
+ {
+ gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ S32 use_occlusion = LLPipeline::sUseOcclusion;
+ LLPipeline::sUseOcclusion = 0;
+
+ //cull, sort, and render hud objects
+ static LLCullResult result;
+ LLSpatialGroup::sNoDelete = TRUE;
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ gPipeline.updateCull(hud_cam, result);
+
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
+
+ gPipeline.stateSort(hud_cam, result);
+
+ gPipeline.renderGeom(hud_cam);
+
+ LLSpatialGroup::sNoDelete = FALSE;
+ //gPipeline.clearReferences();
+
+ render_hud_elements();
+
+ //restore type mask
+ gPipeline.popRenderTypeMask();
+
+ if (has_ui)
+ {
+ gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+ LLPipeline::sUseOcclusion = use_occlusion;
+ }
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ glh_set_current_projection(current_proj);
+ glh_set_current_modelview(current_mod);
+}
+
+LLRect get_whole_screen_region()
+{
+ LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
+
+ // apply camera zoom transform (for high res screenshots)
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+ if (zoom_factor > 1.f)
+ {
+ S32 num_horizontal_tiles = llceil(zoom_factor);
+ S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
+ S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
+ int tile_y = sub_region / num_horizontal_tiles;
+ int tile_x = sub_region - (tile_y * num_horizontal_tiles);
+
+ whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
+ }
+ return whole_screen;
+}
+
+bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
+{
+ if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
+ {
+ F32 zoom_level = gAgentCamera.mHUDCurZoom;
+ LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
+
+ F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
+ proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
+ proj.element(2,2) = -0.01f;
+
+ F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
+
+ glh::matrix4f mat;
+ F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
+ F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
+ mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
+ mat.set_translate(
+ glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
+ clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
+ 0.f));
+ proj *= mat;
+
+ glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
+
+ mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
+ mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
+
+ tmp_model *= mat;
+ model = tmp_model;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
+{
+ LLRect whole_screen = get_whole_screen_region();
+ return get_hud_matrices(whole_screen, proj, model);
+}
+
+BOOL setup_hud_matrices()
+{
+ LLRect whole_screen = get_whole_screen_region();
+ return setup_hud_matrices(whole_screen);
+}
+
+BOOL setup_hud_matrices(const LLRect& screen_region)
+{
+ glh::matrix4f proj, model;
+ bool result = get_hud_matrices(screen_region, proj, model);
+ if (!result) return result;
+
+ // set up transform to keep HUD objects in front of camera
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.loadMatrix(proj.m);
+ glh_set_current_projection(proj);
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(model.m);
+ glh_set_current_modelview(model);
+ return TRUE;
+}
+
+static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
+
+void render_ui(F32 zoom_factor, int subfield)
+{
+ LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
+ LLGLState::checkStates();
+
+ glh::matrix4f saved_view = glh_get_current_modelview();
+
+ if (!gSnapshot)
+ {
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLLastModelView);
+ glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
+ }
+
+ {
+ BOOL to_texture = gPipeline.canUseVertexShaders() &&
+ LLPipeline::sRenderGlow;
+
+ if (to_texture)
+ {
+ gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
+ }
+
+ render_hud_elements();
+ render_hud_attachments();
+ }
+
+ LLGLSDefault gls_default;
+ LLGLSUIDefault gls_ui;
+ {
+ gPipeline.disableLights();
+ }
+
+ {
+ gGL.color4f(1,1,1,1);
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLFastTimer t(FTM_RENDER_UI);
+
+ if (!gDisconnected)
+ {
+ render_ui_3d();
+ LLGLState::checkStates();
+ }
+ else
+ {
+ render_disconnected_background();
+ }
+ render_ui_2d();
+ LLGLState::checkStates();
+ }
+ gGL.flush();
+
+ {
+ gViewerWindow->setup2DRender();
+ gViewerWindow->updateDebugText();
+ gViewerWindow->drawDebugText();
+ }
+
+ LLVertexBuffer::unbind();
+ }
+
+ if (!gSnapshot)
+ {
+ glh_set_current_modelview(saved_view);
+ gGL.popMatrix();
+ }
+
+ if (gDisplaySwapBuffers)
+ {
+ LLFastTimer t(FTM_SWAP);
+ gViewerWindow->getWindow()->swapBuffers();
+ }
+ gDisplaySwapBuffers = TRUE;
+}
+
+void renderCoordinateAxes()
+{
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.begin(LLRender::LINES);
+ gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(2.0f, 0.0f, 0.0f);
+ gGL.vertex3f(3.0f, 0.0f, 0.0f);
+ gGL.vertex3f(5.0f, 0.0f, 0.0f);
+ gGL.vertex3f(6.0f, 0.0f, 0.0f);
+ gGL.vertex3f(8.0f, 0.0f, 0.0f);
+ // Make an X
+ gGL.vertex3f(11.0f, 1.0f, 1.0f);
+ gGL.vertex3f(11.0f, -1.0f, -1.0f);
+ gGL.vertex3f(11.0f, 1.0f, -1.0f);
+ gGL.vertex3f(11.0f, -1.0f, 1.0f);
+
+ gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 2.0f, 0.0f);
+ gGL.vertex3f(0.0f, 3.0f, 0.0f);
+ gGL.vertex3f(0.0f, 5.0f, 0.0f);
+ gGL.vertex3f(0.0f, 6.0f, 0.0f);
+ gGL.vertex3f(0.0f, 8.0f, 0.0f);
+ // Make a Y
+ gGL.vertex3f(1.0f, 11.0f, 1.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(-1.0f, 11.0f, 1.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(0.0f, 11.0f, -1.0f);
+
+ gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 2.0f);
+ gGL.vertex3f(0.0f, 0.0f, 3.0f);
+ gGL.vertex3f(0.0f, 0.0f, 5.0f);
+ gGL.vertex3f(0.0f, 0.0f, 6.0f);
+ gGL.vertex3f(0.0f, 0.0f, 8.0f);
+ // Make a Z
+ gGL.vertex3f(-1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+ gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+ gGL.vertex3f(1.0f, -1.0f, 11.0f);
+ gGL.end();
+}
+
+
+void draw_axes()
+{
+ LLGLSUIDefault gls_ui;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ // A vertical white line at origin
+ LLVector3 v = gAgent.getPositionAgent();
+ gGL.begin(LLRender::LINES);
+ gGL.color3f(1.0f, 1.0f, 1.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 40.0f);
+ gGL.end();
+ // Some coordinate axes
+ gGL.pushMatrix();
+ gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
+ renderCoordinateAxes();
+ gGL.popMatrix();
+}
+
+void render_ui_3d()
+{
+ LLGLSPipeline gls_pipeline;
+
+ //////////////////////////////////////
+ //
+ // Render 3D UI elements
+ // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
+ // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
+ //
+
+ /////////////////////////////////////////////////////////////
+ //
+ // Render 2.5D elements (2D elements in the world)
+ // Stuff without z writes
+ //
+
+ // Debugging stuff goes before the UI.
+
+ stop_glerror();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+ // Coordinate axes
+ if (gSavedSettings.getBOOL("ShowAxes"))
+ {
+ draw_axes();
+ }
+
+ gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements
+ stop_glerror();
+}
+
+void render_ui_2d()
+{
+ LLGLSUIDefault gls_ui;
+
+ /////////////////////////////////////////////////////////////
+ //
+ // Render 2D UI elements that overlay the world (no z compare)
+
+ // Disable wireframe mode below here, as this is HUD/menus
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ // Menu overlays, HUD, etc
+ gViewerWindow->setup2DRender();
+
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+
+ if (zoom_factor > 1.f)
+ {
+ //decompose subregion number to x and y values
+ int pos_y = sub_region / llceil(zoom_factor);
+ int pos_x = sub_region - (pos_y*llceil(zoom_factor));
+ // offset for this tile
+ LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
+ LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
+ }
+
+ stop_glerror();
+ //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ // render outline for HUD
+ if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
+ {
+ gGL.pushMatrix();
+ S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
+ S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
+ gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
+ gGL.translatef((F32)half_width, (F32)half_height, 0.f);
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ gGL.scalef(zoom,zoom,1.f);
+ gGL.color4fv(LLColor4::white.mV);
+ gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
+ gGL.popMatrix();
+ stop_glerror();
+ }
+
+
+ if (gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ if (LLUI::sDirty)
+ {
+ LLUI::sDirty = FALSE;
+ LLRect t_rect;
+
+ gPipeline.mUIScreen.bindTarget();
+ gGL.setColorMask(true, true);
+ {
+ static const S32 pad = 8;
+
+ LLUI::sDirtyRect.mLeft -= pad;
+ LLUI::sDirtyRect.mRight += pad;
+ LLUI::sDirtyRect.mBottom -= pad;
+ LLUI::sDirtyRect.mTop += pad;
+
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ static LLRect last_rect = LLUI::sDirtyRect;
+
+ //union with last rect to avoid mouse poop
+ last_rect.unionWith(LLUI::sDirtyRect);
+
+ t_rect = LLUI::sDirtyRect;
+ LLUI::sDirtyRect = last_rect;
+ last_rect = t_rect;
+
+ last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
+ last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
+ last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
+ last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
+
+ LLRect clip_rect(last_rect);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ gViewerWindow->draw();
+ }
+
+ gPipeline.mUIScreen.flush();
+ gGL.setColorMask(true, false);
+
+ LLUI::sDirtyRect = t_rect;
+ }
+
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ S32 width = gViewerWindow->getWindowWidthScaled();
+ S32 height = gViewerWindow->getWindowHeightScaled();
+ gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.color4f(1,1,1,1);
+ gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0);
+ gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0);
+ gGL.texCoord2f(0, height); gGL.vertex2i(0, height);
+ gGL.texCoord2f(width, height); gGL.vertex2i(width, height);
+ gGL.end();
+ }
+ else
+ {
+ gViewerWindow->draw();
+ }
+
+
+
+ // reset current origin for font rendering, in case of tiling render
+ LLFontGL::sCurOrigin.set(0, 0);
+}
+
+void render_disconnected_background()
+{
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+ gGL.color4f(1,1,1,1);
+ if (!gDisconnectedImagep && gDisconnected)
+ {
+ llinfos << "Loading last bitmap..." << llendl;
+
+ std::string temp_str;
+ temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME;
+
+ LLPointer<LLImageBMP> image_bmp = new LLImageBMP;
+ if( !image_bmp->load(temp_str) )
+ {
+ //llinfos << "Bitmap load failed" << llendl;
+ return;
+ }
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ if (!image_bmp->decode(raw, 0.0f))
+ {
+ llinfos << "Bitmap decode failed" << llendl;
+ gDisconnectedImagep = NULL;
+ return;
+ }
+
+ U8 *rawp = raw->getData();
+ S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight();
+ for (S32 i = 0; i < npixels; i++)
+ {
+ S32 sum = 0;
+ sum = *rawp + *(rawp+1) + *(rawp+2);
+ sum /= 3;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ }
+
+
+ raw->expandToPowerOfTwo();
+ gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE );
+ gStartTexture = gDisconnectedImagep;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ // Make sure the progress view always fills the entire window.
+ S32 width = gViewerWindow->getWindowWidthScaled();
+ S32 height = gViewerWindow->getWindowHeightScaled();
+
+ if (gDisconnectedImagep)
+ {
+ LLGLSUIDefault gls_ui;
+ gViewerWindow->setup2DRender();
+ gGL.pushMatrix();
+ {
+ // scale ui to reflect UIScaleFactor
+ // this can't be done in setup2DRender because it requires a
+ // pushMatrix/popMatrix pair
+ const LLVector2& display_scale = gViewerWindow->getDisplayScale();
+ gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
+
+ gGL.getTexUnit(0)->bind(gDisconnectedImagep);
+ gGL.color4f(1.f, 1.f, 1.f, 1.f);
+ gl_rect_2d_simple_tex(width, height);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ gGL.popMatrix();
+ }
+ gGL.flush();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.unbind();
+ }
+
+}
+
+void display_cleanup()
+{
+ gDisconnectedImagep = NULL;
+}
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 7fdaac68c8..12f802b29a 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -84,6 +84,10 @@ #include "llfloaterobjectweights.h" #include "llfloateropenobject.h" #include "llfloateroutbox.h" +#include "llfloaterpathfindingbasic.h" +#include "llfloaterpathfindingcharacters.h" +#include "llfloaterpathfindinglinksets.h" +#include "llfloaterpathfindingconsole.h" #include "llfloaterpay.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -243,6 +247,10 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); LLFloaterPayUtil::registerFloater(); + LLFloaterReg::add("pathfinding_basic", "floater_pathfinding_basic.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingBasic>); + LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); + LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); + LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 12aed8f448..e91a1d6afa 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -110,6 +110,7 @@ #include "lleconomy.h" #include "lltoolgrab.h" #include "llwindow.h" +#include "llpathfindingmanager.h" #include "boost/unordered_map.hpp" using namespace LLVOAvatarDefines; @@ -197,7 +198,6 @@ void near_sit_object(); BOOL is_selection_buy_not_take(); S32 selection_price(); BOOL enable_take(); -void handle_take(); void handle_object_show_inspector(); void handle_avatar_show_inspector(); bool confirm_take(const LLSD& notification, const LLSD& response); @@ -4753,6 +4753,14 @@ class LLToolsSaveToObjectInventory : public view_listener_t } }; +class LLToolsEnableLinksets : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return LLPathfindingManager::getInstance()->isAllowAlterPermanent(); + } +}; + // Round the position of all root objects to the grid class LLToolsSnapObjectXY : public view_listener_t { @@ -5011,6 +5019,12 @@ class LLEditDelete : public view_listener_t } }; +bool enable_object_return() +{ + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); +} + bool enable_object_delete() { bool new_value = @@ -5026,6 +5040,49 @@ bool enable_object_delete() return new_value; } +class LLObjectsReturnPackage +{ +public: + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; + + LLObjectSelectionHandle mObjectSelection; + LLDynamicArray<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; +}; + +static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) +{ + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } + + delete objectsReturnPackage; +} + +void handle_object_return() +{ + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } +} + void handle_object_delete() { @@ -8090,6 +8147,8 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory"); view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsEnableLinksets(), "Tools.EnableLinksets"); + // Help menu // most items use the ShowFloater method view_listener_t::addMenu(new LLToggleHowTo(), "Help.ToggleHowTo"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 87cb4efbc4..f10891737f 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -93,11 +93,20 @@ void handle_object_touch(); bool enable_object_open(); void handle_object_open(); +bool visible_take_object(); +bool tools_visible_take_object(); +bool enable_object_take_copy(); +bool enable_object_return(); +bool enable_object_delete(); + // Buy either contents or object itself void handle_buy(); +void handle_take(); void handle_take_copy(); void handle_look_at_selection(const LLSD& param); void handle_zoom_to_object(LLUUID object_id); +void handle_object_return(); +void handle_object_delete(); void handle_buy_land(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index dc55247df2..e2f9b1f1a0 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,1298 +1,1298 @@ -/** - * @file llviewermenufile.cpp - * @brief "File" menu in the main menu bar. - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewermenufile.h" - -// project includes -#include "llagent.h" -#include "llagentcamera.h" -#include "llfilepicker.h" -#include "llfloaterreg.h" -#include "llbuycurrencyhtml.h" -#include "llfloatermodelpreview.h" -#include "llfloatersnapshot.h" -#include "llimage.h" -#include "llimagebmp.h" -#include "llimagepng.h" -#include "llimagej2c.h" -#include "llimagejpeg.h" -#include "llimagetga.h" -#include "llinventorymodel.h" // gInventory -#include "llresourcedata.h" -#include "llfloaterperms.h" -#include "llstatusbar.h" -#include "llviewercontrol.h" // gSavedSettings -#include "llviewertexturelist.h" -#include "lluictrlfactory.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llviewerinventory.h" -#include "llviewermenu.h" // gMenuHolder -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llviewerwindow.h" -#include "llappviewer.h" -#include "lluploaddialog.h" -#include "lltrans.h" -#include "llfloaterbuycurrency.h" - -// linden libraries -#include "llassetuploadresponders.h" -#include "lleconomy.h" -#include "llhttpclient.h" -#include "llnotificationsutil.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "llstring.h" -#include "lltransactiontypes.h" -#include "lluuid.h" -#include "llvorbisencode.h" -#include "message.h" - -// system libraries -#include <boost/tokenizer.hpp> - -class LLFileEnableUpload : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); - return new_value; - } -}; - -class LLFileEnableUploadModel : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return true; - } -}; - -class LLMeshEnabled : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gSavedSettings.getBOOL("MeshEnabled"); - } -}; - -class LLMeshUploadVisible : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gMeshRepo.meshUploadEnabled(); - } -}; - -LLMutex* LLFilePickerThread::sMutex = NULL; -std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ; - -void LLFilePickerThread::getFile() -{ -#if LL_WINDOWS - start(); -#else - run(); -#endif -} - -//virtual -void LLFilePickerThread::run() -{ - LLFilePicker picker; -#if LL_WINDOWS - if (picker.getOpenFile(mFilter, false)) - { - mFile = picker.getFirstFile(); - } -#else - if (picker.getOpenFile(mFilter, true)) - { - mFile = picker.getFirstFile(); - } -#endif - - { - LLMutexLock lock(sMutex); - sDeadQ.push(this); - } - -} - -//static -void LLFilePickerThread::initClass() -{ - sMutex = new LLMutex(NULL); -} - -//static -void LLFilePickerThread::cleanupClass() -{ - clearDead(); - - delete sMutex; - sMutex = NULL; -} - -//static -void LLFilePickerThread::clearDead() -{ - if (!sDeadQ.empty()) - { - LLMutexLock lock(sMutex); - while (!sDeadQ.empty()) - { - LLFilePickerThread* thread = sDeadQ.front(); - thread->notify(thread->mFile); - delete thread; - sDeadQ.pop(); - } - } -} - - -//============================================================================ - -#if LL_WINDOWS -static std::string SOUND_EXTENSIONS = "wav"; -static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png"; -static std::string ANIM_EXTENSIONS = "bvh anim"; -#ifdef _CORY_TESTING -static std::string GEOMETRY_EXTENSIONS = "slg"; -#endif -static std::string XML_EXTENSIONS = "xml"; -static std::string SLOBJECT_EXTENSIONS = "slobject"; -#endif -static std::string ALL_FILE_EXTENSIONS = "*.*"; -static std::string MODEL_EXTENSIONS = "dae"; - -std::string build_extensions_string(LLFilePicker::ELoadFilter filter) -{ - switch(filter) - { -#if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: - return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: - return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: - return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: - return SLOBJECT_EXTENSIONS; - case LLFilePicker::FFLOAD_MODEL: - return MODEL_EXTENSIONS; -#ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: - return GEOMETRY_EXTENSIONS; -#endif - case LLFilePicker::FFLOAD_XML: - return XML_EXTENSIONS; - case LLFilePicker::FFLOAD_ALL: - return ALL_FILE_EXTENSIONS; -#endif - default: - return ALL_FILE_EXTENSIONS; - } -} - -/** - char* upload_pick(void* data) - - If applicable, brings up a file chooser in which the user selects a file - to upload for a particular task. If the file is valid for the given action, - returns the string to the full path filename, else returns NULL. - Data is the load filter for the type of file as defined in LLFilePicker. -**/ -const std::string upload_pick(void* data) -{ - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - // This doesn't seem necessary. JC - // display(); - } - - LLFilePicker::ELoadFilter type; - if(data) - { - type = (LLFilePicker::ELoadFilter)((intptr_t)data); - } - else - { - type = LLFilePicker::FFLOAD_ALL; - } - - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(type)) - { - llinfos << "Couldn't import objects from file" << llendl; - return std::string(); - } - - - const std::string& filename = picker.getFirstFile(); - std::string ext = gDirUtilp->getExtension(filename); - - //strincmp doesn't like NULL pointers - if (ext.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - LLSD args; - args["FILE"] = short_name; - LLNotificationsUtil::add("NoFileExtension", args); - return std::string(); - } - else - { - //so there is an extension - //loop over the valid extensions and compare to see - //if the extension is valid - - //now grab the set of valid file extensions - std::string valid_extensions = build_extensions_string(type); - - BOOL ext_valid = FALSE; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(" "); - tokenizer tokens(valid_extensions, sep); - tokenizer::iterator token_iter; - - //now loop over all valid file extensions - //and compare them to the extension of the file - //to be uploaded - for( token_iter = tokens.begin(); - token_iter != tokens.end() && ext_valid != TRUE; - ++token_iter) - { - const std::string& cur_token = *token_iter; - - if (cur_token == ext || cur_token == "*.*") - { - //valid extension - //or the acceptable extension is any - ext_valid = TRUE; - } - }//end for (loop over all tokens) - - if (ext_valid == FALSE) - { - //should only get here if the extension exists - //but is invalid - LLSD args; - args["EXTENSION"] = ext; - args["VALIDS"] = valid_extensions; - LLNotificationsUtil::add("InvalidFileExtension", args); - return std::string(); - } - }//end else (non-null extension) - - //valid file extension - - //now we check to see - //if the file is actually a valid image/sound/etc. - if (type == LLFilePicker::FFLOAD_WAV) - { - // pre-qualify wavs to make sure the format is acceptable - std::string error_msg; - if (check_for_invalid_wav_formats(filename,error_msg)) - { - llinfos << error_msg << ": " << filename << llendl; - LLSD args; - args["FILE"] = filename; - LLNotificationsUtil::add( error_msg, args ); - return std::string(); - } - }//end if a wave/sound file - - - return filename; -} - -class LLFileUploadImage : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } - return TRUE; - } -}; - -class LLFileUploadModel : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); - if (fmp) - { - fmp->loadModel(3); - } - - return TRUE; - } -}; - -class LLFileUploadSound : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); - } - return true; - } -}; - -class LLFileUploadAnim : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); - if (!filename.empty()) - { - if (filename.rfind(".anim") != std::string::npos) - { - LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); - } - else - { - LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); - } - } - return true; - } -}; - -class LLFileUploadBulk : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - - // TODO: - // Iterate over all files - // Check extensions for uploadability, cost - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund - - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - const std::string& filename = picker.getFirstFile(); - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - - upload_new_resource( - filename, - asset_name, - asset_name, - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), - LLFloaterPerms::getGroupPerms(), - LLFloaterPerms::getEveryonePerms(), - display_name, - callback, - expected_upload_cost, - userdata); - - // *NOTE: Ew, we don't iterate over the file list here, - // we handle the next files in upload_done_callback() - } - else - { - llinfos << "Couldn't import objects from file" << llendl; - } - return true; - } -}; - -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) -{ - llwarns << error_message << llendl; - LLNotificationsUtil::add(label, args); - if(LLFile::remove(filename) == -1) - { - lldebugs << "unable to remove temp file" << llendl; - } - LLFilePicker::instance().reset(); -} - -class LLFileEnableCloseWindow : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = NULL != LLFloater::getClosableFloaterFromFocus(); - return new_value; - } -}; - -class LLFileCloseWindow : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloater::closeFocusedFloater(); - - return true; - } -}; - -class LLFileEnableCloseAllWindows : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool open_children = gFloaterView->allChildrenClosed(); - return !open_children; - } -}; - -class LLFileCloseAllWindows : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool app_quitting = false; - gFloaterView->closeAllChildren(app_quitting); - - return true; - } -}; - -class LLFileTakeSnapshotToDisk : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPointer<LLImageRaw> raw = new LLImageRaw; - - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - if (gSavedSettings.getBOOL("HighResSnapshot")) - { - width *= 2; - height *= 2; - } - - if (gViewerWindow->rawSnapshot(raw, - width, - height, - TRUE, - FALSE, - gSavedSettings.getBOOL("RenderUIInSnapshot"), - FALSE)) - { - gViewerWindow->playSnapshotAnimAndSound(); - LLPointer<LLImageFormatted> formatted; - LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); - switch (fmt) - { - case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: - formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); - break; - default: - llwarns << "Unknown local snapshot format: " << fmt << llendl; - case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: - formatted = new LLImagePNG; - break; - case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: - formatted = new LLImageBMP; - break; - } - formatted->enableOverSize() ; - formatted->encode(raw, 0); - formatted->disableOverSize() ; - gViewerWindow->saveImageNumbered(formatted); - } - return true; - } -}; - -class LLFileQuit : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLAppViewer::instance()->userQuit(); - return true; - } -}; - - -void handle_compress_image(void*) -{ - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) - { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) - { - std::string outfile = infile + ".j2c"; - - llinfos << "Input: " << infile << llendl; - llinfos << "Output: " << outfile << llendl; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - llinfos << "Compression complete" << llendl; - } - else - { - llinfos << "Compression failed: " << LLImage::getLastError() << llendl; - } - - infile = picker.getNextFile(); - } - } -} - -LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) -{ - // Generate the temporary UUID. - std::string filename = gDirUtilp->getTempFilename(); - LLTransactionID tid; - LLAssetID uuid; - - LLSD args; - - std::string exten = gDirUtilp->getExtension(src_filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - LLAssetType::EType asset_type = LLAssetType::AT_NONE; - std::string error_message; - - BOOL error = FALSE; - - if (exten.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - error_message = llformat( - "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", - short_name.c_str()); - args["FILE"] = short_name; - upload_error(error_message, "NoFileExtension", filename, args); - return LLUUID(); - } - else if (codec != IMG_CODEC_INVALID) - { - // It's an image file, the upload procedure is the same for all - asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec )) - { - error_message = llformat( "Problem with file %s:\n\n%s\n", - src_filename.c_str(), LLImage::getLastError().c_str()); - args["FILE"] = src_filename; - args["ERROR"] = LLImage::getLastError(); - upload_error(error_message, "ProblemWithFile", filename, args); - return LLUUID(); - } - } - else if(exten == "wav") - { - asset_type = LLAssetType::AT_SOUND; // tag it as audio - S32 encode_result = 0; - - llinfos << "Attempting to encode wav as an ogg file" << llendl; - - encode_result = encode_vorbis_file(src_filename, filename); - - if (LLVORBISENC_NOERR != encode_result) - { - switch(encode_result) - { - case LLVORBISENC_DEST_OPEN_ERR: - error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); - break; - - default: - error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); - break; - } - return LLUUID(); - } - } - else if(exten == "tmp") - { - // This is a generic .lin resource file - asset_type = LLAssetType::AT_OBJECT; - LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */ - if (in) - { - // read in the file header - char buf[16384]; /* Flawfinder: ignore */ - size_t readbytes; - S32 version; - if (fscanf(in, "LindenResource\nversion %d\n", &version)) - { - if (2 == version) - { - // *NOTE: This buffer size is hard coded into scanf() below. - char label[MAX_STRING]; /* Flawfinder: ignore */ - char value[MAX_STRING]; /* Flawfinder: ignore */ - S32 tokens_read; - while (fgets(buf, 1024, in)) - { - label[0] = '\0'; - value[0] = '\0'; - tokens_read = sscanf( /* Flawfinder: ignore */ - buf, - "%254s %254s\n", - label, value); - - llinfos << "got: " << label << " = " << value - << llendl; - - if (EOF == tokens_read) - { - fclose(in); - error_message = llformat("corrupt resource file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "CorruptResourceFile", filename, args); - return LLUUID(); - } - - if (2 == tokens_read) - { - if (! strcmp("type", label)) - { - asset_type = (LLAssetType::EType)(atoi(value)); - } - } - else - { - if (! strcmp("_DATA_", label)) - { - // below is the data section - break; - } - } - // other values are currently discarded - } - - } - else - { - fclose(in); - error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownResourceFileVersion", filename, args); - return LLUUID(); - } - } - else - { - // this is an original binary formatted .lin file - // start over at the beginning of the file - fseek(in, 0, SEEK_SET); - - const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256; - const S32 MAX_ASSET_NAME_LENGTH = 64; - S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH; - S16 type_num; - - // read in and throw out most of the header except for the type - if (fread(buf, header_size, 1, in) != 1) - { - llwarns << "Short read" << llendl; - } - memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */ - asset_type = (LLAssetType::EType)type_num; - } - - // copy the file's data segment into another file for uploading - LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - if (out) - { - while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ - { - if (fwrite(buf, 1, readbytes, out) != readbytes) - { - llwarns << "Short write" << llendl; - } - } - fclose(out); - } - else - { - fclose(in); - error_message = llformat( "Unable to create output file: %s", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "UnableToCreateOutputFile", filename, args); - return LLUUID(); - } - - fclose(in); - } - else - { - llinfos << "Couldn't open .lin file " << src_filename << llendl; - } - } - else if (exten == "bvh") - { - error_message = llformat("We do not currently support bulk upload of animation files\n"); - upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); - return LLUUID(); - } - else if (exten == "anim") - { - asset_type = LLAssetType::AT_ANIMATION; - filename = src_filename; - } - else - { - // Unknown extension - error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); - error = TRUE;; - } - - // gen a new transaction ID for this asset - tid.generate(); - - if (!error) - { - uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - // copy this file into the vfs for upload - S32 file_size; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); - if (infile.getFileHandle()) - { - LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); - - file.setMaxSize(file_size); - - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while ((file_size = infile.read(copy_buf, buf_size))) - { - file.write(copy_buf, file_size); - } - } - else - { - error_message = llformat( "Unable to access output file: %s", filename.c_str()); - error = TRUE; - } - } - - if (!error) - { - std::string t_disp_name = display_name; - if (t_disp_name.empty()) - { - t_disp_name = src_filename; - } - upload_new_resource( - tid, - asset_type, - name, - desc, - compression_info, // tid - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms, - display_name, - callback, - expected_upload_cost, - userdata); - } - else - { - llwarns << error_message << llendl; - LLSD args; - args["ERROR_MESSAGE"] = error_message; - LLNotificationsUtil::add("ErrorMessage", args); - if(LLFile::remove(filename) == -1) - { - lldebugs << "unable to remove temp file" << llendl; - } - LLFilePicker::instance().reset(); - } - - return uuid; -} - -void upload_done_callback( - const LLUUID& uuid, - void* user_data, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLResourceData* data = (LLResourceData*)user_data; - S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; - //LLAssetType::EType pref_loc = data->mPreferredLocation; - BOOL is_balance_sufficient = TRUE; - - if(data) - { - if (result >= 0) - { - LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; - - if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || - LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || - LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) - { - // Charge the user for the upload. - LLViewerRegion* region = gAgent.getRegion(); - - if(!(can_afford_transaction(expected_upload_cost))) - { - LLStringUtil::format_map_t args; - args["NAME"] = data->mAssetInfo.getName(); - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); - is_balance_sufficient = FALSE; - } - else if(region) - { - // Charge user for upload - gStatusBar->debitBalance(expected_upload_cost); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); - msg->addU8("Flags", 0); - // we tell the sim how much we were expecting to pay so it - // can respond to any discrepancy - msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); - msg->addStringFast(_PREHASH_Description, NULL); - msg->sendReliable(region->getHost()); - } - } - - if(is_balance_sufficient) - { - // Actually add the upload to inventory - llinfos << "Adding " << uuid << " to inventory." << llendl; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); - if(folder_id.notNull()) - { - U32 next_owner_perms = data->mNextOwnerPerm; - if(PERM_NONE == next_owner_perms) - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), - data->mAssetInfo.getDescription(), data->mAssetInfo.mType, - data->mInventoryType, NOT_WEARABLE, next_owner_perms, - LLPointer<LLInventoryCallback>(NULL)); - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } - } - } - else // if(result >= 0) - { - LLSD args; - args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); - LLNotificationsUtil::add("CannotUploadReason", args); - } - } - - LLUploadDialog::modalUploadFinished(); - delete data; - data = NULL; - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - void *userdata = NULL; - upload_new_resource( - next_file, - asset_name, - asset_name, // file - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - PERM_NONE, - PERM_NONE, - PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } -} - -static LLAssetID upload_new_resource_prep( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - LLAssetID uuid = generate_asset_id_for_new_upload(tid); - - increase_new_upload_stats(asset_type); - - assign_defaults_and_show_upload_message( - asset_type, - inventory_type, - name, - display_name, - description); - - return uuid; -} - -LLSD generate_new_resource_upload_capability_body( - LLAssetType::EType asset_type, - const std::string& name, - const std::string& desc, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms) -{ - LLSD body; - - body["folder_id"] = gInventory.findCategoryUUIDForType( - (destination_folder_type == LLFolderType::FT_NONE) ? - (LLFolderType::EType) asset_type : - destination_folder_type); - - body["asset_type"] = LLAssetType::lookup(asset_type); - body["inventory_type"] = LLInventoryType::lookup(inv_type); - body["name"] = name; - body["description"] = desc; - body["next_owner_mask"] = LLSD::Integer(next_owner_perms); - body["group_mask"] = LLSD::Integer(group_perms); - body["everyone_mask"] = LLSD::Integer(everyone_perms); - - return body; -} - -void upload_new_resource( - const LLTransactionID &tid, - LLAssetType::EType asset_type, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) -{ - if(gDisconnected) - { - return ; - } - - LLAssetID uuid = - upload_new_resource_prep( - tid, - asset_type, - inv_type, - name, - display_name, - desc); - - if( LLAssetType::AT_SOUND == asset_type ) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT ); - } - else - if( LLAssetType::AT_TEXTURE == asset_type ) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); - } - else - if( LLAssetType::AT_ANIMATION == asset_type) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT ); - } - - if(LLInventoryType::IT_NONE == inv_type) - { - inv_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(desc); - if(name.empty()) - { - name = "(No Name)"; - } - if(desc.empty()) - { - desc = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); - - llinfos << "*** Uploading: " << llendl; - llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; - llinfos << "UUID: " << uuid << llendl; - llinfos << "Name: " << name << llendl; - llinfos << "Desc: " << desc << llendl; - llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl; - lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl; - lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; - - std::string url = gAgent.getRegion()->getCapability( - "NewFileAgentInventory"); - - if ( !url.empty() ) - { - llinfos << "New Agent Inventory via capability" << llendl; - - LLSD body; - body = generate_new_resource_upload_capability_body( - asset_type, - name, - desc, - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms); - - LLHTTPClient::post( - url, - body, - new LLNewAgentInventoryResponder( - body, - uuid, - asset_type)); - } - else - { - llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl; - // check for adequate funds - // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == asset_type || - LLAssetType::AT_TEXTURE == asset_type || - LLAssetType::AT_ANIMATION == asset_type) - { - S32 balance = gStatusBar->getBalance(); - if (balance < expected_upload_cost) - { - // insufficient funds, bail on this upload - LLStringUtil::format_map_t args; - args["NAME"] = name; - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); - return; - } - } - - LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = tid; - data->mAssetInfo.mUuid = uuid; - data->mAssetInfo.mType = asset_type; - data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = inv_type; - data->mNextOwnerPerm = next_owner_perms; - data->mExpectedUploadCost = expected_upload_cost; - data->mUserData = userdata; - data->mAssetInfo.setName(name); - data->mAssetInfo.setDescription(desc); - data->mPreferredLocation = destination_folder_type; - - LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; - if (callback) - { - asset_callback = callback; - } - gAssetStorage->storeAssetData( - data->mAssetInfo.mTransactionID, - data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); - } -} - -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) -{ - if ( gDisconnected ) - { - LLAssetID rv; - - rv.setNull(); - return rv; - } - - LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - - return uuid; -} - -void increase_new_upload_stats(LLAssetType::EType asset_type) -{ - if ( LLAssetType::AT_SOUND == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_SOUND_COUNT ); - } - else if ( LLAssetType::AT_TEXTURE == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); - } - else if ( LLAssetType::AT_ANIMATION == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_ANIM_COUNT ); - } -} - -void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - if ( LLInventoryType::IT_NONE == inventory_type ) - { - inventory_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(description); - - if ( name.empty() ) - { - name = "(No Name)"; - } - if ( description.empty() ) - { - description = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); -} - - -void init_menu_file() -{ - view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); - view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); - view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); - view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); - view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); - view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); - view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); - view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); - view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); - view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); - view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - - view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); - view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); - view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); - - // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. -} +/**
+ * @file llviewermenufile.cpp
+ * @brief "File" menu in the main menu bar.
+ *
+ * $LicenseInfo:firstyear=2002&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewermenufile.h"
+
+// project includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfilepicker.h"
+#include "llfloaterreg.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloatermodelpreview.h"
+#include "llfloatersnapshot.h"
+#include "llimage.h"
+#include "llimagebmp.h"
+#include "llimagepng.h"
+#include "llimagej2c.h"
+#include "llimagejpeg.h"
+#include "llimagetga.h"
+#include "llinventorymodel.h" // gInventory
+#include "llresourcedata.h"
+#include "llfloaterperms.h"
+#include "llstatusbar.h"
+#include "llviewercontrol.h" // gSavedSettings
+#include "llviewertexturelist.h"
+#include "lluictrlfactory.h"
+#include "llvfile.h"
+#include "llvfs.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h" // gMenuHolder
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerwindow.h"
+#include "llappviewer.h"
+#include "lluploaddialog.h"
+#include "lltrans.h"
+#include "llfloaterbuycurrency.h"
+
+// linden libraries
+#include "llassetuploadresponders.h"
+#include "lleconomy.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llstring.h"
+#include "lltransactiontypes.h"
+#include "lluuid.h"
+#include "llvorbisencode.h"
+#include "message.h"
+
+// system libraries
+#include <boost/tokenizer.hpp>
+
+class LLFileEnableUpload : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
+ return new_value;
+ }
+};
+
+class LLFileEnableUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return true;
+ }
+};
+
+class LLMeshEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gSavedSettings.getBOOL("MeshEnabled");
+ }
+};
+
+class LLMeshUploadVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gMeshRepo.meshUploadEnabled();
+ }
+};
+
+LLMutex* LLFilePickerThread::sMutex = NULL;
+std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
+
+void LLFilePickerThread::getFile()
+{
+#if LL_WINDOWS
+ start();
+#else
+ run();
+#endif
+}
+
+//virtual
+void LLFilePickerThread::run()
+{
+ LLFilePicker picker;
+#if LL_WINDOWS
+ if (picker.getOpenFile(mFilter, false))
+ {
+ mFile = picker.getFirstFile();
+ }
+#else
+ if (picker.getOpenFile(mFilter, true))
+ {
+ mFile = picker.getFirstFile();
+ }
+#endif
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(this);
+ }
+
+}
+
+//static
+void LLFilePickerThread::initClass()
+{
+ sMutex = new LLMutex(NULL);
+}
+
+//static
+void LLFilePickerThread::cleanupClass()
+{
+ clearDead();
+
+ delete sMutex;
+ sMutex = NULL;
+}
+
+//static
+void LLFilePickerThread::clearDead()
+{
+ if (!sDeadQ.empty())
+ {
+ LLMutexLock lock(sMutex);
+ while (!sDeadQ.empty())
+ {
+ LLFilePickerThread* thread = sDeadQ.front();
+ thread->notify(thread->mFile);
+ delete thread;
+ sDeadQ.pop();
+ }
+ }
+}
+
+
+//============================================================================
+
+#if LL_WINDOWS
+static std::string SOUND_EXTENSIONS = "wav";
+static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
+static std::string ANIM_EXTENSIONS = "bvh anim";
+#ifdef _CORY_TESTING
+static std::string GEOMETRY_EXTENSIONS = "slg";
+#endif
+static std::string XML_EXTENSIONS = "xml";
+static std::string SLOBJECT_EXTENSIONS = "slobject";
+#endif
+static std::string ALL_FILE_EXTENSIONS = "*.*";
+static std::string MODEL_EXTENSIONS = "dae";
+
+std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
+{
+ switch(filter)
+ {
+#if LL_WINDOWS
+ case LLFilePicker::FFLOAD_IMAGE:
+ return IMAGE_EXTENSIONS;
+ case LLFilePicker::FFLOAD_WAV:
+ return SOUND_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ANIM:
+ return ANIM_EXTENSIONS;
+ case LLFilePicker::FFLOAD_SLOBJECT:
+ return SLOBJECT_EXTENSIONS;
+ case LLFilePicker::FFLOAD_MODEL:
+ return MODEL_EXTENSIONS;
+#ifdef _CORY_TESTING
+ case LLFilePicker::FFLOAD_GEOMETRY:
+ return GEOMETRY_EXTENSIONS;
+#endif
+ case LLFilePicker::FFLOAD_XML:
+ return XML_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ALL:
+ return ALL_FILE_EXTENSIONS;
+#endif
+ default:
+ return ALL_FILE_EXTENSIONS;
+ }
+}
+
+/**
+ char* upload_pick(void* data)
+
+ If applicable, brings up a file chooser in which the user selects a file
+ to upload for a particular task. If the file is valid for the given action,
+ returns the string to the full path filename, else returns NULL.
+ Data is the load filter for the type of file as defined in LLFilePicker.
+**/
+const std::string upload_pick(void* data)
+{
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ // This doesn't seem necessary. JC
+ // display();
+ }
+
+ LLFilePicker::ELoadFilter type;
+ if(data)
+ {
+ type = (LLFilePicker::ELoadFilter)((intptr_t)data);
+ }
+ else
+ {
+ type = LLFilePicker::FFLOAD_ALL;
+ }
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (!picker.getOpenFile(type))
+ {
+ llinfos << "Couldn't import objects from file" << llendl;
+ return std::string();
+ }
+
+
+ const std::string& filename = picker.getFirstFile();
+ std::string ext = gDirUtilp->getExtension(filename);
+
+ //strincmp doesn't like NULL pointers
+ if (ext.empty())
+ {
+ std::string short_name = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ LLSD args;
+ args["FILE"] = short_name;
+ LLNotificationsUtil::add("NoFileExtension", args);
+ return std::string();
+ }
+ else
+ {
+ //so there is an extension
+ //loop over the valid extensions and compare to see
+ //if the extension is valid
+
+ //now grab the set of valid file extensions
+ std::string valid_extensions = build_extensions_string(type);
+
+ BOOL ext_valid = FALSE;
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ tokenizer tokens(valid_extensions, sep);
+ tokenizer::iterator token_iter;
+
+ //now loop over all valid file extensions
+ //and compare them to the extension of the file
+ //to be uploaded
+ for( token_iter = tokens.begin();
+ token_iter != tokens.end() && ext_valid != TRUE;
+ ++token_iter)
+ {
+ const std::string& cur_token = *token_iter;
+
+ if (cur_token == ext || cur_token == "*.*")
+ {
+ //valid extension
+ //or the acceptable extension is any
+ ext_valid = TRUE;
+ }
+ }//end for (loop over all tokens)
+
+ if (ext_valid == FALSE)
+ {
+ //should only get here if the extension exists
+ //but is invalid
+ LLSD args;
+ args["EXTENSION"] = ext;
+ args["VALIDS"] = valid_extensions;
+ LLNotificationsUtil::add("InvalidFileExtension", args);
+ return std::string();
+ }
+ }//end else (non-null extension)
+
+ //valid file extension
+
+ //now we check to see
+ //if the file is actually a valid image/sound/etc.
+ if (type == LLFilePicker::FFLOAD_WAV)
+ {
+ // pre-qualify wavs to make sure the format is acceptable
+ std::string error_msg;
+ if (check_for_invalid_wav_formats(filename,error_msg))
+ {
+ llinfos << error_msg << ": " << filename << llendl;
+ LLSD args;
+ args["FILE"] = filename;
+ LLNotificationsUtil::add( error_msg, args );
+ return std::string();
+ }
+ }//end if a wave/sound file
+
+
+ return filename;
+}
+
+class LLFileUploadImage : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_image", LLSD(filename));
+ }
+ return TRUE;
+ }
+};
+
+class LLFileUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
+ if (fmp)
+ {
+ fmp->loadModel(3);
+ }
+
+ return TRUE;
+ }
+};
+
+class LLFileUploadSound : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_sound", LLSD(filename));
+ }
+ return true;
+ }
+};
+
+class LLFileUploadAnim : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM);
+ if (!filename.empty())
+ {
+ if (filename.rfind(".anim") != std::string::npos)
+ {
+ LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename));
+ }
+ else
+ {
+ LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename));
+ }
+ }
+ return true;
+ }
+};
+
+class LLFileUploadBulk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ // TODO:
+ // Iterate over all files
+ // Check extensions for uploadability, cost
+ // Check user balance for entire cost
+ // Charge user entire cost
+ // Loop, uploading
+ // If an upload fails, refund the user for that one
+ //
+ // Also fix single upload to charge first, then refund
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles())
+ {
+ const std::string& filename = picker.getFirstFile();
+ std::string name = gDirUtilp->getBaseFileName(filename, true);
+
+ std::string asset_name = name;
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string display_name = LLStringUtil::null;
+ LLAssetStorage::LLStoreAssetCallback callback = NULL;
+ S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ void *userdata = NULL;
+
+ upload_new_resource(
+ filename,
+ asset_name,
+ asset_name,
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getEveryonePerms(),
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
+
+ // *NOTE: Ew, we don't iterate over the file list here,
+ // we handle the next files in upload_done_callback()
+ }
+ else
+ {
+ llinfos << "Couldn't import objects from file" << llendl;
+ }
+ return true;
+ }
+};
+
+void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args)
+{
+ llwarns << error_message << llendl;
+ LLNotificationsUtil::add(label, args);
+ if(LLFile::remove(filename) == -1)
+ {
+ lldebugs << "unable to remove temp file" << llendl;
+ }
+ LLFilePicker::instance().reset();
+}
+
+class LLFileEnableCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = NULL != LLFloater::getClosableFloaterFromFocus();
+ return new_value;
+ }
+};
+
+class LLFileCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloater::closeFocusedFloater();
+
+ return true;
+ }
+};
+
+class LLFileEnableCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool open_children = gFloaterView->allChildrenClosed();
+ return !open_children;
+ }
+};
+
+class LLFileCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool app_quitting = false;
+ gFloaterView->closeAllChildren(app_quitting);
+
+ return true;
+ }
+};
+
+class LLFileTakeSnapshotToDisk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+
+ S32 width = gViewerWindow->getWindowWidthRaw();
+ S32 height = gViewerWindow->getWindowHeightRaw();
+
+ if (gSavedSettings.getBOOL("HighResSnapshot"))
+ {
+ width *= 2;
+ height *= 2;
+ }
+
+ if (gViewerWindow->rawSnapshot(raw,
+ width,
+ height,
+ TRUE,
+ FALSE,
+ gSavedSettings.getBOOL("RenderUIInSnapshot"),
+ FALSE))
+ {
+ gViewerWindow->playSnapshotAnimAndSound();
+ LLPointer<LLImageFormatted> formatted;
+ LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
+ switch (fmt)
+ {
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+ formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality"));
+ break;
+ default:
+ llwarns << "Unknown local snapshot format: " << fmt << llendl;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+ formatted = new LLImagePNG;
+ break;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+ formatted = new LLImageBMP;
+ break;
+ }
+ formatted->enableOverSize() ;
+ formatted->encode(raw, 0);
+ formatted->disableOverSize() ;
+ gViewerWindow->saveImageNumbered(formatted);
+ }
+ return true;
+ }
+};
+
+class LLFileQuit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAppViewer::instance()->userQuit();
+ return true;
+ }
+};
+
+
+void handle_compress_image(void*)
+{
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
+ {
+ std::string infile = picker.getFirstFile();
+ while (!infile.empty())
+ {
+ std::string outfile = infile + ".j2c";
+
+ llinfos << "Input: " << infile << llendl;
+ llinfos << "Output: " << outfile << llendl;
+
+ BOOL success;
+
+ success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
+
+ if (success)
+ {
+ llinfos << "Compression complete" << llendl;
+ }
+ else
+ {
+ llinfos << "Compression failed: " << LLImage::getLastError() << llendl;
+ }
+
+ infile = picker.getNextFile();
+ }
+ }
+}
+
+LLUUID upload_new_resource(
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
+{
+ // Generate the temporary UUID.
+ std::string filename = gDirUtilp->getTempFilename();
+ LLTransactionID tid;
+ LLAssetID uuid;
+
+ LLSD args;
+
+ std::string exten = gDirUtilp->getExtension(src_filename);
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
+ LLAssetType::EType asset_type = LLAssetType::AT_NONE;
+ std::string error_message;
+
+ BOOL error = FALSE;
+
+ if (exten.empty())
+ {
+ std::string short_name = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ error_message = llformat(
+ "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
+ short_name.c_str());
+ args["FILE"] = short_name;
+ upload_error(error_message, "NoFileExtension", filename, args);
+ return LLUUID();
+ }
+ else if (codec != IMG_CODEC_INVALID)
+ {
+ // It's an image file, the upload procedure is the same for all
+ asset_type = LLAssetType::AT_TEXTURE;
+ if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
+ {
+ error_message = llformat( "Problem with file %s:\n\n%s\n",
+ src_filename.c_str(), LLImage::getLastError().c_str());
+ args["FILE"] = src_filename;
+ args["ERROR"] = LLImage::getLastError();
+ upload_error(error_message, "ProblemWithFile", filename, args);
+ return LLUUID();
+ }
+ }
+ else if(exten == "wav")
+ {
+ asset_type = LLAssetType::AT_SOUND; // tag it as audio
+ S32 encode_result = 0;
+
+ llinfos << "Attempting to encode wav as an ogg file" << llendl;
+
+ encode_result = encode_vorbis_file(src_filename, filename);
+
+ if (LLVORBISENC_NOERR != encode_result)
+ {
+ switch(encode_result)
+ {
+ case LLVORBISENC_DEST_OPEN_ERR:
+ error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
+ args["FILE"] = filename;
+ upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
+ break;
+
+ default:
+ error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
+ break;
+ }
+ return LLUUID();
+ }
+ }
+ else if(exten == "tmp")
+ {
+ // This is a generic .lin resource file
+ asset_type = LLAssetType::AT_OBJECT;
+ LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */
+ if (in)
+ {
+ // read in the file header
+ char buf[16384]; /* Flawfinder: ignore */
+ size_t readbytes;
+ S32 version;
+ if (fscanf(in, "LindenResource\nversion %d\n", &version))
+ {
+ if (2 == version)
+ {
+ // *NOTE: This buffer size is hard coded into scanf() below.
+ char label[MAX_STRING]; /* Flawfinder: ignore */
+ char value[MAX_STRING]; /* Flawfinder: ignore */
+ S32 tokens_read;
+ while (fgets(buf, 1024, in))
+ {
+ label[0] = '\0';
+ value[0] = '\0';
+ tokens_read = sscanf( /* Flawfinder: ignore */
+ buf,
+ "%254s %254s\n",
+ label, value);
+
+ llinfos << "got: " << label << " = " << value
+ << llendl;
+
+ if (EOF == tokens_read)
+ {
+ fclose(in);
+ error_message = llformat("corrupt resource file: %s", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "CorruptResourceFile", filename, args);
+ return LLUUID();
+ }
+
+ if (2 == tokens_read)
+ {
+ if (! strcmp("type", label))
+ {
+ asset_type = (LLAssetType::EType)(atoi(value));
+ }
+ }
+ else
+ {
+ if (! strcmp("_DATA_", label))
+ {
+ // below is the data section
+ break;
+ }
+ }
+ // other values are currently discarded
+ }
+
+ }
+ else
+ {
+ fclose(in);
+ error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "UnknownResourceFileVersion", filename, args);
+ return LLUUID();
+ }
+ }
+ else
+ {
+ // this is an original binary formatted .lin file
+ // start over at the beginning of the file
+ fseek(in, 0, SEEK_SET);
+
+ const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;
+ const S32 MAX_ASSET_NAME_LENGTH = 64;
+ S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;
+ S16 type_num;
+
+ // read in and throw out most of the header except for the type
+ if (fread(buf, header_size, 1, in) != 1)
+ {
+ llwarns << "Short read" << llendl;
+ }
+ memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */
+ asset_type = (LLAssetType::EType)type_num;
+ }
+
+ // copy the file's data segment into another file for uploading
+ LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */
+ if (out)
+ {
+ while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
+ {
+ if (fwrite(buf, 1, readbytes, out) != readbytes)
+ {
+ llwarns << "Short write" << llendl;
+ }
+ }
+ fclose(out);
+ }
+ else
+ {
+ fclose(in);
+ error_message = llformat( "Unable to create output file: %s", filename.c_str());
+ args["FILE"] = filename;
+ upload_error(error_message, "UnableToCreateOutputFile", filename, args);
+ return LLUUID();
+ }
+
+ fclose(in);
+ }
+ else
+ {
+ llinfos << "Couldn't open .lin file " << src_filename << llendl;
+ }
+ }
+ else if (exten == "bvh")
+ {
+ error_message = llformat("We do not currently support bulk upload of animation files\n");
+ upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
+ return LLUUID();
+ }
+ else if (exten == "anim")
+ {
+ asset_type = LLAssetType::AT_ANIMATION;
+ filename = src_filename;
+ }
+ else
+ {
+ // Unknown extension
+ error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
+ error = TRUE;;
+ }
+
+ // gen a new transaction ID for this asset
+ tid.generate();
+
+ if (!error)
+ {
+ uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+ // copy this file into the vfs for upload
+ S32 file_size;
+ LLAPRFile infile ;
+ infile.open(filename, LL_APR_RB, NULL, &file_size);
+ if (infile.getFileHandle())
+ {
+ LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
+
+ file.setMaxSize(file_size);
+
+ const S32 buf_size = 65536;
+ U8 copy_buf[buf_size];
+ while ((file_size = infile.read(copy_buf, buf_size)))
+ {
+ file.write(copy_buf, file_size);
+ }
+ }
+ else
+ {
+ error_message = llformat( "Unable to access output file: %s", filename.c_str());
+ error = TRUE;
+ }
+ }
+
+ if (!error)
+ {
+ std::string t_disp_name = display_name;
+ if (t_disp_name.empty())
+ {
+ t_disp_name = src_filename;
+ }
+ upload_new_resource(
+ tid,
+ asset_type,
+ name,
+ desc,
+ compression_info, // tid
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms,
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
+ }
+ else
+ {
+ llwarns << error_message << llendl;
+ LLSD args;
+ args["ERROR_MESSAGE"] = error_message;
+ LLNotificationsUtil::add("ErrorMessage", args);
+ if(LLFile::remove(filename) == -1)
+ {
+ lldebugs << "unable to remove temp file" << llendl;
+ }
+ LLFilePicker::instance().reset();
+ }
+
+ return uuid;
+}
+
+void upload_done_callback(
+ const LLUUID& uuid,
+ void* user_data,
+ S32 result,
+ LLExtStat ext_status) // StoreAssetData callback (fixed)
+{
+ LLResourceData* data = (LLResourceData*)user_data;
+ S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
+ //LLAssetType::EType pref_loc = data->mPreferredLocation;
+ BOOL is_balance_sufficient = TRUE;
+
+ if(data)
+ {
+ if (result >= 0)
+ {
+ LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
+
+ if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
+ LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
+ LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
+ {
+ // Charge the user for the upload.
+ LLViewerRegion* region = gAgent.getRegion();
+
+ if(!(can_afford_transaction(expected_upload_cost)))
+ {
+ LLStringUtil::format_map_t args;
+ args["NAME"] = data->mAssetInfo.getName();
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
+ is_balance_sufficient = FALSE;
+ }
+ else if(region)
+ {
+ // Charge user for upload
+ gStatusBar->debitBalance(expected_upload_cost);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MoneyTransferRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MoneyData);
+ msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
+ msg->addU8("Flags", 0);
+ // we tell the sim how much we were expecting to pay so it
+ // can respond to any discrepancy
+ msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
+ msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
+ msg->addStringFast(_PREHASH_Description, NULL);
+ msg->sendReliable(region->getHost());
+ }
+ }
+
+ if(is_balance_sufficient)
+ {
+ // Actually add the upload to inventory
+ llinfos << "Adding " << uuid << " to inventory." << llendl;
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
+ if(folder_id.notNull())
+ {
+ U32 next_owner_perms = data->mNextOwnerPerm;
+ if(PERM_NONE == next_owner_perms)
+ {
+ next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+ }
+ create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
+ folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
+ data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
+ data->mInventoryType, NOT_WEARABLE, next_owner_perms,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ else
+ {
+ llwarns << "Can't find a folder to put it in" << llendl;
+ }
+ }
+ }
+ else // if(result >= 0)
+ {
+ LLSD args;
+ args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
+ args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
+ LLNotificationsUtil::add("CannotUploadReason", args);
+ }
+ }
+
+ LLUploadDialog::modalUploadFinished();
+ delete data;
+ data = NULL;
+
+ // *NOTE: This is a pretty big hack. What this does is check the
+ // file picker if there are any more pending uploads. If so,
+ // upload that file.
+ const std::string& next_file = LLFilePicker::instance().getNextFile();
+ if(is_balance_sufficient && !next_file.empty())
+ {
+ std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string display_name = LLStringUtil::null;
+ LLAssetStorage::LLStoreAssetCallback callback = NULL;
+ void *userdata = NULL;
+ upload_new_resource(
+ next_file,
+ asset_name,
+ asset_name, // file
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ display_name,
+ callback,
+ expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
+ userdata);
+ }
+}
+
+static LLAssetID upload_new_resource_prep(
+ const LLTransactionID& tid,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ LLAssetID uuid = generate_asset_id_for_new_upload(tid);
+
+ increase_new_upload_stats(asset_type);
+
+ assign_defaults_and_show_upload_message(
+ asset_type,
+ inventory_type,
+ name,
+ display_name,
+ description);
+
+ return uuid;
+}
+
+LLSD generate_new_resource_upload_capability_body(
+ LLAssetType::EType asset_type,
+ const std::string& name,
+ const std::string& desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms)
+{
+ LLSD body;
+
+ body["folder_id"] = gInventory.findCategoryUUIDForType(
+ (destination_folder_type == LLFolderType::FT_NONE) ?
+ (LLFolderType::EType) asset_type :
+ destination_folder_type);
+
+ body["asset_type"] = LLAssetType::lookup(asset_type);
+ body["inventory_type"] = LLInventoryType::lookup(inv_type);
+ body["name"] = name;
+ body["description"] = desc;
+ body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
+ body["group_mask"] = LLSD::Integer(group_perms);
+ body["everyone_mask"] = LLSD::Integer(everyone_perms);
+
+ return body;
+}
+
+void upload_new_resource(
+ const LLTransactionID &tid,
+ LLAssetType::EType asset_type,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
+{
+ if(gDisconnected)
+ {
+ return ;
+ }
+
+ LLAssetID uuid =
+ upload_new_resource_prep(
+ tid,
+ asset_type,
+ inv_type,
+ name,
+ display_name,
+ desc);
+
+ if( LLAssetType::AT_SOUND == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+ }
+ else
+ if( LLAssetType::AT_TEXTURE == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+ }
+ else
+ if( LLAssetType::AT_ANIMATION == asset_type)
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+ }
+
+ if(LLInventoryType::IT_NONE == inv_type)
+ {
+ inv_type = LLInventoryType::defaultForAssetType(asset_type);
+ }
+ LLStringUtil::stripNonprintable(name);
+ LLStringUtil::stripNonprintable(desc);
+ if(name.empty())
+ {
+ name = "(No Name)";
+ }
+ if(desc.empty())
+ {
+ desc = "(No Description)";
+ }
+
+ // At this point, we're ready for the upload.
+ std::string upload_message = "Uploading...\n\n";
+ upload_message.append(display_name);
+ LLUploadDialog::modalUploadDialog(upload_message);
+
+ llinfos << "*** Uploading: " << llendl;
+ llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
+ llinfos << "UUID: " << uuid << llendl;
+ llinfos << "Name: " << name << llendl;
+ llinfos << "Desc: " << desc << llendl;
+ llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
+ lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
+ lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+ std::string url = gAgent.getRegion()->getCapability(
+ "NewFileAgentInventory");
+
+ if ( !url.empty() )
+ {
+ llinfos << "New Agent Inventory via capability" << llendl;
+
+ LLSD body;
+ body = generate_new_resource_upload_capability_body(
+ asset_type,
+ name,
+ desc,
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms);
+
+ LLHTTPClient::post(
+ url,
+ body,
+ new LLNewAgentInventoryResponder(
+ body,
+ uuid,
+ asset_type));
+ }
+ else
+ {
+ llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
+ // check for adequate funds
+ // TODO: do this check on the sim
+ if (LLAssetType::AT_SOUND == asset_type ||
+ LLAssetType::AT_TEXTURE == asset_type ||
+ LLAssetType::AT_ANIMATION == asset_type)
+ {
+ S32 balance = gStatusBar->getBalance();
+ if (balance < expected_upload_cost)
+ {
+ // insufficient funds, bail on this upload
+ LLStringUtil::format_map_t args;
+ args["NAME"] = name;
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
+ return;
+ }
+ }
+
+ LLResourceData* data = new LLResourceData;
+ data->mAssetInfo.mTransactionID = tid;
+ data->mAssetInfo.mUuid = uuid;
+ data->mAssetInfo.mType = asset_type;
+ data->mAssetInfo.mCreatorID = gAgentID;
+ data->mInventoryType = inv_type;
+ data->mNextOwnerPerm = next_owner_perms;
+ data->mExpectedUploadCost = expected_upload_cost;
+ data->mUserData = userdata;
+ data->mAssetInfo.setName(name);
+ data->mAssetInfo.setDescription(desc);
+ data->mPreferredLocation = destination_folder_type;
+
+ LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
+ if (callback)
+ {
+ asset_callback = callback;
+ }
+ gAssetStorage->storeAssetData(
+ data->mAssetInfo.mTransactionID,
+ data->mAssetInfo.mType,
+ asset_callback,
+ (void*)data,
+ FALSE);
+ }
+}
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
+{
+ if ( gDisconnected )
+ {
+ LLAssetID rv;
+
+ rv.setNull();
+ return rv;
+ }
+
+ LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ return uuid;
+}
+
+void increase_new_upload_stats(LLAssetType::EType asset_type)
+{
+ if ( LLAssetType::AT_SOUND == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+ }
+ else if ( LLAssetType::AT_TEXTURE == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+ }
+ else if ( LLAssetType::AT_ANIMATION == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+ }
+}
+
+void assign_defaults_and_show_upload_message(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ if ( LLInventoryType::IT_NONE == inventory_type )
+ {
+ inventory_type = LLInventoryType::defaultForAssetType(asset_type);
+ }
+ LLStringUtil::stripNonprintable(name);
+ LLStringUtil::stripNonprintable(description);
+
+ if ( name.empty() )
+ {
+ name = "(No Name)";
+ }
+ if ( description.empty() )
+ {
+ description = "(No Description)";
+ }
+
+ // At this point, we're ready for the upload.
+ std::string upload_message = "Uploading...\n\n";
+ upload_message.append(display_name);
+ LLUploadDialog::modalUploadDialog(upload_message);
+}
+
+
+void init_menu_file()
+{
+ view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
+ view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
+ view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+ view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
+ view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
+ view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
+ view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
+ view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
+ view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
+ view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
+ view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
+
+ view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
+ view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
+ view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
+ view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
+
+ // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
+}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 2917fee62e..05f1be5de5 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4735,7 +4735,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) LLViewerObject* object = gObjectList.findObject(object_id); if (object) { - object->mFlags |= FLAGS_ANIM_SOURCE; + object->setFlags(FLAGS_ANIM_SOURCE, TRUE); BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); @@ -4882,7 +4882,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat LLViewerObject* objectp = gObjectList.findObject(source_id); if (objectp) { - objectp->mFlags |= FLAGS_CAMERA_SOURCE; + objectp->setFlags(FLAGS_CAMERA_SOURCE, TRUE); } S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 37fb77a10a..330cf51b3e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -443,7 +443,7 @@ void LLViewerObject::dump() const /* llinfos << "Velocity: " << getVelocity() << llendl; llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; - llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; + llinfos << "UsePhysics: " << flagUsePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; llinfos << "AppAngle: " << mAppAngle << llendl; llinfos << "PixelArea: " << mPixelArea << llendl; @@ -5123,7 +5123,7 @@ BOOL LLViewerObject::permAnyOwner() const { if (isRootEdit()) { - return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); + return flagObjectAnyOwner(); } else { @@ -5145,7 +5145,7 @@ BOOL LLViewerObject::permYouOwner() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); + return flagObjectYouOwner(); #endif } else @@ -5159,7 +5159,7 @@ BOOL LLViewerObject::permGroupOwner() const { if (isRootEdit()) { - return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); + return flagObjectGroupOwned(); } else { @@ -5182,7 +5182,7 @@ BOOL LLViewerObject::permOwnerModify() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); + return flagObjectOwnerModify(); #endif } else @@ -5206,7 +5206,7 @@ BOOL LLViewerObject::permModify() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); + return flagObjectModify(); #endif } else @@ -5230,7 +5230,7 @@ BOOL LLViewerObject::permCopy() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_COPY) != 0); + return flagObjectCopy(); #endif } else @@ -5254,7 +5254,7 @@ BOOL LLViewerObject::permMove() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_MOVE) != 0); + return flagObjectMove(); #endif } else @@ -5278,7 +5278,7 @@ BOOL LLViewerObject::permTransfer() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); + return flagObjectTransfer(); #endif } else @@ -5323,19 +5323,12 @@ void LLViewerObject::markForUpdate(BOOL priority) bool LLViewerObject::getIncludeInSearch() const { - return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); + return flagIncludeInSearch(); } void LLViewerObject::setIncludeInSearch(bool include_in_search) { - if (include_in_search) - { - mFlags |= FLAGS_INCLUDE_IN_SEARCH; - } - else - { - mFlags &= ~FLAGS_INCLUDE_IN_SEARCH; - } + setFlags(FLAGS_INCLUDE_IN_SEARCH, include_in_search); } void LLViewerObject::setRegion(LLViewerRegion *regionp) @@ -5374,8 +5367,8 @@ void LLViewerObject::updateRegion(LLViewerRegion *regionp) bool LLViewerObject::specialHoverCursor() const { - return (mFlags & FLAGS_USE_PHYSICS) - || (mFlags & FLAGS_HANDLE_TOUCH) + return flagUsePhysics() + || flagHandleTouch() || (mClickAction != 0); } @@ -5388,10 +5381,15 @@ void LLViewerObject::updateFlags(BOOL physics_changed) gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() ); - gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() ); + gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, flagUsePhysics() ); gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); - gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); + + // stinson 02/28/2012 : This CastsShadows BOOL is no longer used in either the viewer or the simulator + // The simulator code does not even unpack this value when the message is received. + // This could be potentially hijacked in the future for another use should the urgent need arise. + gMessageSystem->addBOOL("CastsShadows", FALSE ); + if (physics_changed) { gMessageSystem->nextBlock("ExtraPhysics"); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index c8152e1539..63215942ac 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -468,20 +468,28 @@ public: BOOL permCopy() const; BOOL permMove() const; BOOL permTransfer() const; - inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagUsePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagObjectAnyOwner() const { return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); } + inline BOOL flagObjectYouOwner() const { return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); } + inline BOOL flagObjectGroupOwned() const { return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); } + inline BOOL flagObjectOwnerModify() const { return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); } + inline BOOL flagObjectModify() const { return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); } + inline BOOL flagObjectCopy() const { return ((mFlags & FLAGS_OBJECT_COPY) != 0); } + inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } + inline BOOL flagObjectTransfer() const { return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); } + inline BOOL flagObjectPermanent() const { return ((mFlags & FLAGS_OBJECT_PERMANENT) != 0); } + inline BOOL flagCharacter() const { return ((mFlags & FLAGS_CHARACTER) != 0); } + inline BOOL flagIncludeInSearch() const { return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); } inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); } inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); } inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); } inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); } inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); } - inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); } inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); } - inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); } inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); } inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); } inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } - inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } U8 getPhysicsShapeType() const; inline F32 getPhysicsGravity() const { return mPhysicsGravity; } @@ -595,9 +603,11 @@ public: U32 mGLName; // GL "name" used by selection code BOOL mbCanSelect; // true if user can select this object by clicking +private: // Grabbed from UPDATE_FLAGS U32 mFlags; +public: // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties U8 mPhysicsShapeType; F32 mPhysicsGravity; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 6912faa9ec..6dedf0a2fe 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -385,9 +385,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } else if (compressed) { - U8 compbuffer[2048]; S32 uncompressed_length = 2048; - S32 compressed_length; compressed_dp.reset(); U32 flags = 0; @@ -396,24 +394,9 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); } - // I don't think we ever use this flag from the server. DK 2010/12/09 - if (flags & FLAGS_ZLIB_COMPRESSED) - { - //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl; - compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); - uncompressed_length = 2048; - uncompress(compressed_dpbuffer, (unsigned long *)&uncompressed_length, - compbuffer, compressed_length); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - else - { - uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - + uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e3cb985ddb..6e422a5821 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1489,8 +1489,10 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { + capabilityNames.append("AgentPreferences"); capabilityNames.append("AttachmentResources"); capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("CharacterProperties"); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); @@ -1519,8 +1521,10 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("LandResources"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); - capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("NavMeshUpload"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectNavMeshProperties"); capabilityNames.append("ParcelPropertiesUpdate"); capabilityNames.append("ParcelMediaURLFilterList"); capabilityNames.append("ParcelNavigateMedia"); @@ -1530,6 +1534,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("RemoteParcelRequest"); capabilityNames.append("RequestTextureDownload"); capabilityNames.append("ResourceCostSelected"); + capabilityNames.append("RetrieveNavMeshSrc"); capabilityNames.append("SearchStatRequest"); capabilityNames.append("SearchStatTracking"); capabilityNames.append("SendPostcard"); @@ -1541,6 +1546,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("SetDisplayName"); capabilityNames.append("SimConsoleAsync"); capabilityNames.append("StartGroupProposal"); + capabilityNames.append("TerrainNavMeshProperties"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); capabilityNames.append("UpdateAgentInformation"); @@ -1555,7 +1561,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); - // Please add new capabilities alphabetically to reduce // merge conflicts. } @@ -1794,7 +1799,10 @@ void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& unique { mImpl->mLandp->getNeighboringRegions( uniqueRegions ); } - +void LLViewerRegion::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + mImpl->mLandp->getNeighboringRegionsStatus( regions ); +} void LLViewerRegion::showReleaseNotes() { std::string url = this->getCapability("ServerReleaseNotes"); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c483c6ef52..6004165b0e 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -325,6 +325,7 @@ public: bool objectsCrossParcel(const std::vector<LLBBox>& boxes) const; void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ); + void getNeighboringRegionsStatus( std::vector<S32>& regions ); public: struct CompareDistance diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 589714c25c..8750b3b1f2 100755..100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -199,6 +199,8 @@ #include "llwindowlistener.h" #include "llviewerwindowlistener.h" #include "llpaneltopinfobar.h" +#include "LLPathingLib.h" +#include "llfloaterpathfindingconsole.h" #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods @@ -832,6 +834,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); + // only send mouse clicks to UI if UI is visible if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { @@ -945,13 +948,26 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK } } + //Determine if we have a pathing system and subsequently provide any mouse input + if (LLPathingLib::getInstance() != NULL) + { + LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if (!pathfindingConsoleHandle.isDead()) + { + LLFloaterPathfindingConsole *pathfindingConsoleFloater = pathfindingConsoleHandle.get(); + if (pathfindingConsoleFloater->isGeneratePathMode(mask, clicktype, down)) + { + return pathfindingConsoleFloater->handleAnyMouseClick(x, y, mask, clicktype, down); + } + } + } + // Do not allow tool manager to handle mouseclicks if we have disconnected if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) { return TRUE; } - // If we got this far on a down-click, it wasn't handled. // Up-clicks, though, are always handled as far as the OS is concerned. BOOL default_rtn = !down; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index f063653cc5..c505936097 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -758,7 +758,7 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) LLViewerObject* object = gObjectList.findObject(source_id); if (object) { - object->mFlags &= ~FLAGS_ANIM_SOURCE; + object->setFlags(FLAGS_ANIM_SOURCE, FALSE); } } diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index fbd8b3ada3..e508f768b4 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1,1238 +1,1247 @@ -/** - * @file llworld.cpp - * @brief Initial test structure to organize viewer regions - * - * $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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llworld.h" -#include "llrender.h" - -#include "indra_constants.h" -#include "llstl.h" - -#include "llagent.h" -#include "llviewercontrol.h" -#include "lldrawpool.h" -#include "llglheaders.h" -#include "llhttpnode.h" -#include "llregionhandle.h" -#include "llsurface.h" -#include "lltrans.h" -#include "llviewercamera.h" -#include "llviewertexture.h" -#include "llviewertexturelist.h" -#include "llviewernetwork.h" -#include "llviewerobjectlist.h" -#include "llviewerparceloverlay.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llvlcomposition.h" -#include "llvoavatar.h" -#include "llvocache.h" -#include "llvowater.h" -#include "message.h" -#include "pipeline.h" -#include "llappviewer.h" // for do_disconnect() - -#include <deque> -#include <queue> -#include <map> -#include <cstring> - - -// -// Globals -// -U32 gAgentPauseSerialNum = 0; - -// -// Constants -// -const S32 MAX_NUMBER_OF_CLOUDS = 750; -const S32 WORLD_PATCH_SIZE = 16; - -extern LLColor4U MAX_WATER_COLOR; - -const U32 LLWorld::mWidth = 256; - -// meters/point, therefore mWidth * mScale = meters per edge -const F32 LLWorld::mScale = 1.f; - -const F32 LLWorld::mWidthInMeters = mWidth * mScale; - -// -// Functions -// - -// allocate the stack -LLWorld::LLWorld() : - mLandFarClip(DEFAULT_FAR_PLANE), - mLastPacketsIn(0), - mLastPacketsOut(0), - mLastPacketsLost(0), - mSpaceTimeUSec(0) -{ - for (S32 i = 0; i < 8; i++) - { - mEdgeWaterObjects[i] = NULL; - } - - LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,4); - U8 *default_texture = raw->getData(); - *(default_texture++) = MAX_WATER_COLOR.mV[0]; - *(default_texture++) = MAX_WATER_COLOR.mV[1]; - *(default_texture++) = MAX_WATER_COLOR.mV[2]; - *(default_texture++) = MAX_WATER_COLOR.mV[3]; - - mDefaultWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); - gGL.getTexUnit(0)->bind(mDefaultWaterTexturep); - mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - -} - - -void LLWorld::destroyClass() -{ - mHoleWaterObjects.clear(); - gObjectList.destroy(); - for(region_list_t::iterator region_it = mRegionList.begin(); region_it != mRegionList.end(); ) - { - LLViewerRegion* region_to_delete = *region_it++; - removeRegion(region_to_delete->getHost()); - } - if(LLVOCache::hasInstance()) - { - LLVOCache::getInstance()->destroyClass() ; - } - LLViewerPartSim::getInstance()->destroyClass(); - - mDefaultWaterTexturep = NULL ; - for (S32 i = 0; i < 8; i++) - { - mEdgeWaterObjects[i] = NULL; - } -} - - -LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) -{ - LLMemType mt(LLMemType::MTYPE_REGIONS); - llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl; - LLViewerRegion *regionp = getRegionFromHandle(region_handle); - if (regionp) - { - llinfos << "Region exists, removing it " << llendl; - LLHost old_host = regionp->getHost(); - // region already exists! - if (host == old_host && regionp->isAlive()) - { - // This is a duplicate for the same host and it's alive, don't bother. - return regionp; - } - - if (host != old_host) - { - llwarns << "LLWorld::addRegion exists, but old host " << old_host - << " does not match new host " << host << llendl; - } - if (!regionp->isAlive()) - { - llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl; - } - - // Kill the old host, and then we can continue on and add the new host. We have to kill even if the host - // matches, because all the agent state for the new camera is completely different. - removeRegion(old_host); - } - - U32 iindex = 0; - U32 jindex = 0; - from_region_handle(region_handle, &iindex, &jindex); - S32 x = (S32)(iindex/mWidth); - S32 y = (S32)(jindex/mWidth); - llinfos << "Adding new region (" << x << ":" << y << ")" << llendl; - llinfos << "Host: " << host << llendl; - - LLVector3d origin_global; - - origin_global = from_region_handle(region_handle); - - regionp = new LLViewerRegion(region_handle, - host, - mWidth, - WORLD_PATCH_SIZE, - getRegionWidthInMeters() ); - if (!regionp) - { - llerrs << "Unable to create new region!" << llendl; - } - - mRegionList.push_back(regionp); - mActiveRegionList.push_back(regionp); - mCulledRegionList.push_back(regionp); - - - // Find all the adjacent regions, and attach them. - // Generate handles for all of the adjacent regions, and attach them in the correct way. - // connect the edges - F32 adj_x = 0.f; - F32 adj_y = 0.f; - F32 region_x = 0.f; - F32 region_y = 0.f; - U64 adj_handle = 0; - - F32 width = getRegionWidthInMeters(); - - LLViewerRegion *neighborp; - from_region_handle(region_handle, ®ion_x, ®ion_y); - - // Iterate through all directions, and connect neighbors if there. - S32 dir; - for (dir = 0; dir < 8; dir++) - { - adj_x = region_x + width * gDirAxes[dir][0]; - adj_y = region_y + width * gDirAxes[dir][1]; - to_region_handle(adj_x, adj_y, &adj_handle); - - neighborp = getRegionFromHandle(adj_handle); - if (neighborp) - { - //llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl; - regionp->connectNeighbor(neighborp, dir); - } - } - - updateWaterObjects(); - - return regionp; -} - - -void LLWorld::removeRegion(const LLHost &host) -{ - F32 x, y; - - LLViewerRegion *regionp = getRegion(host); - if (!regionp) - { - llwarns << "Trying to remove region that doesn't exist!" << llendl; - return; - } - - if (regionp == gAgent.getRegion()) - { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* reg = *iter; - llwarns << "RegionDump: " << reg->getName() - << " " << reg->getHost() - << " " << reg->getOriginGlobal() - << llendl; - } - - llwarns << "Agent position global " << gAgent.getPositionGlobal() - << " agent " << gAgent.getPositionAgent() - << llendl; - - llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl; - - llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl; - - llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl; - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected")); - - regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed. - return; - } - - from_region_handle(regionp->getHandle(), &x, &y); - llinfos << "Removing region " << x << ":" << y << llendl; - - mRegionList.remove(regionp); - mActiveRegionList.remove(regionp); - mCulledRegionList.remove(regionp); - mVisibleRegionList.remove(regionp); - - delete regionp; - - updateWaterObjects(); - - //double check all objects of this region are removed. - gObjectList.clearAllMapObjectsInRegion(regionp) ; - //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ; -} - - -LLViewerRegion* LLWorld::getRegion(const LLHost &host) -{ - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - if (regionp->getHost() == host) - { - return regionp; - } - } - return NULL; -} - -LLViewerRegion* LLWorld::getRegionFromPosAgent(const LLVector3 &pos) -{ - return getRegionFromPosGlobal(gAgent.getPosGlobalFromAgent(pos)); -} - -LLViewerRegion* LLWorld::getRegionFromPosGlobal(const LLVector3d &pos) -{ - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - if (regionp->pointInRegionGlobal(pos)) - { - return regionp; - } - } - return NULL; -} - - -LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos) -{ - if (positionRegionValidGlobal(end_pos)) - { - return end_pos; - } - - LLViewerRegion* regionp = getRegionFromPosGlobal(start_pos); - if (!regionp) - { - return start_pos; - } - - LLVector3d delta_pos = end_pos - start_pos; - LLVector3d delta_pos_abs; - delta_pos_abs.setVec(delta_pos); - delta_pos_abs.abs(); - - LLVector3 region_coord = regionp->getPosRegionFromGlobal(end_pos); - F64 clip_factor = 1.0; - F32 region_width = regionp->getWidth(); - if (region_coord.mV[VX] < 0.f) - { - if (region_coord.mV[VY] < region_coord.mV[VX]) - { - // clip along y - - clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]); - } - else - { - // clip along x - - clip_factor = -(region_coord.mV[VX] / delta_pos_abs.mdV[VX]); - } - } - else if (region_coord.mV[VX] > region_width) - { - if (region_coord.mV[VY] > region_coord.mV[VX]) - { - // clip along y + - clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY]; - } - else - { - //clip along x + - clip_factor = (region_coord.mV[VX] - region_width) / delta_pos_abs.mdV[VX]; - } - } - else if (region_coord.mV[VY] < 0.f) - { - // clip along y - - clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]); - } - else if (region_coord.mV[VY] > region_width) - { - // clip along y + - clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY]; - } - - // clamp to within region dimensions - LLVector3d final_region_pos = LLVector3d(region_coord) - (delta_pos * clip_factor); - final_region_pos.mdV[VX] = llclamp(final_region_pos.mdV[VX], 0.0, - (F64)(region_width - F_ALMOST_ZERO)); - final_region_pos.mdV[VY] = llclamp(final_region_pos.mdV[VY], 0.0, - (F64)(region_width - F_ALMOST_ZERO)); - final_region_pos.mdV[VZ] = llclamp(final_region_pos.mdV[VZ], 0.0, - (F64)(LLWorld::getInstance()->getRegionMaxHeight() - F_ALMOST_ZERO)); - return regionp->getPosGlobalFromRegion(LLVector3(final_region_pos)); -} - -LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle) -{ - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - if (regionp->getHandle() == handle) - { - return regionp; - } - } - return NULL; -} - - -void LLWorld::updateAgentOffset(const LLVector3d &offset_global) -{ -#if 0 - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - regionp->setAgentOffset(offset_global); - } -#endif -} - - -BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global) -{ - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - if (regionp->pointInRegionGlobal(pos_global)) - { - return TRUE; - } - } - return FALSE; -} - - -// Allow objects to go up to their radius underground. -F32 LLWorld::getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos) -{ - F32 land_height = resolveLandHeightGlobal(global_pos); - F32 radius = 0.5f * object->getScale().length(); - return land_height - radius; -} - - - -LLViewerRegion* LLWorld::resolveRegionGlobal(LLVector3 &pos_region, const LLVector3d &pos_global) -{ - LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); - - if (regionp) - { - pos_region = regionp->getPosRegionFromGlobal(pos_global); - return regionp; - } - - return NULL; -} - - -LLViewerRegion* LLWorld::resolveRegionAgent(LLVector3 &pos_region, const LLVector3 &pos_agent) -{ - LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); - LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); - - if (regionp) - { - pos_region = regionp->getPosRegionFromGlobal(pos_global); - return regionp; - } - - return NULL; -} - - -F32 LLWorld::resolveLandHeightAgent(const LLVector3 &pos_agent) -{ - LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); - return resolveLandHeightGlobal(pos_global); -} - - -F32 LLWorld::resolveLandHeightGlobal(const LLVector3d &pos_global) -{ - LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); - if (regionp) - { - return regionp->getLand().resolveHeightGlobal(pos_global); - } - return 0.0f; -} - - -// Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a) -// point where the the line intersects an object or the land surface. Stores the results -// in "intersection" and "intersection_normal" and returns a scalar value that represents -// the normalized distance along the line from "point_a" to "intersection". -// -// Currently assumes point_a and point_b only differ in z-direction, -// but it may eventually become more general. -F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b, - LLVector3d &intersection, LLVector3 &intersection_normal, - LLViewerObject **viewerObjectPtr) -{ - // initialize return value to null - if (viewerObjectPtr) - { - *viewerObjectPtr = NULL; - } - - LLViewerRegion *regionp = getRegionFromPosGlobal(point_a); - if (!regionp) - { - // We're outside the world - intersection = 0.5f * (point_a + point_b); - intersection_normal.setVec(0.0f, 0.0f, 1.0f); - return 0.5f; - } - - // calculate the length of the segment - F32 segment_length = (F32)((point_a - point_b).length()); - if (0.0f == segment_length) - { - intersection = point_a; - intersection_normal.setVec(0.0f, 0.0f, 1.0f); - return segment_length; - } - - // get land height - // Note: we assume that the line is parallel to z-axis here - LLVector3d land_intersection = point_a; - F32 normalized_land_distance; - - land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a); - normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length; - intersection = land_intersection; - intersection_normal = resolveLandNormalGlobal(land_intersection); - - if (avatarp && !avatarp->mFootPlane.isExactlyClear()) - { - LLVector3 foot_plane_normal(avatarp->mFootPlane.mV); - LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a); - // added 0.05 meters to compensate for error in foot plane reported by Havok - F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f; - norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f); - if (norm_dist_from_plane < normalized_land_distance) - { - // collided with object before land - normalized_land_distance = norm_dist_from_plane; - intersection = point_a; - intersection.mdV[VZ] -= norm_dist_from_plane * segment_length; - intersection_normal = foot_plane_normal; - } - else - { - intersection = land_intersection; - intersection_normal = resolveLandNormalGlobal(land_intersection); - } - } - - return normalized_land_distance; -} - - -LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global) -{ - // returns a pointer to the patch at this location - LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); - if (!regionp) - { - return NULL; - } - - return regionp->getLand().resolvePatchGlobal(pos_global); -} - - -LLVector3 LLWorld::resolveLandNormalGlobal(const LLVector3d &pos_global) -{ - LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); - if (!regionp) - { - return LLVector3::z_axis; - } - - return regionp->getLand().resolveNormalGlobal(pos_global); -} - - -void LLWorld::updateVisibilities() -{ - F32 cur_far_clip = LLViewerCamera::getInstance()->getFar(); - - // Go through the culled list and check for visible regions (region is visible if land is visible) - for (region_list_t::iterator iter = mCulledRegionList.begin(); - iter != mCulledRegionList.end(); ) - { - region_list_t::iterator curiter = iter++; - LLViewerRegion* regionp = *curiter; - - LLSpatialPartition* part = regionp->getSpatialPartition(LLViewerRegion::PARTITION_TERRAIN); - if (part) - { - LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) - { - mCulledRegionList.erase(curiter); - mVisibleRegionList.push_back(regionp); - } - } - } - - // Update all of the visible regions - for (region_list_t::iterator iter = mVisibleRegionList.begin(); - iter != mVisibleRegionList.end(); ) - { - region_list_t::iterator curiter = iter++; - LLViewerRegion* regionp = *curiter; - if (!regionp->getLand().hasZData()) - { - continue; - } - - LLSpatialPartition* part = regionp->getSpatialPartition(LLViewerRegion::PARTITION_TERRAIN); - if (part) - { - LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) - { - regionp->calculateCameraDistance(); - regionp->getLand().updatePatchVisibilities(gAgent); - } - else - { - mVisibleRegionList.erase(curiter); - mCulledRegionList.push_back(regionp); - } - } - } - - // Sort visible regions - mVisibleRegionList.sort(LLViewerRegion::CompareDistance()); - - LLViewerCamera::getInstance()->setFar(cur_far_clip); -} - -void LLWorld::updateRegions(F32 max_update_time) -{ - LLMemType mt_ur(LLMemType::MTYPE_IDLE_UPDATE_REGIONS); - LLTimer update_timer; - BOOL did_one = FALSE; - - // Perform idle time updates for the regions (and associated surfaces) - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - F32 max_time = max_update_time - update_timer.getElapsedTimeF32(); - if (did_one && max_time <= 0.f) - break; - max_time = llmin(max_time, max_update_time*.1f); - did_one |= regionp->idleUpdate(max_update_time); - } -} - -void LLWorld::updateParticles() -{ - LLViewerPartSim::getInstance()->updateSimulation(); -} - -void LLWorld::renderPropertyLines() -{ - S32 region_count = 0; - S32 vertex_count = 0; - - for (region_list_t::iterator iter = mVisibleRegionList.begin(); - iter != mVisibleRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - region_count++; - vertex_count += regionp->renderPropertyLines(); - } -} - - -void LLWorld::updateNetStats() -{ - F32 bits = 0.f; - U32 packets = 0; - - for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - regionp->updateNetStats(); - bits += regionp->mBitStat.getCurrent(); - packets += llfloor( regionp->mPacketsStat.getCurrent() ); - } - - S32 packets_in = gMessageSystem->mPacketsIn - mLastPacketsIn; - S32 packets_out = gMessageSystem->mPacketsOut - mLastPacketsOut; - S32 packets_lost = gMessageSystem->mDroppedPackets - mLastPacketsLost; - - S32 actual_in_bits = gMessageSystem->mPacketRing.getAndResetActualInBits(); - S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits(); - LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f); - LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f); - LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f); - LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in); - LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out); - LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets); - if (packets_in) - { - LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(100.f*((F32)packets_lost/(F32)packets_in)); - } - else - { - LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(0.f); - } - - mLastPacketsIn = gMessageSystem->mPacketsIn; - mLastPacketsOut = gMessageSystem->mPacketsOut; - mLastPacketsLost = gMessageSystem->mDroppedPackets; -} - - -void LLWorld::printPacketsLost() -{ - llinfos << "Simulators:" << llendl; - llinfos << "----------" << llendl; - - LLCircuitData *cdp = NULL; - for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost()); - if (cdp) - { - LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal(); - - llinfos << regionp->getHost() << ", range: " << range.length() - << " packets lost: " << cdp->getPacketsLost() << llendl; - } - } -} - -void LLWorld::processCoarseUpdate(LLMessageSystem* msg, void** user_data) -{ - LLViewerRegion* region = LLWorld::getInstance()->getRegion(msg->getSender()); - if( region ) - { - region->updateCoarseLocations(msg); - } -} - -F32 LLWorld::getLandFarClip() const -{ - return mLandFarClip; -} - -void LLWorld::setLandFarClip(const F32 far_clip) -{ - static S32 const rwidth = (S32)REGION_WIDTH_U32; - S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth; - S32 const n2 = (llceil(far_clip) - 1) / rwidth; - bool need_water_objects_update = n1 != n2; - - mLandFarClip = far_clip; - - if (need_water_objects_update) - { - updateWaterObjects(); - } -} - -// Some region that we're connected to, but not the one we're in, gave us -// a (possibly) new water height. Update it in our local copy. -void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height) -{ - for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) - { - if ((*iter)->getName() == sim_name) - { - (*iter)->setWaterHeight(water_height); - break; - } - } -} - -void LLWorld::updateWaterObjects() -{ - if (!gAgent.getRegion()) - { - return; - } - if (mRegionList.empty()) - { - llwarns << "No regions!" << llendl; - return; - } - - // First, determine the min and max "box" of water objects - S32 min_x = 0; - S32 min_y = 0; - S32 max_x = 0; - S32 max_y = 0; - U32 region_x, region_y; - - S32 rwidth = 256; - - // We only want to fill in water for stuff that's near us, say, within 256 or 512m - S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256; - - LLViewerRegion* regionp = gAgent.getRegion(); - from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); - - min_x = (S32)region_x - range; - min_y = (S32)region_y - range; - max_x = (S32)region_x + range; - max_y = (S32)region_y + range; - - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - LLVOWater* waterp = regionp->getLand().getWaterObj(); - if (waterp) - { - gObjectList.updateActive(waterp); - } - } - - for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin(); - iter != mHoleWaterObjects.end(); ++ iter) - { - LLVOWater* waterp = *iter; - gObjectList.killObject(waterp); - } - mHoleWaterObjects.clear(); - - // Now, get a list of the holes - S32 x, y; - F32 water_height = gAgent.getRegion()->getWaterHeight() + 256.f; - for (x = min_x; x <= max_x; x += rwidth) - { - for (y = min_y; y <= max_y; y += rwidth) - { - U64 region_handle = to_region_handle(x, y); - if (!getRegionFromHandle(region_handle)) - { - LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion()); - waterp->setUseTexture(FALSE); - waterp->setPositionGlobal(LLVector3d(x + rwidth/2, - y + rwidth/2, - water_height)); - waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f)); - gPipeline.createObject(waterp); - mHoleWaterObjects.push_back(waterp); - } - } - } - - // Update edge water objects - S32 wx, wy; - S32 center_x, center_y; - wx = (max_x - min_x) + rwidth; - wy = (max_y - min_y) + rwidth; - center_x = min_x + (wx >> 1); - center_y = min_y + (wy >> 1); - - S32 add_boundary[4] = { - 512 - (max_x - region_x), - 512 - (max_y - region_y), - 512 - (region_x - min_x), - 512 - (region_y - min_y) }; - - S32 dir; - for (dir = 0; dir < 8; dir++) - { - S32 dim[2] = { 0 }; - switch (gDirAxes[dir][0]) - { - case -1: dim[0] = add_boundary[2]; break; - case 0: dim[0] = wx; break; - default: dim[0] = add_boundary[0]; break; - } - switch (gDirAxes[dir][1]) - { - case -1: dim[1] = add_boundary[3]; break; - case 0: dim[1] = wy; break; - default: dim[1] = add_boundary[1]; break; - } - - // Resize and reshape the water objects - const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]); - const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]); - - LLVOWater* waterp = mEdgeWaterObjects[dir]; - if (!waterp || waterp->isDead()) - { - // The edge water objects can be dead because they're attached to the region that the - // agent was in when they were originally created. - mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, - gAgent.getRegion()); - waterp = mEdgeWaterObjects[dir]; - waterp->setUseTexture(FALSE); - waterp->setIsEdgePatch(TRUE); - gPipeline.createObject(waterp); - } - - waterp->setRegion(gAgent.getRegion()); - LLVector3d water_pos(water_center_x, water_center_y, water_height) ; - LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f); - - //stretch out to horizon - water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]); - water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]); - - water_pos.mdV[0] += 1024.f * gDirAxes[dir][0]; - water_pos.mdV[1] += 1024.f * gDirAxes[dir][1]; - - waterp->setPositionGlobal(water_pos); - waterp->setScale(water_scale); - - gObjectList.updateActive(waterp); - } -} - - -void LLWorld::shiftRegions(const LLVector3& offset) -{ - for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i) - { - LLViewerRegion* region = *i; - region->updateRenderMatrix(); - } - - LLViewerPartSim::getInstance()->shift(offset); -} - -LLViewerTexture* LLWorld::getDefaultWaterTexture() -{ - return mDefaultWaterTexturep; -} - -void LLWorld::setSpaceTimeUSec(const U64 space_time_usec) -{ - mSpaceTimeUSec = space_time_usec; -} - -U64 LLWorld::getSpaceTimeUSec() const -{ - return mSpaceTimeUSec; -} - -void LLWorld::requestCacheMisses() -{ - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - regionp->requestCacheMisses(); - } -} - -void LLWorld::getInfo(LLSD& info) -{ - LLSD region_info; - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - regionp->getInfo(region_info); - info["World"].append(region_info); - } -} - -void LLWorld::disconnectRegions() -{ - LLMessageSystem* msg = gMessageSystem; - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - if (regionp == gAgent.getRegion()) - { - // Skip the main agent - continue; - } - - llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl; - msg->newMessageFast(_PREHASH_AgentQuitCopy); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FuseBlock); - msg->addU32Fast(_PREHASH_ViewerCircuitCode, gMessageSystem->mOurCircuitCode); - msg->sendMessage(regionp->getHost()); - } -} - -static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim"); - -void process_enable_simulator(LLMessageSystem *msg, void **user_data) -{ - LLFastTimer t(FTM_ENABLE_SIMULATOR); - // enable the appropriate circuit for this simulator and - // add its values into the gSimulator structure - U64 handle; - U32 ip_u32; - U16 port; - - msg->getU64Fast(_PREHASH_SimulatorInfo, _PREHASH_Handle, handle); - msg->getIPAddrFast(_PREHASH_SimulatorInfo, _PREHASH_IP, ip_u32); - msg->getIPPortFast(_PREHASH_SimulatorInfo, _PREHASH_Port, port); - - // which simulator should we modify? - LLHost sim(ip_u32, port); - - // Viewer trusts the simulator. - msg->enableCircuit(sim, TRUE); - LLWorld::getInstance()->addRegion(handle, sim); - - // give the simulator a message it can use to get ip and port - llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable(sim); -} - -class LLEstablishAgentCommunication : public LLHTTPNode -{ - LOG_CLASS(LLEstablishAgentCommunication); -public: - virtual void describe(Description& desc) const - { - desc.shortInfo("seed capability info for a region"); - desc.postAPI(); - desc.input( - "{ seed-capability: ..., sim-ip: ..., sim-port }"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const - { - if (!input["body"].has("agent-id") || - !input["body"].has("sim-ip-and-port") || - !input["body"].has("seed-capability")) - { - llwarns << "invalid parameters" << llendl; - return; - } - - LLHost sim(input["body"]["sim-ip-and-port"].asString()); - - LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim); - if (!regionp) - { - llwarns << "Got EstablishAgentCommunication for unknown region " - << sim << llendl; - return; - } - regionp->setSeedCapability(input["body"]["seed-capability"]); - } -}; - -// disable the circuit to this simulator -// Called in response to "DisableSimulator" message. -void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data) -{ - LLHost host = mesgsys->getSender(); - - //llinfos << "Disabling simulator with message from " << host << llendl; - LLWorld::getInstance()->removeRegion(host); - - mesgsys->disableCircuit(host); -} - - -void process_region_handshake(LLMessageSystem* msg, void** user_data) -{ - LLHost host = msg->getSender(); - LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(host); - if (!regionp) - { - llwarns << "Got region handshake for unknown region " - << host << llendl; - return; - } - - regionp->unpackRegionHandshake(); -} - - -void send_agent_pause() -{ - // *NOTE:Mani Pausing the mainloop timeout. Otherwise a long modal event may cause - // the thread monitor to timeout. - LLAppViewer::instance()->pauseMainloopTimeout(); - - // Note: used to check for LLWorld initialization before it became a singleton. - // Rather than just remove this check I'm changing it to assure that the message - // system has been initialized. -MG - if (!gMessageSystem) - { - return; - } - - gMessageSystem->newMessageFast(_PREHASH_AgentPause); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); - - gAgentPauseSerialNum++; - gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* regionp = *iter; - gMessageSystem->sendReliable(regionp->getHost()); - } - - gObjectList.mWasPaused = TRUE; -} - - -void send_agent_resume() -{ - // Note: used to check for LLWorld initialization before it became a singleton. - // Rather than just remove this check I'm changing it to assure that the message - // system has been initialized. -MG - if (!gMessageSystem) - { - return; - } - - gMessageSystem->newMessageFast(_PREHASH_AgentResume); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); - - gAgentPauseSerialNum++; - gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum); - - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* regionp = *iter; - gMessageSystem->sendReliable(regionp->getHost()); - } - - // Reset the FPS counter to avoid an invalid fps - LLViewerStats::getInstance()->mFPSStat.start(); - - LLAppViewer::instance()->resumeMainloopTimeout(); -} - -static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin) -{ - LLVector3d pos_local; - - pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4; - pos_local.mdV[VY] = (compact_local >> 8) & 0xFFU; - pos_local.mdV[VX] = (compact_local >> 16) & 0xFFU; - - return region_origin + pos_local; -} - -void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positions, const LLVector3d& relative_to, F32 radius) const -{ - F32 radius_squared = radius * radius; - - if(avatar_ids != NULL) - { - avatar_ids->clear(); - } - if(positions != NULL) - { - positions->clear(); - } - // get the list of avatars from the character list first, so distances are correct - // when agent is above 1020m and other avatars are nearby - for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter; - LLVector3d pos_global = pVOAvatar->getPositionGlobal(); - LLUUID uuid = pVOAvatar->getID(); - if( !pVOAvatar->isDead() - && !pVOAvatar->isSelf() - && !uuid.isNull() && - dist_vec_squared(pos_global, relative_to) <= radius_squared) - { - if(positions != NULL) - { - positions->push_back(pos_global); - } - if(avatar_ids !=NULL) - { - avatar_ids->push_back(uuid); - } - } - } - // region avatars added for situations where radius is greater than RenderFarClip - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* regionp = *iter; - const LLVector3d& origin_global = regionp->getOriginGlobal(); - S32 count = regionp->mMapAvatars.count(); - for (S32 i = 0; i < count; i++) - { - LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.get(i), origin_global); - if(dist_vec_squared(pos_global, relative_to) <= radius_squared) - { - LLUUID uuid = regionp->mMapAvatarIDs.get(i); - // if this avatar doesn't already exist in the list, add it - if(uuid.notNull() && avatar_ids != NULL && std::find(avatar_ids->begin(), avatar_ids->end(), uuid) == avatar_ids->end()) - { - if (positions != NULL) - { - positions->push_back(pos_global); - } - avatar_ids->push_back(uuid); - } - } - } - } -} - - -LLHTTPRegistration<LLEstablishAgentCommunication> - gHTTPRegistrationEstablishAgentCommunication( - "/message/EstablishAgentCommunication"); +/**
+ * @file llworld.cpp
+ * @brief Initial test structure to organize viewer regions
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llworld.h"
+#include "llrender.h"
+
+#include "indra_constants.h"
+#include "llstl.h"
+
+#include "llagent.h"
+#include "llviewercontrol.h"
+#include "lldrawpool.h"
+#include "llglheaders.h"
+#include "llhttpnode.h"
+#include "llregionhandle.h"
+#include "llsurface.h"
+#include "lltrans.h"
+#include "llviewercamera.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparceloverlay.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llvlcomposition.h"
+#include "llvoavatar.h"
+#include "llvocache.h"
+#include "llvowater.h"
+#include "message.h"
+#include "pipeline.h"
+#include "llappviewer.h" // for do_disconnect()
+#include "llfloaterpathfindingconsole.h"
+
+#include <deque>
+#include <queue>
+#include <map>
+#include <cstring>
+
+
+//
+// Globals
+//
+U32 gAgentPauseSerialNum = 0;
+
+//
+// Constants
+//
+const S32 MAX_NUMBER_OF_CLOUDS = 750;
+const S32 WORLD_PATCH_SIZE = 16;
+
+extern LLColor4U MAX_WATER_COLOR;
+
+const U32 LLWorld::mWidth = 256;
+
+// meters/point, therefore mWidth * mScale = meters per edge
+const F32 LLWorld::mScale = 1.f;
+
+const F32 LLWorld::mWidthInMeters = mWidth * mScale;
+
+//
+// Functions
+//
+
+// allocate the stack
+LLWorld::LLWorld() :
+ mLandFarClip(DEFAULT_FAR_PLANE),
+ mLastPacketsIn(0),
+ mLastPacketsOut(0),
+ mLastPacketsLost(0),
+ mSpaceTimeUSec(0)
+{
+ for (S32 i = 0; i < 8; i++)
+ {
+ mEdgeWaterObjects[i] = NULL;
+ }
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,4);
+ U8 *default_texture = raw->getData();
+ *(default_texture++) = MAX_WATER_COLOR.mV[0];
+ *(default_texture++) = MAX_WATER_COLOR.mV[1];
+ *(default_texture++) = MAX_WATER_COLOR.mV[2];
+ *(default_texture++) = MAX_WATER_COLOR.mV[3];
+
+ mDefaultWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
+ gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
+ mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+}
+
+
+void LLWorld::destroyClass()
+{
+ mHoleWaterObjects.clear();
+ gObjectList.destroy();
+ for(region_list_t::iterator region_it = mRegionList.begin(); region_it != mRegionList.end(); )
+ {
+ LLViewerRegion* region_to_delete = *region_it++;
+ removeRegion(region_to_delete->getHost());
+ }
+ if(LLVOCache::hasInstance())
+ {
+ LLVOCache::getInstance()->destroyClass() ;
+ }
+ LLViewerPartSim::getInstance()->destroyClass();
+
+ mDefaultWaterTexturep = NULL ;
+ for (S32 i = 0; i < 8; i++)
+ {
+ mEdgeWaterObjects[i] = NULL;
+ }
+}
+
+
+LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host)
+{
+ LLMemType mt(LLMemType::MTYPE_REGIONS);
+ llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
+ LLViewerRegion *regionp = getRegionFromHandle(region_handle);
+ if (regionp)
+ {
+ llinfos << "Region exists, removing it " << llendl;
+ LLHost old_host = regionp->getHost();
+ // region already exists!
+ if (host == old_host && regionp->isAlive())
+ {
+ // This is a duplicate for the same host and it's alive, don't bother.
+ return regionp;
+ }
+
+ if (host != old_host)
+ {
+ llwarns << "LLWorld::addRegion exists, but old host " << old_host
+ << " does not match new host " << host << llendl;
+ }
+ if (!regionp->isAlive())
+ {
+ llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl;
+ }
+
+ // Kill the old host, and then we can continue on and add the new host. We have to kill even if the host
+ // matches, because all the agent state for the new camera is completely different.
+ removeRegion(old_host);
+ }
+
+ U32 iindex = 0;
+ U32 jindex = 0;
+ from_region_handle(region_handle, &iindex, &jindex);
+ S32 x = (S32)(iindex/mWidth);
+ S32 y = (S32)(jindex/mWidth);
+ llinfos << "Adding new region (" << x << ":" << y << ")" << llendl;
+ llinfos << "Host: " << host << llendl;
+
+ LLVector3d origin_global;
+
+ origin_global = from_region_handle(region_handle);
+
+ regionp = new LLViewerRegion(region_handle,
+ host,
+ mWidth,
+ WORLD_PATCH_SIZE,
+ getRegionWidthInMeters() );
+ if (!regionp)
+ {
+ llerrs << "Unable to create new region!" << llendl;
+ }
+
+ mRegionList.push_back(regionp);
+ mActiveRegionList.push_back(regionp);
+ mCulledRegionList.push_back(regionp);
+
+
+ // Find all the adjacent regions, and attach them.
+ // Generate handles for all of the adjacent regions, and attach them in the correct way.
+ // connect the edges
+ F32 adj_x = 0.f;
+ F32 adj_y = 0.f;
+ F32 region_x = 0.f;
+ F32 region_y = 0.f;
+ U64 adj_handle = 0;
+
+ F32 width = getRegionWidthInMeters();
+
+ LLViewerRegion *neighborp;
+ from_region_handle(region_handle, ®ion_x, ®ion_y);
+
+ // Iterate through all directions, and connect neighbors if there.
+ S32 dir;
+ for (dir = 0; dir < 8; dir++)
+ {
+ adj_x = region_x + width * gDirAxes[dir][0];
+ adj_y = region_y + width * gDirAxes[dir][1];
+ to_region_handle(adj_x, adj_y, &adj_handle);
+
+ neighborp = getRegionFromHandle(adj_handle);
+ if (neighborp)
+ {
+ //llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
+ regionp->connectNeighbor(neighborp, dir);
+ }
+ }
+
+ updateWaterObjects();
+
+ return regionp;
+}
+
+
+void LLWorld::removeRegion(const LLHost &host)
+{
+ F32 x, y;
+
+ LLViewerRegion *regionp = getRegion(host);
+ if (!regionp)
+ {
+ llwarns << "Trying to remove region that doesn't exist!" << llendl;
+ return;
+ }
+
+ if (regionp == gAgent.getRegion())
+ {
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* reg = *iter;
+ llwarns << "RegionDump: " << reg->getName()
+ << " " << reg->getHost()
+ << " " << reg->getOriginGlobal()
+ << llendl;
+ }
+
+ llwarns << "Agent position global " << gAgent.getPositionGlobal()
+ << " agent " << gAgent.getPositionAgent()
+ << llendl;
+
+ llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl;
+
+ llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl;
+
+ llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl;
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected"));
+
+ regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed.
+ return;
+ }
+
+ from_region_handle(regionp->getHandle(), &x, &y);
+ llinfos << "Removing region " << x << ":" << y << llendl;
+
+ mRegionList.remove(regionp);
+ mActiveRegionList.remove(regionp);
+ mCulledRegionList.remove(regionp);
+ mVisibleRegionList.remove(regionp);
+
+ delete regionp;
+
+ updateWaterObjects();
+
+ //double check all objects of this region are removed.
+ gObjectList.clearAllMapObjectsInRegion(regionp) ;
+ //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ;
+}
+
+
+LLViewerRegion* LLWorld::getRegion(const LLHost &host)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->getHost() == host)
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+LLViewerRegion* LLWorld::getRegionFromPosAgent(const LLVector3 &pos)
+{
+ return getRegionFromPosGlobal(gAgent.getPosGlobalFromAgent(pos));
+}
+
+LLViewerRegion* LLWorld::getRegionFromPosGlobal(const LLVector3d &pos)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->pointInRegionGlobal(pos))
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+
+LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos)
+{
+ if (positionRegionValidGlobal(end_pos))
+ {
+ return end_pos;
+ }
+
+ LLViewerRegion* regionp = getRegionFromPosGlobal(start_pos);
+ if (!regionp)
+ {
+ return start_pos;
+ }
+
+ LLVector3d delta_pos = end_pos - start_pos;
+ LLVector3d delta_pos_abs;
+ delta_pos_abs.setVec(delta_pos);
+ delta_pos_abs.abs();
+
+ LLVector3 region_coord = regionp->getPosRegionFromGlobal(end_pos);
+ F64 clip_factor = 1.0;
+ F32 region_width = regionp->getWidth();
+ if (region_coord.mV[VX] < 0.f)
+ {
+ if (region_coord.mV[VY] < region_coord.mV[VX])
+ {
+ // clip along y -
+ clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
+ }
+ else
+ {
+ // clip along x -
+ clip_factor = -(region_coord.mV[VX] / delta_pos_abs.mdV[VX]);
+ }
+ }
+ else if (region_coord.mV[VX] > region_width)
+ {
+ if (region_coord.mV[VY] > region_coord.mV[VX])
+ {
+ // clip along y +
+ clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
+ }
+ else
+ {
+ //clip along x +
+ clip_factor = (region_coord.mV[VX] - region_width) / delta_pos_abs.mdV[VX];
+ }
+ }
+ else if (region_coord.mV[VY] < 0.f)
+ {
+ // clip along y -
+ clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
+ }
+ else if (region_coord.mV[VY] > region_width)
+ {
+ // clip along y +
+ clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
+ }
+
+ // clamp to within region dimensions
+ LLVector3d final_region_pos = LLVector3d(region_coord) - (delta_pos * clip_factor);
+ final_region_pos.mdV[VX] = llclamp(final_region_pos.mdV[VX], 0.0,
+ (F64)(region_width - F_ALMOST_ZERO));
+ final_region_pos.mdV[VY] = llclamp(final_region_pos.mdV[VY], 0.0,
+ (F64)(region_width - F_ALMOST_ZERO));
+ final_region_pos.mdV[VZ] = llclamp(final_region_pos.mdV[VZ], 0.0,
+ (F64)(LLWorld::getInstance()->getRegionMaxHeight() - F_ALMOST_ZERO));
+ return regionp->getPosGlobalFromRegion(LLVector3(final_region_pos));
+}
+
+LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->getHandle() == handle)
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLWorld::updateAgentOffset(const LLVector3d &offset_global)
+{
+#if 0
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->setAgentOffset(offset_global);
+ }
+#endif
+}
+
+
+BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->pointInRegionGlobal(pos_global))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+// Allow objects to go up to their radius underground.
+F32 LLWorld::getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos)
+{
+ F32 land_height = resolveLandHeightGlobal(global_pos);
+ F32 radius = 0.5f * object->getScale().length();
+ return land_height - radius;
+}
+
+
+
+LLViewerRegion* LLWorld::resolveRegionGlobal(LLVector3 &pos_region, const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+
+ if (regionp)
+ {
+ pos_region = regionp->getPosRegionFromGlobal(pos_global);
+ return regionp;
+ }
+
+ return NULL;
+}
+
+
+LLViewerRegion* LLWorld::resolveRegionAgent(LLVector3 &pos_region, const LLVector3 &pos_agent)
+{
+ LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+
+ if (regionp)
+ {
+ pos_region = regionp->getPosRegionFromGlobal(pos_global);
+ return regionp;
+ }
+
+ return NULL;
+}
+
+
+F32 LLWorld::resolveLandHeightAgent(const LLVector3 &pos_agent)
+{
+ LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
+ return resolveLandHeightGlobal(pos_global);
+}
+
+
+F32 LLWorld::resolveLandHeightGlobal(const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (regionp)
+ {
+ return regionp->getLand().resolveHeightGlobal(pos_global);
+ }
+ return 0.0f;
+}
+
+
+// Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a)
+// point where the the line intersects an object or the land surface. Stores the results
+// in "intersection" and "intersection_normal" and returns a scalar value that represents
+// the normalized distance along the line from "point_a" to "intersection".
+//
+// Currently assumes point_a and point_b only differ in z-direction,
+// but it may eventually become more general.
+F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b,
+ LLVector3d &intersection, LLVector3 &intersection_normal,
+ LLViewerObject **viewerObjectPtr)
+{
+ // initialize return value to null
+ if (viewerObjectPtr)
+ {
+ *viewerObjectPtr = NULL;
+ }
+
+ LLViewerRegion *regionp = getRegionFromPosGlobal(point_a);
+ if (!regionp)
+ {
+ // We're outside the world
+ intersection = 0.5f * (point_a + point_b);
+ intersection_normal.setVec(0.0f, 0.0f, 1.0f);
+ return 0.5f;
+ }
+
+ // calculate the length of the segment
+ F32 segment_length = (F32)((point_a - point_b).length());
+ if (0.0f == segment_length)
+ {
+ intersection = point_a;
+ intersection_normal.setVec(0.0f, 0.0f, 1.0f);
+ return segment_length;
+ }
+
+ // get land height
+ // Note: we assume that the line is parallel to z-axis here
+ LLVector3d land_intersection = point_a;
+ F32 normalized_land_distance;
+
+ land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a);
+ normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length;
+ intersection = land_intersection;
+ intersection_normal = resolveLandNormalGlobal(land_intersection);
+
+ if (avatarp && !avatarp->mFootPlane.isExactlyClear())
+ {
+ LLVector3 foot_plane_normal(avatarp->mFootPlane.mV);
+ LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a);
+ // added 0.05 meters to compensate for error in foot plane reported by Havok
+ F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f;
+ norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f);
+ if (norm_dist_from_plane < normalized_land_distance)
+ {
+ // collided with object before land
+ normalized_land_distance = norm_dist_from_plane;
+ intersection = point_a;
+ intersection.mdV[VZ] -= norm_dist_from_plane * segment_length;
+ intersection_normal = foot_plane_normal;
+ }
+ else
+ {
+ intersection = land_intersection;
+ intersection_normal = resolveLandNormalGlobal(land_intersection);
+ }
+ }
+
+ return normalized_land_distance;
+}
+
+
+LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global)
+{
+ // returns a pointer to the patch at this location
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (!regionp)
+ {
+ return NULL;
+ }
+
+ return regionp->getLand().resolvePatchGlobal(pos_global);
+}
+
+
+LLVector3 LLWorld::resolveLandNormalGlobal(const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (!regionp)
+ {
+ return LLVector3::z_axis;
+ }
+
+ return regionp->getLand().resolveNormalGlobal(pos_global);
+}
+
+
+void LLWorld::updateVisibilities()
+{
+ F32 cur_far_clip = LLViewerCamera::getInstance()->getFar();
+
+ // Go through the culled list and check for visible regions (region is visible if land is visible)
+ for (region_list_t::iterator iter = mCulledRegionList.begin();
+ iter != mCulledRegionList.end(); )
+ {
+ region_list_t::iterator curiter = iter++;
+ LLViewerRegion* regionp = *curiter;
+
+ LLSpatialPartition* part = regionp->getSpatialPartition(LLViewerRegion::PARTITION_TERRAIN);
+ if (part)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+ if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+ {
+ mCulledRegionList.erase(curiter);
+ mVisibleRegionList.push_back(regionp);
+ }
+ }
+ }
+
+ // Update all of the visible regions
+ for (region_list_t::iterator iter = mVisibleRegionList.begin();
+ iter != mVisibleRegionList.end(); )
+ {
+ region_list_t::iterator curiter = iter++;
+ LLViewerRegion* regionp = *curiter;
+ if (!regionp->getLand().hasZData())
+ {
+ continue;
+ }
+
+ LLSpatialPartition* part = regionp->getSpatialPartition(LLViewerRegion::PARTITION_TERRAIN);
+ if (part)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+ if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+ {
+ regionp->calculateCameraDistance();
+ regionp->getLand().updatePatchVisibilities(gAgent);
+ }
+ else
+ {
+ mVisibleRegionList.erase(curiter);
+ mCulledRegionList.push_back(regionp);
+ }
+ }
+ }
+
+ // Sort visible regions
+ mVisibleRegionList.sort(LLViewerRegion::CompareDistance());
+
+ LLViewerCamera::getInstance()->setFar(cur_far_clip);
+}
+
+void LLWorld::updateRegions(F32 max_update_time)
+{
+ LLMemType mt_ur(LLMemType::MTYPE_IDLE_UPDATE_REGIONS);
+ LLTimer update_timer;
+ BOOL did_one = FALSE;
+
+ // Perform idle time updates for the regions (and associated surfaces)
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ F32 max_time = max_update_time - update_timer.getElapsedTimeF32();
+ if (did_one && max_time <= 0.f)
+ break;
+ max_time = llmin(max_time, max_update_time*.1f);
+ did_one |= regionp->idleUpdate(max_update_time);
+ }
+}
+
+void LLWorld::updateParticles()
+{
+ LLViewerPartSim::getInstance()->updateSimulation();
+}
+
+void LLWorld::renderPropertyLines()
+{
+ S32 region_count = 0;
+ S32 vertex_count = 0;
+
+ for (region_list_t::iterator iter = mVisibleRegionList.begin();
+ iter != mVisibleRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ region_count++;
+ vertex_count += regionp->renderPropertyLines();
+ }
+}
+
+
+void LLWorld::updateNetStats()
+{
+ F32 bits = 0.f;
+ U32 packets = 0;
+
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->updateNetStats();
+ bits += regionp->mBitStat.getCurrent();
+ packets += llfloor( regionp->mPacketsStat.getCurrent() );
+ }
+
+ S32 packets_in = gMessageSystem->mPacketsIn - mLastPacketsIn;
+ S32 packets_out = gMessageSystem->mPacketsOut - mLastPacketsOut;
+ S32 packets_lost = gMessageSystem->mDroppedPackets - mLastPacketsLost;
+
+ S32 actual_in_bits = gMessageSystem->mPacketRing.getAndResetActualInBits();
+ S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits();
+ LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f);
+ LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f);
+ LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
+ LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in);
+ LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out);
+ LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets);
+ if (packets_in)
+ {
+ LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(100.f*((F32)packets_lost/(F32)packets_in));
+ }
+ else
+ {
+ LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(0.f);
+ }
+
+ mLastPacketsIn = gMessageSystem->mPacketsIn;
+ mLastPacketsOut = gMessageSystem->mPacketsOut;
+ mLastPacketsLost = gMessageSystem->mDroppedPackets;
+}
+
+
+void LLWorld::printPacketsLost()
+{
+ llinfos << "Simulators:" << llendl;
+ llinfos << "----------" << llendl;
+
+ LLCircuitData *cdp = NULL;
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost());
+ if (cdp)
+ {
+ LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal();
+
+ llinfos << regionp->getHost() << ", range: " << range.length()
+ << " packets lost: " << cdp->getPacketsLost() << llendl;
+ }
+ }
+}
+
+void LLWorld::processCoarseUpdate(LLMessageSystem* msg, void** user_data)
+{
+ LLViewerRegion* region = LLWorld::getInstance()->getRegion(msg->getSender());
+ if( region )
+ {
+ region->updateCoarseLocations(msg);
+ }
+}
+
+F32 LLWorld::getLandFarClip() const
+{
+ return mLandFarClip;
+}
+
+void LLWorld::setLandFarClip(const F32 far_clip)
+{
+ static S32 const rwidth = (S32)REGION_WIDTH_U32;
+ S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
+ S32 const n2 = (llceil(far_clip) - 1) / rwidth;
+ bool need_water_objects_update = n1 != n2;
+
+ mLandFarClip = far_clip;
+
+ if (need_water_objects_update)
+ {
+ updateWaterObjects();
+ }
+}
+
+// Some region that we're connected to, but not the one we're in, gave us
+// a (possibly) new water height. Update it in our local copy.
+void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height)
+{
+ for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
+ {
+ if ((*iter)->getName() == sim_name)
+ {
+ (*iter)->setWaterHeight(water_height);
+ break;
+ }
+ }
+}
+
+void LLWorld::updateWaterObjects()
+{
+ if (!gAgent.getRegion())
+ {
+ return;
+ }
+ if (mRegionList.empty())
+ {
+ llwarns << "No regions!" << llendl;
+ return;
+ }
+
+ // First, determine the min and max "box" of water objects
+ S32 min_x = 0;
+ S32 min_y = 0;
+ S32 max_x = 0;
+ S32 max_y = 0;
+ U32 region_x, region_y;
+
+ S32 rwidth = 256;
+
+ // We only want to fill in water for stuff that's near us, say, within 256 or 512m
+ S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256;
+
+ LLViewerRegion* regionp = gAgent.getRegion();
+ from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y);
+
+ min_x = (S32)region_x - range;
+ min_y = (S32)region_y - range;
+ max_x = (S32)region_x + range;
+ max_y = (S32)region_y + range;
+
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ LLVOWater* waterp = regionp->getLand().getWaterObj();
+ if (waterp)
+ {
+ gObjectList.updateActive(waterp);
+ }
+ }
+
+ for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
+ iter != mHoleWaterObjects.end(); ++ iter)
+ {
+ LLVOWater* waterp = *iter;
+ gObjectList.killObject(waterp);
+ }
+ mHoleWaterObjects.clear();
+
+ // Now, get a list of the holes
+ S32 x, y;
+ F32 water_height = gAgent.getRegion()->getWaterHeight() + 256.f;
+ for (x = min_x; x <= max_x; x += rwidth)
+ {
+ for (y = min_y; y <= max_y; y += rwidth)
+ {
+ U64 region_handle = to_region_handle(x, y);
+ if (!getRegionFromHandle(region_handle))
+ {
+ LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
+ waterp->setUseTexture(FALSE);
+ waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
+ y + rwidth/2,
+ water_height));
+ waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
+ gPipeline.createObject(waterp);
+ mHoleWaterObjects.push_back(waterp);
+ }
+ }
+ }
+
+ // Update edge water objects
+ S32 wx, wy;
+ S32 center_x, center_y;
+ wx = (max_x - min_x) + rwidth;
+ wy = (max_y - min_y) + rwidth;
+ center_x = min_x + (wx >> 1);
+ center_y = min_y + (wy >> 1);
+
+ S32 add_boundary[4] = {
+ 512 - (max_x - region_x),
+ 512 - (max_y - region_y),
+ 512 - (region_x - min_x),
+ 512 - (region_y - min_y) };
+
+ S32 dir;
+ for (dir = 0; dir < 8; dir++)
+ {
+ S32 dim[2] = { 0 };
+ switch (gDirAxes[dir][0])
+ {
+ case -1: dim[0] = add_boundary[2]; break;
+ case 0: dim[0] = wx; break;
+ default: dim[0] = add_boundary[0]; break;
+ }
+ switch (gDirAxes[dir][1])
+ {
+ case -1: dim[1] = add_boundary[3]; break;
+ case 0: dim[1] = wy; break;
+ default: dim[1] = add_boundary[1]; break;
+ }
+
+ // Resize and reshape the water objects
+ const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]);
+ const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]);
+
+ LLVOWater* waterp = mEdgeWaterObjects[dir];
+ if (!waterp || waterp->isDead())
+ {
+ // The edge water objects can be dead because they're attached to the region that the
+ // agent was in when they were originally created.
+ mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER,
+ gAgent.getRegion());
+ waterp = mEdgeWaterObjects[dir];
+ waterp->setUseTexture(FALSE);
+ waterp->setIsEdgePatch(TRUE);
+ gPipeline.createObject(waterp);
+ }
+
+ waterp->setRegion(gAgent.getRegion());
+ LLVector3d water_pos(water_center_x, water_center_y, water_height) ;
+ LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
+
+ //stretch out to horizon
+ water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]);
+ water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]);
+
+ water_pos.mdV[0] += 1024.f * gDirAxes[dir][0];
+ water_pos.mdV[1] += 1024.f * gDirAxes[dir][1];
+
+ waterp->setPositionGlobal(water_pos);
+ waterp->setScale(water_scale);
+
+ gObjectList.updateActive(waterp);
+ }
+}
+
+
+void LLWorld::shiftRegions(const LLVector3& offset)
+{
+ for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
+ {
+ LLViewerRegion* region = *i;
+ region->updateRenderMatrix();
+ }
+
+ LLViewerPartSim::getInstance()->shift(offset);
+}
+
+LLViewerTexture* LLWorld::getDefaultWaterTexture()
+{
+ return mDefaultWaterTexturep;
+}
+
+void LLWorld::setSpaceTimeUSec(const U64 space_time_usec)
+{
+ mSpaceTimeUSec = space_time_usec;
+}
+
+U64 LLWorld::getSpaceTimeUSec() const
+{
+ return mSpaceTimeUSec;
+}
+
+void LLWorld::requestCacheMisses()
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->requestCacheMisses();
+ }
+}
+
+void LLWorld::getInfo(LLSD& info)
+{
+ LLSD region_info;
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->getInfo(region_info);
+ info["World"].append(region_info);
+ }
+}
+
+void LLWorld::disconnectRegions()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp == gAgent.getRegion())
+ {
+ // Skip the main agent
+ continue;
+ }
+
+ llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl;
+ msg->newMessageFast(_PREHASH_AgentQuitCopy);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_FuseBlock);
+ msg->addU32Fast(_PREHASH_ViewerCircuitCode, gMessageSystem->mOurCircuitCode);
+ msg->sendMessage(regionp->getHost());
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim");
+
+void process_enable_simulator(LLMessageSystem *msg, void **user_data)
+{
+ LLFastTimer t(FTM_ENABLE_SIMULATOR);
+ // enable the appropriate circuit for this simulator and
+ // add its values into the gSimulator structure
+ U64 handle;
+ U32 ip_u32;
+ U16 port;
+
+ msg->getU64Fast(_PREHASH_SimulatorInfo, _PREHASH_Handle, handle);
+ msg->getIPAddrFast(_PREHASH_SimulatorInfo, _PREHASH_IP, ip_u32);
+ msg->getIPPortFast(_PREHASH_SimulatorInfo, _PREHASH_Port, port);
+
+ // which simulator should we modify?
+ LLHost sim(ip_u32, port);
+
+ // Viewer trusts the simulator.
+ msg->enableCircuit(sim, TRUE);
+ LLWorld::getInstance()->addRegion(handle, sim);
+
+ // give the simulator a message it can use to get ip and port
+ llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl;
+ msg->newMessageFast(_PREHASH_UseCircuitCode);
+ msg->nextBlockFast(_PREHASH_CircuitCode);
+ msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
+ msg->sendReliable(sim);
+}
+
+class LLEstablishAgentCommunication : public LLHTTPNode
+{
+ LOG_CLASS(LLEstablishAgentCommunication);
+public:
+ virtual void describe(Description& desc) const
+ {
+ desc.shortInfo("seed capability info for a region");
+ desc.postAPI();
+ desc.input(
+ "{ seed-capability: ..., sim-ip: ..., sim-port }");
+ desc.source(__FILE__, __LINE__);
+ }
+
+ virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
+ {
+ if (!input["body"].has("agent-id") ||
+ !input["body"].has("sim-ip-and-port") ||
+ !input["body"].has("seed-capability"))
+ {
+ llwarns << "invalid parameters" << llendl;
+ return;
+ }
+
+ LLHost sim(input["body"]["sim-ip-and-port"].asString());
+
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim);
+ if (!regionp)
+ {
+ llwarns << "Got EstablishAgentCommunication for unknown region "
+ << sim << llendl;
+ return;
+ }
+ regionp->setSeedCapability(input["body"]["seed-capability"]);
+ }
+};
+
+// disable the circuit to this simulator
+// Called in response to "DisableSimulator" message.
+void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLHost host = mesgsys->getSender();
+
+ //llinfos << "Disabling simulator with message from " << host << llendl;
+ LLWorld::getInstance()->removeRegion(host);
+
+ mesgsys->disableCircuit(host);
+}
+
+
+void process_region_handshake(LLMessageSystem* msg, void** user_data)
+{
+ LLHost host = msg->getSender();
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(host);
+ if (!regionp)
+ {
+ llwarns << "Got region handshake for unknown region "
+ << host << llendl;
+ return;
+ }
+
+ regionp->unpackRegionHandshake();
+
+ LLFloaterPathfindingConsole* pWindow = LLFloaterPathfindingConsole::getInstanceHandle().get();
+ if ( pWindow && pWindow->getHeartBeat() )
+ {
+ pWindow->regionCrossingOccured();
+ return;
+ }
+
+}
+
+
+void send_agent_pause()
+{
+ // *NOTE:Mani Pausing the mainloop timeout. Otherwise a long modal event may cause
+ // the thread monitor to timeout.
+ LLAppViewer::instance()->pauseMainloopTimeout();
+
+ // Note: used to check for LLWorld initialization before it became a singleton.
+ // Rather than just remove this check I'm changing it to assure that the message
+ // system has been initialized. -MG
+ if (!gMessageSystem)
+ {
+ return;
+ }
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentPause);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
+
+ gAgentPauseSerialNum++;
+ gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ gMessageSystem->sendReliable(regionp->getHost());
+ }
+
+ gObjectList.mWasPaused = TRUE;
+}
+
+
+void send_agent_resume()
+{
+ // Note: used to check for LLWorld initialization before it became a singleton.
+ // Rather than just remove this check I'm changing it to assure that the message
+ // system has been initialized. -MG
+ if (!gMessageSystem)
+ {
+ return;
+ }
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentResume);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
+
+ gAgentPauseSerialNum++;
+ gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
+
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ gMessageSystem->sendReliable(regionp->getHost());
+ }
+
+ // Reset the FPS counter to avoid an invalid fps
+ LLViewerStats::getInstance()->mFPSStat.start();
+
+ LLAppViewer::instance()->resumeMainloopTimeout();
+}
+
+static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin)
+{
+ LLVector3d pos_local;
+
+ pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4;
+ pos_local.mdV[VY] = (compact_local >> 8) & 0xFFU;
+ pos_local.mdV[VX] = (compact_local >> 16) & 0xFFU;
+
+ return region_origin + pos_local;
+}
+
+void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positions, const LLVector3d& relative_to, F32 radius) const
+{
+ F32 radius_squared = radius * radius;
+
+ if(avatar_ids != NULL)
+ {
+ avatar_ids->clear();
+ }
+ if(positions != NULL)
+ {
+ positions->clear();
+ }
+ // get the list of avatars from the character list first, so distances are correct
+ // when agent is above 1020m and other avatars are nearby
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter;
+ LLVector3d pos_global = pVOAvatar->getPositionGlobal();
+ LLUUID uuid = pVOAvatar->getID();
+ if( !pVOAvatar->isDead()
+ && !pVOAvatar->isSelf()
+ && !uuid.isNull() &&
+ dist_vec_squared(pos_global, relative_to) <= radius_squared)
+ {
+ if(positions != NULL)
+ {
+ positions->push_back(pos_global);
+ }
+ if(avatar_ids !=NULL)
+ {
+ avatar_ids->push_back(uuid);
+ }
+ }
+ }
+ // region avatars added for situations where radius is greater than RenderFarClip
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ const LLVector3d& origin_global = regionp->getOriginGlobal();
+ S32 count = regionp->mMapAvatars.count();
+ for (S32 i = 0; i < count; i++)
+ {
+ LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.get(i), origin_global);
+ if(dist_vec_squared(pos_global, relative_to) <= radius_squared)
+ {
+ LLUUID uuid = regionp->mMapAvatarIDs.get(i);
+ // if this avatar doesn't already exist in the list, add it
+ if(uuid.notNull() && avatar_ids != NULL && std::find(avatar_ids->begin(), avatar_ids->end(), uuid) == avatar_ids->end())
+ {
+ if (positions != NULL)
+ {
+ positions->push_back(pos_global);
+ }
+ avatar_ids->push_back(uuid);
+ }
+ }
+ }
+ }
+}
+
+
+LLHTTPRegistration<LLEstablishAgentCommunication>
+ gHTTPRegistrationEstablishAgentCommunication(
+ "/message/EstablishAgentCommunication");
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a64655960f..28d59785d3 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1,9801 +1,9871 @@ -/** - * @file pipeline.cpp - * @brief Rendering pipeline. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "pipeline.h" - -// library includes -#include "llaudioengine.h" // For debugging. -#include "imageids.h" -#include "llerror.h" -#include "llviewercontrol.h" -#include "llfasttimer.h" -#include "llfontgl.h" -#include "llmemtype.h" -#include "llnamevalue.h" -#include "llpointer.h" -#include "llprimitive.h" -#include "llvolume.h" -#include "material_codes.h" -#include "timing.h" -#include "v3color.h" -#include "llui.h" -#include "llglheaders.h" -#include "llrender.h" -#include "llwindow.h" // swapBuffers() - -// newview includes -#include "llagent.h" -#include "llagentcamera.h" -#include "lldrawable.h" -#include "lldrawpoolalpha.h" -#include "lldrawpoolavatar.h" -#include "lldrawpoolground.h" -#include "lldrawpoolbump.h" -#include "lldrawpooltree.h" -#include "lldrawpoolwater.h" -#include "llface.h" -#include "llfeaturemanager.h" -#include "llfloatertelehub.h" -#include "llfloaterreg.h" -#include "llgldbg.h" -#include "llhudmanager.h" -#include "llhudnametag.h" -#include "llhudtext.h" -#include "lllightconstants.h" -#include "llmeshrepository.h" -#include "llresmgr.h" -#include "llselectmgr.h" -#include "llsky.h" -#include "lltracker.h" -#include "lltool.h" -#include "lltoolmgr.h" -#include "llviewercamera.h" -#include "llviewermediafocus.h" -#include "llviewertexturelist.h" -#include "llviewerobject.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" // for audio debugging. -#include "llviewerwindow.h" // For getSpinAxis -#include "llvoavatarself.h" -#include "llvoground.h" -#include "llvosky.h" -#include "llvotree.h" -#include "llvovolume.h" -#include "llvosurfacepatch.h" -#include "llvowater.h" -#include "llvotree.h" -#include "llvopartgroup.h" -#include "llworld.h" -#include "llcubemap.h" -#include "llviewershadermgr.h" -#include "llviewerstats.h" -#include "llviewerjoystick.h" -#include "llviewerdisplay.h" -#include "llwlparammanager.h" -#include "llwaterparammanager.h" -#include "llspatialpartition.h" -#include "llmutelist.h" -#include "lltoolpie.h" -#include "llcurl.h" -#include "llnotifications.h" - - -#ifdef _DEBUG -// Debug indices is disabled for now for debug performance - djs 4/24/02 -//#define DEBUG_INDICES -#else -//#define DEBUG_INDICES -#endif - -//cached settings -BOOL LLPipeline::RenderAvatarVP; -BOOL LLPipeline::VertexShaderEnable; -BOOL LLPipeline::WindLightUseAtmosShaders; -BOOL LLPipeline::RenderDeferred; -F32 LLPipeline::RenderDeferredSunWash; -U32 LLPipeline::RenderFSAASamples; -U32 LLPipeline::RenderResolutionDivisor; -BOOL LLPipeline::RenderUIBuffer; -S32 LLPipeline::RenderShadowDetail; -BOOL LLPipeline::RenderDeferredSSAO; -F32 LLPipeline::RenderShadowResolutionScale; -BOOL LLPipeline::RenderLocalLights; -BOOL LLPipeline::RenderDelayCreation; -BOOL LLPipeline::RenderAnimateRes; -BOOL LLPipeline::FreezeTime; -S32 LLPipeline::DebugBeaconLineWidth; -F32 LLPipeline::RenderHighlightBrightness; -LLColor4 LLPipeline::RenderHighlightColor; -F32 LLPipeline::RenderHighlightThickness; -BOOL LLPipeline::RenderSpotLightsInNondeferred; -LLColor4 LLPipeline::PreviewAmbientColor; -LLColor4 LLPipeline::PreviewDiffuse0; -LLColor4 LLPipeline::PreviewSpecular0; -LLColor4 LLPipeline::PreviewDiffuse1; -LLColor4 LLPipeline::PreviewSpecular1; -LLColor4 LLPipeline::PreviewDiffuse2; -LLColor4 LLPipeline::PreviewSpecular2; -LLVector3 LLPipeline::PreviewDirection0; -LLVector3 LLPipeline::PreviewDirection1; -LLVector3 LLPipeline::PreviewDirection2; -F32 LLPipeline::RenderGlowMinLuminance; -F32 LLPipeline::RenderGlowMaxExtractAlpha; -F32 LLPipeline::RenderGlowWarmthAmount; -LLVector3 LLPipeline::RenderGlowLumWeights; -LLVector3 LLPipeline::RenderGlowWarmthWeights; -S32 LLPipeline::RenderGlowResolutionPow; -S32 LLPipeline::RenderGlowIterations; -F32 LLPipeline::RenderGlowWidth; -F32 LLPipeline::RenderGlowStrength; -BOOL LLPipeline::RenderDepthOfField; -F32 LLPipeline::CameraFocusTransitionTime; -F32 LLPipeline::CameraFNumber; -F32 LLPipeline::CameraFocalLength; -F32 LLPipeline::CameraFieldOfView; -F32 LLPipeline::RenderShadowNoise; -F32 LLPipeline::RenderShadowBlurSize; -F32 LLPipeline::RenderSSAOScale; -U32 LLPipeline::RenderSSAOMaxScale; -F32 LLPipeline::RenderSSAOFactor; -LLVector3 LLPipeline::RenderSSAOEffect; -F32 LLPipeline::RenderShadowOffsetError; -F32 LLPipeline::RenderShadowBiasError; -F32 LLPipeline::RenderShadowOffset; -F32 LLPipeline::RenderShadowBias; -F32 LLPipeline::RenderSpotShadowOffset; -F32 LLPipeline::RenderSpotShadowBias; -F32 LLPipeline::RenderEdgeDepthCutoff; -F32 LLPipeline::RenderEdgeNormCutoff; -LLVector3 LLPipeline::RenderShadowGaussian; -F32 LLPipeline::RenderShadowBlurDistFactor; -BOOL LLPipeline::RenderDeferredAtmospheric; -S32 LLPipeline::RenderReflectionDetail; -F32 LLPipeline::RenderHighlightFadeTime; -LLVector3 LLPipeline::RenderShadowClipPlanes; -LLVector3 LLPipeline::RenderShadowOrthoClipPlanes; -LLVector3 LLPipeline::RenderShadowNearDist; -F32 LLPipeline::RenderFarClip; -LLVector3 LLPipeline::RenderShadowSplitExponent; -F32 LLPipeline::RenderShadowErrorCutoff; -F32 LLPipeline::RenderShadowFOVCutoff; -BOOL LLPipeline::CameraOffset; -F32 LLPipeline::CameraMaxCoF; -F32 LLPipeline::CameraDoFResScale; - -const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f; -const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f; -const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; -const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; -const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10; -const U32 REFLECTION_MAP_RES = 128; -const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; -// Max number of occluders to search for. JC -const S32 MAX_OCCLUDER_COUNT = 2; - -extern S32 gBoxFrame; -//extern BOOL gHideSelectedObjects; -extern BOOL gDisplaySwapBuffers; -extern BOOL gDebugGL; - -BOOL gAvatarBacklight = FALSE; - -BOOL gDebugPipeline = FALSE; -LLPipeline gPipeline; -const LLMatrix4* gGLLastMatrix = NULL; - -LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); -LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); -LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); -LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); -LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); -LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); -LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); -LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); -LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); -LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); -LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); -LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); -LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); -LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); -LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); -LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); -LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); -LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); -LLFastTimer::DeclareTimer FTM_POOLS("Pools"); -LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); -LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); -LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); -LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); -LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); - - -static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); -static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); - -//---------------------------------------- -std::string gPoolNames[] = -{ - // Correspond to LLDrawpool enum render type - "NONE", - "POOL_SIMPLE", - "POOL_GROUND", - "POOL_FULLBRIGHT", - "POOL_BUMP", - "POOL_TERRAIN," - "POOL_SKY", - "POOL_WL_SKY", - "POOL_TREE", - "POOL_GRASS", - "POOL_INVISIBLE", - "POOL_AVATAR", - "POOL_VOIDWATER", - "POOL_WATER", - "POOL_GLOW", - "POOL_ALPHA" -}; - -void drawBox(const LLVector3& c, const LLVector3& r); -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); -U32 nhpo2(U32 v); - -glh::matrix4f glh_copy_matrix(F32* src) -{ - glh::matrix4f ret; - ret.set_value(src); - return ret; -} - -glh::matrix4f glh_get_current_modelview() -{ - return glh_copy_matrix(gGLModelView); -} - -glh::matrix4f glh_get_current_projection() -{ - return glh_copy_matrix(gGLProjection); -} - -glh::matrix4f glh_get_last_modelview() -{ - return glh_copy_matrix(gGLLastModelView); -} - -glh::matrix4f glh_get_last_projection() -{ - return glh_copy_matrix(gGLLastProjection); -} - -void glh_copy_matrix(const glh::matrix4f& src, F32* dst) -{ - for (U32 i = 0; i < 16; i++) - { - dst[i] = src.m[i]; - } -} - -void glh_set_current_modelview(const glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLModelView); -} - -void glh_set_current_projection(glh::matrix4f& mat) -{ - glh_copy_matrix(mat, gGLProjection); -} - -glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) -{ - glh::matrix4f ret( - 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), - 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), - 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), - 0.f, 0.f, 0.f, 1.f); - - return ret; -} - -void display_update_camera(); -//---------------------------------------- - -S32 LLPipeline::sCompiles = 0; - -BOOL LLPipeline::sPickAvatar = TRUE; -BOOL LLPipeline::sDynamicLOD = TRUE; -BOOL LLPipeline::sShowHUDAttachments = TRUE; -BOOL LLPipeline::sRenderMOAPBeacons = FALSE; -BOOL LLPipeline::sRenderPhysicalBeacons = TRUE; -BOOL LLPipeline::sRenderScriptedBeacons = FALSE; -BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE; -BOOL LLPipeline::sRenderParticleBeacons = FALSE; -BOOL LLPipeline::sRenderSoundBeacons = FALSE; -BOOL LLPipeline::sRenderBeacons = FALSE; -BOOL LLPipeline::sRenderHighlight = TRUE; -BOOL LLPipeline::sForceOldBakedUpload = FALSE; -S32 LLPipeline::sUseOcclusion = 0; -BOOL LLPipeline::sDelayVBUpdate = TRUE; -BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; -BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; -BOOL LLPipeline::sDisableShaders = FALSE; -BOOL LLPipeline::sRenderBump = TRUE; -BOOL LLPipeline::sBakeSunlight = FALSE; -BOOL LLPipeline::sNoAlpha = FALSE; -BOOL LLPipeline::sUseTriStrips = TRUE; -BOOL LLPipeline::sUseFarClip = TRUE; -BOOL LLPipeline::sShadowRender = FALSE; -BOOL LLPipeline::sWaterReflections = FALSE; -BOOL LLPipeline::sRenderGlow = FALSE; -BOOL LLPipeline::sReflectionRender = FALSE; -BOOL LLPipeline::sImpostorRender = FALSE; -BOOL LLPipeline::sUnderWaterRender = FALSE; -BOOL LLPipeline::sTextureBindTest = FALSE; -BOOL LLPipeline::sRenderFrameTest = FALSE; -BOOL LLPipeline::sRenderAttachedLights = TRUE; -BOOL LLPipeline::sRenderAttachedParticles = TRUE; -BOOL LLPipeline::sRenderDeferred = FALSE; -BOOL LLPipeline::sMemAllocationThrottled = FALSE; -S32 LLPipeline::sVisibleLightCount = 0; -F32 LLPipeline::sMinRenderSize = 0.f; - - -static LLCullResult* sCull = NULL; - -static const U32 gl_cube_face[] = -{ - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, -}; - -void validate_framebuffer_object(); - - -bool addDeferredAttachments(LLRenderTarget& target) -{ - return target.addColorAttachment(GL_RGBA) && //specular - target.addColorAttachment(GL_RGBA); //normal+z -} - -LLPipeline::LLPipeline() : - mBackfaceCull(FALSE), - mBatchCount(0), - mMatrixOpCount(0), - mTextureMatrixOps(0), - mMaxBatchSize(0), - mMinBatchSize(0), - mMeanBatchSize(0), - mTrianglesDrawn(0), - mNumVisibleNodes(0), - mVerticesRelit(0), - mLightingChanges(0), - mGeometryChanges(0), - mNumVisibleFaces(0), - - mInitialized(FALSE), - mVertexShadersEnabled(FALSE), - mVertexShadersLoaded(0), - mRenderDebugFeatureMask(0), - mRenderDebugMask(0), - mOldRenderDebugMask(0), - mGroupQ1Locked(false), - mGroupQ2Locked(false), - mResetVertexBuffers(false), - mLastRebuildPool(NULL), - mAlphaPool(NULL), - mSkyPool(NULL), - mTerrainPool(NULL), - mWaterPool(NULL), - mGroundPool(NULL), - mSimplePool(NULL), - mFullbrightPool(NULL), - mInvisiblePool(NULL), - mGlowPool(NULL), - mBumpPool(NULL), - mWLSkyPool(NULL), - mLightMask(0), - mLightMovingMask(0), - mLightingDetail(0), - mScreenWidth(0), - mScreenHeight(0) -{ - mNoiseMap = 0; - mTrueNoiseMap = 0; - mLightFunc = 0; -} - -void LLPipeline::init() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT); - - refreshCachedSettings(); - - gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); - sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); - LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); - sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); - - mInitialized = TRUE; - - stop_glerror(); - - //create render pass pools - getPool(LLDrawPool::POOL_ALPHA); - getPool(LLDrawPool::POOL_SIMPLE); - getPool(LLDrawPool::POOL_GRASS); - getPool(LLDrawPool::POOL_FULLBRIGHT); - getPool(LLDrawPool::POOL_INVISIBLE); - getPool(LLDrawPool::POOL_BUMP); - getPool(LLDrawPool::POOL_GLOW); - - LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); - resetFrameStats(); - - for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) - { - mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled - } - - mRenderDebugFeatureMask = 0xffffffff; // All debugging features on - mRenderDebugMask = 0; // All debug starts off - - // Don't turn on ground when this is set - // Mac Books with intel 950s need this - if(!gSavedSettings.getBOOL("RenderGround")) - { - toggleRenderType(RENDER_TYPE_GROUND); - } - - // make sure RenderPerformanceTest persists (hackity hack hack) - // disables non-object rendering (UI, sky, water, etc) - if (gSavedSettings.getBOOL("RenderPerformanceTest")) - { - gSavedSettings.setBOOL("RenderPerformanceTest", FALSE); - gSavedSettings.setBOOL("RenderPerformanceTest", TRUE); - } - - mOldRenderDebugMask = mRenderDebugMask; - - mBackfaceCull = TRUE; - - stop_glerror(); - - // Enable features - - LLViewerShaderMgr::instance()->setShaders(); - - stop_glerror(); - - for (U32 i = 0; i < 2; ++i) - { - mSpotLightFade[i] = 1.f; - } - - mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); - mDeferredVB->allocateBuffer(8, 0, true); - setLightingDetail(-1); - - // - // Update all settings to trigger a cached settings refresh - // - - gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - - gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - - gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDeferredSunWash")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderResolutionDivisor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderUIBuffer")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDeferredSSAO")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowResolutionScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderLocalLights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDelayCreation")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderAnimateRes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("FreezeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("DebugBeaconLineWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderHighlightBrightness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderHighlightColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderHighlightThickness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSpotLightsInNondeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewAmbientColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDiffuse0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewSpecular0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDiffuse1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewSpecular1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDiffuse2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewSpecular2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDirection0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDirection1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("PreviewDirection2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowMinLuminance")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowMaxExtractAlpha")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowWarmthAmount")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowLumWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowWarmthWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowResolutionPow")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowIterations")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderGlowStrength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDepthOfField")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraFocusTransitionTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraFNumber")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraFocalLength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraFieldOfView")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowNoise")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowBlurSize")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSSAOScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSSAOMaxScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSSAOFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSSAOEffect")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowOffsetError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowBiasError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSpotShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderSpotShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderEdgeDepthCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderEdgeNormCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowGaussian")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowBlurDistFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDeferredAtmospheric")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderReflectionDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderHighlightFadeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowOrthoClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowNearDist")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowSplitExponent")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowErrorCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderShadowFOVCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraMaxCoF")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("CameraDoFResScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); -} - -LLPipeline::~LLPipeline() -{ - -} - -void LLPipeline::cleanup() -{ - assertInitialized(); - - mGroupQ1.clear() ; - mGroupQ2.clear() ; - - for(pool_set_t::iterator iter = mPools.begin(); - iter != mPools.end(); ) - { - pool_set_t::iterator curiter = iter++; - LLDrawPool* poolp = *curiter; - if (poolp->isFacePool()) - { - LLFacePool* face_pool = (LLFacePool*) poolp; - if (face_pool->mReferences.empty()) - { - mPools.erase(curiter); - removeFromQuickLookup( poolp ); - delete poolp; - } - } - else - { - mPools.erase(curiter); - removeFromQuickLookup( poolp ); - delete poolp; - } - } - - if (!mTerrainPools.empty()) - { - llwarns << "Terrain Pools not cleaned up" << llendl; - } - if (!mTreePools.empty()) - { - llwarns << "Tree Pools not cleaned up" << llendl; - } - - delete mAlphaPool; - mAlphaPool = NULL; - delete mSkyPool; - mSkyPool = NULL; - delete mTerrainPool; - mTerrainPool = NULL; - delete mWaterPool; - mWaterPool = NULL; - delete mGroundPool; - mGroundPool = NULL; - delete mSimplePool; - mSimplePool = NULL; - delete mFullbrightPool; - mFullbrightPool = NULL; - delete mInvisiblePool; - mInvisiblePool = NULL; - delete mGlowPool; - mGlowPool = NULL; - delete mBumpPool; - mBumpPool = NULL; - // don't delete wl sky pool it was handled above in the for loop - //delete mWLSkyPool; - mWLSkyPool = NULL; - - releaseGLBuffers(); - - mFaceSelectImagep = NULL; - - mMovedBridge.clear(); - - mInitialized = FALSE; - - mDeferredVB = NULL; -} - -//============================================================================ - -void LLPipeline::destroyGL() -{ - stop_glerror(); - unloadShaders(); - mHighlightFaces.clear(); - - resetDrawOrders(); - - resetVertexBuffers(); - - releaseGLBuffers(); - - if (LLVertexBuffer::sEnableVBOs) - { - LLVertexBuffer::sEnableVBOs = FALSE; - } -} - -static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); - -//static -void LLPipeline::throttleNewMemoryAllocation(BOOL disable) -{ - if(sMemAllocationThrottled != disable) - { - sMemAllocationThrottled = disable ; - - if(sMemAllocationThrottled) - { - //send out notification - LLNotification::Params params("LowMemory"); - LLNotifications::instance().add(params); - - //release some memory. - } - } -} - -void LLPipeline::resizeScreenTexture() -{ - LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); - if (gPipeline.canUseVertexShaders() && assertInitialized()) - { - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - allocateScreenBuffer(resX,resY); - } -} - -void LLPipeline::allocatePhysicsBuffer() -{ - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY) - { - mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); - } -} - -void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) -{ - refreshCachedSettings(); - U32 samples = RenderFSAASamples; - - //try to allocate screen buffers at requested resolution and samples - // - on failure, shrink number of samples and try again - // - if not multisampled, shrink resolution and try again (favor X resolution over Y) - // Make sure to call "releaseScreenBuffers" after each failure to cleanup the partially loaded state - - if (!allocateScreenBuffer(resX, resY, samples)) - { - releaseScreenBuffers(); - //reduce number of samples - while (samples > 0) - { - samples /= 2; - if (allocateScreenBuffer(resX, resY, samples)) - { //success - return; - } - releaseScreenBuffers(); - } - - samples = 0; - - //reduce resolution - while (resY > 0 && resX > 0) - { - resY /= 2; - if (allocateScreenBuffer(resX, resY, samples)) - { - return; - } - releaseScreenBuffers(); - - resX /= 2; - if (allocateScreenBuffer(resX, resY, samples)) - { - return; - } - releaseScreenBuffers(); - } - - llwarns << "Unable to allocate screen buffer at any resolution!" << llendl; - } -} - - -bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) -{ - refreshCachedSettings(); - - // remember these dimensions - mScreenWidth = resX; - mScreenHeight = resY; - - U32 res_mod = RenderResolutionDivisor; - - if (res_mod > 1 && res_mod < resX && res_mod < resY) - { - resX /= res_mod; - resY /= res_mod; - } - - if (RenderUIBuffer) - { - if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) - { - return false; - } - } - - if (LLPipeline::sRenderDeferred) - { - S32 shadow_detail = RenderShadowDetail; - BOOL ssao = RenderDeferredSSAO; - - //allocate deferred rendering color buffers - if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (!addDeferredAttachments(mDeferredScreen)) return false; - - if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (samples > 0) - { - if (!mFXAABuffer.allocate(nhpo2(resX), nhpo2(resY), GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; - } - else - { - mFXAABuffer.release(); - } - - if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) - { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa - if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; - } - else - { - mDeferredLight.release(); - } - - F32 scale = RenderShadowResolutionScale; - - if (shadow_detail > 0) - { //allocate 4 sun shadow maps - for (U32 i = 0; i < 4; i++) - { - if (!mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE)) return false; - } - } - else - { - for (U32 i = 0; i < 4; i++) - { - mShadow[i].release(); - } - } - - U32 width = nhpo2(U32(resX*scale))/2; - U32 height = width; - - if (shadow_detail > 1) - { //allocate two spot shadow maps - for (U32 i = 4; i < 6; i++) - { - if (!mShadow[i].allocate(width, height, 0, TRUE, FALSE)) return false; - } - } - else - { - for (U32 i = 4; i < 6; i++) - { - mShadow[i].release(); - } - } - } - else - { - mDeferredLight.release(); - - for (U32 i = 0; i < 6; i++) - { - mShadow[i].release(); - } - mFXAABuffer.release(); - mScreen.release(); - mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first - mDeferredDepth.release(); - - if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; - } - - if (LLPipeline::sRenderDeferred) - { //share depth buffer between deferred targets - mDeferredScreen.shareDepthBuffer(mScreen); - } - - gGL.getTexUnit(0)->disable(); - - stop_glerror(); - - return true; -} - -//static -void LLPipeline::updateRenderDeferred() -{ - BOOL deferred = ((RenderDeferred && - LLRenderTarget::sUseFBO && - LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - VertexShaderEnable && - RenderAvatarVP && - WindLightUseAtmosShaders) ? TRUE : FALSE) && - !gUseWireframe; - - sRenderDeferred = deferred; - if (deferred) - { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all - sRenderGlow = TRUE; - } -} - -//static -void LLPipeline::refreshCachedSettings() -{ - LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); - LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); - LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); - LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible"); - LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); - - LLPipeline::sUseOcclusion = - (!gUseWireframe - && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") - && gSavedSettings.getBOOL("UseOcclusion") - && gGLManager.mHasOcclusionQuery) ? 2 : 0; - - VertexShaderEnable = gSavedSettings.getBOOL("VertexShaderEnable"); - RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP"); - WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - RenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); - RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); - RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples"); - RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor"); - RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer"); - RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail"); - RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO"); - RenderShadowResolutionScale = gSavedSettings.getF32("RenderShadowResolutionScale"); - RenderLocalLights = gSavedSettings.getBOOL("RenderLocalLights"); - RenderDelayCreation = gSavedSettings.getBOOL("RenderDelayCreation"); - RenderAnimateRes = gSavedSettings.getBOOL("RenderAnimateRes"); - FreezeTime = gSavedSettings.getBOOL("FreezeTime"); - DebugBeaconLineWidth = gSavedSettings.getS32("DebugBeaconLineWidth"); - RenderHighlightBrightness = gSavedSettings.getF32("RenderHighlightBrightness"); - RenderHighlightColor = gSavedSettings.getColor4("RenderHighlightColor"); - RenderHighlightThickness = gSavedSettings.getF32("RenderHighlightThickness"); - RenderSpotLightsInNondeferred = gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"); - PreviewAmbientColor = gSavedSettings.getColor4("PreviewAmbientColor"); - PreviewDiffuse0 = gSavedSettings.getColor4("PreviewDiffuse0"); - PreviewSpecular0 = gSavedSettings.getColor4("PreviewSpecular0"); - PreviewDiffuse1 = gSavedSettings.getColor4("PreviewDiffuse1"); - PreviewSpecular1 = gSavedSettings.getColor4("PreviewSpecular1"); - PreviewDiffuse2 = gSavedSettings.getColor4("PreviewDiffuse2"); - PreviewSpecular2 = gSavedSettings.getColor4("PreviewSpecular2"); - PreviewDirection0 = gSavedSettings.getVector3("PreviewDirection0"); - PreviewDirection1 = gSavedSettings.getVector3("PreviewDirection1"); - PreviewDirection2 = gSavedSettings.getVector3("PreviewDirection2"); - RenderGlowMinLuminance = gSavedSettings.getF32("RenderGlowMinLuminance"); - RenderGlowMaxExtractAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha"); - RenderGlowWarmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount"); - RenderGlowLumWeights = gSavedSettings.getVector3("RenderGlowLumWeights"); - RenderGlowWarmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights"); - RenderGlowResolutionPow = gSavedSettings.getS32("RenderGlowResolutionPow"); - RenderGlowIterations = gSavedSettings.getS32("RenderGlowIterations"); - RenderGlowWidth = gSavedSettings.getF32("RenderGlowWidth"); - RenderGlowStrength = gSavedSettings.getF32("RenderGlowStrength"); - RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField"); - CameraFocusTransitionTime = gSavedSettings.getF32("CameraFocusTransitionTime"); - CameraFNumber = gSavedSettings.getF32("CameraFNumber"); - CameraFocalLength = gSavedSettings.getF32("CameraFocalLength"); - CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView"); - RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise"); - RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize"); - RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale"); - RenderSSAOMaxScale = gSavedSettings.getU32("RenderSSAOMaxScale"); - RenderSSAOFactor = gSavedSettings.getF32("RenderSSAOFactor"); - RenderSSAOEffect = gSavedSettings.getVector3("RenderSSAOEffect"); - RenderShadowOffsetError = gSavedSettings.getF32("RenderShadowOffsetError"); - RenderShadowBiasError = gSavedSettings.getF32("RenderShadowBiasError"); - RenderShadowOffset = gSavedSettings.getF32("RenderShadowOffset"); - RenderShadowBias = gSavedSettings.getF32("RenderShadowBias"); - RenderSpotShadowOffset = gSavedSettings.getF32("RenderSpotShadowOffset"); - RenderSpotShadowBias = gSavedSettings.getF32("RenderSpotShadowBias"); - RenderEdgeDepthCutoff = gSavedSettings.getF32("RenderEdgeDepthCutoff"); - RenderEdgeNormCutoff = gSavedSettings.getF32("RenderEdgeNormCutoff"); - RenderShadowGaussian = gSavedSettings.getVector3("RenderShadowGaussian"); - RenderShadowBlurDistFactor = gSavedSettings.getF32("RenderShadowBlurDistFactor"); - RenderDeferredAtmospheric = gSavedSettings.getBOOL("RenderDeferredAtmospheric"); - RenderReflectionDetail = gSavedSettings.getS32("RenderReflectionDetail"); - RenderHighlightFadeTime = gSavedSettings.getF32("RenderHighlightFadeTime"); - RenderShadowClipPlanes = gSavedSettings.getVector3("RenderShadowClipPlanes"); - RenderShadowOrthoClipPlanes = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes"); - RenderShadowNearDist = gSavedSettings.getVector3("RenderShadowNearDist"); - RenderFarClip = gSavedSettings.getF32("RenderFarClip"); - RenderShadowSplitExponent = gSavedSettings.getVector3("RenderShadowSplitExponent"); - RenderShadowErrorCutoff = gSavedSettings.getF32("RenderShadowErrorCutoff"); - RenderShadowFOVCutoff = gSavedSettings.getF32("RenderShadowFOVCutoff"); - CameraOffset = gSavedSettings.getBOOL("CameraOffset"); - CameraMaxCoF = gSavedSettings.getF32("CameraMaxCoF"); - CameraDoFResScale = gSavedSettings.getF32("CameraDoFResScale"); - - updateRenderDeferred(); -} - -void LLPipeline::releaseGLBuffers() -{ - assertInitialized(); - - if (mNoiseMap) - { - LLImageGL::deleteTextures(1, &mNoiseMap); - mNoiseMap = 0; - } - - if (mTrueNoiseMap) - { - LLImageGL::deleteTextures(1, &mTrueNoiseMap); - mTrueNoiseMap = 0; - } - - if (mLightFunc) - { - LLImageGL::deleteTextures(1, &mLightFunc); - mLightFunc = 0; - } - - mWaterRef.release(); - mWaterDis.release(); - - for (U32 i = 0; i < 3; i++) - { - mGlow[i].release(); - } - - releaseScreenBuffers(); - - gBumpImageList.destroyGL(); - LLVOAvatar::resetImpostors(); -} - -void LLPipeline::releaseScreenBuffers() -{ - mUIScreen.release(); - mScreen.release(); - mFXAABuffer.release(); - mPhysicsDisplay.release(); - mDeferredScreen.release(); - mDeferredDepth.release(); - mDeferredLight.release(); - - mHighlight.release(); - - for (U32 i = 0; i < 6; i++) - { - mShadow[i].release(); - } -} - - -void LLPipeline::createGLBuffers() -{ - stop_glerror(); - LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS); - assertInitialized(); - - updateRenderDeferred(); - - if (LLPipeline::sWaterReflections) - { //water reflection texture - U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution"); - - mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); - mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE); - } - - mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE); - - stop_glerror(); - - GLuint resX = gViewerWindow->getWorldViewWidthRaw(); - GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - - if (LLPipeline::sRenderGlow) - { //screen space glow buffers - const U32 glow_res = llmax(1, - llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); - - for (U32 i = 0; i < 3; i++) - { - mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); - } - - allocateScreenBuffer(resX,resY); - mScreenWidth = 0; - mScreenHeight = 0; - } - - if (sRenderDeferred) - { - if (!mNoiseMap) - { - const U32 noiseRes = 128; - LLVector3 noise[noiseRes*noiseRes]; - - F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f; - for (U32 i = 0; i < noiseRes*noiseRes; ++i) - { - noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); - noise[i].normVec(); - noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; - } - - LLImageGL::generateTextures(1, &mNoiseMap); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (!mTrueNoiseMap) - { - const U32 noiseRes = 128; - F32 noise[noiseRes*noiseRes*3]; - for (U32 i = 0; i < noiseRes*noiseRes*3; i++) - { - noise[i] = ll_frand()*2.0-1.0; - } - - LLImageGL::generateTextures(1, &mTrueNoiseMap); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (!mLightFunc) - { - U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); - U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); - U8* lg = new U8[lightResX*lightResY]; - - for (U32 y = 0; y < lightResY; ++y) - { - for (U32 x = 0; x < lightResX; ++x) - { - //spec func - F32 sa = (F32) x/(lightResX-1); - F32 spec = (F32) y/(lightResY-1); - //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255); - - //F32 sp = acosf(sa)/(1.f-spec); - - sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent")); - F32 a = acosf(sa*0.25f+0.75f); - F32 m = llmax(0.5f-spec*0.5f, 0.001f); - F32 t2 = tanf(a)/m; - t2 *= t2; - - F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f; - F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2); - - lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255); - } - } - - LLImageGL::generateTextures(1, &mLightFunc); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); - - delete [] lg; - } - } - - gBumpImageList.restoreGL(); -} - -void LLPipeline::restoreGL() -{ - LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL); - assertInitialized(); - - if (mVertexShadersEnabled) - { - LLViewerShaderMgr::instance()->setShaders(); - } - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->restoreGL(); - } - } - } -} - - -BOOL LLPipeline::canUseVertexShaders() -{ - static const std::string vertex_shader_enable_feature_string = "VertexShaderEnable"; - - if (sDisableShaders || - !gGLManager.mHasVertexShader || - !gGLManager.mHasFragmentShader || - !LLFeatureManager::getInstance()->isFeatureAvailable(vertex_shader_enable_feature_string) || - (assertInitialized() && mVertexShadersLoaded != 1) ) - { - return FALSE; - } - else - { - return TRUE; - } -} - -BOOL LLPipeline::canUseWindLightShaders() const -{ - return (!LLPipeline::sDisableShaders && - gWLSkyProgram.mProgramObject != 0 && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); -} - -BOOL LLPipeline::canUseWindLightShadersOnObjects() const -{ - return (canUseWindLightShaders() - && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0); -} - -BOOL LLPipeline::canUseAntiAliasing() const -{ - return TRUE; -} - -void LLPipeline::unloadShaders() -{ - LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS); - LLViewerShaderMgr::instance()->unloadShaders(); - - mVertexShadersLoaded = 0; -} - -void LLPipeline::assertInitializedDoError() -{ - llerrs << "LLPipeline used when uninitialized." << llendl; -} - -//============================================================================ - -void LLPipeline::enableShadows(const BOOL enable_shadows) -{ - //should probably do something here to wrangle shadows.... -} - -S32 LLPipeline::getMaxLightingDetail() const -{ - /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) - { - return 3; - } - else*/ - { - return 1; - } -} - -S32 LLPipeline::setLightingDetail(S32 level) -{ - LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); - refreshCachedSettings(); - - if (level < 0) - { - if (RenderLocalLights) - { - level = 1; - } - else - { - level = 0; - } - } - level = llclamp(level, 0, getMaxLightingDetail()); - mLightingDetail = level; - - return mLightingDetail; -} - -class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable> -{ -public: - const std::set<LLViewerFetchedTexture*>& mTextures; - - LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { } - - virtual void visit(const LLOctreeNode<LLDrawable>* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) - { - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - LLDrawInfo* params = *j; - LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture); - if (tex && mTextures.find(tex) != mTextures.end()) - { - group->setState(LLSpatialGroup::GEOM_DIRTY); - } - } - } - } - - for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) - { - LLSpatialBridge* bridge = *i; - traverse(bridge->mOctree); - } - } -}; - -// Called when a texture changes # of channels (causes faces to move to alpha pool) -void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures) -{ - assertInitialized(); - - // *TODO: This is inefficient and causes frame spikes; need a better way to do this - // Most of the time is spent in dirty.traverse. - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (poolp->isFacePool()) - { - ((LLFacePool*) poolp)->dirtyTextures(textures); - } - } - - LLOctreeDirtyTexture dirty(textures); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - dirty.traverse(part->mOctree); - } - } - } -} - -LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) -{ - assertInitialized(); - - LLDrawPool *poolp = NULL; - switch( type ) - { - case LLDrawPool::POOL_SIMPLE: - poolp = mSimplePool; - break; - - case LLDrawPool::POOL_GRASS: - poolp = mGrassPool; - break; - - case LLDrawPool::POOL_FULLBRIGHT: - poolp = mFullbrightPool; - break; - - case LLDrawPool::POOL_INVISIBLE: - poolp = mInvisiblePool; - break; - - case LLDrawPool::POOL_GLOW: - poolp = mGlowPool; - break; - - case LLDrawPool::POOL_TREE: - poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - - case LLDrawPool::POOL_TERRAIN: - poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 ); - break; - - case LLDrawPool::POOL_BUMP: - poolp = mBumpPool; - break; - - case LLDrawPool::POOL_ALPHA: - poolp = mAlphaPool; - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - poolp = mSkyPool; - break; - - case LLDrawPool::POOL_WATER: - poolp = mWaterPool; - break; - - case LLDrawPool::POOL_GROUND: - poolp = mGroundPool; - break; - - case LLDrawPool::POOL_WL_SKY: - poolp = mWLSkyPool; - break; - - default: - llassert(0); - llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; - break; - } - - return poolp; -} - - -LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLDrawPool *poolp = findPool(type, tex0); - if (poolp) - { - return poolp; - } - - LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0); - addPool( new_poolp ); - - return new_poolp; -} - - -// static -LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - U32 type = getPoolTypeFromTE(te, imagep); - return gPipeline.getPool(type, imagep); -} - -//static -U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) -{ - LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE); - - if (!te || !imagep) - { - return 0; - } - - bool alpha = te->getColor().mV[3] < 0.999f; - if (imagep) - { - alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); - } - - if (alpha) - { - return LLDrawPool::POOL_ALPHA; - } - else if ((te->getBumpmap() || te->getShiny())) - { - return LLDrawPool::POOL_BUMP; - } - else - { - return LLDrawPool::POOL_SIMPLE; - } -} - - -void LLPipeline::addPool(LLDrawPool *new_poolp) -{ - LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL); - assertInitialized(); - mPools.insert(new_poolp); - addToQuickLookup( new_poolp ); -} - -void LLPipeline::allocDrawable(LLViewerObject *vobj) -{ - LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE); - LLDrawable *drawable = new LLDrawable(); - vobj->mDrawable = drawable; - - drawable->mVObjp = vobj; - - //encompass completely sheared objects by taking - //the most extreme point possible (<1,1,0.5>) - drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); - if (vobj->isOrphaned()) - { - drawable->setState(LLDrawable::FORCE_INVISIBLE); - } - drawable->updateXform(TRUE); -} - - -static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); - -void LLPipeline::unlinkDrawable(LLDrawable *drawable) -{ - LLFastTimer t(FTM_UNLINK); - - assertInitialized(); - - LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done - - // Based on flags, remove the drawable from the queues that it's on. - if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); - LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); - if (iter != mMovedList.end()) - { - mMovedList.erase(iter); - } - } - - if (drawablep->getSpatialGroup()) - { - LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); - if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) - { -#ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Couldn't remove object from spatial group!" << llendl; -#else - llerrs << "Couldn't remove object from spatial group!" << llendl; -#endif - } - } - - { - LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); - mLights.erase(drawablep); - - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) - { - if (iter->drawable == drawablep) - { - mNearbyLights.erase(iter); - break; - } - } - } - - { - LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET); - HighlightItem item(drawablep); - mHighlightSet.erase(item); - - if (mHighlightObject == drawablep) - { - mHighlightObject = NULL; - } - } - - for (U32 i = 0; i < 2; ++i) - { - if (mShadowSpotLight[i] == drawablep) - { - mShadowSpotLight[i] = NULL; - } - - if (mTargetShadowSpotLight[i] == drawablep) - { - mTargetShadowSpotLight[i] = NULL; - } - } - - -} - -U32 LLPipeline::addObject(LLViewerObject *vobj) -{ - LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); - - if (RenderDelayCreation) - { - mCreateQ.push_back(vobj); - } - else - { - createObject(vobj); - } - - return 1; -} - -void LLPipeline::createObjects(F32 max_dtime) -{ - LLFastTimer ftm(FTM_GEO_UPDATE); - LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); - - LLTimer update_timer; - - while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime) - { - LLViewerObject* vobj = mCreateQ.front(); - if (!vobj->isDead()) - { - createObject(vobj); - } - mCreateQ.pop_front(); - } - - //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter) - //{ - // createObject(*iter); - //} - - //mCreateQ.clear(); -} - -void LLPipeline::createObject(LLViewerObject* vobj) -{ - LLDrawable* drawablep = vobj->mDrawable; - - if (!drawablep) - { - drawablep = vobj->createDrawable(this); - } - else - { - llerrs << "Redundant drawable creation!" << llendl; - } - - llassert(drawablep); - - if (vobj->getParent()) - { - vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1 - } - else - { - vobj->setDrawableParent(NULL); // LLPipeline::addObject 2 - } - - markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE); - - if (drawablep->getVOVolume() && RenderAnimateRes) - { - // fun animated res - drawablep->updateXform(TRUE); - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); - drawablep->setScale(LLVector3(0,0,0)); - drawablep->makeActive(); - } -} - - -void LLPipeline::resetFrameStats() -{ - assertInitialized(); - - LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); - - if (mBatchCount > 0) - { - mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount; - } - mTrianglesDrawn = 0; - sCompiles = 0; - mVerticesRelit = 0; - mLightingChanges = 0; - mGeometryChanges = 0; - mNumVisibleFaces = 0; - - if (mOldRenderDebugMask != mRenderDebugMask) - { - gObjectList.clearDebugText(); - mOldRenderDebugMask = mRenderDebugMask; - } - -} - -//external functions for asynchronous updating -void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) -{ - if (FreezeTime) - { - return; - } - if (!drawablep) - { - llerrs << "updateMove called with NULL drawablep" << llendl; - return; - } - if (drawablep->isState(LLDrawable::EARLY_MOVE)) - { - return; - } - - assertInitialized(); - - // update drawable now - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED - drawablep->updateMove(); // returns done - drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame - // Put on move list so that EARLY_MOVE gets cleared - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - mMovedList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } -} - -void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) -{ - if (FreezeTime) - { - return; - } - if (!drawablep) - { - llerrs << "updateMove called with NULL drawablep" << llendl; - return; - } - if (drawablep->isState(LLDrawable::EARLY_MOVE)) - { - return; - } - - assertInitialized(); - - // update drawable now - drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED - drawablep->updateMove(); - drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame - // Put on move list so that EARLY_MOVE gets cleared - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - mMovedList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } -} - -void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) -{ - for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); - iter != moved_list.end(); ) - { - LLDrawable::drawable_vector_t::iterator curiter = iter++; - LLDrawable *drawablep = *curiter; - BOOL done = TRUE; - if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE))) - { - done = drawablep->updateMove(); - } - drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED); - if (done) - { - drawablep->clearState(LLDrawable::ON_MOVE_LIST); - iter = moved_list.erase(curiter); - } - } -} - -static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); -static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); - -void LLPipeline::updateMove() -{ - LLFastTimer t(FTM_UPDATE_MOVE); - LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE); - - if (FreezeTime) - { - return; - } - - assertInitialized(); - - { - static LLFastTimer::DeclareTimer ftm("Retexture"); - LLFastTimer t(ftm); - - for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); - iter != mRetexturedList.end(); ++iter) - { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) - { - drawablep->updateTexture(); - } - } - mRetexturedList.clear(); - } - - { - static LLFastTimer::DeclareTimer ftm("Moved List"); - LLFastTimer t(ftm); - updateMovedList(mMovedList); - } - - //balance octrees - { - LLFastTimer ot(FTM_OCTREE_BALANCE); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->mOctree->balance(); - } - } - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// Culling and occlusion testing -///////////////////////////////////////////////////////////////////////////// - -//static -F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) -{ - LLVector3 lookAt = center - camera.getOrigin(); - F32 dist = lookAt.length(); - - //ramp down distance for nearby objects - //shrink dist by dist/16. - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - //get area of circle around node - F32 app_angle = atanf(size.length()/dist); - F32 radius = app_angle*LLDrawable::sCurPixelAngle; - return radius*radius * F_PI; -} - -//static -F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera) -{ - LLVector4a origin; - origin.load3(camera.getOrigin().mV); - - LLVector4a lookAt; - lookAt.setSub(center, origin); - F32 dist = lookAt.getLength3().getF32(); - - //ramp down distance for nearby objects - //shrink dist by dist/16. - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - //get area of circle around node - F32 app_angle = atanf(size.getLength3().getF32()/dist); - F32 radius = app_angle*LLDrawable::sCurPixelAngle; - return radius*radius * F_PI; -} - -void LLPipeline::grabReferences(LLCullResult& result) -{ - sCull = &result; -} - -void LLPipeline::clearReferences() -{ - sCull = NULL; -} - -void check_references(LLSpatialGroup* group, LLDrawable* drawable) -{ - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - if (drawable == *i) - { - llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; - } - } -} - -void check_references(LLDrawable* drawable, LLFace* face) -{ - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - if (drawable->getFace(i) == face) - { - llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; - } - } -} - -void check_references(LLSpatialGroup* group, LLFace* face) -{ - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - check_references(drawable, face); - } -} - -void LLPipeline::checkReferences(LLFace* face) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, face); - } - - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) - { - LLDrawable* drawable = *iter; - check_references(drawable, face); - } - } -#endif -} - -void LLPipeline::checkReferences(LLDrawable* drawable) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, drawable); - } - - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) - { - if (drawable == *iter) - { - llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; - } - } - } -#endif -} - -void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) -{ - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo* params = *j; - if (params == draw_info) - { - llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; - } - } - } -} - - -void LLPipeline::checkReferences(LLDrawInfo* draw_info) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - check_references(group, draw_info); - } - } -#endif -} - -void LLPipeline::checkReferences(LLSpatialGroup* group) -{ -#if 0 - if (sCull) - { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - if (group == *iter) - { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; - } - } - } -#endif -} - - -BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) -{ - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - if (part->visibleObjectsInFrustum(camera)) - { - return TRUE; - } - } - } - } - } - - return FALSE; -} - -BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max) -{ - const F32 X = 65536.f; - - min = LLVector3(X,X,X); - max = LLVector3(-X,-X,-X); - - U32 saved_camera_id = LLViewerCamera::sCurCameraID; - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - - BOOL res = TRUE; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - if (!part->getVisibleExtents(camera, min, max)) - { - res = FALSE; - } - } - } - } - } - - LLViewerCamera::sCurCameraID = saved_camera_id; - - return res; -} - -static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); - -void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep) -{ - LLFastTimer t(FTM_CULL); - LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL); - - grabReferences(result); - - sCull->clear(); - - BOOL to_texture = LLPipeline::sUseOcclusion > 1 && - !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && - LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - gPipeline.canUseVertexShaders() && - sRenderGlow; - - if (to_texture) - { - mScreen.bindTarget(); - } - - if (sUseOcclusion > 1) - { - gGL.setColorMask(false, false); - } - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadMatrix(gGLLastProjection); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLLastModelView); - - - LLVertexBuffer::unbind(); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - - //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling) - LLViewerRegion* region = gAgent.getRegion(); - LLPlane plane; - - if (planep) - { - plane = *planep; - } - else - { - if (region) - { - LLVector3 pnorm; - F32 height = region->getWaterHeight(); - if (water_clip < 0) - { //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - plane.setVec(pnorm, -height); - } - else if (water_clip > 0) - { //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - plane.setVec(pnorm, height); - } - } - } - - glh::matrix4f modelview = glh_get_last_modelview(); - glh::matrix4f proj = glh_get_last_projection(); - LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - - bool bound_shader = false; - if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0) - { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can - // (shadow render uses a special shader that clamps to clip planes) - bound_shader = true; - gOcclusionProgram.bind(); - } - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - if (water_clip != 0) - { - LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight()); - camera.setUserClipPlane(plane); - } - else - { - camera.disableUserClipPlane(); - } - - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->cull(camera); - } - } - } - } - - if (bound_shader) - { - gOcclusionProgram.unbind(); - } - - camera.disableUserClipPlane(); - - if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) && - gSky.mVOSkyp.notNull() && - gSky.mVOSkyp->mDrawable.notNull()) - { - gSky.mVOSkyp->mDrawable->setVisible(camera); - sCull->pushDrawable(gSky.mVOSkyp->mDrawable); - gSky.updateCull(); - stop_glerror(); - } - - if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) && - !gPipeline.canUseWindLightShaders() && - gSky.mVOGroundp.notNull() && - gSky.mVOGroundp->mDrawable.notNull() && - !LLPipeline::sWaterReflections) - { - gSky.mVOGroundp->mDrawable->setVisible(camera); - sCull->pushDrawable(gSky.mVOGroundp->mDrawable); - } - - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - if (sUseOcclusion > 1) - { - gGL.setColorMask(true, false); - } - - if (to_texture) - { - mScreen.flush(); - } -} - -void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) -{ - if (group->getData().empty()) - { - return; - } - - group->setVisible(); - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - group->updateDistance(camera); - } - - const F32 MINIMUM_PIXEL_AREA = 16.f; - - if (group->mPixelArea < MINIMUM_PIXEL_AREA) - { - return; - } - - if (sMinRenderSize > 0.f && - llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) - { - return; - } - - assertInitialized(); - - if (!group->mSpatialPartition->mRenderByGroup) - { //render by drawable - sCull->pushDrawableGroup(group); - } - else - { //render by group - sCull->pushVisibleGroup(group); - } - - mNumVisibleNodes++; -} - -void LLPipeline::markOccluder(LLSpatialGroup* group) -{ - if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION)) - { - LLSpatialGroup* parent = group->getParent(); - - if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //only mark top most occluders as active occlusion - sCull->pushOcclusionGroup(group); - group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - - if (parent && - !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) && - parent->getElementCount() == 0 && - parent->needsUpdate()) - { - sCull->pushOcclusionGroup(group); - parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - } - } - } -} - -void LLPipeline::doOcclusion(LLCamera& camera) -{ - if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) - { - LLVertexBuffer::unbind(); - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) - { - gGL.setColorMask(true, false, false, false); - } - else - { - gGL.setColorMask(false, false); - } - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - - LLGLDisable cull(GL_CULL_FACE); - - - bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0; - if (bind_shader) - { - if (LLPipeline::sShadowRender) - { - gDeferredShadowProgram.bind(); - } - else - { - gOcclusionProgram.bind(); - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->doOcclusion(&camera); - group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION); - } - - if (bind_shader) - { - if (LLPipeline::sShadowRender) - { - gDeferredShadowProgram.unbind(); - } - else - { - gOcclusionProgram.unbind(); - } - } - - gGL.setColorMask(true, false); - } -} - -BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) -{ - BOOL update_complete = drawablep->updateGeometry(priority); - if (update_complete && assertInitialized()) - { - drawablep->setState(LLDrawable::BUILT); - mGeometryChanges++; - } - return update_complete; -} - -void LLPipeline::updateGL() -{ - while (!LLGLUpdate::sGLQ.empty()) - { - LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); - glu->updateGL(); - glu->mInQ = FALSE; - LLGLUpdate::sGLQ.pop_front(); - } -} - -void LLPipeline::rebuildPriorityGroups() -{ - LLTimer update_timer; - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - assertInitialized(); - - gMeshRepo.notifyLoadedMeshes(); - - mGroupQ1Locked = true; - // Iterate through all drawables on the priority build queue, - for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); - iter != mGroupQ1.end(); ++iter) - { - LLSpatialGroup* group = *iter; - group->rebuildGeom(); - group->clearState(LLSpatialGroup::IN_BUILD_Q1); - } - - mGroupQ1.clear(); - mGroupQ1Locked = false; - -} - -void LLPipeline::rebuildGroups() -{ - if (mGroupQ2.empty()) - { - return; - } - - mGroupQ2Locked = true; - // Iterate through some drawables on the non-priority build queue - S32 size = (S32) mGroupQ2.size(); - S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); - - S32 count = 0; - - std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); - - LLSpatialGroup::sg_vector_t::iterator iter; - LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); - - for (iter = mGroupQ2.begin(); - iter != mGroupQ2.end() && count <= min_count; ++iter) - { - LLSpatialGroup* group = *iter; - last_iter = iter; - - if (!group->isDead()) - { - group->rebuildGeom(); - - if (group->mSpatialPartition->mRenderByGroup) - { - count++; - } - } - - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - } - - mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); - - mGroupQ2Locked = false; - - updateMovedList(mMovedBridge); -} - -void LLPipeline::updateGeom(F32 max_dtime) -{ - LLTimer update_timer; - LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM); - LLPointer<LLDrawable> drawablep; - - LLFastTimer t(FTM_GEO_UPDATE); - - assertInitialized(); - - // notify various object types to reset internal cost metrics, etc. - // for now, only LLVOVolume does this to throttle LOD changes - LLVOVolume::preUpdateGeom(); - - // Iterate through all drawables on the priority build queue, - for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); - iter != mBuildQ1.end();) - { - LLDrawable::drawable_list_t::iterator curiter = iter++; - LLDrawable* drawablep = *curiter; - if (drawablep && !drawablep->isDead()) - { - if (drawablep->isState(LLDrawable::IN_REBUILD_Q2)) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q2); - LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep); - if (find != mBuildQ2.end()) - { - mBuildQ2.erase(find); - } - } - - if (updateDrawableGeom(drawablep, TRUE)) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q1); - mBuildQ1.erase(curiter); - } - } - else - { - mBuildQ1.erase(curiter); - } - } - - // Iterate through some drawables on the non-priority build queue - S32 min_count = 16; - S32 size = (S32) mBuildQ2.size(); - if (size > 1024) - { - min_count = llclamp((S32) (size * (F32) size/4096), 16, size); - } - - S32 count = 0; - - max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); - LLSpatialGroup* last_group = NULL; - LLSpatialBridge* last_bridge = NULL; - - for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); - iter != mBuildQ2.end(); ) - { - LLDrawable::drawable_list_t::iterator curiter = iter++; - LLDrawable* drawablep = *curiter; - - LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() : - drawablep->getParent()->getSpatialBridge(); - - if (drawablep->getSpatialGroup() != last_group && - (!last_bridge || bridge != last_bridge) && - (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count) - { - break; - } - - //make sure updates don't stop in the middle of a spatial group - //to avoid thrashing (objects are enqueued by group) - last_group = drawablep->getSpatialGroup(); - last_bridge = bridge; - - BOOL update_complete = TRUE; - if (!drawablep->isDead()) - { - update_complete = updateDrawableGeom(drawablep, FALSE); - count++; - } - if (update_complete) - { - drawablep->clearState(LLDrawable::IN_REBUILD_Q2); - mBuildQ2.erase(curiter); - } - } - - updateMovedList(mMovedBridge); -} - -void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE); - - if(drawablep && !drawablep->isDead()) - { - if (drawablep->isSpatialBridge()) - { - const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; - llassert(root); // trying to catch a bad assumption - if (root && // // this test may not be needed, see above - root->getVObj()->isAttachment()) - { - LLDrawable* rootparent = root->getParent(); - if (rootparent) // this IS sometimes NULL - { - LLViewerObject *vobj = rootparent->getVObj(); - llassert(vobj); // trying to catch a bad assumption - if (vobj) // this test may not be needed, see above - { - const LLVOAvatar* av = vobj->asAvatar(); - if (av && av->isImpostor()) - { - return; - } - } - } - } - sCull->pushBridge((LLSpatialBridge*) drawablep); - } - else - { - sCull->pushDrawable(drawablep); - } - - drawablep->setVisible(camera); - } -} - -void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) -{ - LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED); - - if (!drawablep) - { - //llerrs << "Sending null drawable to moved list!" << llendl; - return; - } - - if (drawablep->isDead()) - { - llwarns << "Marking NULL or dead drawable moved!" << llendl; - return; - } - - if (drawablep->getParent()) - { - //ensure that parent drawables are moved first - markMoved(drawablep->getParent(), damped_motion); - } - - assertInitialized(); - - if (!drawablep->isState(LLDrawable::ON_MOVE_LIST)) - { - if (drawablep->isSpatialBridge()) - { - mMovedBridge.push_back(drawablep); - } - else - { - mMovedList.push_back(drawablep); - } - drawablep->setState(LLDrawable::ON_MOVE_LIST); - } - if (damped_motion == FALSE) - { - drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED - } - else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED)) - { - drawablep->clearState(LLDrawable::MOVE_UNDAMPED); - } -} - -void LLPipeline::markShift(LLDrawable *drawablep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT); - - if (!drawablep || drawablep->isDead()) - { - return; - } - - assertInitialized(); - - if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST)) - { - drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE); - if (drawablep->getParent()) - { - markShift(drawablep->getParent()); - } - mShiftList.push_back(drawablep); - drawablep->setState(LLDrawable::ON_SHIFT_LIST); - } -} - -void LLPipeline::shiftObjects(const LLVector3 &offset) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); - - assertInitialized(); - - glClear(GL_DEPTH_BUFFER_BIT); - gDepthDirty = TRUE; - - LLVector4a offseta; - offseta.load3(offset.mV); - - for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); - iter != mShiftList.end(); iter++) - { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) - { - continue; - } - drawablep->shiftPos(offseta); - drawablep->clearState(LLDrawable::ON_SHIFT_LIST); - } - mShiftList.resize(0); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->shift(offseta); - } - } - } - - LLHUDText::shiftAll(offset); - LLHUDNameTag::shiftAll(offset); - display_update_camera(); -} - -void LLPipeline::markTextured(LLDrawable *drawablep) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED); - - if (drawablep && !drawablep->isDead() && assertInitialized()) - { - mRetexturedList.insert(drawablep); - } -} - -void LLPipeline::markGLRebuild(LLGLUpdate* glu) -{ - if (glu && !glu->mInQ) - { - LLGLUpdate::sGLQ.push_back(glu); - glu->mInQ = TRUE; - } -} - -void LLPipeline::markPartitionMove(LLDrawable* drawable) -{ - if (!drawable->isState(LLDrawable::PARTITION_MOVE) && - !drawable->getPositionGroup().equals3(LLVector4a::getZero())) - { - drawable->setState(LLDrawable::PARTITION_MOVE); - mPartitionQ.push_back(drawable); - } -} - -void LLPipeline::processPartitionQ() -{ - for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) - { - LLDrawable* drawable = *iter; - if (!drawable->isDead()) - { - drawable->updateBinRadius(); - drawable->movePartition(); - } - drawable->clearState(LLDrawable::PARTITION_MOVE); - } - - mPartitionQ.clear(); -} - -void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - if (group && !group->isDead() && group->mSpatialPartition) - { - if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) - { - priority = TRUE; - } - - if (priority) - { - if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) - { - llassert_always(!mGroupQ1Locked); - - mGroupQ1.push_back(group); - group->setState(LLSpatialGroup::IN_BUILD_Q1); - - if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) - { - LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group); - if (iter != mGroupQ2.end()) - { - mGroupQ2.erase(iter); - } - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - } - } - } - else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) - { - llassert_always(!mGroupQ2Locked); - mGroupQ2.push_back(group); - group->setState(LLSpatialGroup::IN_BUILD_Q2); - - } - } -} - -void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); - - if (drawablep && !drawablep->isDead() && assertInitialized()) - { - if (!drawablep->isState(LLDrawable::BUILT)) - { - priority = TRUE; - } - if (priority) - { - if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1)) - { - mBuildQ1.push_back(drawablep); - drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue - } - } - else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2)) - { - mBuildQ2.push_back(drawablep); - drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list - } - if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) - { - drawablep->getVObj()->setChanged(LLXform::SILHOUETTE); - } - drawablep->setState(flag); - } -} - -static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); - -void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) -{ - if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_TERRAIN, - LLPipeline::RENDER_TYPE_TREE, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_WATER, - LLPipeline::END_RENDER_TYPES)) - { - //clear faces from face pools - LLFastTimer t(FTM_RESET_DRAWORDER); - gPipeline.resetDrawOrders(); - } - - LLFastTimer ftm(FTM_STATESORT); - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - - //LLVertexBuffer::unbind(); - - grabReferences(result); - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->checkOcclusion(); - if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - markOccluder(group); - } - else - { - group->setVisible(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - markVisible(*i, camera); - } - - if (!sDelayVBUpdate) - { //rebuild mesh as soon as we know it's visible - group->rebuildMesh(); - } - } - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - LLSpatialGroup* last_group = NULL; - for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLCullResult::bridge_list_t::iterator cur_iter = i; - LLSpatialBridge* bridge = *cur_iter; - LLSpatialGroup* group = bridge->getSpatialGroup(); - - if (last_group == NULL) - { - last_group = group; - } - - if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - stateSort(bridge, camera); - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - last_group != group && last_group->changeLOD()) - { - last_group->mLastUpdateDistance = last_group->mDistance; - } - - last_group = group; - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - last_group && last_group->changeLOD()) - { - last_group->mLastUpdateDistance = last_group->mDistance; - } - } - - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) - { - LLSpatialGroup* group = *iter; - group->checkOcclusion(); - if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - markOccluder(group); - } - else - { - group->setVisible(); - stateSort(group, camera); - - if (!sDelayVBUpdate) - { //rebuild mesh as soon as we know it's visible - group->rebuildMesh(); - } - } - } - - { - LLFastTimer ftm(FTM_STATESORT_DRAWABLE); - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); - iter != sCull->endVisibleList(); ++iter) - { - LLDrawable *drawablep = *iter; - if (!drawablep->isDead()) - { - stateSort(drawablep, camera); - } - } - } - - postSort(camera); -} - -void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - if (group->changeLOD()) - { - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawablep = *i; - stateSort(drawablep, camera); - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { //avoid redundant stateSort calls - group->mLastUpdateDistance = group->mDistance; - } - } - -} - -void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - if (bridge->getSpatialGroup()->changeLOD()) - { - bool force_update = false; - bridge->updateDistance(camera, force_update); - } -} - -void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); - - if (!drawablep - || drawablep->isDead() - || !hasRenderType(drawablep->getRenderType())) - { - return; - } - - if (LLSelectMgr::getInstance()->mHideSelectedObjects) - { - if (drawablep->getVObj().notNull() && - drawablep->getVObj()->isSelected()) - { - return; - } - } - - if (drawablep->isAvatar()) - { //don't draw avatars beyond render distance or if we don't have a spatial group. - if ((drawablep->getSpatialGroup() == NULL) || - (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance)) - { - return; - } - - LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get(); - if (!avatarp->isVisible()) - { - return; - } - } - - assertInitialized(); - - if (hasRenderType(drawablep->mRenderType)) - { - if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE)) - { - drawablep->setVisible(camera, NULL, FALSE); - } - else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE)) - { - // clear invisible flag here to avoid single frame glitch - drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE); - } - } - - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here - { - if (!drawablep->isActive()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); - } - else if (drawablep->isAvatar()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() - } - } - } - - if (!drawablep->getVOVolume()) - { - for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin(); - iter != drawablep->mFaces.end(); iter++) - { - LLFace* facep = *iter; - - if (facep->hasGeometry()) - { - if (facep->getPool()) - { - facep->getPool()->enqueue(facep); - } - else - { - break; - } - } - } - } - - - mNumVisibleFaces += drawablep->getNumFaces(); -} - - -void forAllDrawables(LLCullResult::sg_list_t::iterator begin, - LLCullResult::sg_list_t::iterator end, - void (*func)(LLDrawable*)) -{ - for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i) - { - for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) - { - func(*j); - } - } -} - -void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*)) -{ - forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func); - forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func); -} - -//function for creating scripted beacons -void renderScriptedBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->flagScripted()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderScriptedTouchBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - && !vobj->getParent() - && vobj->flagScripted() - && vobj->flagHandleTouch()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderPhysicalBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && !vobj->isAvatar() - //&& !vobj->getParent() - && vobj->usePhysics()) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderMOAPBeacons(LLDrawable* drawablep) -{ - LLViewerObject *vobj = drawablep->getVObj(); - - if(!vobj || vobj->isAvatar()) - return; - - BOOL beacon=FALSE; - U8 tecount=vobj->getNumTEs(); - for(int x=0;x<tecount;x++) - { - if(vobj->getTE(x)->hasMedia()) - { - beacon=TRUE; - break; - } - } - if(beacon==TRUE) - { - if (gPipeline.sRenderBeacons) - { - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderParticleBeacons(LLDrawable* drawablep) -{ - // Look for attachments, objects, etc. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj - && vobj->isParticleSource()) - { - if (gPipeline.sRenderBeacons) - { - LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f); - gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth); - } - - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void renderSoundHighlights(LLDrawable* drawablep) -{ - // Look for attachments, objects, etc. - LLViewerObject *vobj = drawablep->getVObj(); - if (vobj && vobj->isAudioSource()) - { - if (gPipeline.sRenderHighlight) - { - S32 face_id; - S32 count = drawablep->getNumFaces(); - for (face_id = 0; face_id < count; face_id++) - { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); - } - } - } -} - -void LLPipeline::postSort(LLCamera& camera) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT); - LLFastTimer ftm(FTM_STATESORT_POSTSORT); - - assertInitialized(); - - llpushcallstacks ; - //rebuild drawable geometry - for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (!sUseOcclusion || - !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - group->rebuildGeom(); - } - } - llpushcallstacks ; - //rebuild groups - sCull->assertDrawMapsEmpty(); - - rebuildPriorityGroups(); - llpushcallstacks ; - - const S32 bin_count = 1024*8; - - static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; - static U32 bin_size[bin_count]; - - //clear one bin per frame to avoid memory bloat - static S32 clear_idx = 0; - clear_idx = (1+clear_idx)%bin_count; - alpha_bins[clear_idx].clear(); - - for (U32 j = 0; j < bin_count; j++) - { - bin_size[j] = 0; - } - - //build render map - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (sUseOcclusion && - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - continue; - } - - if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) - { //no way this group is going to be drawable without a rebuild - group->rebuildGeom(); - } - - for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j) - { - LLSpatialGroup::drawmap_elem_t& src_vec = j->second; - if (!hasRenderType(j->first)) - { - continue; - } - - for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) - { - if (sMinRenderSize > 0.f) - { - LLVector4a bounds; - bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); - - if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) - { - sCull->pushDrawInfo(j->first, *k); - } - } - else - { - sCull->pushDrawInfo(j->first, *k); - } - } - } - - if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) - { - LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); - - if (alpha != group->mDrawMap.end()) - { //store alpha groups for sorting - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - if (bridge) - { - LLCamera trans_camera = bridge->transformCamera(camera); - group->updateDistance(trans_camera); - } - else - { - group->updateDistance(camera); - } - } - - if (hasRenderType(LLDrawPool::POOL_ALPHA)) - { - sCull->pushAlphaGroup(group); - } - } - } - } - - if (!sShadowRender) - { - std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); - } - llpushcallstacks ; - // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus - if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) - { - if (sRenderScriptedTouchBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderScriptedTouchBeacons); - } - else - if (sRenderScriptedBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderScriptedBeacons); - } - - if (sRenderPhysicalBeacons) - { - // Only show the beacon on the root object. - forAllVisibleDrawables(renderPhysicalBeacons); - } - - if(sRenderMOAPBeacons) - { - forAllVisibleDrawables(renderMOAPBeacons); - } - - if (sRenderParticleBeacons) - { - forAllVisibleDrawables(renderParticleBeacons); - } - - // If god mode, also show audio cues - if (sRenderSoundBeacons && gAudiop) - { - // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible. - LLAudioEngine::source_map::iterator iter; - for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) - { - LLAudioSource *sourcep = iter->second; - - LLVector3d pos_global = sourcep->getPositionGlobal(); - LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global); - if (gPipeline.sRenderBeacons) - { - //pos += LLVector3(0.f, 0.f, 0.2f); - gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), DebugBeaconLineWidth); - } - } - // now deal with highlights for all those seeable sound sources - forAllVisibleDrawables(renderSoundHighlights); - } - } - llpushcallstacks ; - // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. - if (LLFloaterTelehub::renderBeacons()) - { - LLFloaterTelehub::addBeacons(); - } - - if (!sShadowRender) - { - mSelectedFaces.clear(); - - // Draw face highlights for selected faces. - if (LLSelectMgr::getInstance()->getTEMode()) - { - struct f : public LLSelectedTEFunctor - { - virtual bool apply(LLViewerObject* object, S32 te) - { - if (object->mDrawable) - { - gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); - } - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); - } - } - - //LLSpatialGroup::sNoDelete = FALSE; - llpushcallstacks ; -} - - -void render_hud_elements() -{ - LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS); - LLFastTimer t(FTM_RENDER_UI); - gPipeline.disableLights(); - - LLGLDisable fog(GL_FOG); - LLGLSUIDefault gls_ui; - - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF); - glStencilMask(0xFFFFFFFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - gGL.color4f(1,1,1,1); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - - if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLGLEnable multisample(LLPipeline::RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() - - // Draw the tracking overlays - LLTracker::render3D(); - - // Show the property lines - LLWorld::getInstance()->renderPropertyLines(); - LLViewerParcelMgr::getInstance()->render(); - LLViewerParcelMgr::getInstance()->renderParcelCollision(); - - // Render name tags. - LLHUDObject::renderAll(); - } - else if (gForceRenderLandFence) - { - // This is only set when not rendering the UI, for parcel snapshots - LLViewerParcelMgr::getInstance()->render(); - } - else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - LLHUDText::renderAllHUD(); - } - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - gGL.flush(); -} - -void LLPipeline::renderHighlights() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL); - - assertInitialized(); - - // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) - // Render highlighted faces. - LLGLSPipelineAlpha gls_pipeline_alpha; - LLColor4 color(1.f, 1.f, 1.f, 0.5f); - LLGLEnable color_mat(GL_COLOR_MATERIAL); - disableLights(); - - if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty()) - { //draw blurry highlight image over screen - LLGLEnable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - LLGLDisable test(GL_ALPHA_TEST); - - LLGLEnable stencil(GL_STENCIL_TEST); - gGL.flush(); - glStencilMask(0xFFFFFFFF); - glClearStencil(1); - glClear(GL_STENCIL_BUFFER_BIT); - - glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - - gGL.setColorMask(false, false); - for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) - { - renderHighlight(iter->mItem->getVObj(), 1.f); - } - gGL.setColorMask(true, false); - - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); - - //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - gGL.getTexUnit(0)->bind(&mHighlight); - - LLVector2 tc1; - LLVector2 tc2; - - tc1.setVec(0,0); - tc2.setVec(2,2); - - gGL.begin(LLRender::TRIANGLES); - - F32 scale = RenderHighlightBrightness; - LLColor4 color = RenderHighlightColor; - F32 thickness = RenderHighlightThickness; - - for (S32 pass = 0; pass < 2; ++pass) - { - if (pass == 0) - { - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - } - else - { - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - for (S32 i = 0; i < 8; ++i) - { - for (S32 j = 0; j < 8; ++j) - { - LLVector2 tc(i-4+0.5f, j-4+0.5f); - - F32 dist = 1.f-(tc.length()/sqrtf(32.f)); - dist *= scale/64.f; - - tc *= thickness; - tc.mV[0] = (tc.mV[0])/mHighlight.getWidth(); - tc.mV[1] = (tc.mV[1])/mHighlight.getHeight(); - - gGL.color4f(color.mV[0], - color.mV[1], - color.mV[2], - color.mV[3]*dist); - - gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]); - gGL.vertex2f(3,-1); - } - } - } - - gGL.end(); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - //gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) - { - gHighlightProgram.bind(); - gGL.diffuseColor4f(1,1,1,0.5f); - } - - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) - { - // Make sure the selection image gets downloaded and decoded - if (!mFaceSelectImagep) - { - mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); - } - mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); - - U32 count = mSelectedFaces.size(); - for (U32 i = 0; i < count; i++) - { - LLFace *facep = mSelectedFaces[i]; - if (!facep || facep->getDrawable()->isDead()) - { - llerrs << "Bad face on selection" << llendl; - return; - } - - facep->renderSelected(mFaceSelectImagep, color); - } - } - - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) - { - // Paint 'em red! - color.setVec(1.f, 0.f, 0.f, 0.5f); - - int count = mHighlightFaces.size(); - for (S32 i = 0; i < count; i++) - { - LLFace* facep = mHighlightFaces[i]; - facep->renderSelected(LLViewerTexture::sNullImagep, color); - } - } - - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.clear(); - - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) - { - gHighlightProgram.unbind(); - } -} - -//debug use -U32 LLPipeline::sCurRenderPoolType = 0 ; - -void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM); - LLFastTimer t(FTM_RENDER_GEOMETRY); - - assertInitialized(); - - F32 saved_modelview[16]; - F32 saved_projection[16]; - - //HACK: preserve/restore matrices around HUD render - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - for (U32 i = 0; i < 16; i++) - { - saved_modelview[i] = gGLModelView[i]; - saved_projection[i] = gGLProjection[i]; - } - } - - /////////////////////////////////////////// - // - // Sync and verify GL state - // - // - - stop_glerror(); - - LLVertexBuffer::unbind(); - - // Do verification of GL state - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - if (mRenderDebugMask & RENDER_DEBUG_VERIFY) - { - if (!verify()) - { - llerrs << "Pipeline verification failed!" << llendl; - } - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO"); - - // Initialize lots of GL state to "safe" values - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - - LLGLSPipeline gls_pipeline; - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); - - // Toggle backface culling for debugging - LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); - // Set fog - BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG); - LLGLEnable fog_enable(use_fog && - !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0); - gSky.updateFog(camera.getFar()); - if (!use_fog) - { - sUnderWaterRender = FALSE; - } - - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); - LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); - - ////////////////////////////////////////////// - // - // Actually render all of the geometry - // - // - stop_glerror(); - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools"); - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (hasRenderType(poolp->getType())) - { - poolp->prerender(); - } - } - - { - LLFastTimer t(FTM_POOLS); - - // HACK: don't calculate local lights if we're rendering the HUD! - // Removing this check will cause bad flickering when there are - // HUD elements being rendered AND the user is in flycam mode -nyx - if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - calcNearbyLights(camera); - setupHWLights(NULL); - } - - BOOL occlude = sUseOcclusion > 1; - U32 cur_type = 0; - - pool_set_t::iterator iter1 = mPools.begin(); - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - //debug use - sCurRenderPoolType = cur_type ; - - if (occlude && cur_type >= LLDrawPool::POOL_GRASS) - { - occlude = FALSE; - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - LLGLSLShader::bindNoShader(); - doOcclusion(camera); - } - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - for( S32 i = 0; i < poolp->getNumPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginRenderPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->render(i); - } - poolp->endRenderPass(i); - LLVertexBuffer::unbind(); - if (gDebugGL) - { - std::string msg = llformat("pass %d", i); - LLGLState::checkStates(msg); - //LLGLState::checkTextureChannels(msg); - //LLGLState::checkClientArrays(msg); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd"); - - LLVertexBuffer::unbind(); - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - if (occlude) - { - occlude = FALSE; - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - LLGLSLShader::bindNoShader(); - doOcclusion(camera); - } - } - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - - if (!LLPipeline::sImpostorRender) - { - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights"); - - if (!sReflectionRender) - { - renderHighlights(); - } - - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.clear(); - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug"); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred) - { - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - gObjectList.resetObjectBeacons(); - } - else - { - // Make sure particle effects disappear - LLHUDObject::renderAllForTimer(); - } - } - else - { - // Make sure particle effects disappear - LLHUDObject::renderAllForTimer(); - } - - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd"); - - //HACK: preserve/restore matrices around HUD render - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - for (U32 i = 0; i < 16; i++) - { - gGLModelView[i] = saved_modelview[i]; - gGLProjection[i] = saved_projection[i]; - } - } - } - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); -// LLGLState::checkTextureChannels(); -// LLGLState::checkClientArrays(); -} - -void LLPipeline::renderGeomDeferred(LLCamera& camera) -{ - LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - - LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); - LLFastTimer t(FTM_RENDER_GEOMETRY); - - LLFastTimer t2(FTM_POOLS); - - LLGLEnable cull(GL_CULL_FACE); - - LLGLEnable stencil(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); - stop_glerror(); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - stop_glerror(); - - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (hasRenderType(poolp->getType())) - { - poolp->prerender(); - } - } - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - U32 cur_type = 0; - - gGL.setColorMask(true, true); - - pool_set_t::iterator iter1 = mPools.begin(); - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginDeferredPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderDeferred(i); - } - poolp->endDeferredPass(i); - LLVertexBuffer::unbind(); - - if (gDebugGL || gDebugPipeline) - { - LLGLState::checkStates(); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - gGL.setColorMask(true, false); -} - -void LLPipeline::renderGeomPostDeferred(LLCamera& camera) -{ - LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); - LLFastTimer t(FTM_POOLS); - U32 cur_type = 0; - - LLGLEnable cull(GL_CULL_FACE); - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - calcNearbyLights(camera); - setupHWLights(NULL); - - gGL.setColorMask(true, false); - - pool_set_t::iterator iter1 = mPools.begin(); - BOOL occlude = LLPipeline::sUseOcclusion > 1; - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - if (occlude && cur_type >= LLDrawPool::POOL_GRASS) - { - occlude = FALSE; - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - LLGLSLShader::bindNoShader(); - doOcclusion(camera); - gGL.setColorMask(true, false); - } - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) - { - LLFastTimer t(FTM_POOLRENDER); - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginPostDeferredPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderPostDeferred(i); - } - poolp->endPostDeferredPass(i); - LLVertexBuffer::unbind(); - - if (gDebugGL || gDebugPipeline) - { - LLGLState::checkStates(); - } - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - if (occlude) - { - occlude = FALSE; - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - LLGLSLShader::bindNoShader(); - doOcclusion(camera); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - } -} - -void LLPipeline::renderGeomShadow(LLCamera& camera) -{ - LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW); - U32 cur_type = 0; - - LLGLEnable cull(GL_CULL_FACE); - - LLVertexBuffer::unbind(); - - pool_set_t::iterator iter1 = mPools.begin(); - - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; - - cur_type = poolp->getType(); - - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0) - { - poolp->prerender() ; - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - - for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginShadowPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - - p->renderShadow(i); - } - poolp->endShadowPass(i); - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) - { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) - { - break; - } - } - } - iter1 = iter2; - stop_glerror(); - } - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); -} - - -void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type) -{ - assertInitialized(); - S32 count = 0; - if (render_type == LLRender::TRIANGLE_STRIP) - { - count = index_count-2; - } - else - { - count = index_count/3; - } - - mTrianglesDrawn += count; - mBatchCount++; - mMaxBatchSize = llmax(mMaxBatchSize, count); - mMinBatchSize = llmin(mMinBatchSize, count); - - if (LLPipeline::sRenderFrameTest) - { - gViewerWindow->getWindow()->swapBuffers(); - ms_sleep(16); - } -} - -void LLPipeline::renderPhysicsDisplay() -{ - if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) - { - return; - } - - allocatePhysicsBuffer(); - - gGL.flush(); - mPhysicsDisplay.bindTarget(); - glClearColor(0,0,0,1); - gGL.setColorMask(true, true); - mPhysicsDisplay.clear(); - glClearColor(0,0,0,0); - - gGL.setColorMask(true, false); - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->renderPhysicsShapes(); - } - } - } - } - - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) - { - gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - bridge->renderPhysicsShapes(); - gGL.popMatrix(); - } - } - - gGL.flush(); - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } - - mPhysicsDisplay.flush(); -} - - -void LLPipeline::renderDebug() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE); - - assertInitialized(); - - gGL.color4f(1,1,1,1); - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - gGL.setColorMask(true, false); - - bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD); - - - if (!hud_only && !mDebugBlips.empty()) - { //render debug blips - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true); - - glPointSize(8.f); - LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); - - gGL.begin(LLRender::POINTS); - for (std::list<DebugBlip>::iterator iter = mDebugBlips.begin(); iter != mDebugBlips.end(); ) - { - DebugBlip& blip = *iter; - - blip.mAge += gFrameIntervalSeconds; - if (blip.mAge > 2.f) - { - mDebugBlips.erase(iter++); - } - else - { - iter++; - } - - blip.mPosition.mV[2] += gFrameIntervalSeconds*2.f; - - gGL.color4fv(blip.mColor.mV); - gGL.vertex3fv(blip.mPosition.mV); - } - gGL.end(); - gGL.flush(); - glPointSize(1.f); - } - - - // Debug stuff. - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) || - !hud_only && hasRenderType(part->mDrawableType) ) - { - part->renderDebug(); - } - } - } - } - - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) - { - gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - bridge->renderDebug(); - gGL.popMatrix(); - } - } - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - LLVertexBuffer::unbind(); - - LLGLEnable blend(GL_BLEND); - LLGLDepthTest depth(TRUE, FALSE); - LLGLDisable cull(GL_CULL_FACE); - - gGL.color4f(1,1,1,1); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - F32 a = 0.1f; - - F32 col[] = - { - 1,0,0,a, - 0,1,0,a, - 0,0,1,a, - 1,0,1,a, - - 1,1,0,a, - 0,1,1,a, - 1,1,1,a, - 1,0,1,a, - }; - - for (U32 i = 0; i < 8; i++) - { - LLVector3* frust = mShadowCamera[i].mAgentFrustum; - - if (i > 3) - { //render shadow frusta as volumes - if (mShadowFrustPoints[i-4].empty()) - { - continue; - } - - gGL.color4fv(col+(i-4)*4); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.end(); - - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[0].mV); - gGL.vertex3fv(frust[1].mV); - gGL.vertex3fv(frust[3].mV); - gGL.vertex3fv(frust[2].mV); - gGL.end(); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[6].mV); - gGL.end(); - } - - - if (i < 4) - { - - //if (i == 0 || !mShadowFrustPoints[i].empty()) - { - //render visible point cloud - gGL.flush(); - glPointSize(8.f); - gGL.begin(LLRender::POINTS); - - F32* c = col+i*4; - gGL.color3fv(c); - - for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j) - { - gGL.vertex3fv(mShadowFrustPoints[i][j].mV); - - } - gGL.end(); - - gGL.flush(); - glPointSize(1.f); - - LLVector3* ext = mShadowExtents[i]; - LLVector3 pos = (ext[0]+ext[1])*0.5f; - LLVector3 size = (ext[1]-ext[0])*0.5f; - drawBoxOutline(pos, size); - - //render camera frustum splits as outlines - gGL.begin(LLRender::LINES); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV); - gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV); - gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV); - gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV); - gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); - gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); - gGL.end(); - } - } - - /*gGL.flush(); - glLineWidth(16-i*2); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) - { - LLSpatialPartition* part = region->getSpatialPartition(j); - if (part) - { - if (hasRenderType(part->mDrawableType)) - { - part->renderIntersectingBBoxes(&mShadowCamera[i]); - } - } - } - } - gGL.flush(); - glLineWidth(1.f);*/ - } - } - - if (mRenderDebugMask & RENDER_DEBUG_WIND_VECTORS) - { - gAgent.getRegion()->mWind.renderVectors(); - } - - if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION) - { - // Debug composition layers - F32 x, y; - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (gAgent.getRegion()) - { - gGL.begin(LLRender::POINTS); - // Draw the composition layer for the region that I'm in. - for (x = 0; x <= 260; x++) - { - for (y = 0; y <= 260; y++) - { - if ((x > 255) || (y > 255)) - { - gGL.color4f(1.f, 0.f, 0.f, 1.f); - } - else - { - gGL.color4f(0.f, 0.f, 1.f, 1.f); - } - F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y); - z *= 5.f; - z += 50.f; - gGL.vertex3f(x, y, z); - } - } - gGL.end(); - } - } - - if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) - { - U32 count = 0; - U32 size = mGroupQ2.size(); - LLColor4 col; - - LLVertexBuffer::unbind(); - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - - gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - - for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) - { - LLSpatialGroup* group = *iter; - if (group->isDead()) - { - continue; - } - - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); - - if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead())) - { - continue; - } - - if (bridge) - { - gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - } - - F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); - - - LLVector2 c(1.f-alpha, alpha); - c.normVec(); - - - ++count; - col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); - group->drawObjectBox(col); - - if (bridge) - { - gGL.popMatrix(); - } - } - - gGL.popMatrix(); - } - - gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } -} - -void LLPipeline::rebuildPools() -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); - - assertInitialized(); - - S32 max_count = mPools.size(); - pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool); - while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS) - { - if (iter1 == mPools.end()) - { - iter1 = mPools.begin(); - } - LLDrawPool* poolp = *iter1; - - if (poolp->isDead()) - { - mPools.erase(iter1++); - removeFromQuickLookup( poolp ); - if (poolp == mLastRebuildPool) - { - mLastRebuildPool = NULL; - } - delete poolp; - } - else - { - mLastRebuildPool = poolp; - iter1++; - } - max_count--; - } - - if (isAgentAvatarValid()) - { - gAgentAvatarp->rebuildHUD(); - } -} - -void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) -{ - LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP); - - assertInitialized(); - - switch( new_poolp->getType() ) - { - case LLDrawPool::POOL_SIMPLE: - if (mSimplePool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mSimplePool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_GRASS: - if (mGrassPool) - { - llassert(0); - llwarns << "Ignoring duplicate grass pool." << llendl; - } - else - { - mGrassPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_FULLBRIGHT: - if (mFullbrightPool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mFullbrightPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_INVISIBLE: - if (mInvisiblePool) - { - llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; - } - else - { - mInvisiblePool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_GLOW: - if (mGlowPool) - { - llassert(0); - llwarns << "Ignoring duplicate glow pool." << llendl; - } - else - { - mGlowPool = (LLRenderPass*) new_poolp; - } - break; - - case LLDrawPool::POOL_TREE: - mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; - - case LLDrawPool::POOL_TERRAIN: - mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ; - break; - - case LLDrawPool::POOL_BUMP: - if (mBumpPool) - { - llassert(0); - llwarns << "Ignoring duplicate bump pool." << llendl; - } - else - { - mBumpPool = new_poolp; - } - break; - - case LLDrawPool::POOL_ALPHA: - if( mAlphaPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; - } - else - { - mAlphaPool = new_poolp; - } - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - if( mSkyPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl; - } - else - { - mSkyPool = new_poolp; - } - break; - - case LLDrawPool::POOL_WATER: - if( mWaterPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl; - } - else - { - mWaterPool = new_poolp; - } - break; - - case LLDrawPool::POOL_GROUND: - if( mGroundPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl; - } - else - { - mGroundPool = new_poolp; - } - break; - - case LLDrawPool::POOL_WL_SKY: - if( mWLSkyPool ) - { - llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl; - } - else - { - mWLSkyPool = new_poolp; - } - break; - - default: - llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; - break; - } -} - -void LLPipeline::removePool( LLDrawPool* poolp ) -{ - assertInitialized(); - removeFromQuickLookup(poolp); - mPools.erase(poolp); - delete poolp; -} - -void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) -{ - assertInitialized(); - LLMemType mt(LLMemType::MTYPE_PIPELINE); - switch( poolp->getType() ) - { - case LLDrawPool::POOL_SIMPLE: - llassert(mSimplePool == poolp); - mSimplePool = NULL; - break; - - case LLDrawPool::POOL_GRASS: - llassert(mGrassPool == poolp); - mGrassPool = NULL; - break; - - case LLDrawPool::POOL_FULLBRIGHT: - llassert(mFullbrightPool == poolp); - mFullbrightPool = NULL; - break; - - case LLDrawPool::POOL_INVISIBLE: - llassert(mInvisiblePool == poolp); - mInvisiblePool = NULL; - break; - - case LLDrawPool::POOL_WL_SKY: - llassert(mWLSkyPool == poolp); - mWLSkyPool = NULL; - break; - - case LLDrawPool::POOL_GLOW: - llassert(mGlowPool == poolp); - mGlowPool = NULL; - break; - - case LLDrawPool::POOL_TREE: - #ifdef _DEBUG - { - BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTreePools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - - case LLDrawPool::POOL_TERRAIN: - #ifdef _DEBUG - { - BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - #endif - break; - - case LLDrawPool::POOL_BUMP: - llassert( poolp == mBumpPool ); - mBumpPool = NULL; - break; - - case LLDrawPool::POOL_ALPHA: - llassert( poolp == mAlphaPool ); - mAlphaPool = NULL; - break; - - case LLDrawPool::POOL_AVATAR: - break; // Do nothing - - case LLDrawPool::POOL_SKY: - llassert( poolp == mSkyPool ); - mSkyPool = NULL; - break; - - case LLDrawPool::POOL_WATER: - llassert( poolp == mWaterPool ); - mWaterPool = NULL; - break; - - case LLDrawPool::POOL_GROUND: - llassert( poolp == mGroundPool ); - mGroundPool = NULL; - break; - - default: - llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; - break; - } -} - -void LLPipeline::resetDrawOrders() -{ - assertInitialized(); - // Iterate through all of the draw pools and rebuild them. - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - poolp->resetDrawOrders(); - } -} - -//============================================================================ -// Once-per-frame setup of hardware lights, -// including sun/moon, avatar backlight, and up to 6 local lights - -void LLPipeline::setupAvatarLights(BOOL for_edit) -{ - assertInitialized(); - - if (for_edit) - { - LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); - LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light - LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); - LLMatrix4 camera_rot(camera_mat.getMat3()); - camera_rot.invert(); - LLVector4 light_pos = light_pos_cam * camera_rot; - - light_pos.normalize(); - - LLLightState* light = gGL.getLight(1); - - mHWLightColors[1] = diffuse; - - light->setDiffuse(diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setPosition(light_pos); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) - { - LLVector3 opposite_pos = -1.f * mSunDir; - LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; - LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f); - backlight_pos.normalize(); - - LLColor4 light_diffuse = mSunDiffuse; - LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f); - F32 max_component = 0.001f; - for (S32 i = 0; i < 3; i++) - { - if (backlight_diffuse.mV[i] > max_component) - { - max_component = backlight_diffuse.mV[i]; - } - } - F32 backlight_mag; - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) - { - backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT; - } - else - { - backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT; - } - backlight_diffuse *= backlight_mag / max_component; - - mHWLightColors[1] = backlight_diffuse; - - LLLightState* light = gGL.getLight(1); - - light->setPosition(backlight_pos); - light->setDiffuse(backlight_diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - else - { - LLLightState* light = gGL.getLight(1); - - mHWLightColors[1] = LLColor4::black; - - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - } -} - -static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) -{ - F32 inten = light->getLightIntensity(); - if (inten < .001f) - { - return max_dist; - } - F32 radius = light->getLightRadius(); - BOOL selected = light->isSelected(); - LLVector3 dpos = light->getRenderPosition() - cam_pos; - F32 dist2 = dpos.lengthSquared(); - if (!selected && dist2 > (max_dist + radius)*(max_dist + radius)) - { - return max_dist; - } - F32 dist = (F32) sqrt(dist2); - dist *= 1.f / inten; - dist -= radius; - if (selected) - { - dist -= 10000.f; // selected lights get highest priority - } - if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE)) - { - // moving lights get a little higher priority (too much causes artifacts) - dist -= light->getLightRadius()*0.25f; - } - return dist; -} - -void LLPipeline::calcNearbyLights(LLCamera& camera) -{ - assertInitialized(); - - if (LLPipeline::sReflectionRender) - { - return; - } - - if (mLightingDetail >= 1) - { - // mNearbyLight (and all light_set_t's) are sorted such that - // begin() == the closest light and rbegin() == the farthest light - const S32 MAX_LOCAL_LIGHTS = 6; -// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); - LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? - camera.getOrigin() : - gAgent.getPositionAgent(); - - F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad - - // UPDATE THE EXISTING NEARBY LIGHTS - light_set_t cur_nearby_lights; - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) - { - const Light* light = &(*iter); - LLDrawable* drawable = light->drawable; - LLVOVolume* volight = drawable->getVOVolume(); - if (!volight || !drawable->isState(LLDrawable::LIGHT)) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - if (light->fade <= -LIGHT_FADE_TIME) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - if (!sRenderAttachedLights && volight && volight->isAttachment()) - { - drawable->clearState(LLDrawable::NEARBY_LIGHT); - continue; - } - - F32 dist = calc_light_dist(volight, cam_pos, max_dist); - cur_nearby_lights.insert(Light(drawable, dist, light->fade)); - } - mNearbyLights = cur_nearby_lights; - - // FIND NEW LIGHTS THAT ARE IN RANGE - light_set_t new_nearby_lights; - for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); - iter != mLights.end(); ++iter) - { - LLDrawable* drawable = *iter; - LLVOVolume* light = drawable->getVOVolume(); - if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT)) - { - continue; - } - if (light->isHUDAttachment()) - { - continue; // no lighting from HUD objects - } - F32 dist = calc_light_dist(light, cam_pos, max_dist); - if (dist >= max_dist) - { - continue; - } - if (!sRenderAttachedLights && light && light->isAttachment()) - { - continue; - } - new_nearby_lights.insert(Light(drawable, dist, 0.f)); - if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS) - { - new_nearby_lights.erase(--new_nearby_lights.end()); - const Light& last = *new_nearby_lights.rbegin(); - max_dist = last.dist; - } - } - - // INSERT ANY NEW LIGHTS - for (light_set_t::iterator iter = new_nearby_lights.begin(); - iter != new_nearby_lights.end(); iter++) - { - const Light* light = &(*iter); - if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS) - { - mNearbyLights.insert(*light); - ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT); - } - else - { - // crazy cast so that we can overwrite the fade value - // even though gcc enforces sets as const - // (fade value doesn't affect sort so this is safe) - Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin())))); - if (light->dist < farthest_light->dist) - { - if (farthest_light->fade >= 0.f) - { - farthest_light->fade = -gFrameIntervalSeconds; - } - } - else - { - break; // none of the other lights are closer - } - } - } - - } -} - -void LLPipeline::setupHWLights(LLDrawPool* pool) -{ - assertInitialized(); - - // Ambient - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.syncMatrices(); - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); - } - - // Light 0 = Sun or Moon (All objects) - { - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) - { - mSunDir.setVec(gSky.getSunDirection()); - mSunDiffuse.setVec(gSky.getSunDiffuseColor()); - } - else - { - mSunDir.setVec(gSky.getMoonDirection()); - mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); - } - - F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); - if (max_color > 1.f) - { - mSunDiffuse *= 1.f/max_color; - } - mSunDiffuse.clamp(); - - LLVector4 light_pos(mSunDir, 0.0f); - LLColor4 light_diffuse = mSunDiffuse; - mHWLightColors[0] = light_diffuse; - - LLLightState* light = gGL.getLight(0); - light->setPosition(light_pos); - light->setDiffuse(light_diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - - // Light 1 = Backlight (for avatars) - // (set by enableLightsAvatar) - - S32 cur_light = 2; - - // Nearby lights = LIGHT 2-7 - - mLightMovingMask = 0; - - if (mLightingDetail >= 1) - { - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); ++iter) - { - LLDrawable* drawable = iter->drawable; - LLVOVolume* light = drawable->getVOVolume(); - if (!light) - { - continue; - } - if (drawable->isState(LLDrawable::ACTIVE)) - { - mLightMovingMask |= (1<<cur_light); - } - - LLColor4 light_color = light->getLightColor(); - light_color.mV[3] = 0.0f; - - F32 fade = iter->fade; - if (fade < LIGHT_FADE_TIME) - { - // fade in/out light - if (fade >= 0.f) - { - fade = fade / LIGHT_FADE_TIME; - ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds; - } - else - { - fade = 1.f + fade / LIGHT_FADE_TIME; - ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds; - } - fade = llclamp(fade,0.f,1.f); - light_color *= fade; - } - - LLVector3 light_pos(light->getRenderPosition()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = llmax(light->getLightRadius(), 0.001f); - - F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior. - float linatten = x / (light_radius); // % of brightness at radius - - mHWLightColors[cur_light] = light_color; - LLLightState* light_state = gGL.getLight(cur_light); - - light_state->setPosition(light_pos_gl); - light_state->setDiffuse(light_color); - light_state->setAmbient(LLColor4::black); - light_state->setConstantAttenuation(0.f); - if (sRenderDeferred) - { - F32 size = light_radius*1.5f; - light_state->setLinearAttenuation(size*size); - light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f); - } - else - { - light_state->setLinearAttenuation(linatten); - light_state->setQuadraticAttenuation(0.f); - } - - - if (light->isLightSpotlight() // directional (spot-)light - && (LLPipeline::sRenderDeferred || RenderSpotLightsInNondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on - { - LLVector3 spotparams = light->getSpotLightParams(); - LLQuaternion quat = light->getRenderRotation(); - LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction - at_axis *= quat; - - light_state->setSpotDirection(at_axis); - light_state->setSpotCutoff(90.f); - light_state->setSpotExponent(2.f); - - const LLColor4 specular(0.f, 0.f, 0.f, 0.f); - light_state->setSpecular(specular); - } - else // omnidirectional (point) light - { - light_state->setSpotExponent(0.f); - light_state->setSpotCutoff(180.f); - - // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight - const LLColor4 specular(0.f, 0.f, 0.f, 1.f); - light_state->setSpecular(specular); - } - cur_light++; - if (cur_light >= 8) - { - break; // safety - } - } - } - for ( ; cur_light < 8 ; cur_light++) - { - mHWLightColors[cur_light] = LLColor4::black; - LLLightState* light = gGL.getLight(cur_light); - - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - } - if (gAgentAvatarp && - gAgentAvatarp->mSpecialRenderMode == 3) - { - LLColor4 light_color = LLColor4::white; - light_color.mV[3] = 0.0f; - - LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = 16.f; - - F32 x = 3.f; - float linatten = x / (light_radius); // % of brightness at radius - - mHWLightColors[2] = light_color; - LLLightState* light = gGL.getLight(2); - - light->setPosition(light_pos_gl); - light->setDiffuse(light_color); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setQuadraticAttenuation(0.f); - light->setConstantAttenuation(0.f); - light->setLinearAttenuation(linatten); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - - // Init GL state - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } - - for (S32 i = 0; i < 8; ++i) - { - gGL.getLight(i)->disable(); - } - mLightMask = 0; -} - -void LLPipeline::enableLights(U32 mask) -{ - assertInitialized(); - - if (mLightingDetail == 0) - { - mask &= 0xf003; // sun and backlight only (and fullbright bit) - } - if (mLightMask != mask) - { - stop_glerror(); - if (!mLightMask) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } - } - if (mask) - { - stop_glerror(); - for (S32 i=0; i<8; i++) - { - LLLightState* light = gGL.getLight(i); - if (mask & (1<<i)) - { - light->enable(); - light->setDiffuse(mHWLightColors[i]); - } - else - { - light->disable(); - light->setDiffuse(LLColor4::black); - } - } - stop_glerror(); - } - else - { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } - } - mLightMask = mask; - stop_glerror(); - - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); - } -} - -void LLPipeline::enableLightsStatic() -{ - assertInitialized(); - U32 mask = 0x01; // Sun - if (mLightingDetail >= 2) - { - mask |= mLightMovingMask; // Hardware moving lights - } - else - { - mask |= 0xff & (~2); // Hardware local lights - } - enableLights(mask); -} - -void LLPipeline::enableLightsDynamic() -{ - assertInitialized(); - U32 mask = 0xff & (~2); // Local lights - enableLights(mask); - - if (isAgentAvatarValid() && getLightingDetail() <= 0) - { - if (gAgentAvatarp->mSpecialRenderMode == 0) // normal - { - gPipeline.enableLightsAvatar(); - } - else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview - { - gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); - } - } -} - -void LLPipeline::enableLightsAvatar() -{ - U32 mask = 0xff; // All lights - setupAvatarLights(FALSE); - enableLights(mask); -} - -void LLPipeline::enableLightsPreview() -{ - disableLights(); - - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } - - LLColor4 ambient = PreviewAmbientColor; - gGL.setAmbientLightColor(ambient); - - LLColor4 diffuse0 = PreviewDiffuse0; - LLColor4 specular0 = PreviewSpecular0; - LLColor4 diffuse1 = PreviewDiffuse1; - LLColor4 specular1 = PreviewSpecular1; - LLColor4 diffuse2 = PreviewDiffuse2; - LLColor4 specular2 = PreviewSpecular2; - - LLVector3 dir0 = PreviewDirection0; - LLVector3 dir1 = PreviewDirection1; - LLVector3 dir2 = PreviewDirection2; - - dir0.normVec(); - dir1.normVec(); - dir2.normVec(); - - LLVector4 light_pos(dir0, 0.0f); - - LLLightState* light = gGL.getLight(0); - - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse0); - light->setAmbient(LLColor4::black); - light->setSpecular(specular0); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir1, 0.f); - - light = gGL.getLight(1); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse1); - light->setAmbient(LLColor4::black); - light->setSpecular(specular1); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir2, 0.f); - light = gGL.getLight(2); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse2); - light->setAmbient(LLColor4::black); - light->setSpecular(specular2); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); -} - - -void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) -{ - U32 mask = 0x2002; // Avatar backlight only, set ambient - setupAvatarLights(TRUE); - enableLights(mask); - - gGL.setAmbientLightColor(color); -} - -void LLPipeline::enableLightsFullbright(const LLColor4& color) -{ - assertInitialized(); - U32 mask = 0x1000; // Non-0 mask, set ambient - enableLights(mask); - - gGL.setAmbientLightColor(color); -} - -void LLPipeline::disableLights() -{ - enableLights(0); // no lighting (full bright) -} - -//============================================================================ - -class LLMenuItemGL; -class LLInvFVBridge; -struct cat_folder_pair; -class LLVOBranch; -class LLVOLeaf; - -void LLPipeline::findReferences(LLDrawable *drawablep) -{ - assertInitialized(); - if (mLights.find(drawablep) != mLights.end()) - { - llinfos << "In mLights" << llendl; - } - if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) - { - llinfos << "In mMovedList" << llendl; - } - if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end()) - { - llinfos << "In mShiftList" << llendl; - } - if (mRetexturedList.find(drawablep) != mRetexturedList.end()) - { - llinfos << "In mRetexturedList" << llendl; - } - - if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) - { - llinfos << "In mBuildQ1" << llendl; - } - if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) - { - llinfos << "In mBuildQ2" << llendl; - } - - S32 count; - - count = gObjectList.findReferences(drawablep); - if (count) - { - llinfos << "In other drawables: " << count << " references" << llendl; - } -} - -BOOL LLPipeline::verify() -{ - BOOL ok = assertInitialized(); - if (ok) - { - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (!poolp->verify()) - { - ok = FALSE; - } - } - } - - if (!ok) - { - llwarns << "Pipeline verify failed!" << llendl; - } - return ok; -} - -////////////////////////////// -// -// Collision detection -// -// - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/** - * A method to compute a ray-AABB intersection. - * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 - * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) - * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) - * - * Hence this version is faster as well as more robust than the original one. - * - * Should work provided: - * 1) the integer representation of 0.0f is 0x00000000 - * 2) the sign bit of the float is the most significant one - * - * Report bugs: p.terdiman@codercorner.com - * - * \param aabb [in] the axis-aligned bounding box - * \param origin [in] ray origin - * \param dir [in] ray direction - * \param coord [out] impact coordinates - * \return true if ray intersects AABB - */ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//#define RAYAABB_EPSILON 0.00001f -#define IR(x) ((U32&)x) - -bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon) -{ - BOOL Inside = TRUE; - LLVector3 MinB = center - size; - LLVector3 MaxB = center + size; - LLVector3 MaxT; - MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f; - - // Find candidate planes. - for(U32 i=0;i<3;i++) - { - if(origin.mV[i] < MinB.mV[i]) - { - coord.mV[i] = MinB.mV[i]; - Inside = FALSE; - - // Calculate T distances to candidate planes - if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i]; - } - else if(origin.mV[i] > MaxB.mV[i]) - { - coord.mV[i] = MaxB.mV[i]; - Inside = FALSE; - - // Calculate T distances to candidate planes - if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i]; - } - } - - // Ray origin inside bounding box - if(Inside) - { - coord = origin; - return true; - } - - // Get largest of the maxT's for final choice of intersection - U32 WhichPlane = 0; - if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1; - if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2; - - // Check final candidate actually inside box - if(IR(MaxT.mV[WhichPlane])&0x80000000) return false; - - for(U32 i=0;i<3;i++) - { - if(i!=WhichPlane) - { - coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i]; - if (epsilon > 0) - { - if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false; - } - else - { - if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false; - } - } - } - return true; // ray hits box -} - -////////////////////////////// -// -// Macros, functions, and inline methods from other classes -// -// - -void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light) -{ - if (drawablep && assertInitialized()) - { - if (is_light) - { - mLights.insert(drawablep); - drawablep->setState(LLDrawable::LIGHT); - } - else - { - drawablep->clearState(LLDrawable::LIGHT); - mLights.erase(drawablep); - } - } -} - -//static -void LLPipeline::toggleRenderType(U32 type) -{ - gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type]; - if (type == LLPipeline::RENDER_TYPE_WATER) - { - gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER]; - } -} - -//static -void LLPipeline::toggleRenderTypeControl(void* data) -{ - U32 type = (U32)(intptr_t)data; - U32 bit = (1<<type); - if (gPipeline.hasRenderType(type)) - { - llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl; - } - else - { - llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl; - } - gPipeline.toggleRenderType(type); -} - -//static -BOOL LLPipeline::hasRenderTypeControl(void* data) -{ - U32 type = (U32)(intptr_t)data; - return gPipeline.hasRenderType(type); -} - -// Allows UI items labeled "Hide foo" instead of "Show foo" -//static -BOOL LLPipeline::toggleRenderTypeControlNegated(void* data) -{ - S32 type = (S32)(intptr_t)data; - return !gPipeline.hasRenderType(type); -} - -//static -void LLPipeline::toggleRenderDebug(void* data) -{ - U32 bit = (U32)(intptr_t)data; - if (gPipeline.hasRenderDebugMask(bit)) - { - llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl; - } - else - { - llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl; - } - gPipeline.mRenderDebugMask ^= bit; -} - - -//static -BOOL LLPipeline::toggleRenderDebugControl(void* data) -{ - U32 bit = (U32)(intptr_t)data; - return gPipeline.hasRenderDebugMask(bit); -} - -//static -void LLPipeline::toggleRenderDebugFeature(void* data) -{ - U32 bit = (U32)(intptr_t)data; - gPipeline.mRenderDebugFeatureMask ^= bit; -} - - -//static -BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data) -{ - U32 bit = (U32)(intptr_t)data; - return gPipeline.hasRenderDebugFeatureMask(bit); -} - -void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value) -{ - if (value) - { - gPipeline.mRenderDebugFeatureMask |= bit; - } - else - { - gPipeline.mRenderDebugFeatureMask &= !bit; - } -} - -// static -void LLPipeline::setRenderScriptedBeacons(BOOL val) -{ - sRenderScriptedBeacons = val; -} - -// static -void LLPipeline::toggleRenderScriptedBeacons(void*) -{ - sRenderScriptedBeacons = !sRenderScriptedBeacons; -} - -// static -BOOL LLPipeline::getRenderScriptedBeacons(void*) -{ - return sRenderScriptedBeacons; -} - -// static -void LLPipeline::setRenderScriptedTouchBeacons(BOOL val) -{ - sRenderScriptedTouchBeacons = val; -} - -// static -void LLPipeline::toggleRenderScriptedTouchBeacons(void*) -{ - sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons; -} - -// static -BOOL LLPipeline::getRenderScriptedTouchBeacons(void*) -{ - return sRenderScriptedTouchBeacons; -} - -// static -void LLPipeline::setRenderMOAPBeacons(BOOL val) -{ - sRenderMOAPBeacons = val; -} - -// static -void LLPipeline::toggleRenderMOAPBeacons(void*) -{ - sRenderMOAPBeacons = !sRenderMOAPBeacons; -} - -// static -BOOL LLPipeline::getRenderMOAPBeacons(void*) -{ - return sRenderMOAPBeacons; -} - -// static -void LLPipeline::setRenderPhysicalBeacons(BOOL val) -{ - sRenderPhysicalBeacons = val; -} - -// static -void LLPipeline::toggleRenderPhysicalBeacons(void*) -{ - sRenderPhysicalBeacons = !sRenderPhysicalBeacons; -} - -// static -BOOL LLPipeline::getRenderPhysicalBeacons(void*) -{ - return sRenderPhysicalBeacons; -} - -// static -void LLPipeline::setRenderParticleBeacons(BOOL val) -{ - sRenderParticleBeacons = val; -} - -// static -void LLPipeline::toggleRenderParticleBeacons(void*) -{ - sRenderParticleBeacons = !sRenderParticleBeacons; -} - -// static -BOOL LLPipeline::getRenderParticleBeacons(void*) -{ - return sRenderParticleBeacons; -} - -// static -void LLPipeline::setRenderSoundBeacons(BOOL val) -{ - sRenderSoundBeacons = val; -} - -// static -void LLPipeline::toggleRenderSoundBeacons(void*) -{ - sRenderSoundBeacons = !sRenderSoundBeacons; -} - -// static -BOOL LLPipeline::getRenderSoundBeacons(void*) -{ - return sRenderSoundBeacons; -} - -// static -void LLPipeline::setRenderBeacons(BOOL val) -{ - sRenderBeacons = val; -} - -// static -void LLPipeline::toggleRenderBeacons(void*) -{ - sRenderBeacons = !sRenderBeacons; -} - -// static -BOOL LLPipeline::getRenderBeacons(void*) -{ - return sRenderBeacons; -} - -// static -void LLPipeline::setRenderHighlights(BOOL val) -{ - sRenderHighlight = val; -} - -// static -void LLPipeline::toggleRenderHighlights(void*) -{ - sRenderHighlight = !sRenderHighlight; -} - -// static -BOOL LLPipeline::getRenderHighlights(void*) -{ - return sRenderHighlight; -} - -LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, - BOOL pick_transparent, - S32* face_hit, - LLVector3* intersection, // return the intersection point - LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point - ) -{ - LLDrawable* drawable = NULL; - - LLVector3 local_end = end; - - LLVector3 position; - - sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) - { - if ((j == LLViewerRegion::PARTITION_VOLUME) || - (j == LLViewerRegion::PARTITION_BRIDGE) || - (j == LLViewerRegion::PARTITION_TERRAIN) || - (j == LLViewerRegion::PARTITION_TREE) || - (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now - { - LLSpatialPartition* part = region->getSpatialPartition(j); - if (part && hasRenderType(part->mDrawableType)) - { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); - if (hit) - { - drawable = hit; - local_end = position; - } - } - } - } - } - - if (!sPickAvatar) - { - //save hit info in case we need to restore - //due to attachment override - LLVector3 local_normal; - LLVector3 local_binormal; - LLVector2 local_texcoord; - S32 local_face_hit = -1; - - if (face_hit) - { - local_face_hit = *face_hit; - } - if (tex_coord) - { - local_texcoord = *tex_coord; - } - if (bi_normal) - { - local_binormal = *bi_normal; - } - if (normal) - { - local_normal = *normal; - } - - const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f; - - //check against avatars - sPickAvatar = TRUE; - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); - if (part && hasRenderType(part->mDrawableType)) - { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); - if (hit) - { - if (!drawable || - !drawable->getVObj()->isAttachment() || - (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST) - { //avatar overrides if previously hit drawable is not an attachment or - //attachment is far enough away from detected intersection - drawable = hit; - local_end = position; - } - else - { //prioritize attachments over avatars - position = local_end; - - if (face_hit) - { - *face_hit = local_face_hit; - } - if (tex_coord) - { - *tex_coord = local_texcoord; - } - if (bi_normal) - { - *bi_normal = local_binormal; - } - if (normal) - { - *normal = local_normal; - } - } - } - } - } - } - - //check all avatar nametags (silly, isn't it?) - for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); - ++iter) - { - LLVOAvatar* av = (LLVOAvatar*) *iter; - if (av->mNameText.notNull() - && av->mNameText->lineSegmentIntersect(start, local_end, position)) - { - drawable = av->mDrawable; - local_end = position; - } - } - - if (intersection) - { - *intersection = position; - } - - return drawable ? drawable->getVObj().get() : NULL; -} - -LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, - BOOL pick_transparent, - S32* face_hit, - LLVector3* intersection, // return the intersection point - LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point - ) -{ - LLDrawable* drawable = NULL; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - - BOOL toggle = FALSE; - if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - toggle = TRUE; - } - - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); - if (part) - { - LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); - if (hit) - { - drawable = hit; - } - } - - if (toggle) - { - toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - } - return drawable ? drawable->getVObj().get() : NULL; -} - -LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) -{ - if (vobj) - { - LLViewerRegion* region = vobj->getRegion(); - if (region) - { - return region->getSpatialPartition(vobj->getPartitionType()); - } - } - return NULL; -} - -void LLPipeline::resetVertexBuffers(LLDrawable* drawable) -{ - if (!drawable) - { - return; - } - - for (S32 i = 0; i < drawable->getNumFaces(); i++) - { - LLFace* facep = drawable->getFace(i); - facep->clearVertexBuffer(); - } -} - -void LLPipeline::resetVertexBuffers() -{ - mResetVertexBuffers = true; -} - -void LLPipeline::doResetVertexBuffers() -{ - if (!mResetVertexBuffers) - { - return; - } - - mResetVertexBuffers = false; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->resetVertexBuffers(); - } - } - } - - resetDrawOrders(); - - gSky.resetVertexBuffers(); - - LLVertexBuffer::cleanupClass(); - - //delete all name pool caches - LLGLNamePool::cleanupPools(); - - if (LLVertexBuffer::sGLCount > 0) - { - llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl; - } - - LLVertexBuffer::unbind(); - - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); - LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); - LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ; - sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); - sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); - LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); - - LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping); -} - -void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) -{ - LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS); - assertInitialized(); - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; - mSimplePool->pushBatches(type, mask, texture, batch_texture); - gGL.loadMatrix(gGLModelView); - gGLLastMatrix = NULL; -} - -void apply_cube_face_rotation(U32 face) -{ - switch (face) - { - case 0: - gGL.rotatef(90.f, 0, 1, 0); - gGL.rotatef(180.f, 1, 0, 0); - break; - case 2: - gGL.rotatef(-90.f, 1, 0, 0); - break; - case 4: - gGL.rotatef(180.f, 0, 1, 0); - gGL.rotatef(180.f, 0, 0, 1); - break; - case 1: - gGL.rotatef(-90.f, 0, 1, 0); - gGL.rotatef(180.f, 1, 0, 0); - break; - case 3: - gGL.rotatef(90, 1, 0, 0); - break; - case 5: - gGL.rotatef(180, 0, 0, 1); - break; - } -} - -void validate_framebuffer_object() -{ - GLenum status; - status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); - switch(status) - { - case GL_FRAMEBUFFER_COMPLETE: - //framebuffer OK, no error. - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Missing Attachment." << llendl; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Attachment." << llendl; - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - /* choose different formats */ - llerrs << "Framebuffer unsupported." << llendl; - break; - default: - llerrs << "Unknown framebuffer status." << llendl; - break; - } -} - -void LLPipeline::bindScreenToTexture() -{ - -} - -static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); - -void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) -{ - LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM); - if (!(gPipeline.canUseVertexShaders() && - sRenderGlow)) - { - return; - } - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - - assertInitialized(); - - if (gUseWireframe) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - LLVector2 tc1(0,0); - LLVector2 tc2((F32) mScreen.getWidth()*2, - (F32) mScreen.getHeight()*2); - - LLFastTimer ftm(FTM_RENDER_BLOOM); - gGL.color4f(1,1,1,1); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable cull(GL_CULL_FACE); - - enableLightsFullbright(LLColor4(1,1,1,1)); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); - - LLGLDisable test(GL_ALPHA_TEST); - - gGL.setColorMask(true, true); - glClearColor(0,0,0,0); - - { - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - mGlow[2].bindTarget(); - mGlow[2].clear(); - } - - gGlowExtractProgram.bind(); - F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); - F32 maxAlpha = RenderGlowMaxExtractAlpha; - F32 warmthAmount = RenderGlowWarmthAmount; - LLVector3 lumWeights = RenderGlowLumWeights; - LLVector3 warmthWeights = RenderGlowWarmthWeights; - - - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); - gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]); - gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]); - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount); - LLGLEnable blend_on(GL_BLEND); - LLGLEnable test(GL_ALPHA_TEST); - - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - mScreen.bindTexture(0, 0); - - gGL.color4f(1,1,1,1); - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - gGL.getTexUnit(0)->unbind(mScreen.getUsage()); - - mGlow[2].flush(); - } - - tc1.setVec(0,0); - tc2.setVec(2,2); - - // power of two between 1 and 1024 - U32 glowResPow = RenderGlowResolutionPow; - const U32 glow_res = llmax(1, - llmin(1024, 1 << glowResPow)); - - S32 kernel = RenderGlowIterations*2; - F32 delta = RenderGlowWidth / glow_res; - // Use half the glow width if we have the res set to less than 9 so that it looks - // almost the same in either case. - if (glowResPow < 9) - { - delta *= 0.5f; - } - F32 strength = RenderGlowStrength; - - gGlowProgram.bind(); - gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); - - for (S32 i = 0; i < kernel; i++) - { - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - mGlow[i%2].bindTarget(); - mGlow[i%2].clear(); - } - - if (i == 0) - { - gGL.getTexUnit(0)->bind(&mGlow[2]); - } - else - { - gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]); - } - - if (i%2 == 0) - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); - } - else - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); - } - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - mGlow[i%2].flush(); - } - - gGlowProgram.unbind(); - - if (LLRenderTarget::sUseFBO) - { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - tc2.setVec((F32) mScreen.getWidth(), - (F32) mScreen.getHeight()); - - gGL.flush(); - - LLVertexBuffer::unbind(); - - if (LLPipeline::sRenderDeferred) - { - - bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && - !LLToolMgr::getInstance()->inBuildMode() && - RenderDepthOfField; - - - bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); - - gViewerWindow->setup3DViewport(); - - if (dof_enabled) - { - LLGLSLShader* shader = &gDeferredPostProgram; - LLGLDisable blend(GL_BLEND); - - //depth of field focal plane calculations - static F32 current_distance = 16.f; - static F32 start_distance = 16.f; - static F32 transition_time = 1.f; - - LLVector3 focus_point; - - LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); - if (obj && obj->mDrawable && obj->isSelected()) - { //focus on selected media object - S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); - if (obj && obj->mDrawable) - { - LLFace* face = obj->mDrawable->getFace(face_idx); - if (face) - { - focus_point = face->getPositionAgent(); - } - } - } - - if (focus_point.isExactlyZero()) - { - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { //focus on point under cursor - focus_point = gDebugRaycastIntersection; - } - else if (gAgentCamera.cameraMouselook()) - { //focus on point under mouselook crosshairs - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, - NULL, - &focus_point); - } - else - { - LLViewerObject* obj = gAgentCamera.getFocusObject(); - if (obj) - { //focus on alt-zoom target - focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal()); - } - else - { //focus on your avatar - focus_point = gAgent.getPositionAgent(); - } - } - } - - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - F32 target_distance = 16.f; - if (!focus_point.isExactlyZero()) - { - target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye); - } - - if (transition_time >= 1.f && - fabsf(current_distance-target_distance)/current_distance > 0.01f) - { //large shift happened, interpolate smoothly to new target distance - transition_time = 0.f; - start_distance = current_distance; - } - else if (transition_time < 1.f) - { //currently in a transition, continue interpolating - transition_time += 1.f/CameraFocusTransitionTime*gFrameIntervalSeconds; - transition_time = llmin(transition_time, 1.f); - - F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f; - current_distance = start_distance + (target_distance-start_distance)*t; - } - else - { //small or no change, just snap to target distance - current_distance = target_distance; - } - - //convert to mm - F32 subject_distance = current_distance*1000.f; - F32 fnumber = CameraFNumber; - F32 default_focal_length = CameraFocalLength; - - F32 fov = LLViewerCamera::getInstance()->getView(); - - const F32 default_fov = CameraFieldOfView * F_PI/180.f; - //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio"); - - //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); - - F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f); - //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f); - - F32 focal_length = dv/(2*tanf(fov/2.f)); - - //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); - - // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) - // where N = fnumber - // s2 = dot distance - // s1 = subject distance - // f = focal length - // - - F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); - blur_constant /= 1000.f; //convert to meters for shader - F32 magnification = focal_length/(subject_distance-focal_length); - - { //build diffuse+bloom+CoF - mDeferredLight.bindTarget(); - shader = &gDeferredCoFProgram; - - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - } - - shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f); - shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); - shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f/LLDrawable::sCurPixelAngle)); - shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); - mDeferredLight.flush(); - } - - { //perform DoF sampling at half-res (preserve alpha channel) - mScreen.bindTarget(); - glViewport(0,0,(GLsizei) (mScreen.getWidth()*CameraDoFResScale), (GLsizei) (mScreen.getHeight()*CameraDoFResScale)); - gGL.setColorMask(true, false); - - shader = &gDeferredPostProgram; - bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - if (channel > -1) - { - mDeferredLight.bindTexture(0, channel); - } - - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); - mScreen.flush(); - gGL.setColorMask(true, true); - } - - { //combine result based on alpha - if (multisample) - { - mDeferredLight.bindTarget(); - glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); - } - else - { - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - } - - shader = &gDeferredDoFCombineProgram; - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); - - if (multisample) - { - mDeferredLight.flush(); - } - } - } - else - { - if (multisample) - { - mDeferredLight.bindTarget(); - } - LLGLSLShader* shader = &gDeferredPostNoDoFProgram; - - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - } - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); - - if (multisample) - { - mDeferredLight.flush(); - } - } - - if (multisample) - { - //bake out texture2D with RGBL for FXAA shader - mFXAABuffer.bindTarget(); - - S32 width = mScreen.getWidth(); - S32 height = mScreen.getHeight(); - glViewport(0, 0, width, height); - - LLGLSLShader* shader = &gGlowCombineFXAAProgram; - - shader->bind(); - shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - if (channel > -1) - { - mDeferredLight.bindTexture(0, channel); - } - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); - - gGL.flush(); - - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - shader->unbind(); - - mFXAABuffer.flush(); - - shader = &gFXAAProgram; - shader->bind(); - - channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage()); - if (channel > -1) - { - mFXAABuffer.bindTexture(0, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - } - - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - F32 scale_x = (F32) width/mFXAABuffer.getWidth(); - F32 scale_y = (F32) height/mFXAABuffer.getHeight(); - shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); - shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width*scale_x, 1.f/height*scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width*scale_x, -0.5f/height*scale_y, 0.5f/width*scale_x, 0.5f/height*scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width*scale_x, -2.f/height*scale_y, 2.f/width*scale_x, 2.f/height*scale_y); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); - - gGL.flush(); - shader->unbind(); - } - } - else - { - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0); - buff->allocateBuffer(3,0,TRUE); - - LLStrider<LLVector3> v; - LLStrider<LLVector2> uv1; - LLStrider<LLVector2> uv2; - - buff->getVertexStrider(v); - buff->getTexCoord0Strider(uv1); - buff->getTexCoord1Strider(uv2); - - uv1[0] = LLVector2(0, 0); - uv1[1] = LLVector2(0, 2); - uv1[2] = LLVector2(2, 0); - - uv2[0] = LLVector2(0, 0); - uv2[1] = LLVector2(0, tc2.mV[1]*2.f); - uv2[2] = LLVector2(tc2.mV[0]*2.f, 0); - - v[0] = LLVector3(-1,-1,0); - v[1] = LLVector3(-1,3,0); - v[2] = LLVector3(3,-1,0); - - buff->flush(); - - LLGLDisable blend(GL_BLEND); - - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.bind(); - } - else - { - //tex unit 0 - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - //tex unit 1 - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); - } - - gGL.getTexUnit(0)->bind(&mGlow[1]); - gGL.getTexUnit(1)->bind(&mScreen); - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - buff->setBuffer(mask); - buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); - - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.unbind(); - } - else - { - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); - - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } - - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) - { - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.bind(); - } - - gGL.setColorMask(true, false); - - LLVector2 tc1(0,0); - LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, - (F32) gViewerWindow->getWorldViewHeightRaw()*2); - - LLGLEnable blend(GL_BLEND); - gGL.color4f(1,1,1,0.75f); - - gGL.getTexUnit(0)->bind(&mPhysicsDisplay); - - gGL.begin(LLRender::TRIANGLES); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - gGL.flush(); - - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.unbind(); - } - } - - - if (LLRenderTarget::sUseFBO) - { //copy depth buffer from mScreen to framebuffer - LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), - 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - -} - -static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); - -void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map) -{ - LLFastTimer t(FTM_BIND_DEFERRED); - - if (noise_map == 0xFFFFFFFF) - { - noise_map = mNoiseMap; - } - - shader.bind(); - S32 channel = 0; - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); - if (channel > -1) - { - mDeferredScreen.bindTexture(0,channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); - if (channel > -1) - { - mDeferredScreen.bindTexture(1, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); - if (channel > -1) - { - mDeferredScreen.bindTexture(2, channel); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); - if (channel > -1) - { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); - stop_glerror(); - - //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); - - stop_glerror(); - - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f inv_proj = projection.inverse(); - - shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); - shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0], - (F32) gGLViewport[1], - (F32) gGLViewport[2], - (F32) gGLViewport[3]); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE); - if (channel > -1) - { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC); - if (channel > -1) - { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); - } - - stop_glerror(); - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); - if (channel > -1) - { - if (light_index > 0) - { - mScreen.bindTexture(0, channel); - } - else - { - mDeferredLight.bindTexture(0, channel); - } - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - channel = shader.enableTexture(LLShaderMgr::DEFERRED_BLOOM); - if (channel > -1) - { - mGlow[1].bindTexture(0, channel); - } - - stop_glerror(); - - for (U32 i = 0; i < 4; i++) - { - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); - stop_glerror(); - if (channel > -1) - { - stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - stop_glerror(); - } - } - - for (U32 i = 4; i < 6; i++) - { - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i); - stop_glerror(); - if (channel > -1) - { - stop_glerror(); - gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - stop_glerror(); - } - } - - stop_glerror(); - - F32 mat[16*6]; - for (U32 i = 0; i < 16; i++) - { - mat[i] = mSunShadowMatrix[0].m[i]; - mat[i+16] = mSunShadowMatrix[1].m[i]; - mat[i+32] = mSunShadowMatrix[2].m[i]; - mat[i+48] = mSunShadowMatrix[3].m[i]; - mat[i+64] = mSunShadowMatrix[4].m[i]; - mat[i+80] = mSunShadowMatrix[5].m[i]; - } - - shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); - - stop_glerror(); - - channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - if (channel > -1) - { - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if (cube_map) - { - cube_map->enable(channel); - cube_map->bind(); - F32* m = gGLModelView; - - F32 mat[] = { m[0], m[1], m[2], - m[4], m[5], m[6], - m[8], m[9], m[10] }; - - shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat); - } - } - - shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); - shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise); - shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize); - - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale); - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale); - - F32 ssao_factor = RenderSSAOFactor; - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor); - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0/ssao_factor); - - LLVector3 ssao_effect = RenderSSAOEffect; - F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0; - F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0; - // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by - // value factor, and scales remainder by saturation factor - F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag, - matrix_nondiag, matrix_diag, matrix_nondiag, - matrix_nondiag, matrix_nondiag, matrix_diag}; - shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat); - - F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - F32 shadow_bias_error = 1.f + RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - - shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); - shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear()*2.f); - shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset*shadow_offset_error); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias*shadow_bias_error); - shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset); - shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias); - - shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV); - shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight()); - shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight()); - shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); - shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); - - - if (shader.getUniformLocation("norm_mat") >= 0) - { - glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); - shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m); - } -} - -static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); -static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); -static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); -static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); -static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); -static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); -static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); -static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); -static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); -static LLFastTimer::DeclareTimer FTM_POST("Post"); - - -void LLPipeline::renderDeferredLighting() -{ - if (!sCull) - { - return; - } - - { - LLFastTimer ftm(FTM_RENDER_DEFERRED); - - LLViewerCamera* camera = LLViewerCamera::getInstance(); - { - LLGLDepthTest depth(GL_TRUE); - mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - - if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) - { - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); - } - - //ati doesn't seem to love actually using the stencil buffer on FBO's - LLGLDisable stencil(GL_STENCIL_TEST); - //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); - //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - gGL.setColorMask(true, true); - - //draw a cube around every light - LLVertexBuffer::unbind(); - - LLGLEnable cull(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - - glh::matrix4f mat = glh_copy_matrix(gGLModelView); - - LLStrider<LLVector3> vert; - mDeferredVB->getVertexStrider(vert); - LLStrider<LLVector2> tc0; - LLStrider<LLVector2> tc1; - mDeferredVB->getTexCoord0Strider(tc0); - mDeferredVB->getTexCoord1Strider(tc1); - - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - - { - setupHWLights(NULL); //to set mSunDir; - LLVector4 dir(mSunDir, 0.f); - glh::vec4f tc(dir.mV); - mat.mult_matrix_vec(tc); - mTransformedSunDir.set(tc.v); - } - - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - if (RenderDeferredSSAO || RenderShadowDetail > 0) - { - mDeferredLight.bindTarget(); - { //paint shadow/SSAO light map (direct lighting lightmap) - LLFastTimer ftm(FTM_SUN_SHADOW); - bindDeferredShader(gDeferredSunProgram, 0); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glClearColor(1,1,1,1); - mDeferredLight.clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); - - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); - - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) - { - for (U32 j = 0; j < 8; j++) - { - glh::vec3f v; - v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); - v.normalize(); - inv_trans.mult_matrix_vec(v); - v.normalize(); - offset[(i*8+j)*3+0] = v.v[0]; - offset[(i*8+j)*3+1] = v.v[2]; - offset[(i*8+j)*3+2] = v.v[1]; - } - } - - gDeferredSunProgram.uniform3fv("offset", slice, offset); - gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight()); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - - unbindDeferredShader(gDeferredSunProgram); - } - mDeferredLight.flush(); - } - - if (RenderDeferredSSAO) - { //soften direct lighting lightmap - LLFastTimer ftm(FTM_SOFTEN_SHADOW); - //blur lightmap - mScreen.bindTarget(); - glClearColor(1,1,1,1); - mScreen.clear(GL_COLOR_BUFFER_BIT); - glClearColor(0,0,0,0); - - bindDeferredShader(gDeferredBlurLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - LLVector3 go = RenderShadowGaussian; - const U32 kern_length = 4; - F32 blur_size = RenderShadowBlurSize; - F32 dist_factor = RenderShadowBlurDistFactor; - - // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = 0.f; - - LLVector3 gauss[32]; // xweight, yweight, offset - - for (U32 i = 0; i < kern_length; i++) - { - gauss[i].mV[0] = llgaussian(x, go.mV[0]); - gauss[i].mV[1] = llgaussian(x, go.mV[1]); - gauss[i].mV[2] = x; - x += 1.f; - } - - gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); - gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor); - gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - - mScreen.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - - bindDeferredShader(gDeferredBlurLightProgram, 1); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - mDeferredLight.bindTarget(); - - gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } - mDeferredLight.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - } - - stop_glerror(); - gGL.popMatrix(); - stop_glerror(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - stop_glerror(); - gGL.popMatrix(); - stop_glerror(); - - //copy depth and stencil from deferred screen - //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); - - mScreen.bindTarget(); - // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky - glClearColor(0,0,0,0); - mScreen.clear(GL_COLOR_BUFFER_BIT); - - if (RenderDeferredAtmospheric) - { //apply sunlight contribution - LLFastTimer ftm(FTM_ATMOSPHERICS); - bindDeferredShader(gDeferredSoftenProgram); - { - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - - //full screen blit - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - - unbindDeferredShader(gDeferredSoftenProgram); - } - - { //render non-deferred geometry (fullbright, alpha, etc) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gPipeline.pushRenderTypeMask(); - - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - - renderGeomPostDeferred(*LLViewerCamera::getInstance()); - gPipeline.popRenderTypeMask(); - } - - BOOL render_local = RenderLocalLights; - - if (render_local) - { - gGL.setSceneBlendType(LLRender::BT_ADD); - std::list<LLVector4> fullscreen_lights; - LLDrawable::drawable_list_t spot_lights; - LLDrawable::drawable_list_t fullscreen_spot_lights; - - for (U32 i = 0; i < 2; i++) - { - mTargetShadowSpotLight[i] = NULL; - } - - std::list<LLVector4> light_colors; - - LLVertexBuffer::unbind(); - LLVector4a* v = (LLVector4a*) vert.get(); - - { - bindDeferredShader(gDeferredLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) - { - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - if (!volume) - { - continue; - } - - if (volume->isAttachment()) - { - if (!sRenderAttachedLights) - { - continue; - } - } - - - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; - - LLColor3 col = volume->getLightColor(); - - if (col.magVecSquared() < 0.001f) - { - continue; - } - - if (s <= 0.001f) - { - continue; - } - - LLVector4a sa; - sa.splat(s); - if (camera->AABBInFrustumNoFarClip(center, sa) == 0) - { - continue; - } - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - - if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || - camera->getOrigin().mV[0] < c[0] - s - 0.2f || - camera->getOrigin().mV[1] > c[1] + s + 0.2f || - camera->getOrigin().mV[1] < c[1] - s - 0.2f || - camera->getOrigin().mV[2] > c[2] + s + 0.2f || - camera->getOrigin().mV[2] < c[2] - s - 0.2f) - { //draw box if camera is outside box - if (render_local) - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - spot_lights.push_back(drawablep); - continue; - } - - LLFastTimer ftm(FTM_LOCAL_LIGHTS); - //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); - gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); - gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); - gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); - gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); - stop_glerror(); - } - } - else - { - if (volume->isLightSpotlight()) - { - drawablep->getVOVolume()->updateSpotLightPriority(); - fullscreen_spot_lights.push_back(drawablep); - continue; - } - - fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); - light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); - } - } - unbindDeferredShader(gDeferredLightProgram); - } - - if (!spot_lights.empty()) - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - bindDeferredShader(gDeferredSpotLightProgram); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); - - for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) - { - LLFastTimer ftm(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - - LLVector4a center; - center.load3(drawablep->getPositionAgent().mV); - const F32* c = center.getF32ptr(); - F32 s = volume->getLightRadius()*1.5f; - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - setupSpotLight(gDeferredSpotLightProgram, drawablep); - - LLColor3 col = volume->getLightColor(); - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - - gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); - gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); - gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); - gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); - } - gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredSpotLightProgram); - } - - //reset mDeferredVB to fullscreen triangle - mDeferredVB->getVertexStrider(vert); - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - - { - bindDeferredShader(gDeferredMultiLightProgram); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - LLGLDepthTest depth(GL_FALSE); - - //full screen blit - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - U32 count = 0; - - const U32 max_count = 8; - LLVector4 light[max_count]; - LLVector4 col[max_count]; - -// glVertexPointer(2, GL_FLOAT, 0, vert); - - F32 far_z = 0.f; - - while (!fullscreen_lights.empty()) - { - LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); - light[count] = fullscreen_lights.front(); - fullscreen_lights.pop_front(); - col[count] = light_colors.front(); - light_colors.pop_front(); - - far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); - - count++; - if (count == max_count || fullscreen_lights.empty()) - { - gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); - gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light); - gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col); - gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); - far_z = 0.f; - count = 0; - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - } - - unbindDeferredShader(gDeferredMultiLightProgram); - - bindDeferredShader(gDeferredMultiSpotLightProgram); - - gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) - { - LLFastTimer ftm(FTM_PROJECTORS); - LLDrawable* drawablep = *iter; - - LLVOVolume* volume = drawablep->getVOVolume(); - - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; - F32 s = volume->getLightRadius()*1.5f; - - sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); - - LLColor3 col = volume->getLightColor(); - - gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); - gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); - gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); - gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - - gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); - unbindDeferredShader(gDeferredMultiSpotLightProgram); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - } - - gGL.setColorMask(true, true); - } - - { //render non-deferred geometry (alpha, fullbright, glow) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); - - pushRenderTypeMask(); - andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_GLOW, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_POST_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - LLPipeline::RENDER_TYPE_PASS_GLOW, - LLPipeline::RENDER_TYPE_PASS_GRASS, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, - LLPipeline::RENDER_TYPE_AVATAR, - END_RENDER_TYPES); - - renderGeomPostDeferred(*LLViewerCamera::getInstance()); - popRenderTypeMask(); - } - - { - //render highlights, etc. - renderHighlights(); - mHighlightFaces.clear(); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - gObjectList.resetObjectBeacons(); - } - } - - mScreen.flush(); - -} - -void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) -{ - //construct frustum - LLVOVolume* volume = drawablep->getVOVolume(); - LLVector3 params = volume->getSpotLightParams(); - - F32 fov = params.mV[0]; - F32 focus = params.mV[1]; - - LLVector3 pos = drawablep->getPositionAgent(); - LLQuaternion quat = volume->getRenderRotation(); - LLVector3 scale = volume->getScale(); - - //get near clip plane - LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); - at_axis *= quat; - - LLVector3 np = pos+at_axis; - at_axis.normVec(); - - //get origin that has given fov for plane np, at_axis, and given scale - F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); - - LLVector3 origin = np - at_axis*dist; - - //matrix from volume space to agent space - LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); - - glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); - glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; - - glh::matrix4f screen_to_light = light_to_screen.inverse(); - - F32 s = volume->getLightRadius()*1.5f; - F32 near_clip = dist; - F32 width = scale.mV[VX]; - F32 height = scale.mV[VY]; - F32 far_clip = s+dist-scale.mV[VZ]; - - F32 fovy = fov * RAD_TO_DEG; - F32 aspect = width/height; - - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh::vec3f p1(0, 0, -(near_clip+0.01f)); - glh::vec3f p2(0, 0, -(near_clip+1.f)); - - glh::vec3f screen_origin(0, 0, 0); - - light_to_screen.mult_matrix_vec(p1); - light_to_screen.mult_matrix_vec(p2); - light_to_screen.mult_matrix_vec(screen_origin); - - glh::vec3f n = p2-p1; - n.normalize(); - - F32 proj_range = far_clip - near_clip; - glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); - screen_to_light = trans * light_proj * screen_to_light; - shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m); - shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip); - shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v); - shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v); - shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v); - shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range); - shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]); - S32 s_idx = -1; - - for (U32 i = 0; i < 2; i++) - { - if (mShadowSpotLight[i] == drawablep) - { - s_idx = i; - } - } - - shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx); - - if (s_idx >= 0) - { - shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]); - } - else - { - shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f); - } - - { - LLDrawable* potential = drawablep; - //determine if this is a good light for casting shadows - F32 m_pri = volume->getSpotLightPriority(); - - for (U32 i = 0; i < 2; i++) - { - F32 pri = 0.f; - - if (mTargetShadowSpotLight[i].notNull()) - { - pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority(); - } - - if (m_pri > pri) - { - LLDrawable* temp = mTargetShadowSpotLight[i]; - mTargetShadowSpotLight[i] = potential; - potential = temp; - m_pri = pri; - } - } - } - - LLViewerTexture* img = volume->getLightTexture(); - - if (img == NULL) - { - img = LLViewerFetchedTexture::sWhiteImagep; - } - - S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); - - if (channel > -1) - { - if (img) - { - gGL.getTexUnit(channel)->bind(img); - - F32 lod_range = logf(img->getWidth())/logf(2.f); - - shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus); - shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range); - shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f)); - } - } - -} - -void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) -{ - stop_glerror(); - shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); - shader.disableTexture(LLShaderMgr::DIFFUSE_MAP); - shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM); - - for (U32 i = 0; i < 4; i++) - { - if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) - { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - } - } - - for (U32 i = 4; i < 6; i++) - { - if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i) > -1) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); - } - } - - shader.disableTexture(LLShaderMgr::DEFERRED_NOISE); - shader.disableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC); - - S32 channel = shader.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - if (channel > -1) - { - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if (cube_map) - { - cube_map->disable(); - } - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->activate(); - shader.unbind(); -} - -inline float sgn(float a) -{ - if (a > 0.0F) return (1.0F); - if (a < 0.0F) return (-1.0F); - return (0.0F); -} - -void LLPipeline::generateWaterReflection(LLCamera& camera_in) -{ - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) - { - BOOL skip_avatar_update = FALSE; - if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) - { - skip_avatar_update = TRUE; - } - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); - } - LLVertexBuffer::unbind(); - - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - LLCamera camera = camera_in; - camera.setFar(camera.getFar()*0.87654321f); - LLPipeline::sReflectionRender = TRUE; - - gPipeline.pushRenderTypeMask(); - - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f mat; - - stop_glerror(); - LLPlane plane; - - F32 height = gAgent.getRegion()->getWaterHeight(); - F32 to_clip = fabsf(camera.getOrigin().mV[2]-height); - F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by - - //plane params - LLVector3 pnorm; - F32 pd; - - S32 water_clip = 0; - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - pd = -height; - plane.setVec(pnorm, pd); - water_clip = -1; - } - else - { //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - pd = height; - plane.setVec(pnorm, pd); - water_clip = 1; - } - - if (!LLViewerCamera::getInstance()->cameraUnderWater()) - { //generate planar reflection map - - //disable occlusion culling for reflection map for now - S32 occlusion = LLPipeline::sUseOcclusion; - LLPipeline::sUseOcclusion = 0; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glClearColor(0,0,0,0); - mWaterRef.bindTarget(); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0; - gGL.setColorMask(true, true); - mWaterRef.clear(); - gGL.setColorMask(true, false); - - mWaterRef.getViewport(gGLViewport); - - stop_glerror(); - - gGL.pushMatrix(); - - mat.set_scale(glh::vec3f(1,1,-1)); - mat.set_translate(glh::vec3f(0,0,height*2.f)); - - glh::matrix4f current = glh_get_current_modelview(); - - mat = current * mat; - - glh_set_current_modelview(mat); - gGL.loadMatrix(mat.m); - - LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); - - glh::matrix4f inv_mat = mat.inverse(); - - glh::vec3f origin(0,0,0); - inv_mat.mult_matrix_vec(origin); - - camera.setOrigin(origin.v); - - glCullFace(GL_FRONT); - - static LLCullResult ref_result; - - if (LLDrawPoolWater::sNeedsReflectionUpdate) - { - //initial sky pass (no user clip plane) - { //mask out everything but the sky - gPipeline.pushRenderTypeMask(); - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::END_RENDER_TYPES); - - static LLCullResult result; - updateCull(camera, result); - stateSort(camera, result); - - renderGeom(camera, TRUE); - - gPipeline.popRenderTypeMask(); - } - - gPipeline.pushRenderTypeMask(); - - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::END_RENDER_TYPES); - - S32 detail = RenderReflectionDetail; - if (detail > 0) - { //mask out selected geometry based on reflection detail - if (detail < 4) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); - if (detail < 3) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - if (detail < 2) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); - } - } - } - - LLGLUserClipPlane clip_plane(plane, mat, projection); - LLGLDisable cull(GL_CULL_FACE); - updateCull(camera, ref_result, -water_clip, &plane); - stateSort(camera, ref_result); - } - - if (LLDrawPoolWater::sNeedsDistortionUpdate) - { - if (RenderReflectionDetail > 0) - { - gPipeline.grabReferences(ref_result); - LLGLUserClipPlane clip_plane(plane, mat, projection); - renderGeom(camera); - } - } - - gPipeline.popRenderTypeMask(); - } - glCullFace(GL_BACK); - gGL.popMatrix(); - mWaterRef.flush(); - glh_set_current_modelview(current); - LLPipeline::sUseOcclusion = occlusion; - } - - camera.setOrigin(camera_in.getOrigin()); - //render distortion map - static BOOL last_update = TRUE; - if (last_update) - { - camera.setFar(camera_in.getFar()); - clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_GROUND, - END_RENDER_TYPES); - stop_glerror(); - - LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE; - - if (LLPipeline::sUnderWaterRender) - { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, - LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - END_RENDER_TYPES); - } - LLViewerCamera::updateFrustumPlanes(camera); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLColor4& col = LLDrawPoolWater::sWaterFogColor; - glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - mWaterDis.bindTarget(); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; - mWaterDis.getViewport(gGLViewport); - - if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) - { - //clip out geometry on the same side of water as the camera - mat = glh_get_current_modelview(); - LLPlane plane(-pnorm, -(pd+pad)); - - LLGLUserClipPlane clip_plane(plane, mat, projection); - static LLCullResult result; - updateCull(camera, result, water_clip, &plane); - stateSort(camera, result); - - gGL.setColorMask(true, true); - mWaterDis.clear(); - gGL.setColorMask(true, false); - - renderGeom(camera); - } - - LLPipeline::sUnderWaterRender = FALSE; - mWaterDis.flush(); - } - last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; - - LLRenderTarget::unbindTarget(); - - LLPipeline::sReflectionRender = FALSE; - - if (!LLRenderTarget::sUseFBO) - { - glClear(GL_DEPTH_BUFFER_BIT); - } - glClearColor(0.f, 0.f, 0.f, 0.f); - gViewerWindow->setup3DViewport(); - gPipeline.popRenderTypeMask(); - LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; - LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; - LLPlane npnorm(-pnorm, -pd); - LLViewerCamera::getInstance()->setUserClipPlane(npnorm); - - LLGLState::checkStates(); - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); - } - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - } -} - -glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) -{ - glh::matrix4f ret; - - LLVector3 dirN; - LLVector3 upN; - LLVector3 lftN; - - lftN = dir % up; - lftN.normVec(); - - upN = lftN % dir; - upN.normVec(); - - dirN = dir; - dirN.normVec(); - - ret.m[ 0] = lftN[0]; - ret.m[ 1] = upN[0]; - ret.m[ 2] = -dirN[0]; - ret.m[ 3] = 0.f; - - ret.m[ 4] = lftN[1]; - ret.m[ 5] = upN[1]; - ret.m[ 6] = -dirN[1]; - ret.m[ 7] = 0.f; - - ret.m[ 8] = lftN[2]; - ret.m[ 9] = upN[2]; - ret.m[10] = -dirN[2]; - ret.m[11] = 0.f; - - ret.m[12] = -(lftN*pos); - ret.m[13] = -(upN*pos); - ret.m[14] = dirN*pos; - ret.m[15] = 1.f; - - return ret; -} - -glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) -{ - glh::matrix4f ret; - ret.m[ 0] = 2/(max[0]-min[0]); - ret.m[ 4] = 0; - ret.m[ 8] = 0; - ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]); - - ret.m[ 1] = 0; - ret.m[ 5] = 2/(max[1]-min[1]); - ret.m[ 9] = 0; - ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]); - - ret.m[ 2] = 0; - ret.m[ 6] = 0; - ret.m[10] = 2/(max[2]-min[2]); - ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]); - - ret.m[ 3] = 0; - ret.m[ 7] = 0; - ret.m[11] = 0; - ret.m[15] = 1; - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); -static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); -static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); - -void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion) -{ - LLFastTimer t(FTM_SHADOW_RENDER); - - //clip out geometry on the same side of water as the camera - S32 occlude = LLPipeline::sUseOcclusion; - if (!use_occlusion) - { - LLPipeline::sUseOcclusion = 0; - } - LLPipeline::sShadowRender = TRUE; - - U32 types[] = { - LLRenderPass::PASS_SIMPLE, - LLRenderPass::PASS_FULLBRIGHT, - LLRenderPass::PASS_SHINY, - LLRenderPass::PASS_BUMP, - LLRenderPass::PASS_FULLBRIGHT_SHINY - }; - - LLGLEnable cull(GL_CULL_FACE); - - if (use_shader) - { - gDeferredShadowProgram.bind(); - } - - updateCull(shadow_cam, result); - stateSort(shadow_cam, result); - - //generate shadow map - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadMatrix(proj.m); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); - - stop_glerror(); - gGLLastMatrix = NULL; - - { - //LLGLDepthTest depth(GL_TRUE); - //glClear(GL_DEPTH_BUFFER_BIT); - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - stop_glerror(); - - //glCullFace(GL_FRONT); - - LLVertexBuffer::unbind(); - - { - if (!use_shader) - { //occlusion program is general purpose depth-only no-textures - gOcclusionProgram.bind(); - } - - gGL.diffuseColor4f(1,1,1,1); - gGL.setColorMask(false, false); - - LLFastTimer ftm(FTM_SHADOW_SIMPLE); - gGL.getTexUnit(0)->disable(); - for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) - { - renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); - } - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - if (!use_shader) - { - gOcclusionProgram.unbind(); - } - } - - if (use_shader) - { - gDeferredShadowProgram.unbind(); - renderGeomShadow(shadow_cam); - gDeferredShadowProgram.bind(); - } - else - { - renderGeomShadow(shadow_cam); - } - - { - LLFastTimer ftm(FTM_SHADOW_ALPHA); - gDeferredShadowAlphaMaskProgram.bind(); - gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); - - U32 mask = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_TEXTURE_INDEX; - - renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); - renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); - renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE); - gDeferredTreeShadowProgram.bind(); - gDeferredTreeShadowProgram.setMinimumAlpha(0.598f); - renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); - } - - //glCullFace(GL_BACK); - - gDeferredShadowProgram.bind(); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - doOcclusion(shadow_cam); - - if (use_shader) - { - gDeferredShadowProgram.unbind(); - } - - gGL.setColorMask(true, true); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - gGLLastMatrix = NULL; - - LLPipeline::sUseOcclusion = occlude; - LLPipeline::sShadowRender = FALSE; -} - -static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); -BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir) -{ - LLFastTimer t(FTM_VISIBLE_CLOUD); - //get point cloud of intersection of frust and min, max - - if (getVisibleExtents(camera, min, max)) - { - return FALSE; - } - - //get set of planes on bounding box - LLPlane bp[] = { - LLPlane(min, LLVector3(-1,0,0)), - LLPlane(min, LLVector3(0,-1,0)), - LLPlane(min, LLVector3(0,0,-1)), - LLPlane(max, LLVector3(1,0,0)), - LLPlane(max, LLVector3(0,1,0)), - LLPlane(max, LLVector3(0,0,1))}; - - //potential points - std::vector<LLVector3> pp; - - //add corners of AABB - pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2])); - pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2])); - pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2])); - pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2])); - pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2])); - pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2])); - pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2])); - pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); - - //add corners of camera frustum - for (U32 i = 0; i < 8; i++) - { - pp.push_back(camera.mAgentFrustum[i]); - } - - - //bounding box line segments - U32 bs[] = - { - 0,1, - 1,3, - 3,2, - 2,0, - - 4,5, - 5,7, - 7,6, - 6,4, - - 0,4, - 1,5, - 3,7, - 2,6 - }; - - for (U32 i = 0; i < 12; i++) - { //for each line segment in bounding box - for (U32 j = 0; j < 6; j++) - { //for each plane in camera frustum - const LLPlane& cp = camera.getAgentPlane(j); - const LLVector3& v1 = pp[bs[i*2+0]]; - const LLVector3& v2 = pp[bs[i*2+1]]; - LLVector3 n; - cp.getVector3(n); - - LLVector3 line = v1-v2; - - F32 d1 = line*n; - F32 d2 = -cp.dist(v2); - - F32 t = d2/d1; - - if (t > 0.f && t < 1.f) - { - LLVector3 intersect = v2+line*t; - pp.push_back(intersect); - } - } - } - - //camera frustum line segments - const U32 fs[] = - { - 0,1, - 1,2, - 2,3, - 3,0, - - 4,5, - 5,6, - 6,7, - 7,4, - - 0,4, - 1,5, - 2,6, - 3,7 - }; - - LLVector3 center = (max+min)*0.5f; - LLVector3 size = (max-min)*0.5f; - - for (U32 i = 0; i < 12; i++) - { - for (U32 j = 0; j < 6; ++j) - { - const LLVector3& v1 = pp[fs[i*2+0]+8]; - const LLVector3& v2 = pp[fs[i*2+1]+8]; - const LLPlane& cp = bp[j]; - LLVector3 n; - cp.getVector3(n); - - LLVector3 line = v1-v2; - - F32 d1 = line*n; - F32 d2 = -cp.dist(v2); - - F32 t = d2/d1; - - if (t > 0.f && t < 1.f) - { - LLVector3 intersect = v2+line*t; - pp.push_back(intersect); - } - } - } - - LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f), - max+LLVector3(0.05f,0.05f,0.05f) }; - - for (U32 i = 0; i < pp.size(); ++i) - { - bool found = true; - - const F32* p = pp[i].mV; - - for (U32 j = 0; j < 3; ++j) - { - if (p[j] < ext[0].mV[j] || - p[j] > ext[1].mV[j]) - { - found = false; - break; - } - } - - for (U32 j = 0; j < 6; ++j) - { - const LLPlane& cp = camera.getAgentPlane(j); - F32 dist = cp.dist(pp[i]); - if (dist > 0.05f) //point is above some plane, not contained - { - found = false; - break; - } - } - - if (found) - { - fp.push_back(pp[i]); - } - } - - if (fp.empty()) - { - return FALSE; - } - - return TRUE; -} - -void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade) -{ - if (obj && obj->getVolume()) - { - for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter) - { - renderHighlight(*iter, fade); - } - - LLDrawable* drawable = obj->mDrawable; - if (drawable) - { - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* face = drawable->getFace(i); - if (face) - { - face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade)); - } - } - } - } -} - -void LLPipeline::generateHighlight(LLCamera& camera) -{ - //render highlighted object as white into offscreen render target - if (mHighlightObject.notNull()) - { - mHighlightSet.insert(HighlightItem(mHighlightObject)); - } - - if (!mHighlightSet.empty()) - { - F32 transition = gFrameIntervalSeconds/RenderHighlightFadeTime; - - LLGLDisable test(GL_ALPHA_TEST); - LLGLDepthTest depth(GL_FALSE); - mHighlight.bindTarget(); - disableLights(); - gGL.setColorMask(true, true); - mHighlight.clear(); - - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) - { - std::set<HighlightItem>::iterator cur_iter = iter++; - - if (cur_iter->mItem.isNull()) - { - mHighlightSet.erase(cur_iter); - continue; - } - - if (cur_iter->mItem == mHighlightObject) - { - cur_iter->incrFade(transition); - } - else - { - cur_iter->incrFade(-transition); - if (cur_iter->mFade <= 0.f) - { - mHighlightSet.erase(cur_iter); - continue; - } - } - - renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade); - } - - mHighlight.flush(); - gGL.setColorMask(true, false); - gViewerWindow->setup3DViewport(); - } -} - - -void LLPipeline::generateSunShadow(LLCamera& camera) -{ - if (!sRenderDeferred || RenderShadowDetail <= 0) - { - return; - } - - BOOL skip_avatar_update = FALSE; - if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) - { - - skip_avatar_update = TRUE; - } - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); - } - - F64 last_modelview[16]; - F64 last_projection[16]; - for (U32 i = 0; i < 16; i++) - { //store last_modelview of world camera - last_modelview[i] = gGLLastModelView[i]; - last_projection[i] = gGLLastProjection[i]; - } - - pushRenderTypeMask(); - andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_GRASS, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_TREE, - LLPipeline::RENDER_TYPE_TERRAIN, - LLPipeline::RENDER_TYPE_WATER, - LLPipeline::RENDER_TYPE_VOIDWATER, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_GRASS, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - END_RENDER_TYPES); - - gGL.setColorMask(false, false); - - //get sun view matrix - - //store current projection/modelview matrix - glh::matrix4f saved_proj = glh_get_current_projection(); - glh::matrix4f saved_view = glh_get_current_modelview(); - glh::matrix4f inv_view = saved_view.inverse(); - - glh::matrix4f view[6]; - glh::matrix4f proj[6]; - - //clip contains parallel split distances for 3 splits - LLVector3 clip = RenderShadowClipPlanes; - - //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold"); - - //far clip on last split is minimum of camera view distance and 128 - mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]); - - clip = RenderShadowOrthoClipPlanes; - mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); - - //currently used for amount to extrude frusta corners for constructing shadow frusta - LLVector3 n = RenderShadowNearDist; - //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; - - //put together a universal "near clip" plane for shadow frusta - LLPlane shadow_near_clip; - { - LLVector3 p = gAgent.getPositionAgent(); - p += mSunDir * RenderFarClip*2.f; - shadow_near_clip.setVec(p, mSunDir); - } - - LLVector3 lightDir = -mSunDir; - lightDir.normVec(); - - glh::vec3f light_dir(lightDir.mV); - - //create light space camera matrix - - LLVector3 at = lightDir; - - LLVector3 up = camera.getAtAxis(); - - if (fabsf(up*lightDir) > 0.75f) - { - up = camera.getUpAxis(); - } - - /*LLVector3 left = up%at; - up = at%left;*/ - - up.normVec(); - at.normVec(); - - - LLCamera main_camera = camera; - - F32 near_clip = 0.f; - { - //get visible point cloud - std::vector<LLVector3> fp; - - main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum); - - LLVector3 min,max; - getVisiblePointCloud(main_camera,min,max,fp); - - if (fp.empty()) - { - if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowCamera[0] = main_camera; - mShadowExtents[0][0] = min; - mShadowExtents[0][1] = max; - - mShadowFrustPoints[0].clear(); - mShadowFrustPoints[1].clear(); - mShadowFrustPoints[2].clear(); - mShadowFrustPoints[3].clear(); - } - popRenderTypeMask(); - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); - } - - return; - } - - //get good split distances for frustum - for (U32 i = 0; i < fp.size(); ++i) - { - glh::vec3f v(fp[i].mV); - saved_view.mult_matrix_vec(v); - fp[i].setVec(v.v); - } - - min = fp[0]; - max = fp[0]; - - //get camera space bounding box - for (U32 i = 1; i < fp.size(); ++i) - { - update_min_max(min, max, fp[i]); - } - - near_clip = -max.mV[2]; - F32 far_clip = -min.mV[2]*2.f; - - //far_clip = llmin(far_clip, 128.f); - far_clip = llmin(far_clip, camera.getFar()); - - F32 range = far_clip-near_clip; - - LLVector3 split_exp = RenderShadowSplitExponent; - - F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) ); - - da = powf(da, split_exp.mV[2]); - - - F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da; - - - for (U32 i = 0; i < 4; ++i) - { - F32 x = (F32)(i+1)/4.f; - x = powf(x, sxp); - mSunClipPlanes.mV[i] = near_clip+range*x; - } - } - - // convenience array of 4 near clip plane distances - F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; - - - if (mSunDiffuse == LLColor4::black) - { //sun diffuse is totally black, shadows don't matter - LLGLDepthTest depth(GL_TRUE); - - for (S32 j = 0; j < 4; j++) - { - mShadow[j].bindTarget(); - mShadow[j].clear(); - mShadow[j].flush(); - } - } - else - { - for (S32 j = 0; j < 4; j++) - { - if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowFrustPoints[j].clear(); - } - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; - - //restore render matrices - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - - LLVector3 eye = camera.getOrigin(); - - //camera used for shadow cull/render - LLCamera shadow_cam; - - //create world space camera frustum for this split - shadow_cam = camera; - shadow_cam.setFar(16.f); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - LLVector3* frust = shadow_cam.mAgentFrustum; - - LLVector3 pn = shadow_cam.getAtAxis(); - - LLVector3 min, max; - - //construct 8 corners of split frustum section - for (U32 i = 0; i < 4; i++) - { - LLVector3 delta = frust[i+4]-eye; - delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f; - delta.normVec(); - F32 dp = delta*pn; - frust[i] = eye + (delta*dist[j]*0.95f)/dp; - frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp; - } - - shadow_cam.calcAgentFrustumPlanes(frust); - shadow_cam.mFrustumCornerDist = 0.f; - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowCamera[j] = shadow_cam; - } - - std::vector<LLVector3> fp; - - if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) - { - //no possible shadow receivers - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowExtents[j][0] = LLVector3(); - mShadowExtents[j][1] = LLVector3(); - mShadowCamera[j+4] = shadow_cam; - } - - mShadow[j].bindTarget(); - { - LLGLDepthTest depth(GL_TRUE); - mShadow[j].clear(); - } - mShadow[j].flush(); - - mShadowError.mV[j] = 0.f; - mShadowFOV.mV[j] = 0.f; - - continue; - } - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowExtents[j][0] = min; - mShadowExtents[j][1] = max; - mShadowFrustPoints[j] = fp; - } - - - //find a good origin for shadow projection - LLVector3 origin; - - //get a temporary view projection - view[j] = look(camera.getOrigin(), lightDir, -up); - - std::vector<LLVector3> wpf; - - for (U32 i = 0; i < fp.size(); i++) - { - glh::vec3f p = glh::vec3f(fp[i].mV); - view[j].mult_matrix_vec(p); - wpf.push_back(LLVector3(p.v)); - } - - min = wpf[0]; - max = wpf[0]; - - for (U32 i = 0; i < fp.size(); ++i) - { //get AABB in camera space - update_min_max(min, max, wpf[i]); - } - - // Construct a perspective transform with perspective along y-axis that contains - // points in wpf - //Known: - // - far clip plane - // - near clip plane - // - points in frustum - //Find: - // - origin - - //get some "interesting" points of reference - LLVector3 center = (min+max)*0.5f; - LLVector3 size = (max-min)*0.5f; - LLVector3 near_center = center; - near_center.mV[1] += size.mV[1]*2.f; - - - //put all points in wpf in quadrant 0, reletive to center of min/max - //get the best fit line using least squares - F32 bfm = 0.f; - F32 bfb = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - wpf[i] -= center; - wpf[i].mV[0] = fabsf(wpf[i].mV[0]); - wpf[i].mV[2] = fabsf(wpf[i].mV[2]); - } - - if (!wpf.empty()) - { - F32 sx = 0.f; - F32 sx2 = 0.f; - F32 sy = 0.f; - F32 sxy = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - sx += wpf[i].mV[0]; - sx2 += wpf[i].mV[0]*wpf[i].mV[0]; - sy += wpf[i].mV[1]; - sxy += wpf[i].mV[0]*wpf[i].mV[1]; - } - - bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2); - bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2); - } - - { - // best fit line is y=bfm*x+bfb - - //find point that is furthest to the right of line - F32 off_x = -1.f; - LLVector3 lp; - - for (U32 i = 0; i < wpf.size(); ++i) - { - //y = bfm*x+bfb - //x = (y-bfb)/bfm - F32 lx = (wpf[i].mV[1]-bfb)/bfm; - - lx = wpf[i].mV[0]-lx; - - if (off_x < lx) - { - off_x = lx; - lp = wpf[i]; - } - } - - //get line with slope bfm through lp - // bfb = y-bfm*x - bfb = lp.mV[1]-bfm*lp.mV[0]; - - //calculate error - mShadowError.mV[j] = 0.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - F32 lx = (wpf[i].mV[1]-bfb)/bfm; - mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); - } - - mShadowError.mV[j] /= wpf.size(); - mShadowError.mV[j] /= size.mV[0]; - - if (mShadowError.mV[j] > RenderShadowErrorCutoff) - { //just use ortho projection - mShadowFOV.mV[j] = -1.f; - origin.clearVec(); - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - } - else - { - //origin is where line x = 0; - origin.setVec(0,bfb,0); - - F32 fovz = 1.f; - F32 fovx = 1.f; - - LLVector3 zp; - LLVector3 xp; - - for (U32 i = 0; i < wpf.size(); ++i) - { - LLVector3 atz = wpf[i]-origin; - atz.mV[0] = 0.f; - atz.normVec(); - if (fovz > -atz.mV[1]) - { - zp = wpf[i]; - fovz = -atz.mV[1]; - } - - LLVector3 atx = wpf[i]-origin; - atx.mV[2] = 0.f; - atx.normVec(); - if (fovx > -atx.mV[1]) - { - fovx = -atx.mV[1]; - xp = wpf[i]; - } - } - - fovx = acos(fovx); - fovz = acos(fovz); - - F32 cutoff = llmin((F32) RenderShadowFOVCutoff, 1.4f); - - mShadowFOV.mV[j] = fovx; - - if (fovx < cutoff && fovz > cutoff) - { - //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff - F32 d = zp.mV[2]/tan(cutoff); - F32 ny = zp.mV[1] + fabsf(d); - - origin.mV[1] = ny; - - fovz = 1.f; - fovx = 1.f; - - for (U32 i = 0; i < wpf.size(); ++i) - { - LLVector3 atz = wpf[i]-origin; - atz.mV[0] = 0.f; - atz.normVec(); - fovz = llmin(fovz, -atz.mV[1]); - - LLVector3 atx = wpf[i]-origin; - atx.mV[2] = 0.f; - atx.normVec(); - fovx = llmin(fovx, -atx.mV[1]); - } - - fovx = acos(fovx); - fovz = acos(fovz); - - mShadowFOV.mV[j] = cutoff; - } - - - origin += center; - - F32 ynear = -(max.mV[1]-origin.mV[1]); - F32 yfar = -(min.mV[1]-origin.mV[1]); - - if (ynear < 0.1f) //keep a sensible near clip plane - { - F32 diff = 0.1f-ynear; - origin.mV[1] += diff; - ynear += diff; - yfar += diff; - } - - if (fovx > cutoff) - { //just use ortho projection - origin.clearVec(); - mShadowError.mV[j] = -1.f; - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); - } - else - { - //get perspective projection - view[j] = view[j].inverse(); - - glh::vec3f origin_agent(origin.mV); - - //translate view to origin - view[j].mult_matrix_vec(origin_agent); - - eye = LLVector3(origin_agent.v); - - if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowFrustOrigin[j] = eye; - } - - view[j] = look(LLVector3(origin_agent.v), lightDir, -up); - - F32 fx = 1.f/tanf(fovx); - F32 fz = 1.f/tanf(fovz); - - proj[j] = glh::matrix4f(-fx, 0, 0, 0, - 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), - 0, 0, -fz, 0, - 0, -1.f, 0, 0); - } - } - } - - //shadow_cam.setFar(128.f); - shadow_cam.setOriginAndLookAt(eye, up, center); - - shadow_cam.setOrigin(0,0,0); - - glh_set_current_modelview(view[j]); - glh_set_current_projection(proj[j]); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); - shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); - - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh_set_current_modelview(view[j]); - glh_set_current_projection(proj[j]); - - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = mShadowModelview[j].m[i]; - gGLLastProjection[i] = mShadowProjection[j].m[i]; - } - - mShadowModelview[j] = view[j]; - mShadowProjection[j] = proj[j]; - - - mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; - - stop_glerror(); - - mShadow[j].bindTarget(); - mShadow[j].getViewport(gGLViewport); - mShadow[j].clear(); - - { - static LLCullResult result[4]; - - //LLGLEnable enable(GL_DEPTH_CLAMP_NV); - renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE); - } - - mShadow[j].flush(); - - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - mShadowCamera[j+4] = shadow_cam; - } - } - } - - - //hack to disable projector shadows - bool gen_shadow = RenderShadowDetail > 1; - - if (gen_shadow) - { - F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f); - - //update shadow targets - for (U32 i = 0; i < 2; i++) - { //for each current shadow - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; - - if (mShadowSpotLight[i].notNull() && - (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || - mShadowSpotLight[i] == mTargetShadowSpotLight[1])) - { //keep this spotlight - mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); - } - else - { //fade out this light - mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); - - if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) - { //faded out, grab one of the pending spots (whichever one isn't already taken) - if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) - { - mShadowSpotLight[i] = mTargetShadowSpotLight[0]; - } - else - { - mShadowSpotLight[i] = mTargetShadowSpotLight[1]; - } - } - } - } - - for (S32 i = 0; i < 2; i++) - { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - - if (mShadowSpotLight[i].isNull()) - { - continue; - } - - LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); - - if (!volume) - { - mShadowSpotLight[i] = NULL; - continue; - } - - LLDrawable* drawable = mShadowSpotLight[i]; - - LLVector3 params = volume->getSpotLightParams(); - F32 fov = params.mV[0]; - - //get agent->light space matrix (modelview) - LLVector3 center = drawable->getPositionAgent(); - LLQuaternion quat = volume->getRenderRotation(); - - //get near clip plane - LLVector3 scale = volume->getScale(); - LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); - at_axis *= quat; - - LLVector3 np = center+at_axis; - at_axis.normVec(); - - //get origin that has given fov for plane np, at_axis, and given scale - F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); - - LLVector3 origin = np - at_axis*dist; - - LLMatrix4 mat(quat, LLVector4(origin, 1.f)); - - view[i+4] = glh::matrix4f((F32*) mat.mMatrix); - - view[i+4] = view[i+4].inverse(); - - //get perspective matrix - F32 near_clip = dist+0.01f; - F32 width = scale.mV[VX]; - F32 height = scale.mV[VY]; - F32 far_clip = dist+volume->getLightRadius()*1.5f; - - F32 fovy = fov * RAD_TO_DEG; - F32 aspect = width/height; - - proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); - - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - - glh_set_current_modelview(view[i+4]); - glh_set_current_projection(proj[i+4]); - - mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; - - for (U32 j = 0; j < 16; j++) - { - gGLLastModelView[j] = mShadowModelview[i+4].m[j]; - gGLLastProjection[j] = mShadowProjection[i+4].m[j]; - } - - mShadowModelview[i+4] = view[i+4]; - mShadowProjection[i+4] = proj[i+4]; - - LLCamera shadow_cam = camera; - shadow_cam.setFar(far_clip); - shadow_cam.setOrigin(origin); - - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - - stop_glerror(); - - mShadow[i+4].bindTarget(); - mShadow[i+4].getViewport(gGLViewport); - mShadow[i+4].clear(); - - static LLCullResult result[2]; - - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; - - renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE); - - mShadow[i+4].flush(); - } - } - else - { //no spotlight shadows - mShadowSpotLight[0] = mShadowSpotLight[1] = NULL; - } - - - if (!CameraOffset) - { - glh_set_current_modelview(saved_view); - glh_set_current_projection(saved_proj); - } - else - { - glh_set_current_modelview(view[1]); - glh_set_current_projection(proj[1]); - gGL.loadMatrix(view[1].m); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj[1].m); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } - gGL.setColorMask(true, false); - - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = last_modelview[i]; - gGLLastProjection[i] = last_projection[i]; - } - - popRenderTypeMask(); - - if (!skip_avatar_update) - { - gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); - } -} - -void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture) -{ - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (!group->isDead() && - (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && - gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && - group->mDrawMap.find(type) != group->mDrawMap.end()) - { - pass->renderGroup(group,type,mask,texture); - } - } -} - -void LLPipeline::generateImpostor(LLVOAvatar* avatar) -{ - LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - - static LLCullResult result; - result.clear(); - grabReferences(result); - - if (!avatar || !avatar->mDrawable) - { - return; - } - - assertInitialized(); - - bool muted = avatar->isVisuallyMuted(); - - pushRenderTypeMask(); - - if (muted) - { - andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); - } - else - { - andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_GRASS, - LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, - END_RENDER_TYPES); - } - - S32 occlusion = sUseOcclusion; - sUseOcclusion = 0; - sReflectionRender = sRenderDeferred ? FALSE : TRUE; - sShadowRender = TRUE; - sImpostorRender = TRUE; - - LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); - markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::sUseImpostors = FALSE; - - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - if (LLViewerObject* attached_object = (*attachment_iter)) - { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); - } - } - } - - stateSort(*LLViewerCamera::getInstance(), result); - - const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); - LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - - LLCamera camera = *viewer_camera; - - camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); - - LLVector2 tdim; - - - LLVector4a half_height; - half_height.setSub(ext[1], ext[0]); - half_height.mul(0.5f); - - LLVector4a left; - left.load3(camera.getLeftAxis().mV); - left.mul(left); - left.normalize3fast(); - - LLVector4a up; - up.load3(camera.getUpAxis().mV); - up.mul(up); - up.normalize3fast(); - - tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); - tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - - F32 distance = (pos-camera.getOrigin()).length(); - F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); - glh_set_current_projection(persp); - gGL.loadMatrix(persp.m); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); - - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; - - gGL.loadMatrix(mat.m); - glh_set_current_modelview(mat); - - glClearColor(0.0f,0.0f,0.0f,0.0f); - gGL.setColorMask(true, true); - - // get the number of pixels per angle - F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); - - //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) - U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); - U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - - if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) - { - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); - - if (LLPipeline::sRenderDeferred) - { - addDeferredAttachments(avatar->mImpostor); - } - - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - - avatar->mImpostor.bindTarget(); - - if (LLPipeline::sRenderDeferred) - { - avatar->mImpostor.clear(); - renderGeomDeferred(camera); - renderGeomPostDeferred(camera); - } - else - { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, resX, resY); - avatar->mImpostor.clear(); - renderGeom(camera); - } - - { //create alpha mask based on depth buffer (grey out if muted) - if (LLPipeline::sRenderDeferred) - { - GLuint buff = GL_COLOR_ATTACHMENT0; - glDrawBuffersARB(1, &buff); - } - - LLGLDisable blend(GL_BLEND); - - if (muted) - { - gGL.setColorMask(true, true); - } - else - { - gGL.setColorMask(false, true); - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - - gGL.flush(); - - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - - static const F32 clip_plane = 0.99999f; - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - gGL.color4ub(64,64,64,255); - gGL.begin(LLRender::QUADS); - gGL.vertex3f(-1, -1, clip_plane); - gGL.vertex3f(1, -1, clip_plane); - gGL.vertex3f(1, 1, clip_plane); - gGL.vertex3f(-1, 1, clip_plane); - gGL.end(); - gGL.flush(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - } - - avatar->mImpostor.flush(); - - avatar->setImpostorDim(tdim); - - LLVOAvatar::sUseImpostors = TRUE; - sUseOcclusion = occlusion; - sReflectionRender = FALSE; - sImpostorRender = FALSE; - sShadowRender = FALSE; - popRenderTypeMask(); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - - avatar->mNeedsImpostorUpdate = FALSE; - avatar->cacheImpostorValues(); - - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); -} - -BOOL LLPipeline::hasRenderBatches(const U32 type) const -{ - return sCull->getRenderMapSize(type) > 0; -} - -LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type) -{ - return sCull->beginRenderMap(type); -} - -LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type) -{ - return sCull->endRenderMap(type); -} - -LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups() -{ - return sCull->beginAlphaGroups(); -} - -LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() -{ - return sCull->endAlphaGroups(); -} - -BOOL LLPipeline::hasRenderType(const U32 type) const -{ - // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" - // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance) - // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely - return (type == 0 ? FALSE : mRenderTypeEnabled[type]); -} - -void LLPipeline::setRenderTypeMask(U32 type, ...) -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - mRenderTypeEnabled[type] = TRUE; - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } -} - -BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - if (mRenderTypeEnabled[type]) - { - return TRUE; - } - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } - - return FALSE; -} - -void LLPipeline::pushRenderTypeMask() -{ - std::string cur_mask; - cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled)); - mRenderTypeEnableStack.push(cur_mask); -} - -void LLPipeline::popRenderTypeMask() -{ - if (mRenderTypeEnableStack.empty()) - { - llerrs << "Depleted render type stack." << llendl; - } - - memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled)); - mRenderTypeEnableStack.pop(); -} - -void LLPipeline::andRenderTypeMask(U32 type, ...) -{ - va_list args; - - BOOL tmp[NUM_RENDER_TYPES]; - for (U32 i = 0; i < NUM_RENDER_TYPES; ++i) - { - tmp[i] = FALSE; - } - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - if (mRenderTypeEnabled[type]) - { - tmp[type] = TRUE; - } - - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } - - for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i) - { - mRenderTypeEnabled[i] = tmp[i]; - } - -} - -void LLPipeline::clearRenderTypeMask(U32 type, ...) -{ - va_list args; - - va_start(args, type); - while (type < END_RENDER_TYPES) - { - mRenderTypeEnabled[type] = FALSE; - - type = va_arg(args, U32); - } - va_end(args); - - if (type > END_RENDER_TYPES) - { - llerrs << "Invalid render type." << llendl; - } -} - -void LLPipeline::addDebugBlip(const LLVector3& position, const LLColor4& color) -{ - DebugBlip blip(position, color); - mDebugBlips.push_back(blip); -} - +/**
+ * @file pipeline.cpp
+ * @brief Rendering pipeline.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+
+// library includes
+#include "llaudioengine.h" // For debugging.
+#include "imageids.h"
+#include "llerror.h"
+#include "llviewercontrol.h"
+#include "llfasttimer.h"
+#include "llfontgl.h"
+#include "llmemtype.h"
+#include "llnamevalue.h"
+#include "llpointer.h"
+#include "llprimitive.h"
+#include "llvolume.h"
+#include "material_codes.h"
+#include "timing.h"
+#include "v3color.h"
+#include "llui.h"
+#include "llglheaders.h"
+#include "llrender.h"
+#include "llwindow.h" // swapBuffers()
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolavatar.h"
+#include "lldrawpoolground.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpooltree.h"
+#include "lldrawpoolwater.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfloatertelehub.h"
+#include "llfloaterreg.h"
+#include "llgldbg.h"
+#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h"
+#include "lllightconstants.h"
+#include "llmeshrepository.h"
+#include "llresmgr.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "lltracker.h"
+#include "lltool.h"
+#include "lltoolmgr.h"
+#include "llviewercamera.h"
+#include "llviewermediafocus.h"
+#include "llviewertexturelist.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h" // for audio debugging.
+#include "llviewerwindow.h" // For getSpinAxis
+#include "llvoavatarself.h"
+#include "llvoground.h"
+#include "llvosky.h"
+#include "llvotree.h"
+#include "llvovolume.h"
+#include "llvosurfacepatch.h"
+#include "llvowater.h"
+#include "llvotree.h"
+#include "llvopartgroup.h"
+#include "llworld.h"
+#include "llcubemap.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llviewerjoystick.h"
+#include "llviewerdisplay.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llspatialpartition.h"
+#include "llmutelist.h"
+#include "lltoolpie.h"
+#include "llcurl.h"
+#include "llnotifications.h"
+#include "LLPathingLib.h"
+#include "llfloaterpathfindingconsole.h"
+
+#ifdef _DEBUG
+// Debug indices is disabled for now for debug performance - djs 4/24/02
+//#define DEBUG_INDICES
+#else
+//#define DEBUG_INDICES
+#endif
+
+//cached settings
+BOOL LLPipeline::RenderAvatarVP;
+BOOL LLPipeline::VertexShaderEnable;
+BOOL LLPipeline::WindLightUseAtmosShaders;
+BOOL LLPipeline::RenderDeferred;
+F32 LLPipeline::RenderDeferredSunWash;
+U32 LLPipeline::RenderFSAASamples;
+U32 LLPipeline::RenderResolutionDivisor;
+BOOL LLPipeline::RenderUIBuffer;
+S32 LLPipeline::RenderShadowDetail;
+BOOL LLPipeline::RenderDeferredSSAO;
+F32 LLPipeline::RenderShadowResolutionScale;
+BOOL LLPipeline::RenderLocalLights;
+BOOL LLPipeline::RenderDelayCreation;
+BOOL LLPipeline::RenderAnimateRes;
+BOOL LLPipeline::FreezeTime;
+S32 LLPipeline::DebugBeaconLineWidth;
+F32 LLPipeline::RenderHighlightBrightness;
+LLColor4 LLPipeline::RenderHighlightColor;
+F32 LLPipeline::RenderHighlightThickness;
+BOOL LLPipeline::RenderSpotLightsInNondeferred;
+LLColor4 LLPipeline::PreviewAmbientColor;
+LLColor4 LLPipeline::PreviewDiffuse0;
+LLColor4 LLPipeline::PreviewSpecular0;
+LLColor4 LLPipeline::PreviewDiffuse1;
+LLColor4 LLPipeline::PreviewSpecular1;
+LLColor4 LLPipeline::PreviewDiffuse2;
+LLColor4 LLPipeline::PreviewSpecular2;
+LLVector3 LLPipeline::PreviewDirection0;
+LLVector3 LLPipeline::PreviewDirection1;
+LLVector3 LLPipeline::PreviewDirection2;
+F32 LLPipeline::RenderGlowMinLuminance;
+F32 LLPipeline::RenderGlowMaxExtractAlpha;
+F32 LLPipeline::RenderGlowWarmthAmount;
+LLVector3 LLPipeline::RenderGlowLumWeights;
+LLVector3 LLPipeline::RenderGlowWarmthWeights;
+S32 LLPipeline::RenderGlowResolutionPow;
+S32 LLPipeline::RenderGlowIterations;
+F32 LLPipeline::RenderGlowWidth;
+F32 LLPipeline::RenderGlowStrength;
+BOOL LLPipeline::RenderDepthOfField;
+F32 LLPipeline::CameraFocusTransitionTime;
+F32 LLPipeline::CameraFNumber;
+F32 LLPipeline::CameraFocalLength;
+F32 LLPipeline::CameraFieldOfView;
+F32 LLPipeline::RenderShadowNoise;
+F32 LLPipeline::RenderShadowBlurSize;
+F32 LLPipeline::RenderSSAOScale;
+U32 LLPipeline::RenderSSAOMaxScale;
+F32 LLPipeline::RenderSSAOFactor;
+LLVector3 LLPipeline::RenderSSAOEffect;
+F32 LLPipeline::RenderShadowOffsetError;
+F32 LLPipeline::RenderShadowBiasError;
+F32 LLPipeline::RenderShadowOffset;
+F32 LLPipeline::RenderShadowBias;
+F32 LLPipeline::RenderSpotShadowOffset;
+F32 LLPipeline::RenderSpotShadowBias;
+F32 LLPipeline::RenderEdgeDepthCutoff;
+F32 LLPipeline::RenderEdgeNormCutoff;
+LLVector3 LLPipeline::RenderShadowGaussian;
+F32 LLPipeline::RenderShadowBlurDistFactor;
+BOOL LLPipeline::RenderDeferredAtmospheric;
+S32 LLPipeline::RenderReflectionDetail;
+F32 LLPipeline::RenderHighlightFadeTime;
+LLVector3 LLPipeline::RenderShadowClipPlanes;
+LLVector3 LLPipeline::RenderShadowOrthoClipPlanes;
+LLVector3 LLPipeline::RenderShadowNearDist;
+F32 LLPipeline::RenderFarClip;
+LLVector3 LLPipeline::RenderShadowSplitExponent;
+F32 LLPipeline::RenderShadowErrorCutoff;
+F32 LLPipeline::RenderShadowFOVCutoff;
+BOOL LLPipeline::CameraOffset;
+F32 LLPipeline::CameraMaxCoF;
+F32 LLPipeline::CameraDoFResScale;
+
+const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
+const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
+const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
+const U32 REFLECTION_MAP_RES = 128;
+const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
+// Max number of occluders to search for. JC
+const S32 MAX_OCCLUDER_COUNT = 2;
+
+extern S32 gBoxFrame;
+//extern BOOL gHideSelectedObjects;
+extern BOOL gDisplaySwapBuffers;
+extern BOOL gDebugGL;
+
+BOOL gAvatarBacklight = FALSE;
+
+BOOL gDebugPipeline = FALSE;
+LLPipeline gPipeline;
+const LLMatrix4* gGLLastMatrix = NULL;
+
+LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
+LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
+LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
+LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
+LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
+LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
+LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
+LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
+LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
+LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
+LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
+LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
+LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
+LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
+LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
+LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
+LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
+LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
+LLFastTimer::DeclareTimer FTM_POOLS("Pools");
+LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
+LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
+LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
+LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
+LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
+
+
+static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
+static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
+
+//----------------------------------------
+std::string gPoolNames[] =
+{
+ // Correspond to LLDrawpool enum render type
+ "NONE",
+ "POOL_SIMPLE",
+ "POOL_GROUND",
+ "POOL_FULLBRIGHT",
+ "POOL_BUMP",
+ "POOL_TERRAIN,"
+ "POOL_SKY",
+ "POOL_WL_SKY",
+ "POOL_TREE",
+ "POOL_GRASS",
+ "POOL_INVISIBLE",
+ "POOL_AVATAR",
+ "POOL_VOIDWATER",
+ "POOL_WATER",
+ "POOL_GLOW",
+ "POOL_ALPHA"
+};
+
+void drawBox(const LLVector3& c, const LLVector3& r);
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
+U32 nhpo2(U32 v);
+
+glh::matrix4f glh_copy_matrix(F32* src)
+{
+ glh::matrix4f ret;
+ ret.set_value(src);
+ return ret;
+}
+
+glh::matrix4f glh_get_current_modelview()
+{
+ return glh_copy_matrix(gGLModelView);
+}
+
+glh::matrix4f glh_get_current_projection()
+{
+ return glh_copy_matrix(gGLProjection);
+}
+
+glh::matrix4f glh_get_last_modelview()
+{
+ return glh_copy_matrix(gGLLastModelView);
+}
+
+glh::matrix4f glh_get_last_projection()
+{
+ return glh_copy_matrix(gGLLastProjection);
+}
+
+void glh_copy_matrix(const glh::matrix4f& src, F32* dst)
+{
+ for (U32 i = 0; i < 16; i++)
+ {
+ dst[i] = src.m[i];
+ }
+}
+
+void glh_set_current_modelview(const glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLModelView);
+}
+
+void glh_set_current_projection(glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLProjection);
+}
+
+glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
+{
+ glh::matrix4f ret(
+ 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
+ 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
+ 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
+ 0.f, 0.f, 0.f, 1.f);
+
+ return ret;
+}
+
+void display_update_camera();
+//----------------------------------------
+
+S32 LLPipeline::sCompiles = 0;
+
+BOOL LLPipeline::sPickAvatar = TRUE;
+BOOL LLPipeline::sDynamicLOD = TRUE;
+BOOL LLPipeline::sShowHUDAttachments = TRUE;
+BOOL LLPipeline::sRenderMOAPBeacons = FALSE;
+BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
+BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
+BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
+BOOL LLPipeline::sRenderParticleBeacons = FALSE;
+BOOL LLPipeline::sRenderSoundBeacons = FALSE;
+BOOL LLPipeline::sRenderBeacons = FALSE;
+BOOL LLPipeline::sRenderHighlight = TRUE;
+BOOL LLPipeline::sForceOldBakedUpload = FALSE;
+S32 LLPipeline::sUseOcclusion = 0;
+BOOL LLPipeline::sDelayVBUpdate = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
+BOOL LLPipeline::sDisableShaders = FALSE;
+BOOL LLPipeline::sRenderBump = TRUE;
+BOOL LLPipeline::sBakeSunlight = FALSE;
+BOOL LLPipeline::sNoAlpha = FALSE;
+BOOL LLPipeline::sUseTriStrips = TRUE;
+BOOL LLPipeline::sUseFarClip = TRUE;
+BOOL LLPipeline::sShadowRender = FALSE;
+BOOL LLPipeline::sWaterReflections = FALSE;
+BOOL LLPipeline::sRenderGlow = FALSE;
+BOOL LLPipeline::sReflectionRender = FALSE;
+BOOL LLPipeline::sImpostorRender = FALSE;
+BOOL LLPipeline::sUnderWaterRender = FALSE;
+BOOL LLPipeline::sTextureBindTest = FALSE;
+BOOL LLPipeline::sRenderFrameTest = FALSE;
+BOOL LLPipeline::sRenderAttachedLights = TRUE;
+BOOL LLPipeline::sRenderAttachedParticles = TRUE;
+BOOL LLPipeline::sRenderDeferred = FALSE;
+BOOL LLPipeline::sMemAllocationThrottled = FALSE;
+S32 LLPipeline::sVisibleLightCount = 0;
+F32 LLPipeline::sMinRenderSize = 0.f;
+
+
+static LLCullResult* sCull = NULL;
+
+static const U32 gl_cube_face[] =
+{
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
+};
+
+void validate_framebuffer_object();
+
+
+bool addDeferredAttachments(LLRenderTarget& target)
+{
+ return target.addColorAttachment(GL_RGBA) && //specular
+ target.addColorAttachment(GL_RGBA); //normal+z
+}
+
+LLPipeline::LLPipeline() :
+ mBackfaceCull(FALSE),
+ mBatchCount(0),
+ mMatrixOpCount(0),
+ mTextureMatrixOps(0),
+ mMaxBatchSize(0),
+ mMinBatchSize(0),
+ mMeanBatchSize(0),
+ mTrianglesDrawn(0),
+ mNumVisibleNodes(0),
+ mVerticesRelit(0),
+ mLightingChanges(0),
+ mGeometryChanges(0),
+ mNumVisibleFaces(0),
+
+ mInitialized(FALSE),
+ mVertexShadersEnabled(FALSE),
+ mVertexShadersLoaded(0),
+ mRenderDebugFeatureMask(0),
+ mRenderDebugMask(0),
+ mOldRenderDebugMask(0),
+ mGroupQ1Locked(false),
+ mGroupQ2Locked(false),
+ mResetVertexBuffers(false),
+ mLastRebuildPool(NULL),
+ mAlphaPool(NULL),
+ mSkyPool(NULL),
+ mTerrainPool(NULL),
+ mWaterPool(NULL),
+ mGroundPool(NULL),
+ mSimplePool(NULL),
+ mFullbrightPool(NULL),
+ mInvisiblePool(NULL),
+ mGlowPool(NULL),
+ mBumpPool(NULL),
+ mWLSkyPool(NULL),
+ mLightMask(0),
+ mLightMovingMask(0),
+ mLightingDetail(0),
+ mScreenWidth(0),
+ mScreenHeight(0)
+{
+ mNoiseMap = 0;
+ mTrueNoiseMap = 0;
+ mLightFunc = 0;
+}
+
+void LLPipeline::init()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
+
+ refreshCachedSettings();
+
+ gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
+ sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+ LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
+ LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
+ sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
+ sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
+
+ mInitialized = TRUE;
+
+ stop_glerror();
+
+ //create render pass pools
+ getPool(LLDrawPool::POOL_ALPHA);
+ getPool(LLDrawPool::POOL_SIMPLE);
+ getPool(LLDrawPool::POOL_GRASS);
+ getPool(LLDrawPool::POOL_FULLBRIGHT);
+ getPool(LLDrawPool::POOL_INVISIBLE);
+ getPool(LLDrawPool::POOL_BUMP);
+ getPool(LLDrawPool::POOL_GLOW);
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
+ resetFrameStats();
+
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
+ }
+
+ mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
+ mRenderDebugMask = 0; // All debug starts off
+
+ // Don't turn on ground when this is set
+ // Mac Books with intel 950s need this
+ if(!gSavedSettings.getBOOL("RenderGround"))
+ {
+ toggleRenderType(RENDER_TYPE_GROUND);
+ }
+
+ // make sure RenderPerformanceTest persists (hackity hack hack)
+ // disables non-object rendering (UI, sky, water, etc)
+ if (gSavedSettings.getBOOL("RenderPerformanceTest"))
+ {
+ gSavedSettings.setBOOL("RenderPerformanceTest", FALSE);
+ gSavedSettings.setBOOL("RenderPerformanceTest", TRUE);
+ }
+
+ mOldRenderDebugMask = mRenderDebugMask;
+
+ mBackfaceCull = TRUE;
+
+ stop_glerror();
+
+ // Enable features
+
+ LLViewerShaderMgr::instance()->setShaders();
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ mSpotLightFade[i] = 1.f;
+ }
+
+ mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
+ mDeferredVB->allocateBuffer(8, 0, true);
+ setLightingDetail(-1);
+
+ //
+ // Update all settings to trigger a cached settings refresh
+ //
+
+ gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+
+ gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+
+ gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDeferredSunWash")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderResolutionDivisor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderUIBuffer")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDeferredSSAO")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowResolutionScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderLocalLights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDelayCreation")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderAnimateRes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("FreezeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("DebugBeaconLineWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderHighlightBrightness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderHighlightColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderHighlightThickness")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSpotLightsInNondeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewAmbientColor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDiffuse0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewSpecular0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDiffuse1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewSpecular1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDiffuse2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewSpecular2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDirection0")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDirection1")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("PreviewDirection2")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowMinLuminance")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowMaxExtractAlpha")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowWarmthAmount")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowLumWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowWarmthWeights")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowResolutionPow")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowIterations")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowWidth")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderGlowStrength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDepthOfField")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraFocusTransitionTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraFNumber")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraFocalLength")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraFieldOfView")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowNoise")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowBlurSize")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSSAOScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSSAOMaxScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSSAOFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSSAOEffect")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowOffsetError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowBiasError")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSpotShadowOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderSpotShadowBias")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderEdgeDepthCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderEdgeNormCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowGaussian")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowBlurDistFactor")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderDeferredAtmospheric")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderReflectionDetail")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderHighlightFadeTime")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowOrthoClipPlanes")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowNearDist")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowSplitExponent")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowErrorCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("RenderShadowFOVCutoff")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraOffset")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraMaxCoF")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+ gSavedSettings.getControl("CameraDoFResScale")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));
+}
+
+LLPipeline::~LLPipeline()
+{
+
+}
+
+void LLPipeline::cleanup()
+{
+ assertInitialized();
+
+ mGroupQ1.clear() ;
+ mGroupQ2.clear() ;
+
+ for(pool_set_t::iterator iter = mPools.begin();
+ iter != mPools.end(); )
+ {
+ pool_set_t::iterator curiter = iter++;
+ LLDrawPool* poolp = *curiter;
+ if (poolp->isFacePool())
+ {
+ LLFacePool* face_pool = (LLFacePool*) poolp;
+ if (face_pool->mReferences.empty())
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+ else
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+
+ if (!mTerrainPools.empty())
+ {
+ llwarns << "Terrain Pools not cleaned up" << llendl;
+ }
+ if (!mTreePools.empty())
+ {
+ llwarns << "Tree Pools not cleaned up" << llendl;
+ }
+
+ delete mAlphaPool;
+ mAlphaPool = NULL;
+ delete mSkyPool;
+ mSkyPool = NULL;
+ delete mTerrainPool;
+ mTerrainPool = NULL;
+ delete mWaterPool;
+ mWaterPool = NULL;
+ delete mGroundPool;
+ mGroundPool = NULL;
+ delete mSimplePool;
+ mSimplePool = NULL;
+ delete mFullbrightPool;
+ mFullbrightPool = NULL;
+ delete mInvisiblePool;
+ mInvisiblePool = NULL;
+ delete mGlowPool;
+ mGlowPool = NULL;
+ delete mBumpPool;
+ mBumpPool = NULL;
+ // don't delete wl sky pool it was handled above in the for loop
+ //delete mWLSkyPool;
+ mWLSkyPool = NULL;
+
+ releaseGLBuffers();
+
+ mFaceSelectImagep = NULL;
+
+ mMovedBridge.clear();
+
+ mInitialized = FALSE;
+
+ mDeferredVB = NULL;
+}
+
+//============================================================================
+
+void LLPipeline::destroyGL()
+{
+ stop_glerror();
+ unloadShaders();
+ mHighlightFaces.clear();
+
+ resetDrawOrders();
+
+ resetVertexBuffers();
+
+ releaseGLBuffers();
+
+ if (LLVertexBuffer::sEnableVBOs)
+ {
+ LLVertexBuffer::sEnableVBOs = FALSE;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
+
+//static
+void LLPipeline::throttleNewMemoryAllocation(BOOL disable)
+{
+ if(sMemAllocationThrottled != disable)
+ {
+ sMemAllocationThrottled = disable ;
+
+ if(sMemAllocationThrottled)
+ {
+ //send out notification
+ LLNotification::Params params("LowMemory");
+ LLNotifications::instance().add(params);
+
+ //release some memory.
+ }
+ }
+}
+
+void LLPipeline::resizeScreenTexture()
+{
+ LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
+ if (gPipeline.canUseVertexShaders() && assertInitialized())
+ {
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ allocateScreenBuffer(resX,resY);
+ }
+}
+
+void LLPipeline::allocatePhysicsBuffer()
+{
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY)
+ {
+ mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ }
+}
+
+void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
+{
+ refreshCachedSettings();
+ U32 samples = RenderFSAASamples;
+
+ //try to allocate screen buffers at requested resolution and samples
+ // - on failure, shrink number of samples and try again
+ // - if not multisampled, shrink resolution and try again (favor X resolution over Y)
+ // Make sure to call "releaseScreenBuffers" after each failure to cleanup the partially loaded state
+
+ if (!allocateScreenBuffer(resX, resY, samples))
+ {
+ releaseScreenBuffers();
+ //reduce number of samples
+ while (samples > 0)
+ {
+ samples /= 2;
+ if (allocateScreenBuffer(resX, resY, samples))
+ { //success
+ return;
+ }
+ releaseScreenBuffers();
+ }
+
+ samples = 0;
+
+ //reduce resolution
+ while (resY > 0 && resX > 0)
+ {
+ resY /= 2;
+ if (allocateScreenBuffer(resX, resY, samples))
+ {
+ return;
+ }
+ releaseScreenBuffers();
+
+ resX /= 2;
+ if (allocateScreenBuffer(resX, resY, samples))
+ {
+ return;
+ }
+ releaseScreenBuffers();
+ }
+
+ llwarns << "Unable to allocate screen buffer at any resolution!" << llendl;
+ }
+}
+
+
+bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
+{
+ refreshCachedSettings();
+
+ // remember these dimensions
+ mScreenWidth = resX;
+ mScreenHeight = resY;
+
+ U32 res_mod = RenderResolutionDivisor;
+
+ if (res_mod > 1 && res_mod < resX && res_mod < resY)
+ {
+ resX /= res_mod;
+ resY /= res_mod;
+ }
+
+ if (RenderUIBuffer)
+ {
+ if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE))
+ {
+ return false;
+ }
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ S32 shadow_detail = RenderShadowDetail;
+ BOOL ssao = RenderDeferredSSAO;
+
+ //allocate deferred rendering color buffers
+ if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+ if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+ if (!addDeferredAttachments(mDeferredScreen)) return false;
+
+ if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+ if (samples > 0)
+ {
+ if (!mFXAABuffer.allocate(nhpo2(resX), nhpo2(resY), GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
+ }
+ else
+ {
+ mFXAABuffer.release();
+ }
+
+ if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
+ { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa
+ if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
+ }
+ else
+ {
+ mDeferredLight.release();
+ }
+
+ F32 scale = RenderShadowResolutionScale;
+
+ if (shadow_detail > 0)
+ { //allocate 4 sun shadow maps
+ for (U32 i = 0; i < 4; i++)
+ {
+ if (!mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE)) return false;
+ }
+ }
+ else
+ {
+ for (U32 i = 0; i < 4; i++)
+ {
+ mShadow[i].release();
+ }
+ }
+
+ U32 width = nhpo2(U32(resX*scale))/2;
+ U32 height = width;
+
+ if (shadow_detail > 1)
+ { //allocate two spot shadow maps
+ for (U32 i = 4; i < 6; i++)
+ {
+ if (!mShadow[i].allocate(width, height, 0, TRUE, FALSE)) return false;
+ }
+ }
+ else
+ {
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+ }
+ }
+ else
+ {
+ mDeferredLight.release();
+
+ for (U32 i = 0; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+ mFXAABuffer.release();
+ mScreen.release();
+ mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
+ mDeferredDepth.release();
+
+ if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ { //share depth buffer between deferred targets
+ mDeferredScreen.shareDepthBuffer(mScreen);
+ }
+
+ gGL.getTexUnit(0)->disable();
+
+ stop_glerror();
+
+ return true;
+}
+
+//static
+void LLPipeline::updateRenderDeferred()
+{
+ BOOL deferred = ((RenderDeferred &&
+ LLRenderTarget::sUseFBO &&
+ LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+ VertexShaderEnable &&
+ RenderAvatarVP &&
+ WindLightUseAtmosShaders) ? TRUE : FALSE) &&
+ !gUseWireframe;
+
+ sRenderDeferred = deferred;
+ if (deferred)
+ { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all
+ sRenderGlow = TRUE;
+ }
+}
+
+//static
+void LLPipeline::refreshCachedSettings()
+{
+ LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred");
+ LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred");
+ LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
+ LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
+ LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
+
+ LLPipeline::sUseOcclusion =
+ (!gUseWireframe
+ && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")
+ && gSavedSettings.getBOOL("UseOcclusion")
+ && gGLManager.mHasOcclusionQuery) ? 2 : 0;
+
+ VertexShaderEnable = gSavedSettings.getBOOL("VertexShaderEnable");
+ RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP");
+ WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders");
+ RenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
+ RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash");
+ RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples");
+ RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor");
+ RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer");
+ RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail");
+ RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO");
+ RenderShadowResolutionScale = gSavedSettings.getF32("RenderShadowResolutionScale");
+ RenderLocalLights = gSavedSettings.getBOOL("RenderLocalLights");
+ RenderDelayCreation = gSavedSettings.getBOOL("RenderDelayCreation");
+ RenderAnimateRes = gSavedSettings.getBOOL("RenderAnimateRes");
+ FreezeTime = gSavedSettings.getBOOL("FreezeTime");
+ DebugBeaconLineWidth = gSavedSettings.getS32("DebugBeaconLineWidth");
+ RenderHighlightBrightness = gSavedSettings.getF32("RenderHighlightBrightness");
+ RenderHighlightColor = gSavedSettings.getColor4("RenderHighlightColor");
+ RenderHighlightThickness = gSavedSettings.getF32("RenderHighlightThickness");
+ RenderSpotLightsInNondeferred = gSavedSettings.getBOOL("RenderSpotLightsInNondeferred");
+ PreviewAmbientColor = gSavedSettings.getColor4("PreviewAmbientColor");
+ PreviewDiffuse0 = gSavedSettings.getColor4("PreviewDiffuse0");
+ PreviewSpecular0 = gSavedSettings.getColor4("PreviewSpecular0");
+ PreviewDiffuse1 = gSavedSettings.getColor4("PreviewDiffuse1");
+ PreviewSpecular1 = gSavedSettings.getColor4("PreviewSpecular1");
+ PreviewDiffuse2 = gSavedSettings.getColor4("PreviewDiffuse2");
+ PreviewSpecular2 = gSavedSettings.getColor4("PreviewSpecular2");
+ PreviewDirection0 = gSavedSettings.getVector3("PreviewDirection0");
+ PreviewDirection1 = gSavedSettings.getVector3("PreviewDirection1");
+ PreviewDirection2 = gSavedSettings.getVector3("PreviewDirection2");
+ RenderGlowMinLuminance = gSavedSettings.getF32("RenderGlowMinLuminance");
+ RenderGlowMaxExtractAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
+ RenderGlowWarmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
+ RenderGlowLumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
+ RenderGlowWarmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
+ RenderGlowResolutionPow = gSavedSettings.getS32("RenderGlowResolutionPow");
+ RenderGlowIterations = gSavedSettings.getS32("RenderGlowIterations");
+ RenderGlowWidth = gSavedSettings.getF32("RenderGlowWidth");
+ RenderGlowStrength = gSavedSettings.getF32("RenderGlowStrength");
+ RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField");
+ CameraFocusTransitionTime = gSavedSettings.getF32("CameraFocusTransitionTime");
+ CameraFNumber = gSavedSettings.getF32("CameraFNumber");
+ CameraFocalLength = gSavedSettings.getF32("CameraFocalLength");
+ CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView");
+ RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise");
+ RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize");
+ RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale");
+ RenderSSAOMaxScale = gSavedSettings.getU32("RenderSSAOMaxScale");
+ RenderSSAOFactor = gSavedSettings.getF32("RenderSSAOFactor");
+ RenderSSAOEffect = gSavedSettings.getVector3("RenderSSAOEffect");
+ RenderShadowOffsetError = gSavedSettings.getF32("RenderShadowOffsetError");
+ RenderShadowBiasError = gSavedSettings.getF32("RenderShadowBiasError");
+ RenderShadowOffset = gSavedSettings.getF32("RenderShadowOffset");
+ RenderShadowBias = gSavedSettings.getF32("RenderShadowBias");
+ RenderSpotShadowOffset = gSavedSettings.getF32("RenderSpotShadowOffset");
+ RenderSpotShadowBias = gSavedSettings.getF32("RenderSpotShadowBias");
+ RenderEdgeDepthCutoff = gSavedSettings.getF32("RenderEdgeDepthCutoff");
+ RenderEdgeNormCutoff = gSavedSettings.getF32("RenderEdgeNormCutoff");
+ RenderShadowGaussian = gSavedSettings.getVector3("RenderShadowGaussian");
+ RenderShadowBlurDistFactor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
+ RenderDeferredAtmospheric = gSavedSettings.getBOOL("RenderDeferredAtmospheric");
+ RenderReflectionDetail = gSavedSettings.getS32("RenderReflectionDetail");
+ RenderHighlightFadeTime = gSavedSettings.getF32("RenderHighlightFadeTime");
+ RenderShadowClipPlanes = gSavedSettings.getVector3("RenderShadowClipPlanes");
+ RenderShadowOrthoClipPlanes = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
+ RenderShadowNearDist = gSavedSettings.getVector3("RenderShadowNearDist");
+ RenderFarClip = gSavedSettings.getF32("RenderFarClip");
+ RenderShadowSplitExponent = gSavedSettings.getVector3("RenderShadowSplitExponent");
+ RenderShadowErrorCutoff = gSavedSettings.getF32("RenderShadowErrorCutoff");
+ RenderShadowFOVCutoff = gSavedSettings.getF32("RenderShadowFOVCutoff");
+ CameraOffset = gSavedSettings.getBOOL("CameraOffset");
+ CameraMaxCoF = gSavedSettings.getF32("CameraMaxCoF");
+ CameraDoFResScale = gSavedSettings.getF32("CameraDoFResScale");
+
+ updateRenderDeferred();
+}
+
+void LLPipeline::releaseGLBuffers()
+{
+ assertInitialized();
+
+ if (mNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mNoiseMap);
+ mNoiseMap = 0;
+ }
+
+ if (mTrueNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mTrueNoiseMap);
+ mTrueNoiseMap = 0;
+ }
+
+ if (mLightFunc)
+ {
+ LLImageGL::deleteTextures(1, &mLightFunc);
+ mLightFunc = 0;
+ }
+
+ mWaterRef.release();
+ mWaterDis.release();
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].release();
+ }
+
+ releaseScreenBuffers();
+
+ gBumpImageList.destroyGL();
+ LLVOAvatar::resetImpostors();
+}
+
+void LLPipeline::releaseScreenBuffers()
+{
+ mUIScreen.release();
+ mScreen.release();
+ mFXAABuffer.release();
+ mPhysicsDisplay.release();
+ mDeferredScreen.release();
+ mDeferredDepth.release();
+ mDeferredLight.release();
+
+ mHighlight.release();
+
+ for (U32 i = 0; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+}
+
+
+void LLPipeline::createGLBuffers()
+{
+ stop_glerror();
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
+ assertInitialized();
+
+ updateRenderDeferred();
+
+ if (LLPipeline::sWaterReflections)
+ { //water reflection texture
+ U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
+
+ mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ }
+
+ mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
+
+ stop_glerror();
+
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ if (LLPipeline::sRenderGlow)
+ { //screen space glow buffers
+ const U32 glow_res = llmax(1,
+ llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
+ }
+
+ allocateScreenBuffer(resX,resY);
+ mScreenWidth = 0;
+ mScreenHeight = 0;
+ }
+
+ if (sRenderDeferred)
+ {
+ if (!mNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ LLVector3 noise[noiseRes*noiseRes];
+
+ F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
+ for (U32 i = 0; i < noiseRes*noiseRes; ++i)
+ {
+ noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
+ noise[i].normVec();
+ noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
+ }
+
+ LLImageGL::generateTextures(1, &mNoiseMap);
+
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mTrueNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ F32 noise[noiseRes*noiseRes*3];
+ for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
+ {
+ noise[i] = ll_frand()*2.0-1.0;
+ }
+
+ LLImageGL::generateTextures(1, &mTrueNoiseMap);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mLightFunc)
+ {
+ U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+ U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
+ U8* lg = new U8[lightResX*lightResY];
+
+ for (U32 y = 0; y < lightResY; ++y)
+ {
+ for (U32 x = 0; x < lightResX; ++x)
+ {
+ //spec func
+ F32 sa = (F32) x/(lightResX-1);
+ F32 spec = (F32) y/(lightResY-1);
+ //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
+
+ //F32 sp = acosf(sa)/(1.f-spec);
+
+ sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
+ F32 a = acosf(sa*0.25f+0.75f);
+ F32 m = llmax(0.5f-spec*0.5f, 0.001f);
+ F32 t2 = tanf(a)/m;
+ t2 *= t2;
+
+ F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
+ F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
+
+ lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
+ }
+ }
+
+ LLImageGL::generateTextures(1, &mLightFunc);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg);
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+
+ delete [] lg;
+ }
+ }
+
+ gBumpImageList.restoreGL();
+}
+
+void LLPipeline::restoreGL()
+{
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
+ assertInitialized();
+
+ if (mVertexShadersEnabled)
+ {
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->restoreGL();
+ }
+ }
+ }
+}
+
+
+BOOL LLPipeline::canUseVertexShaders()
+{
+ static const std::string vertex_shader_enable_feature_string = "VertexShaderEnable";
+
+ if (sDisableShaders ||
+ !gGLManager.mHasVertexShader ||
+ !gGLManager.mHasFragmentShader ||
+ !LLFeatureManager::getInstance()->isFeatureAvailable(vertex_shader_enable_feature_string) ||
+ (assertInitialized() && mVertexShadersLoaded != 1) )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+BOOL LLPipeline::canUseWindLightShaders() const
+{
+ return (!LLPipeline::sDisableShaders &&
+ gWLSkyProgram.mProgramObject != 0 &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
+}
+
+BOOL LLPipeline::canUseWindLightShadersOnObjects() const
+{
+ return (canUseWindLightShaders()
+ && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
+}
+
+BOOL LLPipeline::canUseAntiAliasing() const
+{
+ return TRUE;
+}
+
+void LLPipeline::unloadShaders()
+{
+ LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
+ LLViewerShaderMgr::instance()->unloadShaders();
+
+ mVertexShadersLoaded = 0;
+}
+
+void LLPipeline::assertInitializedDoError()
+{
+ llerrs << "LLPipeline used when uninitialized." << llendl;
+}
+
+//============================================================================
+
+void LLPipeline::enableShadows(const BOOL enable_shadows)
+{
+ //should probably do something here to wrangle shadows....
+}
+
+S32 LLPipeline::getMaxLightingDetail() const
+{
+ /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
+ {
+ return 3;
+ }
+ else*/
+ {
+ return 1;
+ }
+}
+
+S32 LLPipeline::setLightingDetail(S32 level)
+{
+ LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
+ refreshCachedSettings();
+
+ if (level < 0)
+ {
+ if (RenderLocalLights)
+ {
+ level = 1;
+ }
+ else
+ {
+ level = 0;
+ }
+ }
+ level = llclamp(level, 0, getMaxLightingDetail());
+ mLightingDetail = level;
+
+ return mLightingDetail;
+}
+
+class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ const std::set<LLViewerFetchedTexture*>& mTextures;
+
+ LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
+
+ virtual void visit(const LLOctreeNode<LLDrawable>* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
+ {
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ LLDrawInfo* params = *j;
+ LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
+ if (tex && mTextures.find(tex) != mTextures.end())
+ {
+ group->setState(LLSpatialGroup::GEOM_DIRTY);
+ }
+ }
+ }
+ }
+
+ for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ traverse(bridge->mOctree);
+ }
+ }
+};
+
+// Called when a texture changes # of channels (causes faces to move to alpha pool)
+void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
+{
+ assertInitialized();
+
+ // *TODO: This is inefficient and causes frame spikes; need a better way to do this
+ // Most of the time is spent in dirty.traverse.
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (poolp->isFacePool())
+ {
+ ((LLFacePool*) poolp)->dirtyTextures(textures);
+ }
+ }
+
+ LLOctreeDirtyTexture dirty(textures);
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ dirty.traverse(part->mOctree);
+ }
+ }
+ }
+}
+
+LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
+{
+ assertInitialized();
+
+ LLDrawPool *poolp = NULL;
+ switch( type )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ poolp = mSimplePool;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ poolp = mGrassPool;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ poolp = mFullbrightPool;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ poolp = mInvisiblePool;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ poolp = mGlowPool;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ poolp = mBumpPool;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ poolp = mAlphaPool;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ poolp = mSkyPool;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ poolp = mWaterPool;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ poolp = mGroundPool;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ poolp = mWLSkyPool;
+ break;
+
+ default:
+ llassert(0);
+ llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
+ break;
+ }
+
+ return poolp;
+}
+
+
+LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ LLDrawPool *poolp = findPool(type, tex0);
+ if (poolp)
+ {
+ return poolp;
+ }
+
+ LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
+ addPool( new_poolp );
+
+ return new_poolp;
+}
+
+
+// static
+LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ U32 type = getPoolTypeFromTE(te, imagep);
+ return gPipeline.getPool(type, imagep);
+}
+
+//static
+U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
+
+ if (!te || !imagep)
+ {
+ return 0;
+ }
+
+ bool alpha = te->getColor().mV[3] < 0.999f;
+ if (imagep)
+ {
+ alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
+ }
+
+ if (alpha)
+ {
+ return LLDrawPool::POOL_ALPHA;
+ }
+ else if ((te->getBumpmap() || te->getShiny()))
+ {
+ return LLDrawPool::POOL_BUMP;
+ }
+ else
+ {
+ return LLDrawPool::POOL_SIMPLE;
+ }
+}
+
+
+void LLPipeline::addPool(LLDrawPool *new_poolp)
+{
+ LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
+ assertInitialized();
+ mPools.insert(new_poolp);
+ addToQuickLookup( new_poolp );
+}
+
+void LLPipeline::allocDrawable(LLViewerObject *vobj)
+{
+ LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
+ LLDrawable *drawable = new LLDrawable();
+ vobj->mDrawable = drawable;
+
+ drawable->mVObjp = vobj;
+
+ //encompass completely sheared objects by taking
+ //the most extreme point possible (<1,1,0.5>)
+ drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
+ if (vobj->isOrphaned())
+ {
+ drawable->setState(LLDrawable::FORCE_INVISIBLE);
+ }
+ drawable->updateXform(TRUE);
+}
+
+
+static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
+
+void LLPipeline::unlinkDrawable(LLDrawable *drawable)
+{
+ LLFastTimer t(FTM_UNLINK);
+
+ assertInitialized();
+
+ LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
+
+ // Based on flags, remove the drawable from the queues that it's on.
+ if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST);
+ LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
+ if (iter != mMovedList.end())
+ {
+ mMovedList.erase(iter);
+ }
+ }
+
+ if (drawablep->getSpatialGroup())
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
+ if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
+ {
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+ llwarns << "Couldn't remove object from spatial group!" << llendl;
+#else
+ llerrs << "Couldn't remove object from spatial group!" << llendl;
+#endif
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
+ mLights.erase(drawablep);
+
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ if (iter->drawable == drawablep)
+ {
+ mNearbyLights.erase(iter);
+ break;
+ }
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
+ HighlightItem item(drawablep);
+ mHighlightSet.erase(item);
+
+ if (mHighlightObject == drawablep)
+ {
+ mHighlightObject = NULL;
+ }
+ }
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ mShadowSpotLight[i] = NULL;
+ }
+
+ if (mTargetShadowSpotLight[i] == drawablep)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+ }
+
+
+}
+
+U32 LLPipeline::addObject(LLViewerObject *vobj)
+{
+ LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
+
+ if (RenderDelayCreation)
+ {
+ mCreateQ.push_back(vobj);
+ }
+ else
+ {
+ createObject(vobj);
+ }
+
+ return 1;
+}
+
+void LLPipeline::createObjects(F32 max_dtime)
+{
+ LLFastTimer ftm(FTM_GEO_UPDATE);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
+
+ LLTimer update_timer;
+
+ while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
+ {
+ LLViewerObject* vobj = mCreateQ.front();
+ if (!vobj->isDead())
+ {
+ createObject(vobj);
+ }
+ mCreateQ.pop_front();
+ }
+
+ //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
+ //{
+ // createObject(*iter);
+ //}
+
+ //mCreateQ.clear();
+}
+
+void LLPipeline::createObject(LLViewerObject* vobj)
+{
+ LLDrawable* drawablep = vobj->mDrawable;
+
+ if (!drawablep)
+ {
+ drawablep = vobj->createDrawable(this);
+ }
+ else
+ {
+ llerrs << "Redundant drawable creation!" << llendl;
+ }
+
+ llassert(drawablep);
+
+ if (vobj->getParent())
+ {
+ vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
+ }
+ else
+ {
+ vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
+ }
+
+ markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
+
+ if (drawablep->getVOVolume() && RenderAnimateRes)
+ {
+ // fun animated res
+ drawablep->updateXform(TRUE);
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ drawablep->setScale(LLVector3(0,0,0));
+ drawablep->makeActive();
+ }
+}
+
+
+void LLPipeline::resetFrameStats()
+{
+ assertInitialized();
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
+
+ if (mBatchCount > 0)
+ {
+ mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
+ }
+ mTrianglesDrawn = 0;
+ sCompiles = 0;
+ mVerticesRelit = 0;
+ mLightingChanges = 0;
+ mGeometryChanges = 0;
+ mNumVisibleFaces = 0;
+
+ if (mOldRenderDebugMask != mRenderDebugMask)
+ {
+ gObjectList.clearDebugText();
+ mOldRenderDebugMask = mRenderDebugMask;
+ }
+
+}
+
+//external functions for asynchronous updating
+void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
+{
+ if (FreezeTime)
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
+ drawablep->updateMove(); // returns done
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
+{
+ if (FreezeTime)
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
+ drawablep->updateMove();
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
+{
+ for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
+ iter != moved_list.end(); )
+ {
+ LLDrawable::drawable_vector_t::iterator curiter = iter++;
+ LLDrawable *drawablep = *curiter;
+ BOOL done = TRUE;
+ if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
+ {
+ done = drawablep->updateMove();
+ }
+ drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
+ if (done)
+ {
+ drawablep->clearState(LLDrawable::ON_MOVE_LIST);
+ iter = moved_list.erase(curiter);
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
+static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
+
+void LLPipeline::updateMove()
+{
+ LLFastTimer t(FTM_UPDATE_MOVE);
+ LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
+
+ if (FreezeTime)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Retexture");
+ LLFastTimer t(ftm);
+
+ for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
+ iter != mRetexturedList.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+ if (drawablep && !drawablep->isDead())
+ {
+ drawablep->updateTexture();
+ }
+ }
+ mRetexturedList.clear();
+ }
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Moved List");
+ LLFastTimer t(ftm);
+ updateMovedList(mMovedList);
+ }
+
+ //balance octrees
+ {
+ LLFastTimer ot(FTM_OCTREE_BALANCE);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->mOctree->balance();
+ }
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Culling and occlusion testing
+/////////////////////////////////////////////////////////////////////////////
+
+//static
+F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
+{
+ LLVector3 lookAt = center - camera.getOrigin();
+ F32 dist = lookAt.length();
+
+ //ramp down distance for nearby objects
+ //shrink dist by dist/16.
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.length()/dist);
+ F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+ return radius*radius * F_PI;
+}
+
+//static
+F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera)
+{
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ LLVector4a lookAt;
+ lookAt.setSub(center, origin);
+ F32 dist = lookAt.getLength3().getF32();
+
+ //ramp down distance for nearby objects
+ //shrink dist by dist/16.
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.getLength3().getF32()/dist);
+ F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+ return radius*radius * F_PI;
+}
+
+void LLPipeline::grabReferences(LLCullResult& result)
+{
+ sCull = &result;
+}
+
+void LLPipeline::clearReferences()
+{
+ sCull = NULL;
+}
+
+void check_references(LLSpatialGroup* group, LLDrawable* drawable)
+{
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ if (drawable == *i)
+ {
+ llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
+ }
+ }
+}
+
+void check_references(LLDrawable* drawable, LLFace* face)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ if (drawable->getFace(i) == face)
+ {
+ llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+}
+
+void check_references(LLSpatialGroup* group, LLFace* face)
+{
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ check_references(drawable, face);
+ }
+}
+
+void LLPipeline::checkReferences(LLFace* face)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ check_references(drawable, face);
+ }
+ }
+#endif
+}
+
+void LLPipeline::checkReferences(LLDrawable* drawable)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+ {
+ if (drawable == *iter)
+ {
+ llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+#endif
+}
+
+void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info)
+{
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo* params = *j;
+ if (params == draw_info)
+ {
+ llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+}
+
+
+void LLPipeline::checkReferences(LLDrawInfo* draw_info)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+ }
+#endif
+}
+
+void LLPipeline::checkReferences(LLSpatialGroup* group)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+#endif
+}
+
+
+BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
+{
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (part->visibleObjectsInFrustum(camera))
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
+{
+ const F32 X = 65536.f;
+
+ min = LLVector3(X,X,X);
+ max = LLVector3(-X,-X,-X);
+
+ U32 saved_camera_id = LLViewerCamera::sCurCameraID;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+ BOOL res = TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (!part->getVisibleExtents(camera, min, max))
+ {
+ res = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ LLViewerCamera::sCurCameraID = saved_camera_id;
+
+ return res;
+}
+
+static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
+
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
+{
+ LLFastTimer t(FTM_CULL);
+ LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
+
+ grabReferences(result);
+
+ sCull->clear();
+
+ BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
+ !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
+ LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ gPipeline.canUseVertexShaders() &&
+ sRenderGlow;
+
+ if (to_texture)
+ {
+ mScreen.bindTarget();
+ }
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(false, false);
+ }
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLLastProjection);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLLastModelView);
+
+
+ LLVertexBuffer::unbind();
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+
+ //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling)
+ LLViewerRegion* region = gAgent.getRegion();
+ LLPlane plane;
+
+ if (planep)
+ {
+ plane = *planep;
+ }
+ else
+ {
+ if (region)
+ {
+ LLVector3 pnorm;
+ F32 height = region->getWaterHeight();
+ if (water_clip < 0)
+ { //camera is above water, clip plane points up
+ pnorm.setVec(0,0,1);
+ plane.setVec(pnorm, -height);
+ }
+ else if (water_clip > 0)
+ { //camera is below water, clip plane points down
+ pnorm = LLVector3(0,0,-1);
+ plane.setVec(pnorm, height);
+ }
+ }
+ }
+
+ glh::matrix4f modelview = glh_get_last_modelview();
+ glh::matrix4f proj = glh_get_last_projection();
+ LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ bool bound_shader = false;
+ if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0)
+ { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can
+ // (shadow render uses a special shader that clamps to clip planes)
+ bound_shader = true;
+ gOcclusionProgram.bind();
+ }
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ if (water_clip != 0)
+ {
+ LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
+ camera.setUserClipPlane(plane);
+ }
+ else
+ {
+ camera.disableUserClipPlane();
+ }
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->cull(camera);
+ }
+ }
+ }
+ }
+
+ if (bound_shader)
+ {
+ gOcclusionProgram.unbind();
+ }
+
+ camera.disableUserClipPlane();
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
+ gSky.mVOSkyp.notNull() &&
+ gSky.mVOSkyp->mDrawable.notNull())
+ {
+ gSky.mVOSkyp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
+ gSky.updateCull();
+ stop_glerror();
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
+ !gPipeline.canUseWindLightShaders() &&
+ gSky.mVOGroundp.notNull() &&
+ gSky.mVOGroundp->mDrawable.notNull() &&
+ !LLPipeline::sWaterReflections)
+ {
+ gSky.mVOGroundp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
+ }
+
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(true, false);
+ }
+
+ if (to_texture)
+ {
+ mScreen.flush();
+ }
+}
+
+void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
+{
+ if (group->getData().empty())
+ {
+ return;
+ }
+
+ group->setVisible();
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ group->updateDistance(camera);
+ }
+
+ const F32 MINIMUM_PIXEL_AREA = 16.f;
+
+ if (group->mPixelArea < MINIMUM_PIXEL_AREA)
+ {
+ return;
+ }
+
+ if (sMinRenderSize > 0.f &&
+ llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!group->mSpatialPartition->mRenderByGroup)
+ { //render by drawable
+ sCull->pushDrawableGroup(group);
+ }
+ else
+ { //render by group
+ sCull->pushVisibleGroup(group);
+ }
+
+ mNumVisibleNodes++;
+}
+
+void LLPipeline::markOccluder(LLSpatialGroup* group)
+{
+ if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
+ {
+ LLSpatialGroup* parent = group->getParent();
+
+ if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //only mark top most occluders as active occlusion
+ sCull->pushOcclusionGroup(group);
+ group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+
+ if (parent &&
+ !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
+ parent->getElementCount() == 0 &&
+ parent->needsUpdate())
+ {
+ sCull->pushOcclusionGroup(group);
+ parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+ }
+ }
+}
+
+void LLPipeline::doOcclusion(LLCamera& camera)
+{
+ if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
+ {
+ LLVertexBuffer::unbind();
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ {
+ gGL.setColorMask(true, false, false, false);
+ }
+ else
+ {
+ gGL.setColorMask(false, false);
+ }
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ LLGLDisable cull(GL_CULL_FACE);
+
+
+ bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0;
+ if (bind_shader)
+ {
+ if (LLPipeline::sShadowRender)
+ {
+ gDeferredShadowProgram.bind();
+ }
+ else
+ {
+ gOcclusionProgram.bind();
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->doOcclusion(&camera);
+ group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+
+ if (bind_shader)
+ {
+ if (LLPipeline::sShadowRender)
+ {
+ gDeferredShadowProgram.unbind();
+ }
+ else
+ {
+ gOcclusionProgram.unbind();
+ }
+ }
+
+ gGL.setColorMask(true, false);
+ }
+}
+
+BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
+{
+ BOOL update_complete = drawablep->updateGeometry(priority);
+ if (update_complete && assertInitialized())
+ {
+ drawablep->setState(LLDrawable::BUILT);
+ mGeometryChanges++;
+ }
+ return update_complete;
+}
+
+void LLPipeline::updateGL()
+{
+ while (!LLGLUpdate::sGLQ.empty())
+ {
+ LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
+ glu->updateGL();
+ glu->mInQ = FALSE;
+ LLGLUpdate::sGLQ.pop_front();
+ }
+}
+
+void LLPipeline::rebuildPriorityGroups()
+{
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ gMeshRepo.notifyLoadedMeshes();
+
+ mGroupQ1Locked = true;
+ // Iterate through all drawables on the priority build queue,
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
+ iter != mGroupQ1.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->rebuildGeom();
+ group->clearState(LLSpatialGroup::IN_BUILD_Q1);
+ }
+
+ mGroupQ1.clear();
+ mGroupQ1Locked = false;
+
+}
+
+void LLPipeline::rebuildGroups()
+{
+ if (mGroupQ2.empty())
+ {
+ return;
+ }
+
+ mGroupQ2Locked = true;
+ // Iterate through some drawables on the non-priority build queue
+ S32 size = (S32) mGroupQ2.size();
+ S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
+
+ S32 count = 0;
+
+ std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
+
+ LLSpatialGroup::sg_vector_t::iterator iter;
+ LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin();
+
+ for (iter = mGroupQ2.begin();
+ iter != mGroupQ2.end() && count <= min_count; ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ last_iter = iter;
+
+ if (!group->isDead())
+ {
+ group->rebuildGeom();
+
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ count++;
+ }
+ }
+
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+ }
+
+ mGroupQ2.erase(mGroupQ2.begin(), ++last_iter);
+
+ mGroupQ2Locked = false;
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::updateGeom(F32 max_dtime)
+{
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
+ LLPointer<LLDrawable> drawablep;
+
+ LLFastTimer t(FTM_GEO_UPDATE);
+
+ assertInitialized();
+
+ // notify various object types to reset internal cost metrics, etc.
+ // for now, only LLVOVolume does this to throttle LOD changes
+ LLVOVolume::preUpdateGeom();
+
+ // Iterate through all drawables on the priority build queue,
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
+ iter != mBuildQ1.end();)
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+ if (drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
+ if (find != mBuildQ2.end())
+ {
+ mBuildQ2.erase(find);
+ }
+ }
+
+ if (updateDrawableGeom(drawablep, TRUE))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
+ mBuildQ1.erase(curiter);
+ }
+ }
+ else
+ {
+ mBuildQ1.erase(curiter);
+ }
+ }
+
+ // Iterate through some drawables on the non-priority build queue
+ S32 min_count = 16;
+ S32 size = (S32) mBuildQ2.size();
+ if (size > 1024)
+ {
+ min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
+ }
+
+ S32 count = 0;
+
+ max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
+ LLSpatialGroup* last_group = NULL;
+ LLSpatialBridge* last_bridge = NULL;
+
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
+ iter != mBuildQ2.end(); )
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+
+ LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
+ drawablep->getParent()->getSpatialBridge();
+
+ if (drawablep->getSpatialGroup() != last_group &&
+ (!last_bridge || bridge != last_bridge) &&
+ (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
+ {
+ break;
+ }
+
+ //make sure updates don't stop in the middle of a spatial group
+ //to avoid thrashing (objects are enqueued by group)
+ last_group = drawablep->getSpatialGroup();
+ last_bridge = bridge;
+
+ BOOL update_complete = TRUE;
+ if (!drawablep->isDead())
+ {
+ update_complete = updateDrawableGeom(drawablep, FALSE);
+ count++;
+ }
+ if (update_complete)
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ mBuildQ2.erase(curiter);
+ }
+ }
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
+
+ if(drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
+ llassert(root); // trying to catch a bad assumption
+ if (root && // // this test may not be needed, see above
+ root->getVObj()->isAttachment())
+ {
+ LLDrawable* rootparent = root->getParent();
+ if (rootparent) // this IS sometimes NULL
+ {
+ LLViewerObject *vobj = rootparent->getVObj();
+ llassert(vobj); // trying to catch a bad assumption
+ if (vobj) // this test may not be needed, see above
+ {
+ const LLVOAvatar* av = vobj->asAvatar();
+ if (av && av->isImpostor())
+ {
+ return;
+ }
+ }
+ }
+ }
+ sCull->pushBridge((LLSpatialBridge*) drawablep);
+ }
+ else
+ {
+ sCull->pushDrawable(drawablep);
+ }
+
+ drawablep->setVisible(camera);
+ }
+}
+
+void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
+{
+ LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
+
+ if (!drawablep)
+ {
+ //llerrs << "Sending null drawable to moved list!" << llendl;
+ return;
+ }
+
+ if (drawablep->isDead())
+ {
+ llwarns << "Marking NULL or dead drawable moved!" << llendl;
+ return;
+ }
+
+ if (drawablep->getParent())
+ {
+ //ensure that parent drawables are moved first
+ markMoved(drawablep->getParent(), damped_motion);
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ mMovedBridge.push_back(drawablep);
+ }
+ else
+ {
+ mMovedList.push_back(drawablep);
+ }
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+ if (damped_motion == FALSE)
+ {
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
+ }
+ else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
+ {
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ }
+}
+
+void LLPipeline::markShift(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
+
+ if (!drawablep || drawablep->isDead())
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
+ if (drawablep->getParent())
+ {
+ markShift(drawablep->getParent());
+ }
+ mShiftList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_SHIFT_LIST);
+ }
+}
+
+void LLPipeline::shiftObjects(const LLVector3 &offset)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
+
+ assertInitialized();
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ gDepthDirty = TRUE;
+
+ LLVector4a offseta;
+ offseta.load3(offset.mV);
+
+ for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+ iter != mShiftList.end(); iter++)
+ {
+ LLDrawable *drawablep = *iter;
+ if (drawablep->isDead())
+ {
+ continue;
+ }
+ drawablep->shiftPos(offseta);
+ drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
+ }
+ mShiftList.resize(0);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->shift(offseta);
+ }
+ }
+ }
+
+ LLHUDText::shiftAll(offset);
+ LLHUDNameTag::shiftAll(offset);
+ display_update_camera();
+}
+
+void LLPipeline::markTextured(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ mRetexturedList.insert(drawablep);
+ }
+}
+
+void LLPipeline::markGLRebuild(LLGLUpdate* glu)
+{
+ if (glu && !glu->mInQ)
+ {
+ LLGLUpdate::sGLQ.push_back(glu);
+ glu->mInQ = TRUE;
+ }
+}
+
+void LLPipeline::markPartitionMove(LLDrawable* drawable)
+{
+ if (!drawable->isState(LLDrawable::PARTITION_MOVE) &&
+ !drawable->getPositionGroup().equals3(LLVector4a::getZero()))
+ {
+ drawable->setState(LLDrawable::PARTITION_MOVE);
+ mPartitionQ.push_back(drawable);
+ }
+}
+
+void LLPipeline::processPartitionQ()
+{
+ for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ if (!drawable->isDead())
+ {
+ drawable->updateBinRadius();
+ drawable->movePartition();
+ }
+ drawable->clearState(LLDrawable::PARTITION_MOVE);
+ }
+
+ mPartitionQ.clear();
+}
+
+void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ if (group && !group->isDead() && group->mSpatialPartition)
+ {
+ if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
+ {
+ priority = TRUE;
+ }
+
+ if (priority)
+ {
+ if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
+ {
+ llassert_always(!mGroupQ1Locked);
+
+ mGroupQ1.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q1);
+
+ if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
+ {
+ LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
+ if (iter != mGroupQ2.end())
+ {
+ mGroupQ2.erase(iter);
+ }
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+ }
+ }
+ }
+ else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
+ {
+ llassert_always(!mGroupQ2Locked);
+ mGroupQ2.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q2);
+
+ }
+ }
+}
+
+void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ if (!drawablep->isState(LLDrawable::BUILT))
+ {
+ priority = TRUE;
+ }
+ if (priority)
+ {
+ if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
+ {
+ mBuildQ1.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
+ }
+ }
+ else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ mBuildQ2.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
+ }
+ if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
+ }
+ drawablep->setState(flag);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
+
+void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
+{
+ if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::END_RENDER_TYPES))
+ {
+ //clear faces from face pools
+ LLFastTimer t(FTM_RESET_DRAWORDER);
+ gPipeline.resetDrawOrders();
+ }
+
+ LLFastTimer ftm(FTM_STATESORT);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ //LLVertexBuffer::unbind();
+
+ grabReferences(result);
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ markVisible(*i, camera);
+ }
+
+ if (!sDelayVBUpdate)
+ { //rebuild mesh as soon as we know it's visible
+ group->rebuildMesh();
+ }
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ LLSpatialGroup* last_group = NULL;
+ for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLCullResult::bridge_list_t::iterator cur_iter = i;
+ LLSpatialBridge* bridge = *cur_iter;
+ LLSpatialGroup* group = bridge->getSpatialGroup();
+
+ if (last_group == NULL)
+ {
+ last_group = group;
+ }
+
+ if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ stateSort(bridge, camera);
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ last_group != group && last_group->changeLOD())
+ {
+ last_group->mLastUpdateDistance = last_group->mDistance;
+ }
+
+ last_group = group;
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ last_group && last_group->changeLOD())
+ {
+ last_group->mLastUpdateDistance = last_group->mDistance;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ stateSort(group, camera);
+
+ if (!sDelayVBUpdate)
+ { //rebuild mesh as soon as we know it's visible
+ group->rebuildMesh();
+ }
+ }
+ }
+
+ {
+ LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
+ iter != sCull->endVisibleList(); ++iter)
+ {
+ LLDrawable *drawablep = *iter;
+ if (!drawablep->isDead())
+ {
+ stateSort(drawablep, camera);
+ }
+ }
+ }
+
+ postSort(camera);
+}
+
+void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (group->changeLOD())
+ {
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawablep = *i;
+ stateSort(drawablep, camera);
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ { //avoid redundant stateSort calls
+ group->mLastUpdateDistance = group->mDistance;
+ }
+ }
+
+}
+
+void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (bridge->getSpatialGroup()->changeLOD())
+ {
+ bool force_update = false;
+ bridge->updateDistance(camera, force_update);
+ }
+}
+
+void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ if (!drawablep
+ || drawablep->isDead()
+ || !hasRenderType(drawablep->getRenderType()))
+ {
+ return;
+ }
+
+ if (LLSelectMgr::getInstance()->mHideSelectedObjects)
+ {
+ if (drawablep->getVObj().notNull() &&
+ drawablep->getVObj()->isSelected())
+ {
+ return;
+ }
+ }
+
+ if (drawablep->isAvatar())
+ { //don't draw avatars beyond render distance or if we don't have a spatial group.
+ if ((drawablep->getSpatialGroup() == NULL) ||
+ (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
+ {
+ return;
+ }
+
+ LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
+ if (!avatarp->isVisible())
+ {
+ return;
+ }
+ }
+
+ assertInitialized();
+
+ if (hasRenderType(drawablep->mRenderType))
+ {
+ if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
+ {
+ drawablep->setVisible(camera, NULL, FALSE);
+ }
+ else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
+ {
+ // clear invisible flag here to avoid single frame glitch
+ drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
+ {
+ if (!drawablep->isActive())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update);
+ }
+ else if (drawablep->isAvatar())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
+ }
+ }
+ }
+
+ if (!drawablep->getVOVolume())
+ {
+ for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
+ iter != drawablep->mFaces.end(); iter++)
+ {
+ LLFace* facep = *iter;
+
+ if (facep->hasGeometry())
+ {
+ if (facep->getPool())
+ {
+ facep->getPool()->enqueue(facep);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+
+ mNumVisibleFaces += drawablep->getNumFaces();
+}
+
+
+void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
+ LLCullResult::sg_list_t::iterator end,
+ void (*func)(LLDrawable*))
+{
+ for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
+ {
+ for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
+ {
+ func(*j);
+ }
+ }
+}
+
+void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
+{
+ forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
+ forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
+}
+
+//function for creating scripted beacons
+void renderScriptedBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderScriptedTouchBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted()
+ && vobj->flagHandleTouch())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderPhysicalBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ //&& !vobj->getParent()
+ && vobj->flagUsePhysics())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderMOAPBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+
+ if(!vobj || vobj->isAvatar())
+ return;
+
+ BOOL beacon=FALSE;
+ U8 tecount=vobj->getNumTEs();
+ for(int x=0;x<tecount;x++)
+ {
+ if(vobj->getTE(x)->hasMedia())
+ {
+ beacon=TRUE;
+ break;
+ }
+ }
+ if(beacon==TRUE)
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderParticleBeacons(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && vobj->isParticleSource())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), LLPipeline::DebugBeaconLineWidth);
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderSoundHighlights(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj && vobj->isAudioSource())
+ {
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void LLPipeline::postSort(LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
+ LLFastTimer ftm(FTM_STATESORT_POSTSORT);
+
+ assertInitialized();
+
+ llpushcallstacks ;
+ //rebuild drawable geometry
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!sUseOcclusion ||
+ !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ group->rebuildGeom();
+ }
+ }
+ llpushcallstacks ;
+ //rebuild groups
+ sCull->assertDrawMapsEmpty();
+
+ rebuildPriorityGroups();
+ llpushcallstacks ;
+
+ const S32 bin_count = 1024*8;
+
+ static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
+ static U32 bin_size[bin_count];
+
+ //clear one bin per frame to avoid memory bloat
+ static S32 clear_idx = 0;
+ clear_idx = (1+clear_idx)%bin_count;
+ alpha_bins[clear_idx].clear();
+
+ for (U32 j = 0; j < bin_count; j++)
+ {
+ bin_size[j] = 0;
+ }
+
+ //build render map
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (sUseOcclusion &&
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ continue;
+ }
+
+ if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
+ { //no way this group is going to be drawable without a rebuild
+ group->rebuildGeom();
+ }
+
+ for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
+ {
+ LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
+ if (!hasRenderType(j->first))
+ {
+ continue;
+ }
+
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
+ {
+ if (sMinRenderSize > 0.f)
+ {
+ LLVector4a bounds;
+ bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
+
+ if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ else
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
+ {
+ LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
+
+ if (alpha != group->mDrawMap.end())
+ { //store alpha groups for sorting
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ if (bridge)
+ {
+ LLCamera trans_camera = bridge->transformCamera(camera);
+ group->updateDistance(trans_camera);
+ }
+ else
+ {
+ group->updateDistance(camera);
+ }
+ }
+
+ if (hasRenderType(LLDrawPool::POOL_ALPHA))
+ {
+ sCull->pushAlphaGroup(group);
+ }
+ }
+ }
+ }
+
+ if (!sShadowRender)
+ {
+ std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
+ }
+ llpushcallstacks ;
+ // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
+ if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
+ {
+ if (sRenderScriptedTouchBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedTouchBeacons);
+ }
+ else
+ if (sRenderScriptedBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedBeacons);
+ }
+
+ if (sRenderPhysicalBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderPhysicalBeacons);
+ }
+
+ if(sRenderMOAPBeacons)
+ {
+ forAllVisibleDrawables(renderMOAPBeacons);
+ }
+
+ if (sRenderParticleBeacons)
+ {
+ forAllVisibleDrawables(renderParticleBeacons);
+ }
+
+ // If god mode, also show audio cues
+ if (sRenderSoundBeacons && gAudiop)
+ {
+ // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
+ LLAudioEngine::source_map::iterator iter;
+ for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
+ {
+ LLAudioSource *sourcep = iter->second;
+
+ LLVector3d pos_global = sourcep->getPositionGlobal();
+ LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
+ if (gPipeline.sRenderBeacons)
+ {
+ //pos += LLVector3(0.f, 0.f, 0.2f);
+ gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), DebugBeaconLineWidth);
+ }
+ }
+ // now deal with highlights for all those seeable sound sources
+ forAllVisibleDrawables(renderSoundHighlights);
+ }
+ }
+ llpushcallstacks ;
+ // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
+ if (LLFloaterTelehub::renderBeacons())
+ {
+ LLFloaterTelehub::addBeacons();
+ }
+
+ if (!sShadowRender)
+ {
+ mSelectedFaces.clear();
+
+ // Draw face highlights for selected faces.
+ if (LLSelectMgr::getInstance()->getTEMode())
+ {
+ struct f : public LLSelectedTEFunctor
+ {
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ if (object->mDrawable)
+ {
+ gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+ }
+ }
+
+ //LLSpatialGroup::sNoDelete = FALSE;
+ llpushcallstacks ;
+}
+
+
+void render_hud_elements()
+{
+ LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
+ LLFastTimer t(FTM_RENDER_UI);
+ gPipeline.disableLights();
+
+ LLGLDisable fog(GL_FOG);
+ LLGLSUIDefault gls_ui;
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
+ glStencilMask(0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ gGL.color4f(1,1,1,1);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLGLEnable multisample(LLPipeline::RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+ gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
+
+ // Draw the tracking overlays
+ LLTracker::render3D();
+
+ // Show the property lines
+ LLWorld::getInstance()->renderPropertyLines();
+ LLViewerParcelMgr::getInstance()->render();
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+
+ // Render name tags.
+ LLHUDObject::renderAll();
+ }
+ else if (gForceRenderLandFence)
+ {
+ // This is only set when not rendering the UI, for parcel snapshots
+ LLViewerParcelMgr::getInstance()->render();
+ }
+ else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ LLHUDText::renderAllHUD();
+ }
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.unbind();
+ }
+ gGL.flush();
+}
+
+void LLPipeline::renderHighlights()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
+
+ assertInitialized();
+
+ // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
+ // Render highlighted faces.
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+ LLColor4 color(1.f, 1.f, 1.f, 0.5f);
+ LLGLEnable color_mat(GL_COLOR_MATERIAL);
+ disableLights();
+
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
+ { //draw blurry highlight image over screen
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ gGL.flush();
+ glStencilMask(0xFFFFFFFF);
+ glClearStencil(1);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ gGL.setColorMask(false, false);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
+ {
+ renderHighlight(iter->mItem->getVObj(), 1.f);
+ }
+ gGL.setColorMask(true, false);
+
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
+
+ //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ gGL.getTexUnit(0)->bind(&mHighlight);
+
+ LLVector2 tc1;
+ LLVector2 tc2;
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ gGL.begin(LLRender::TRIANGLES);
+
+ F32 scale = RenderHighlightBrightness;
+ LLColor4 color = RenderHighlightColor;
+ F32 thickness = RenderHighlightThickness;
+
+ for (S32 pass = 0; pass < 2; ++pass)
+ {
+ if (pass == 0)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+ }
+ else
+ {
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ for (S32 j = 0; j < 8; ++j)
+ {
+ LLVector2 tc(i-4+0.5f, j-4+0.5f);
+
+ F32 dist = 1.f-(tc.length()/sqrtf(32.f));
+ dist *= scale/64.f;
+
+ tc *= thickness;
+ tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
+ tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
+
+ gGL.color4f(color.mV[0],
+ color.mV[1],
+ color.mV[2],
+ color.mV[3]*dist);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+ }
+ }
+ }
+
+ gGL.end();
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ //gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+ {
+ gHighlightProgram.bind();
+ gGL.diffuseColor4f(1,1,1,0.5f);
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Make sure the selection image gets downloaded and decoded
+ if (!mFaceSelectImagep)
+ {
+ mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
+ }
+ mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
+
+ U32 count = mSelectedFaces.size();
+ for (U32 i = 0; i < count; i++)
+ {
+ LLFace *facep = mSelectedFaces[i];
+ if (!facep || facep->getDrawable()->isDead())
+ {
+ llerrs << "Bad face on selection" << llendl;
+ return;
+ }
+
+ facep->renderSelected(mFaceSelectImagep, color);
+ }
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Paint 'em red!
+ color.setVec(1.f, 0.f, 0.f, 0.5f);
+
+ int count = mHighlightFaces.size();
+ for (S32 i = 0; i < count; i++)
+ {
+ LLFace* facep = mHighlightFaces[i];
+ facep->renderSelected(LLViewerTexture::sNullImagep, color);
+ }
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
+ {
+ gHighlightProgram.unbind();
+ }
+}
+
+//debug use
+U32 LLPipeline::sCurRenderPoolType = 0 ;
+
+void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ assertInitialized();
+
+ F32 saved_modelview[16];
+ F32 saved_projection[16];
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ saved_modelview[i] = gGLModelView[i];
+ saved_projection[i] = gGLProjection[i];
+ }
+ }
+
+ ///////////////////////////////////////////
+ //
+ // Sync and verify GL state
+ //
+ //
+
+ stop_glerror();
+
+ LLVertexBuffer::unbind();
+
+ // Do verification of GL state
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
+ {
+ if (!verify())
+ {
+ llerrs << "Pipeline verification failed!" << llendl;
+ }
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
+
+ // Initialize lots of GL state to "safe" values
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+
+ LLGLSPipeline gls_pipeline;
+ LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
+
+ // Toggle backface culling for debugging
+ LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
+ // Set fog
+ BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
+ LLGLEnable fog_enable(use_fog &&
+ !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
+ gSky.updateFog(camera.getFar());
+ if (!use_fog)
+ {
+ sUnderWaterRender = FALSE;
+ }
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
+ LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
+
+
+ //////////////////////////////////////////////
+ //
+ // Actually render all of the geometry
+ //
+ //
+ stop_glerror();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_POOLS);
+
+ // HACK: don't calculate local lights if we're rendering the HUD!
+ // Removing this check will cause bad flickering when there are
+ // HUD elements being rendered AND the user is in flycam mode -nyx
+ if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+ }
+
+ BOOL occlude = sUseOcclusion > 1;
+ U32 cur_type = 0;
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ //debug use
+ sCurRenderPoolType = cur_type ;
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ LLGLSLShader::bindNoShader();
+ doOcclusion(camera);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginRenderPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->render(i);
+ }
+ poolp->endRenderPass(i);
+ LLVertexBuffer::unbind();
+ if (gDebugGL)
+ {
+ std::string msg = llformat("pass %d", i);
+ LLGLState::checkStates(msg);
+ //LLGLState::checkTextureChannels(msg);
+ //LLGLState::checkClientArrays(msg);
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
+
+ LLVertexBuffer::unbind();
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ LLGLSLShader::bindNoShader();
+ doOcclusion(camera);
+ }
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+
+ if (!LLPipeline::sImpostorRender)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
+
+ if (!sReflectionRender)
+ {
+ renderHighlights();
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
+ {
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLModelView[i] = saved_modelview[i];
+ gGLProjection[i] = saved_projection[i];
+ }
+ }
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+// LLGLState::checkTextureChannels();
+// LLGLState::checkClientArrays();
+}
+
+void LLPipeline::renderGeomDeferred(LLCamera& camera)
+{
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
+
+ LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ LLFastTimer t2(FTM_POOLS);
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+ stop_glerror();
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ stop_glerror();
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ U32 cur_type = 0;
+
+ gGL.setColorMask(true, true);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderDeferred(i);
+ }
+ poolp->endDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ LLGLState::checkStates();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ gGL.setColorMask(true, false);
+}
+
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+{
+ LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
+ LLFastTimer t(FTM_POOLS);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+
+ gGL.setColorMask(true, false);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ BOOL occlude = LLPipeline::sUseOcclusion > 1;
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ LLGLSLShader::bindNoShader();
+ doOcclusion(camera);
+ gGL.setColorMask(true, false);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginPostDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderPostDeferred(i);
+ }
+ poolp->endPostDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ LLGLState::checkStates();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ LLGLSLShader::bindNoShader();
+ doOcclusion(camera);
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ }
+}
+
+void LLPipeline::renderGeomShadow(LLCamera& camera)
+{
+ LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLVertexBuffer::unbind();
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
+ {
+ poolp->prerender() ;
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginShadowPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderShadow(i);
+ }
+ poolp->endShadowPass(i);
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+}
+
+
+void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
+{
+ assertInitialized();
+ S32 count = 0;
+ if (render_type == LLRender::TRIANGLE_STRIP)
+ {
+ count = index_count-2;
+ }
+ else
+ {
+ count = index_count/3;
+ }
+
+ mTrianglesDrawn += count;
+ mBatchCount++;
+ mMaxBatchSize = llmax(mMaxBatchSize, count);
+ mMinBatchSize = llmin(mMinBatchSize, count);
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ gViewerWindow->getWindow()->swapBuffers();
+ ms_sleep(16);
+ }
+}
+
+void LLPipeline::renderPhysicsDisplay()
+{
+ if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
+ {
+ return;
+ }
+
+ allocatePhysicsBuffer();
+
+ gGL.flush();
+ mPhysicsDisplay.bindTarget();
+ glClearColor(0,0,0,1);
+ gGL.setColorMask(true, true);
+ mPhysicsDisplay.clear();
+ glClearColor(0,0,0,0);
+
+ gGL.setColorMask(true, false);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.bind();
+ }
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderPhysicsShapes();
+ }
+ }
+ }
+ }
+
+ for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+ {
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ bridge->renderPhysicsShapes();
+ gGL.popMatrix();
+ }
+ }
+
+ gGL.flush();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.unbind();
+ }
+
+ mPhysicsDisplay.flush();
+}
+
+
+void LLPipeline::renderDebug()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gPipeline.disableLights();
+
+ //Render any navmesh geometry
+ LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance();
+ if ( llPathingLibInstance != NULL )
+ {
+ LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle();
+ if (!pathfindingConsoleHandle.isDead())
+ {
+ LLFloaterPathfindingConsole *pathfindingConsole = pathfindingConsoleHandle.get();
+ //NavMesh
+ if ( pathfindingConsole->isRenderNavMesh() )
+ {
+ glLineWidth(1.5f);
+ LLGLEnable cull(GL_CULL_FACE);
+ if ( pathfindingConsole->isRenderWorld() )
+ {
+ glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ }
+ else
+ {
+ glClearColor(0,0,0,0);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+ llPathingLibInstance->renderNavMesh();
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ glLineWidth(1.0f);
+ gGL.flush();
+ }
+ //physics/exclusion shapes
+ if ( pathfindingConsole->isRenderAnyShapes() )
+ {
+ LLGLEnable blend(GL_BLEND);
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ llPathingLibInstance->renderNavMeshShapesVBO( pathfindingConsole->getRenderShapeFlags() );
+ gGL.flush();
+ LLGLDisable blendOut(GL_BLEND);
+ glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ llPathingLibInstance->renderNavMeshShapesVBO( pathfindingConsole->getRenderShapeFlags() );
+ gGL.flush();
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+ //User designated path
+ if ( pathfindingConsole->isRenderPath() )
+ {
+ llPathingLibInstance->renderPath();
+ }
+ }
+ }
+ gGL.flush();
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.unbind();
+ }
+
+ gGL.color4f(1,1,1,1);
+
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ gGL.setColorMask(true, false);
+
+ bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD);
+
+
+ if (!hud_only && !mDebugBlips.empty())
+ { //render debug blips
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true);
+
+ glPointSize(8.f);
+ LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+
+ gGL.begin(LLRender::POINTS);
+ for (std::list<DebugBlip>::iterator iter = mDebugBlips.begin(); iter != mDebugBlips.end(); )
+ {
+ DebugBlip& blip = *iter;
+
+ blip.mAge += gFrameIntervalSeconds;
+ if (blip.mAge > 2.f)
+ {
+ mDebugBlips.erase(iter++);
+ }
+ else
+ {
+ iter++;
+ }
+
+ blip.mPosition.mV[2] += gFrameIntervalSeconds*2.f;
+
+ gGL.color4fv(blip.mColor.mV);
+ gGL.vertex3fv(blip.mPosition.mV);
+ }
+ gGL.end();
+ gGL.flush();
+ glPointSize(1.f);
+ }
+
+
+ // Debug stuff.
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
+ !hud_only && hasRenderType(part->mDrawableType) )
+ {
+ part->renderDebug();
+ }
+ }
+ }
+ }
+
+ for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+ {
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ bridge->renderDebug();
+ gGL.popMatrix();
+ }
+ }
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLVertexBuffer::unbind();
+
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(TRUE, FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gGL.color4f(1,1,1,1);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ F32 a = 0.1f;
+
+ F32 col[] =
+ {
+ 1,0,0,a,
+ 0,1,0,a,
+ 0,0,1,a,
+ 1,0,1,a,
+
+ 1,1,0,a,
+ 0,1,1,a,
+ 1,1,1,a,
+ 1,0,1,a,
+ };
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
+ if (i > 3)
+ { //render shadow frusta as volumes
+ if (mShadowFrustPoints[i-4].empty())
+ {
+ continue;
+ }
+
+ gGL.color4fv(col+(i-4)*4);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.end();
+
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[2].mV);
+ gGL.end();
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[6].mV);
+ gGL.end();
+ }
+
+
+ if (i < 4)
+ {
+
+ //if (i == 0 || !mShadowFrustPoints[i].empty())
+ {
+ //render visible point cloud
+ gGL.flush();
+ glPointSize(8.f);
+ gGL.begin(LLRender::POINTS);
+
+ F32* c = col+i*4;
+ gGL.color3fv(c);
+
+ for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
+ {
+ gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
+
+ }
+ gGL.end();
+
+ gGL.flush();
+ glPointSize(1.f);
+
+ LLVector3* ext = mShadowExtents[i];
+ LLVector3 pos = (ext[0]+ext[1])*0.5f;
+ LLVector3 size = (ext[1]-ext[0])*0.5f;
+ drawBoxOutline(pos, size);
+
+ //render camera frustum splits as outlines
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.end();
+ }
+ }
+
+ /*gGL.flush();
+ glLineWidth(16-i*2);
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderIntersectingBBoxes(&mShadowCamera[i]);
+ }
+ }
+ }
+ }
+ gGL.flush();
+ glLineWidth(1.f);*/
+ }
+ }
+
+ if (mRenderDebugMask & RENDER_DEBUG_WIND_VECTORS)
+ {
+ gAgent.getRegion()->mWind.renderVectors();
+ }
+
+ if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
+ {
+ // Debug composition layers
+ F32 x, y;
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (gAgent.getRegion())
+ {
+ gGL.begin(LLRender::POINTS);
+ // Draw the composition layer for the region that I'm in.
+ for (x = 0; x <= 260; x++)
+ {
+ for (y = 0; y <= 260; y++)
+ {
+ if ((x > 255) || (y > 255))
+ {
+ gGL.color4f(1.f, 0.f, 0.f, 1.f);
+ }
+ else
+ {
+ gGL.color4f(0.f, 0.f, 1.f, 1.f);
+ }
+ F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
+ z *= 5.f;
+ z += 50.f;
+ gGL.vertex3f(x, y, z);
+ }
+ }
+ gGL.end();
+ }
+ }
+
+ if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
+ {
+ U32 count = 0;
+ U32 size = mGroupQ2.size();
+ LLColor4 col;
+
+ LLVertexBuffer::unbind();
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLModelView);
+ gGLLastMatrix = NULL;
+
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ if (group->isDead())
+ {
+ continue;
+ }
+
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+
+ if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
+ {
+ continue;
+ }
+
+ if (bridge)
+ {
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ }
+
+ F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f);
+
+
+ LLVector2 c(1.f-alpha, alpha);
+ c.normVec();
+
+
+ ++count;
+ col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f);
+ group->drawObjectBox(col);
+
+ if (bridge)
+ {
+ gGL.popMatrix();
+ }
+ }
+
+ gGL.popMatrix();
+ }
+
+ gGL.flush();
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.unbind();
+ }
+}
+
+void LLPipeline::rebuildPools()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
+
+ assertInitialized();
+
+ S32 max_count = mPools.size();
+ pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
+ while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
+ {
+ if (iter1 == mPools.end())
+ {
+ iter1 = mPools.begin();
+ }
+ LLDrawPool* poolp = *iter1;
+
+ if (poolp->isDead())
+ {
+ mPools.erase(iter1++);
+ removeFromQuickLookup( poolp );
+ if (poolp == mLastRebuildPool)
+ {
+ mLastRebuildPool = NULL;
+ }
+ delete poolp;
+ }
+ else
+ {
+ mLastRebuildPool = poolp;
+ iter1++;
+ }
+ max_count--;
+ }
+
+ if (isAgentAvatarValid())
+ {
+ gAgentAvatarp->rebuildHUD();
+ }
+}
+
+void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
+
+ assertInitialized();
+
+ switch( new_poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ if (mSimplePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mSimplePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ if (mGrassPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate grass pool." << llendl;
+ }
+ else
+ {
+ mGrassPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ if (mFullbrightPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mFullbrightPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ if (mInvisiblePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mInvisiblePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ if (mGlowPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate glow pool." << llendl;
+ }
+ else
+ {
+ mGlowPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ if (mBumpPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate bump pool." << llendl;
+ }
+ else
+ {
+ mBumpPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ if( mAlphaPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
+ }
+ else
+ {
+ mAlphaPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ if( mSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
+ }
+ else
+ {
+ mSkyPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ if( mWaterPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
+ }
+ else
+ {
+ mWaterPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ if( mGroundPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
+ }
+ else
+ {
+ mGroundPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ if( mWLSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
+ }
+ else
+ {
+ mWLSkyPool = new_poolp;
+ }
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
+ break;
+ }
+}
+
+void LLPipeline::removePool( LLDrawPool* poolp )
+{
+ assertInitialized();
+ removeFromQuickLookup(poolp);
+ mPools.erase(poolp);
+ delete poolp;
+}
+
+void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
+{
+ assertInitialized();
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ switch( poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ llassert(mSimplePool == poolp);
+ mSimplePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ llassert(mGrassPool == poolp);
+ mGrassPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ llassert(mFullbrightPool == poolp);
+ mFullbrightPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ llassert(mInvisiblePool == poolp);
+ mInvisiblePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ llassert(mWLSkyPool == poolp);
+ mWLSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ llassert(mGlowPool == poolp);
+ mGlowPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ llassert( poolp == mBumpPool );
+ mBumpPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ llassert( poolp == mAlphaPool );
+ mAlphaPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ llassert( poolp == mSkyPool );
+ mSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ llassert( poolp == mWaterPool );
+ mWaterPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ llassert( poolp == mGroundPool );
+ mGroundPool = NULL;
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
+ break;
+ }
+}
+
+void LLPipeline::resetDrawOrders()
+{
+ assertInitialized();
+ // Iterate through all of the draw pools and rebuild them.
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ poolp->resetDrawOrders();
+ }
+}
+
+//============================================================================
+// Once-per-frame setup of hardware lights,
+// including sun/moon, avatar backlight, and up to 6 local lights
+
+void LLPipeline::setupAvatarLights(BOOL for_edit)
+{
+ assertInitialized();
+
+ if (for_edit)
+ {
+ LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
+ LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
+ LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
+ LLMatrix4 camera_rot(camera_mat.getMat3());
+ camera_rot.invert();
+ LLVector4 light_pos = light_pos_cam * camera_rot;
+
+ light_pos.normalize();
+
+ LLLightState* light = gGL.getLight(1);
+
+ mHWLightColors[1] = diffuse;
+
+ light->setDiffuse(diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setPosition(light_pos);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+ else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
+ {
+ LLVector3 opposite_pos = -1.f * mSunDir;
+ LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
+ LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
+ backlight_pos.normalize();
+
+ LLColor4 light_diffuse = mSunDiffuse;
+ LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
+ F32 max_component = 0.001f;
+ for (S32 i = 0; i < 3; i++)
+ {
+ if (backlight_diffuse.mV[i] > max_component)
+ {
+ max_component = backlight_diffuse.mV[i];
+ }
+ }
+ F32 backlight_mag;
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
+ }
+ else
+ {
+ backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
+ }
+ backlight_diffuse *= backlight_mag / max_component;
+
+ mHWLightColors[1] = backlight_diffuse;
+
+ LLLightState* light = gGL.getLight(1);
+
+ light->setPosition(backlight_pos);
+ light->setDiffuse(backlight_diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+ else
+ {
+ LLLightState* light = gGL.getLight(1);
+
+ mHWLightColors[1] = LLColor4::black;
+
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ }
+}
+
+static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
+{
+ F32 inten = light->getLightIntensity();
+ if (inten < .001f)
+ {
+ return max_dist;
+ }
+ F32 radius = light->getLightRadius();
+ BOOL selected = light->isSelected();
+ LLVector3 dpos = light->getRenderPosition() - cam_pos;
+ F32 dist2 = dpos.lengthSquared();
+ if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
+ {
+ return max_dist;
+ }
+ F32 dist = (F32) sqrt(dist2);
+ dist *= 1.f / inten;
+ dist -= radius;
+ if (selected)
+ {
+ dist -= 10000.f; // selected lights get highest priority
+ }
+ if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
+ {
+ // moving lights get a little higher priority (too much causes artifacts)
+ dist -= light->getLightRadius()*0.25f;
+ }
+ return dist;
+}
+
+void LLPipeline::calcNearbyLights(LLCamera& camera)
+{
+ assertInitialized();
+
+ if (LLPipeline::sReflectionRender)
+ {
+ return;
+ }
+
+ if (mLightingDetail >= 1)
+ {
+ // mNearbyLight (and all light_set_t's) are sorted such that
+ // begin() == the closest light and rbegin() == the farthest light
+ const S32 MAX_LOCAL_LIGHTS = 6;
+// LLVector3 cam_pos = gAgent.getCameraPositionAgent();
+ LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
+ camera.getOrigin() :
+ gAgent.getPositionAgent();
+
+ F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
+
+ // UPDATE THE EXISTING NEARBY LIGHTS
+ light_set_t cur_nearby_lights;
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ LLDrawable* drawable = light->drawable;
+ LLVOVolume* volight = drawable->getVOVolume();
+ if (!volight || !drawable->isState(LLDrawable::LIGHT))
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (light->fade <= -LIGHT_FADE_TIME)
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (!sRenderAttachedLights && volight && volight->isAttachment())
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+
+ F32 dist = calc_light_dist(volight, cam_pos, max_dist);
+ cur_nearby_lights.insert(Light(drawable, dist, light->fade));
+ }
+ mNearbyLights = cur_nearby_lights;
+
+ // FIND NEW LIGHTS THAT ARE IN RANGE
+ light_set_t new_nearby_lights;
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
+ iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
+ {
+ continue;
+ }
+ if (light->isHUDAttachment())
+ {
+ continue; // no lighting from HUD objects
+ }
+ F32 dist = calc_light_dist(light, cam_pos, max_dist);
+ if (dist >= max_dist)
+ {
+ continue;
+ }
+ if (!sRenderAttachedLights && light && light->isAttachment())
+ {
+ continue;
+ }
+ new_nearby_lights.insert(Light(drawable, dist, 0.f));
+ if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
+ {
+ new_nearby_lights.erase(--new_nearby_lights.end());
+ const Light& last = *new_nearby_lights.rbegin();
+ max_dist = last.dist;
+ }
+ }
+
+ // INSERT ANY NEW LIGHTS
+ for (light_set_t::iterator iter = new_nearby_lights.begin();
+ iter != new_nearby_lights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
+ {
+ mNearbyLights.insert(*light);
+ ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
+ }
+ else
+ {
+ // crazy cast so that we can overwrite the fade value
+ // even though gcc enforces sets as const
+ // (fade value doesn't affect sort so this is safe)
+ Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
+ if (light->dist < farthest_light->dist)
+ {
+ if (farthest_light->fade >= 0.f)
+ {
+ farthest_light->fade = -gFrameIntervalSeconds;
+ }
+ }
+ else
+ {
+ break; // none of the other lights are closer
+ }
+ }
+ }
+
+ }
+}
+
+void LLPipeline::setupHWLights(LLDrawPool* pool)
+{
+ assertInitialized();
+
+ // Ambient
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ gGL.syncMatrices();
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ gGL.setAmbientLightColor(ambient);
+ }
+
+ // Light 0 = Sun or Moon (All objects)
+ {
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ mSunDir.setVec(gSky.getSunDirection());
+ mSunDiffuse.setVec(gSky.getSunDiffuseColor());
+ }
+ else
+ {
+ mSunDir.setVec(gSky.getMoonDirection());
+ mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
+ }
+
+ F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
+ if (max_color > 1.f)
+ {
+ mSunDiffuse *= 1.f/max_color;
+ }
+ mSunDiffuse.clamp();
+
+ LLVector4 light_pos(mSunDir, 0.0f);
+ LLColor4 light_diffuse = mSunDiffuse;
+ mHWLightColors[0] = light_diffuse;
+
+ LLLightState* light = gGL.getLight(0);
+ light->setPosition(light_pos);
+ light->setDiffuse(light_diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+
+ // Light 1 = Backlight (for avatars)
+ // (set by enableLightsAvatar)
+
+ S32 cur_light = 2;
+
+ // Nearby lights = LIGHT 2-7
+
+ mLightMovingMask = 0;
+
+ if (mLightingDetail >= 1)
+ {
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); ++iter)
+ {
+ LLDrawable* drawable = iter->drawable;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light)
+ {
+ continue;
+ }
+ if (drawable->isState(LLDrawable::ACTIVE))
+ {
+ mLightMovingMask |= (1<<cur_light);
+ }
+
+ LLColor4 light_color = light->getLightColor();
+ light_color.mV[3] = 0.0f;
+
+ F32 fade = iter->fade;
+ if (fade < LIGHT_FADE_TIME)
+ {
+ // fade in/out light
+ if (fade >= 0.f)
+ {
+ fade = fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
+ }
+ else
+ {
+ fade = 1.f + fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
+ }
+ fade = llclamp(fade,0.f,1.f);
+ light_color *= fade;
+ }
+
+ LLVector3 light_pos(light->getRenderPosition());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = llmax(light->getLightRadius(), 0.001f);
+
+ F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[cur_light] = light_color;
+ LLLightState* light_state = gGL.getLight(cur_light);
+
+ light_state->setPosition(light_pos_gl);
+ light_state->setDiffuse(light_color);
+ light_state->setAmbient(LLColor4::black);
+ light_state->setConstantAttenuation(0.f);
+ if (sRenderDeferred)
+ {
+ F32 size = light_radius*1.5f;
+ light_state->setLinearAttenuation(size*size);
+ light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f);
+ }
+ else
+ {
+ light_state->setLinearAttenuation(linatten);
+ light_state->setQuadraticAttenuation(0.f);
+ }
+
+
+ if (light->isLightSpotlight() // directional (spot-)light
+ && (LLPipeline::sRenderDeferred || RenderSpotLightsInNondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
+ {
+ LLVector3 spotparams = light->getSpotLightParams();
+ LLQuaternion quat = light->getRenderRotation();
+ LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
+ at_axis *= quat;
+
+ light_state->setSpotDirection(at_axis);
+ light_state->setSpotCutoff(90.f);
+ light_state->setSpotExponent(2.f);
+
+ const LLColor4 specular(0.f, 0.f, 0.f, 0.f);
+ light_state->setSpecular(specular);
+ }
+ else // omnidirectional (point) light
+ {
+ light_state->setSpotExponent(0.f);
+ light_state->setSpotCutoff(180.f);
+
+ // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
+ const LLColor4 specular(0.f, 0.f, 0.f, 1.f);
+ light_state->setSpecular(specular);
+ }
+ cur_light++;
+ if (cur_light >= 8)
+ {
+ break; // safety
+ }
+ }
+ }
+ for ( ; cur_light < 8 ; cur_light++)
+ {
+ mHWLightColors[cur_light] = LLColor4::black;
+ LLLightState* light = gGL.getLight(cur_light);
+
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ }
+ if (gAgentAvatarp &&
+ gAgentAvatarp->mSpecialRenderMode == 3)
+ {
+ LLColor4 light_color = LLColor4::white;
+ light_color.mV[3] = 0.0f;
+
+ LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = 16.f;
+
+ F32 x = 3.f;
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[2] = light_color;
+ LLLightState* light = gGL.getLight(2);
+
+ light->setPosition(light_pos_gl);
+ light->setDiffuse(light_color);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setQuadraticAttenuation(0.f);
+ light->setConstantAttenuation(0.f);
+ light->setLinearAttenuation(linatten);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+
+ // Init GL state
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHTING);
+ }
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ gGL.getLight(i)->disable();
+ }
+ mLightMask = 0;
+}
+
+void LLPipeline::enableLights(U32 mask)
+{
+ assertInitialized();
+
+ if (mLightingDetail == 0)
+ {
+ mask &= 0xf003; // sun and backlight only (and fullbright bit)
+ }
+ if (mLightMask != mask)
+ {
+ stop_glerror();
+ if (!mLightMask)
+ {
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glEnable(GL_LIGHTING);
+ }
+ }
+ if (mask)
+ {
+ stop_glerror();
+ for (S32 i=0; i<8; i++)
+ {
+ LLLightState* light = gGL.getLight(i);
+ if (mask & (1<<i))
+ {
+ light->enable();
+ light->setDiffuse(mHWLightColors[i]);
+ }
+ else
+ {
+ light->disable();
+ light->setDiffuse(LLColor4::black);
+ }
+ }
+ stop_glerror();
+ }
+ else
+ {
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHTING);
+ }
+ }
+ mLightMask = mask;
+ stop_glerror();
+
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ gGL.setAmbientLightColor(ambient);
+ }
+}
+
+void LLPipeline::enableLightsStatic()
+{
+ assertInitialized();
+ U32 mask = 0x01; // Sun
+ if (mLightingDetail >= 2)
+ {
+ mask |= mLightMovingMask; // Hardware moving lights
+ }
+ else
+ {
+ mask |= 0xff & (~2); // Hardware local lights
+ }
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsDynamic()
+{
+ assertInitialized();
+ U32 mask = 0xff & (~2); // Local lights
+ enableLights(mask);
+
+ if (isAgentAvatarValid() && getLightingDetail() <= 0)
+ {
+ if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
+ {
+ gPipeline.enableLightsAvatar();
+ }
+ else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
+ {
+ gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
+ }
+ }
+}
+
+void LLPipeline::enableLightsAvatar()
+{
+ U32 mask = 0xff; // All lights
+ setupAvatarLights(FALSE);
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsPreview()
+{
+ disableLights();
+
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glEnable(GL_LIGHTING);
+ }
+
+ LLColor4 ambient = PreviewAmbientColor;
+ gGL.setAmbientLightColor(ambient);
+
+ LLColor4 diffuse0 = PreviewDiffuse0;
+ LLColor4 specular0 = PreviewSpecular0;
+ LLColor4 diffuse1 = PreviewDiffuse1;
+ LLColor4 specular1 = PreviewSpecular1;
+ LLColor4 diffuse2 = PreviewDiffuse2;
+ LLColor4 specular2 = PreviewSpecular2;
+
+ LLVector3 dir0 = PreviewDirection0;
+ LLVector3 dir1 = PreviewDirection1;
+ LLVector3 dir2 = PreviewDirection2;
+
+ dir0.normVec();
+ dir1.normVec();
+ dir2.normVec();
+
+ LLVector4 light_pos(dir0, 0.0f);
+
+ LLLightState* light = gGL.getLight(0);
+
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse0);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular0);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+
+ light_pos = LLVector4(dir1, 0.f);
+
+ light = gGL.getLight(1);
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse1);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular1);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+
+ light_pos = LLVector4(dir2, 0.f);
+ light = gGL.getLight(2);
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse2);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular2);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+}
+
+
+void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
+{
+ U32 mask = 0x2002; // Avatar backlight only, set ambient
+ setupAvatarLights(TRUE);
+ enableLights(mask);
+
+ gGL.setAmbientLightColor(color);
+}
+
+void LLPipeline::enableLightsFullbright(const LLColor4& color)
+{
+ assertInitialized();
+ U32 mask = 0x1000; // Non-0 mask, set ambient
+ enableLights(mask);
+
+ gGL.setAmbientLightColor(color);
+}
+
+void LLPipeline::disableLights()
+{
+ enableLights(0); // no lighting (full bright)
+}
+
+//============================================================================
+
+class LLMenuItemGL;
+class LLInvFVBridge;
+struct cat_folder_pair;
+class LLVOBranch;
+class LLVOLeaf;
+
+void LLPipeline::findReferences(LLDrawable *drawablep)
+{
+ assertInitialized();
+ if (mLights.find(drawablep) != mLights.end())
+ {
+ llinfos << "In mLights" << llendl;
+ }
+ if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
+ {
+ llinfos << "In mMovedList" << llendl;
+ }
+ if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
+ {
+ llinfos << "In mShiftList" << llendl;
+ }
+ if (mRetexturedList.find(drawablep) != mRetexturedList.end())
+ {
+ llinfos << "In mRetexturedList" << llendl;
+ }
+
+ if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
+ {
+ llinfos << "In mBuildQ1" << llendl;
+ }
+ if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
+ {
+ llinfos << "In mBuildQ2" << llendl;
+ }
+
+ S32 count;
+
+ count = gObjectList.findReferences(drawablep);
+ if (count)
+ {
+ llinfos << "In other drawables: " << count << " references" << llendl;
+ }
+}
+
+BOOL LLPipeline::verify()
+{
+ BOOL ok = assertInitialized();
+ if (ok)
+ {
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (!poolp->verify())
+ {
+ ok = FALSE;
+ }
+ }
+ }
+
+ if (!ok)
+ {
+ llwarns << "Pipeline verify failed!" << llendl;
+ }
+ return ok;
+}
+
+//////////////////////////////
+//
+// Collision detection
+//
+//
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A method to compute a ray-AABB intersection.
+ * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
+ * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
+ * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
+ *
+ * Hence this version is faster as well as more robust than the original one.
+ *
+ * Should work provided:
+ * 1) the integer representation of 0.0f is 0x00000000
+ * 2) the sign bit of the float is the most significant one
+ *
+ * Report bugs: p.terdiman@codercorner.com
+ *
+ * \param aabb [in] the axis-aligned bounding box
+ * \param origin [in] ray origin
+ * \param dir [in] ray direction
+ * \param coord [out] impact coordinates
+ * \return true if ray intersects AABB
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//#define RAYAABB_EPSILON 0.00001f
+#define IR(x) ((U32&)x)
+
+bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
+{
+ BOOL Inside = TRUE;
+ LLVector3 MinB = center - size;
+ LLVector3 MaxB = center + size;
+ LLVector3 MaxT;
+ MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
+
+ // Find candidate planes.
+ for(U32 i=0;i<3;i++)
+ {
+ if(origin.mV[i] < MinB.mV[i])
+ {
+ coord.mV[i] = MinB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ else if(origin.mV[i] > MaxB.mV[i])
+ {
+ coord.mV[i] = MaxB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ }
+
+ // Ray origin inside bounding box
+ if(Inside)
+ {
+ coord = origin;
+ return true;
+ }
+
+ // Get largest of the maxT's for final choice of intersection
+ U32 WhichPlane = 0;
+ if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
+ if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
+
+ // Check final candidate actually inside box
+ if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
+
+ for(U32 i=0;i<3;i++)
+ {
+ if(i!=WhichPlane)
+ {
+ coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
+ if (epsilon > 0)
+ {
+ if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
+ }
+ else
+ {
+ if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
+ }
+ }
+ }
+ return true; // ray hits box
+}
+
+//////////////////////////////
+//
+// Macros, functions, and inline methods from other classes
+//
+//
+
+void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
+{
+ if (drawablep && assertInitialized())
+ {
+ if (is_light)
+ {
+ mLights.insert(drawablep);
+ drawablep->setState(LLDrawable::LIGHT);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::LIGHT);
+ mLights.erase(drawablep);
+ }
+ }
+}
+
+//static
+void LLPipeline::toggleRenderType(U32 type)
+{
+ gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
+ if (type == LLPipeline::RENDER_TYPE_WATER)
+ {
+ gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
+ }
+}
+
+//static
+void LLPipeline::toggleRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ U32 bit = (1<<type);
+ if (gPipeline.hasRenderType(type))
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.toggleRenderType(type);
+}
+
+//static
+BOOL LLPipeline::hasRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ return gPipeline.hasRenderType(type);
+}
+
+// Allows UI items labeled "Hide foo" instead of "Show foo"
+//static
+BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
+{
+ S32 type = (S32)(intptr_t)data;
+ return !gPipeline.hasRenderType(type);
+}
+
+//static
+void LLPipeline::toggleRenderDebug(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ if (gPipeline.hasRenderDebugMask(bit))
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.mRenderDebugMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugMask(bit);
+}
+
+//static
+void LLPipeline::toggleRenderDebugFeature(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ gPipeline.mRenderDebugFeatureMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugFeatureMask(bit);
+}
+
+void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value)
+{
+ if (value)
+ {
+ gPipeline.mRenderDebugFeatureMask |= bit;
+ }
+ else
+ {
+ gPipeline.mRenderDebugFeatureMask &= !bit;
+ }
+}
+
+// static
+void LLPipeline::setRenderScriptedBeacons(BOOL val)
+{
+ sRenderScriptedBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedBeacons(void*)
+{
+ sRenderScriptedBeacons = !sRenderScriptedBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedBeacons(void*)
+{
+ return sRenderScriptedBeacons;
+}
+
+// static
+void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
+{
+ sRenderScriptedTouchBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
+{
+ sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
+{
+ return sRenderScriptedTouchBeacons;
+}
+
+// static
+void LLPipeline::setRenderMOAPBeacons(BOOL val)
+{
+ sRenderMOAPBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderMOAPBeacons(void*)
+{
+ sRenderMOAPBeacons = !sRenderMOAPBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderMOAPBeacons(void*)
+{
+ return sRenderMOAPBeacons;
+}
+
+// static
+void LLPipeline::setRenderPhysicalBeacons(BOOL val)
+{
+ sRenderPhysicalBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderPhysicalBeacons(void*)
+{
+ sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderPhysicalBeacons(void*)
+{
+ return sRenderPhysicalBeacons;
+}
+
+// static
+void LLPipeline::setRenderParticleBeacons(BOOL val)
+{
+ sRenderParticleBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderParticleBeacons(void*)
+{
+ sRenderParticleBeacons = !sRenderParticleBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderParticleBeacons(void*)
+{
+ return sRenderParticleBeacons;
+}
+
+// static
+void LLPipeline::setRenderSoundBeacons(BOOL val)
+{
+ sRenderSoundBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderSoundBeacons(void*)
+{
+ sRenderSoundBeacons = !sRenderSoundBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderSoundBeacons(void*)
+{
+ return sRenderSoundBeacons;
+}
+
+// static
+void LLPipeline::setRenderBeacons(BOOL val)
+{
+ sRenderBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderBeacons(void*)
+{
+ sRenderBeacons = !sRenderBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderBeacons(void*)
+{
+ return sRenderBeacons;
+}
+
+// static
+void LLPipeline::setRenderHighlights(BOOL val)
+{
+ sRenderHighlight = val;
+}
+
+// static
+void LLPipeline::toggleRenderHighlights(void*)
+{
+ sRenderHighlight = !sRenderHighlight;
+}
+
+// static
+BOOL LLPipeline::getRenderHighlights(void*)
+{
+ return sRenderHighlight;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ LLVector3 local_end = end;
+
+ LLVector3 position;
+
+ sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ if ((j == LLViewerRegion::PARTITION_VOLUME) ||
+ (j == LLViewerRegion::PARTITION_BRIDGE) ||
+ (j == LLViewerRegion::PARTITION_TERRAIN) ||
+ (j == LLViewerRegion::PARTITION_TREE) ||
+ (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ local_end = position;
+ }
+ }
+ }
+ }
+ }
+
+ if (!sPickAvatar)
+ {
+ //save hit info in case we need to restore
+ //due to attachment override
+ LLVector3 local_normal;
+ LLVector3 local_binormal;
+ LLVector2 local_texcoord;
+ S32 local_face_hit = -1;
+
+ if (face_hit)
+ {
+ local_face_hit = *face_hit;
+ }
+ if (tex_coord)
+ {
+ local_texcoord = *tex_coord;
+ }
+ if (bi_normal)
+ {
+ local_binormal = *bi_normal;
+ }
+ if (normal)
+ {
+ local_normal = *normal;
+ }
+
+ const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
+
+ //check against avatars
+ sPickAvatar = TRUE;
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ if (!drawable ||
+ !drawable->getVObj()->isAttachment() ||
+ (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
+ { //avatar overrides if previously hit drawable is not an attachment or
+ //attachment is far enough away from detected intersection
+ drawable = hit;
+ local_end = position;
+ }
+ else
+ { //prioritize attachments over avatars
+ position = local_end;
+
+ if (face_hit)
+ {
+ *face_hit = local_face_hit;
+ }
+ if (tex_coord)
+ {
+ *tex_coord = local_texcoord;
+ }
+ if (bi_normal)
+ {
+ *bi_normal = local_binormal;
+ }
+ if (normal)
+ {
+ *normal = local_normal;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //check all avatar nametags (silly, isn't it?)
+ for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end();
+ ++iter)
+ {
+ LLVOAvatar* av = (LLVOAvatar*) *iter;
+ if (av->mNameText.notNull()
+ && av->mNameText->lineSegmentIntersect(start, local_end, position))
+ {
+ drawable = av->mDrawable;
+ local_end = position;
+ }
+ }
+
+ if (intersection)
+ {
+ *intersection = position;
+ }
+
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ BOOL toggle = FALSE;
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ toggle = TRUE;
+ }
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
+ if (part)
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ }
+ }
+
+ if (toggle)
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+ }
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
+{
+ if (vobj)
+ {
+ LLViewerRegion* region = vobj->getRegion();
+ if (region)
+ {
+ return region->getSpatialPartition(vobj->getPartitionType());
+ }
+ }
+ return NULL;
+}
+
+void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
+{
+ if (!drawable)
+ {
+ return;
+ }
+
+ for (S32 i = 0; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+ facep->clearVertexBuffer();
+ }
+}
+
+void LLPipeline::resetVertexBuffers()
+{
+ mResetVertexBuffers = true;
+}
+
+void LLPipeline::doResetVertexBuffers()
+{
+ if (!mResetVertexBuffers)
+ {
+ return;
+ }
+
+ mResetVertexBuffers = false;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->resetVertexBuffers();
+ }
+ }
+ }
+
+ resetDrawOrders();
+
+ gSky.resetVertexBuffers();
+
+ if ( LLPathingLib::getInstance() )
+ {
+ LLPathingLib::getInstance()->cleanupVBOManger();
+ }
+ LLVertexBuffer::cleanupClass();
+
+ //delete all name pool caches
+ LLGLNamePool::cleanupPools();
+
+ if (LLVertexBuffer::sGLCount > 0)
+ {
+ llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl;
+ }
+
+ LLVertexBuffer::unbind();
+
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+ LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
+ LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
+ LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
+ LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
+ sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
+ sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
+ LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
+
+ LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping);
+}
+
+void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture)
+{
+ LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
+ assertInitialized();
+ gGL.loadMatrix(gGLModelView);
+ gGLLastMatrix = NULL;
+ mSimplePool->pushBatches(type, mask, texture, batch_texture);
+ gGL.loadMatrix(gGLModelView);
+ gGLLastMatrix = NULL;
+}
+
+void apply_cube_face_rotation(U32 face)
+{
+ switch (face)
+ {
+ case 0:
+ gGL.rotatef(90.f, 0, 1, 0);
+ gGL.rotatef(180.f, 1, 0, 0);
+ break;
+ case 2:
+ gGL.rotatef(-90.f, 1, 0, 0);
+ break;
+ case 4:
+ gGL.rotatef(180.f, 0, 1, 0);
+ gGL.rotatef(180.f, 0, 0, 1);
+ break;
+ case 1:
+ gGL.rotatef(-90.f, 0, 1, 0);
+ gGL.rotatef(180.f, 1, 0, 0);
+ break;
+ case 3:
+ gGL.rotatef(90, 1, 0, 0);
+ break;
+ case 5:
+ gGL.rotatef(180, 0, 0, 1);
+ break;
+ }
+}
+
+void validate_framebuffer_object()
+{
+ GLenum status;
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE:
+ //framebuffer OK, no error.
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Missing Attachment." << llendl;
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Attachment." << llendl;
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ /* choose different formats */
+ llerrs << "Framebuffer unsupported." << llendl;
+ break;
+ default:
+ llerrs << "Unknown framebuffer status." << llendl;
+ break;
+ }
+}
+
+void LLPipeline::bindScreenToTexture()
+{
+
+}
+
+static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
+
+void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
+{
+ LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
+ if (!(gPipeline.canUseVertexShaders() &&
+ sRenderGlow))
+ {
+ return;
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ assertInitialized();
+
+ if (gUseWireframe)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+
+ LLVector2 tc1(0,0);
+ LLVector2 tc2((F32) mScreen.getWidth()*2,
+ (F32) mScreen.getHeight()*2);
+
+ LLFastTimer ftm(FTM_RENDER_BLOOM);
+ gGL.color4f(1,1,1,1);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ enableLightsFullbright(LLColor4(1,1,1,1));
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ gGL.setColorMask(true, true);
+ glClearColor(0,0,0,0);
+
+ {
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[2].bindTarget();
+ mGlow[2].clear();
+ }
+
+ gGlowExtractProgram.bind();
+ F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f);
+ F32 maxAlpha = RenderGlowMaxExtractAlpha;
+ F32 warmthAmount = RenderGlowWarmthAmount;
+ LLVector3 lumWeights = RenderGlowLumWeights;
+ LLVector3 warmthWeights = RenderGlowWarmthWeights;
+
+
+ gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum);
+ gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha);
+ gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
+ gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
+ gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount);
+ LLGLEnable blend_on(GL_BLEND);
+ LLGLEnable test(GL_ALPHA_TEST);
+
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ mScreen.bindTexture(0, 0);
+
+ gGL.color4f(1,1,1,1);
+ gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ gGL.getTexUnit(0)->unbind(mScreen.getUsage());
+
+ mGlow[2].flush();
+ }
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ // power of two between 1 and 1024
+ U32 glowResPow = RenderGlowResolutionPow;
+ const U32 glow_res = llmax(1,
+ llmin(1024, 1 << glowResPow));
+
+ S32 kernel = RenderGlowIterations*2;
+ F32 delta = RenderGlowWidth / glow_res;
+ // Use half the glow width if we have the res set to less than 9 so that it looks
+ // almost the same in either case.
+ if (glowResPow < 9)
+ {
+ delta *= 0.5f;
+ }
+ F32 strength = RenderGlowStrength;
+
+ gGlowProgram.bind();
+ gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength);
+
+ for (S32 i = 0; i < kernel; i++)
+ {
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[i%2].bindTarget();
+ mGlow[i%2].clear();
+ }
+
+ if (i == 0)
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[2]);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
+ }
+
+ if (i%2 == 0)
+ {
+ gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0);
+ }
+ else
+ {
+ gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ mGlow[i%2].flush();
+ }
+
+ gGlowProgram.unbind();
+
+ if (LLRenderTarget::sUseFBO)
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+ gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+ gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+ gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+ tc2.setVec((F32) mScreen.getWidth(),
+ (F32) mScreen.getHeight());
+
+ gGL.flush();
+
+ LLVertexBuffer::unbind();
+
+ if (LLPipeline::sRenderDeferred)
+ {
+
+ bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
+ !LLToolMgr::getInstance()->inBuildMode() &&
+ RenderDepthOfField;
+
+
+ bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete();
+
+ gViewerWindow->setup3DViewport();
+
+ if (dof_enabled)
+ {
+ LLGLSLShader* shader = &gDeferredPostProgram;
+ LLGLDisable blend(GL_BLEND);
+
+ //depth of field focal plane calculations
+ static F32 current_distance = 16.f;
+ static F32 start_distance = 16.f;
+ static F32 transition_time = 1.f;
+
+ LLVector3 focus_point;
+
+ LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
+ if (obj && obj->mDrawable && obj->isSelected())
+ { //focus on selected media object
+ S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
+ if (obj && obj->mDrawable)
+ {
+ LLFace* face = obj->mDrawable->getFace(face_idx);
+ if (face)
+ {
+ focus_point = face->getPositionAgent();
+ }
+ }
+ }
+
+ if (focus_point.isExactlyZero())
+ {
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ { //focus on point under cursor
+ focus_point = gDebugRaycastIntersection;
+ }
+ else if (gAgentCamera.cameraMouselook())
+ { //focus on point under mouselook crosshairs
+ gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
+ NULL,
+ &focus_point);
+ }
+ else
+ {
+ LLViewerObject* obj = gAgentCamera.getFocusObject();
+ if (obj)
+ { //focus on alt-zoom target
+ focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal());
+ }
+ else
+ { //focus on your avatar
+ focus_point = gAgent.getPositionAgent();
+ }
+ }
+ }
+
+ LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
+ F32 target_distance = 16.f;
+ if (!focus_point.isExactlyZero())
+ {
+ target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye);
+ }
+
+ if (transition_time >= 1.f &&
+ fabsf(current_distance-target_distance)/current_distance > 0.01f)
+ { //large shift happened, interpolate smoothly to new target distance
+ transition_time = 0.f;
+ start_distance = current_distance;
+ }
+ else if (transition_time < 1.f)
+ { //currently in a transition, continue interpolating
+ transition_time += 1.f/CameraFocusTransitionTime*gFrameIntervalSeconds;
+ transition_time = llmin(transition_time, 1.f);
+
+ F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f;
+ current_distance = start_distance + (target_distance-start_distance)*t;
+ }
+ else
+ { //small or no change, just snap to target distance
+ current_distance = target_distance;
+ }
+
+ //convert to mm
+ F32 subject_distance = current_distance*1000.f;
+ F32 fnumber = CameraFNumber;
+ F32 default_focal_length = CameraFocalLength;
+
+ F32 fov = LLViewerCamera::getInstance()->getView();
+
+ const F32 default_fov = CameraFieldOfView * F_PI/180.f;
+ //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio");
+
+ //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
+
+ F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f);
+ //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f);
+
+ F32 focal_length = dv/(2*tanf(fov/2.f));
+
+ //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
+
+ // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
+ // where N = fnumber
+ // s2 = dot distance
+ // s1 = subject distance
+ // f = focal length
+ //
+
+ F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length));
+ blur_constant /= 1000.f; //convert to meters for shader
+ F32 magnification = focal_length/(subject_distance-focal_length);
+
+ { //build diffuse+bloom+CoF
+ mDeferredLight.bindTarget();
+ shader = &gDeferredCoFProgram;
+
+ bindDeferredShader(*shader);
+
+ S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+ if (channel > -1)
+ {
+ mScreen.bindTexture(0, channel);
+ }
+
+ shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f);
+ shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant);
+ shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f/LLDrawable::sCurPixelAngle));
+ shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification);
+ shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+ shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(*shader);
+ mDeferredLight.flush();
+ }
+
+ { //perform DoF sampling at half-res (preserve alpha channel)
+ mScreen.bindTarget();
+ glViewport(0,0,(GLsizei) (mScreen.getWidth()*CameraDoFResScale), (GLsizei) (mScreen.getHeight()*CameraDoFResScale));
+ gGL.setColorMask(true, false);
+
+ shader = &gDeferredPostProgram;
+ bindDeferredShader(*shader);
+ S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+ if (channel > -1)
+ {
+ mDeferredLight.bindTexture(0, channel);
+ }
+
+ shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+ shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(*shader);
+ mScreen.flush();
+ gGL.setColorMask(true, true);
+ }
+
+ { //combine result based on alpha
+ if (multisample)
+ {
+ mDeferredLight.bindTarget();
+ glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+ }
+ else
+ {
+ gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+ gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+ gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+ gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+ }
+
+ shader = &gDeferredDoFCombineProgram;
+ bindDeferredShader(*shader);
+
+ S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+ if (channel > -1)
+ {
+ mScreen.bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+ shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(*shader);
+
+ if (multisample)
+ {
+ mDeferredLight.flush();
+ }
+ }
+ }
+ else
+ {
+ if (multisample)
+ {
+ mDeferredLight.bindTarget();
+ }
+ LLGLSLShader* shader = &gDeferredPostNoDoFProgram;
+
+ bindDeferredShader(*shader);
+
+ S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+ if (channel > -1)
+ {
+ mScreen.bindTexture(0, channel);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(*shader);
+
+ if (multisample)
+ {
+ mDeferredLight.flush();
+ }
+ }
+
+ if (multisample)
+ {
+ //bake out texture2D with RGBL for FXAA shader
+ mFXAABuffer.bindTarget();
+
+ S32 width = mScreen.getWidth();
+ S32 height = mScreen.getHeight();
+ glViewport(0, 0, width, height);
+
+ LLGLSLShader* shader = &gGlowCombineFXAAProgram;
+
+ shader->bind();
+ shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height);
+
+ S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+ if (channel > -1)
+ {
+ mDeferredLight.bindTexture(0, channel);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex2f(-1,-1);
+ gGL.vertex2f(-1,3);
+ gGL.vertex2f(3,-1);
+ gGL.end();
+
+ gGL.flush();
+
+ shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+ shader->unbind();
+
+ mFXAABuffer.flush();
+
+ shader = &gFXAAProgram;
+ shader->bind();
+
+ channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage());
+ if (channel > -1)
+ {
+ mFXAABuffer.bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+ gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+ gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+ gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+ F32 scale_x = (F32) width/mFXAABuffer.getWidth();
+ F32 scale_y = (F32) height/mFXAABuffer.getHeight();
+ shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y);
+ shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width*scale_x, 1.f/height*scale_y);
+ shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width*scale_x, -0.5f/height*scale_y, 0.5f/width*scale_x, 0.5f/height*scale_y);
+ shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width*scale_x, -2.f/height*scale_y, 2.f/width*scale_x, 2.f/height*scale_y);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex2f(-1,-1);
+ gGL.vertex2f(-1,3);
+ gGL.vertex2f(3,-1);
+ gGL.end();
+
+ gGL.flush();
+ shader->unbind();
+ }
+ }
+ else
+ {
+ U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
+ buff->allocateBuffer(3,0,TRUE);
+
+ LLStrider<LLVector3> v;
+ LLStrider<LLVector2> uv1;
+ LLStrider<LLVector2> uv2;
+
+ buff->getVertexStrider(v);
+ buff->getTexCoord0Strider(uv1);
+ buff->getTexCoord1Strider(uv2);
+
+ uv1[0] = LLVector2(0, 0);
+ uv1[1] = LLVector2(0, 2);
+ uv1[2] = LLVector2(2, 0);
+
+ uv2[0] = LLVector2(0, 0);
+ uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
+ uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
+
+ v[0] = LLVector3(-1,-1,0);
+ v[1] = LLVector3(-1,3,0);
+ v[2] = LLVector3(3,-1,0);
+
+ buff->flush();
+
+ LLGLDisable blend(GL_BLEND);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gGlowCombineProgram.bind();
+ }
+ else
+ {
+ //tex unit 0
+ gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
+ //tex unit 1
+ gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+ }
+
+ gGL.getTexUnit(0)->bind(&mGlow[1]);
+ gGL.getTexUnit(1)->bind(&mScreen);
+
+ LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ buff->setBuffer(mask);
+ buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gGlowCombineProgram.unbind();
+ }
+ else
+ {
+ gGL.getTexUnit(1)->disable();
+ gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ gGL.getTexUnit(0)->activate();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+ }
+
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
+ {
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gSplatTextureRectProgram.bind();
+ }
+
+ gGL.setColorMask(true, false);
+
+ LLVector2 tc1(0,0);
+ LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
+ (F32) gViewerWindow->getWorldViewHeightRaw()*2);
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.color4f(1,1,1,0.75f);
+
+ gGL.getTexUnit(0)->bind(&mPhysicsDisplay);
+
+ gGL.begin(LLRender::TRIANGLES);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+ gGL.flush();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gSplatTextureRectProgram.unbind();
+ }
+ }
+
+
+ if (LLRenderTarget::sUseFBO)
+ { //copy depth buffer from mScreen to framebuffer
+ LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
+ 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
+
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map)
+{
+ LLFastTimer t(FTM_BIND_DEFERRED);
+
+ if (noise_map == 0xFFFFFFFF)
+ {
+ noise_map = mNoiseMap;
+ }
+
+ shader.bind();
+ S32 channel = 0;
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage());
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(0,channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage());
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage());
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage());
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
+ stop_glerror();
+
+ //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ //glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
+
+ stop_glerror();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f inv_proj = projection.inverse();
+
+ shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m);
+ shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0],
+ (F32) gGLViewport[1],
+ (F32) gGLViewport[2],
+ (F32) gGLViewport[3]);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ }
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage());
+ if (channel > -1)
+ {
+ if (light_index > 0)
+ {
+ mScreen.bindTexture(0, channel);
+ }
+ else
+ {
+ mDeferredLight.bindTexture(0, channel);
+ }
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_BLOOM);
+ if (channel > -1)
+ {
+ mGlow[1].bindTexture(0, channel);
+ }
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ stop_glerror();
+
+ F32 mat[16*6];
+ for (U32 i = 0; i < 16; i++)
+ {
+ mat[i] = mSunShadowMatrix[0].m[i];
+ mat[i+16] = mSunShadowMatrix[1].m[i];
+ mat[i+32] = mSunShadowMatrix[2].m[i];
+ mat[i+48] = mSunShadowMatrix[3].m[i];
+ mat[i+64] = mSunShadowMatrix[4].m[i];
+ mat[i+80] = mSunShadowMatrix[5].m[i];
+ }
+
+ shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat);
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->enable(channel);
+ cube_map->bind();
+ F32* m = gGLModelView;
+
+ F32 mat[] = { m[0], m[1], m[2],
+ m[4], m[5], m[6],
+ m[8], m[9], m[10] };
+
+ shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
+ }
+ }
+
+ shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
+ shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize);
+
+ shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale);
+
+ F32 ssao_factor = RenderSSAOFactor;
+ shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0/ssao_factor);
+
+ LLVector3 ssao_effect = RenderSSAOEffect;
+ F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
+ F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
+ // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
+ // value factor, and scales remainder by saturation factor
+ F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
+ matrix_nondiag, matrix_diag, matrix_nondiag,
+ matrix_nondiag, matrix_nondiag, matrix_diag};
+ shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat);
+
+ F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+ F32 shadow_bias_error = 1.f + RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+
+ shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+ shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear()*2.f);
+ shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset*shadow_offset_error);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias*shadow_bias_error);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset);
+ shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias);
+
+ shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV);
+ shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight());
+ shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight());
+ shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
+ shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
+
+
+ if (shader.getUniformLocation("norm_mat") >= 0)
+ {
+ glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
+ shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
+static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
+static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
+static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
+static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
+static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
+static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
+static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
+static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
+static LLFastTimer::DeclareTimer FTM_POST("Post");
+
+
+void LLPipeline::renderDeferredLighting()
+{
+ if (!sCull)
+ {
+ return;
+ }
+
+ {
+ LLFastTimer ftm(FTM_RENDER_DEFERRED);
+
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ //ati doesn't seem to love actually using the stencil buffer on FBO's
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+ //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ gGL.setColorMask(true, true);
+
+ //draw a cube around every light
+ LLVertexBuffer::unbind();
+
+ LLGLEnable cull(GL_CULL_FACE);
+ LLGLEnable blend(GL_BLEND);
+
+ glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+
+ LLStrider<LLVector3> vert;
+ mDeferredVB->getVertexStrider(vert);
+ LLStrider<LLVector2> tc0;
+ LLStrider<LLVector2> tc1;
+ mDeferredVB->getTexCoord0Strider(tc0);
+ mDeferredVB->getTexCoord1Strider(tc1);
+
+ vert[0].set(-1,1,0);
+ vert[1].set(-1,-3,0);
+ vert[2].set(3,1,0);
+
+ {
+ setupHWLights(NULL); //to set mSunDir;
+ LLVector4 dir(mSunDir, 0.f);
+ glh::vec4f tc(dir.mV);
+ mat.mult_matrix_vec(tc);
+ mTransformedSunDir.set(tc.v);
+ }
+
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ if (RenderDeferredSSAO || RenderShadowDetail > 0)
+ {
+ mDeferredLight.bindTarget();
+ { //paint shadow/SSAO light map (direct lighting lightmap)
+ LLFastTimer ftm(FTM_SUN_SHADOW);
+ bindDeferredShader(gDeferredSunProgram, 0);
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ glClearColor(1,1,1,1);
+ mDeferredLight.clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+
+ const U32 slice = 32;
+ F32 offset[slice*3];
+ for (U32 i = 0; i < 4; i++)
+ {
+ for (U32 j = 0; j < 8; j++)
+ {
+ glh::vec3f v;
+ v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+ v.normalize();
+ inv_trans.mult_matrix_vec(v);
+ v.normalize();
+ offset[(i*8+j)*3+0] = v.v[0];
+ offset[(i*8+j)*3+1] = v.v[2];
+ offset[(i*8+j)*3+2] = v.v[1];
+ }
+ }
+
+ gDeferredSunProgram.uniform3fv("offset", slice, offset);
+ gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight());
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ stop_glerror();
+ }
+
+ unbindDeferredShader(gDeferredSunProgram);
+ }
+ mDeferredLight.flush();
+ }
+
+ if (RenderDeferredSSAO)
+ { //soften direct lighting lightmap
+ LLFastTimer ftm(FTM_SOFTEN_SHADOW);
+ //blur lightmap
+ mScreen.bindTarget();
+ glClearColor(1,1,1,1);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ bindDeferredShader(gDeferredBlurLightProgram);
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ LLVector3 go = RenderShadowGaussian;
+ const U32 kern_length = 4;
+ F32 blur_size = RenderShadowBlurSize;
+ F32 dist_factor = RenderShadowBlurDistFactor;
+
+ // sample symmetrically with the middle sample falling exactly on 0.0
+ F32 x = 0.f;
+
+ LLVector3 gauss[32]; // xweight, yweight, offset
+
+ for (U32 i = 0; i < kern_length; i++)
+ {
+ gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+ gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+ gauss[i].mV[2] = x;
+ x += 1.f;
+ }
+
+ gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+ gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
+ gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+ gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ stop_glerror();
+ }
+
+ mScreen.flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+
+ bindDeferredShader(gDeferredBlurLightProgram, 1);
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ mDeferredLight.bindTarget();
+
+ gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ stop_glerror();
+ }
+ mDeferredLight.flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+ }
+
+ stop_glerror();
+ gGL.popMatrix();
+ stop_glerror();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ stop_glerror();
+ gGL.popMatrix();
+ stop_glerror();
+
+ //copy depth and stencil from deferred screen
+ //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+
+ mScreen.bindTarget();
+ // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
+ glClearColor(0,0,0,0);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+
+ if (RenderDeferredAtmospheric)
+ { //apply sunlight contribution
+ LLFastTimer ftm(FTM_ATMOSPHERICS);
+ bindDeferredShader(gDeferredSoftenProgram);
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ //full screen blit
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ }
+
+ unbindDeferredShader(gDeferredSoftenProgram);
+ }
+
+ { //render non-deferred geometry (fullbright, alpha, etc)
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ gPipeline.pushRenderTypeMask();
+
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::END_RENDER_TYPES);
+
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ gPipeline.popRenderTypeMask();
+ }
+
+ BOOL render_local = RenderLocalLights;
+
+ if (render_local)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+ std::list<LLVector4> fullscreen_lights;
+ LLDrawable::drawable_list_t spot_lights;
+ LLDrawable::drawable_list_t fullscreen_spot_lights;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+
+ std::list<LLVector4> light_colors;
+
+ LLVertexBuffer::unbind();
+ LLVector4a* v = (LLVector4a*) vert.get();
+
+ {
+ bindDeferredShader(gDeferredLightProgram);
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+ if (!volume)
+ {
+ continue;
+ }
+
+ if (volume->isAttachment())
+ {
+ if (!sRenderAttachedLights)
+ {
+ continue;
+ }
+ }
+
+
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
+ F32 s = volume->getLightRadius()*1.5f;
+
+ LLColor3 col = volume->getLightColor();
+
+ if (col.magVecSquared() < 0.001f)
+ {
+ continue;
+ }
+
+ if (s <= 0.001f)
+ {
+ continue;
+ }
+
+ LLVector4a sa;
+ sa.splat(s);
+ if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
+ {
+ continue;
+ }
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ mDeferredVB->getVertexStrider(vert);
+ v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000
+ v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001
+ v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010
+ v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011
+
+ v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
+ v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
+ v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
+ v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
+
+ if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
+ camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
+ camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
+ camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
+ camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
+ camera->getOrigin().mV[2] < c[2] - s - 0.2f)
+ { //draw box if camera is outside box
+ if (render_local)
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+ //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+ gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
+ gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+ gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+ //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ gGL.syncMatrices();
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ fullscreen_spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+ light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+ }
+ }
+ unbindDeferredShader(gDeferredLightProgram);
+ }
+
+ if (!spot_lights.empty())
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ bindDeferredShader(gDeferredSpotLightProgram);
+
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+ for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ mDeferredVB->getVertexStrider(vert);
+ v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000
+ v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001
+ v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010
+ v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011
+
+ v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
+ v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
+ v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
+ v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
+
+ gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+ gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
+ gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+ gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+ gGL.syncMatrices();
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
+ }
+ gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredSpotLightProgram);
+ }
+
+ //reset mDeferredVB to fullscreen triangle
+ mDeferredVB->getVertexStrider(vert);
+ vert[0].set(-1,1,0);
+ vert[1].set(-1,-3,0);
+ vert[2].set(3,1,0);
+
+ {
+ bindDeferredShader(gDeferredMultiLightProgram);
+
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ LLGLDepthTest depth(GL_FALSE);
+
+ //full screen blit
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ U32 count = 0;
+
+ const U32 max_count = 8;
+ LLVector4 light[max_count];
+ LLVector4 col[max_count];
+
+// glVertexPointer(2, GL_FLOAT, 0, vert);
+
+ F32 far_z = 0.f;
+
+ while (!fullscreen_lights.empty())
+ {
+ LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
+ light[count] = fullscreen_lights.front();
+ fullscreen_lights.pop_front();
+ col[count] = light_colors.front();
+ light_colors.pop_front();
+
+ far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
+
+ count++;
+ if (count == max_count || fullscreen_lights.empty())
+ {
+ gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
+ gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
+ gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
+ gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
+ far_z = 0.f;
+ count = 0;
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ }
+ }
+
+ unbindDeferredShader(gDeferredMultiLightProgram);
+
+ bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector3 center = drawablep->getPositionAgent();
+ F32* c = center.mV;
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+
+ gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+ gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
+ gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+ gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ }
+
+ gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ }
+ }
+
+ gGL.setColorMask(true, true);
+ }
+
+ { //render non-deferred geometry (alpha, fullbright, glow)
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_GLOW,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_GLOW,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ END_RENDER_TYPES);
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ popRenderTypeMask();
+ }
+
+ {
+ //render highlights, etc.
+ renderHighlights();
+ mHighlightFaces.clear();
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ }
+
+ mScreen.flush();
+
+}
+
+void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+{
+ //construct frustum
+ LLVOVolume* volume = drawablep->getVOVolume();
+ LLVector3 params = volume->getSpotLightParams();
+
+ F32 fov = params.mV[0];
+ F32 focus = params.mV[1];
+
+ LLVector3 pos = drawablep->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+ LLVector3 scale = volume->getScale();
+
+ //get near clip plane
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = pos+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ //matrix from volume space to agent space
+ LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+
+ glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
+ glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+
+ glh::matrix4f screen_to_light = light_to_screen.inverse();
+
+ F32 s = volume->getLightRadius()*1.5f;
+ F32 near_clip = dist;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = s+dist-scale.mV[VZ];
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh::vec3f p1(0, 0, -(near_clip+0.01f));
+ glh::vec3f p2(0, 0, -(near_clip+1.f));
+
+ glh::vec3f screen_origin(0, 0, 0);
+
+ light_to_screen.mult_matrix_vec(p1);
+ light_to_screen.mult_matrix_vec(p2);
+ light_to_screen.mult_matrix_vec(screen_origin);
+
+ glh::vec3f n = p2-p1;
+ n.normalize();
+
+ F32 proj_range = far_clip - near_clip;
+ glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
+ screen_to_light = trans * light_proj * screen_to_light;
+ shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
+ shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
+ shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
+ shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
+ shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
+ shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
+ shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
+ S32 s_idx = -1;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ s_idx = i;
+ }
+ }
+
+ shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
+
+ if (s_idx >= 0)
+ {
+ shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
+ }
+ else
+ {
+ shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
+ }
+
+ {
+ LLDrawable* potential = drawablep;
+ //determine if this is a good light for casting shadows
+ F32 m_pri = volume->getSpotLightPriority();
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ F32 pri = 0.f;
+
+ if (mTargetShadowSpotLight[i].notNull())
+ {
+ pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
+ }
+
+ if (m_pri > pri)
+ {
+ LLDrawable* temp = mTargetShadowSpotLight[i];
+ mTargetShadowSpotLight[i] = potential;
+ potential = temp;
+ m_pri = pri;
+ }
+ }
+ }
+
+ LLViewerTexture* img = volume->getLightTexture();
+
+ if (img == NULL)
+ {
+ img = LLViewerFetchedTexture::sWhiteImagep;
+ }
+
+ S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+ if (channel > -1)
+ {
+ if (img)
+ {
+ gGL.getTexUnit(channel)->bind(img);
+
+ F32 lod_range = logf(img->getWidth())/logf(2.f);
+
+ shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus);
+ shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range);
+ shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+ }
+ }
+
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+{
+ stop_glerror();
+ shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage());
+ shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage());
+ shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage());
+ shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredScreen.getUsage());
+ shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage());
+ shader.disableTexture(LLShaderMgr::DIFFUSE_MAP);
+ shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM);
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ shader.disableTexture(LLShaderMgr::DEFERRED_NOISE);
+ shader.disableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC);
+
+ S32 channel = shader.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->disable();
+ }
+ }
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->activate();
+ shader.unbind();
+}
+
+inline float sgn(float a)
+{
+ if (a > 0.0F) return (1.0F);
+ if (a < 0.0F) return (-1.0F);
+ return (0.0F);
+}
+
+void LLPipeline::generateWaterReflection(LLCamera& camera_in)
+{
+ if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ BOOL skip_avatar_update = FALSE;
+ if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
+ {
+ skip_avatar_update = TRUE;
+ }
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
+ }
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ LLCamera camera = camera_in;
+ camera.setFar(camera.getFar()*0.87654321f);
+ LLPipeline::sReflectionRender = TRUE;
+
+ gPipeline.pushRenderTypeMask();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f mat;
+
+ stop_glerror();
+ LLPlane plane;
+
+ F32 height = gAgent.getRegion()->getWaterHeight();
+ F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
+ F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
+
+ //plane params
+ LLVector3 pnorm;
+ F32 pd;
+
+ S32 water_clip = 0;
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //camera is above water, clip plane points up
+ pnorm.setVec(0,0,1);
+ pd = -height;
+ plane.setVec(pnorm, pd);
+ water_clip = -1;
+ }
+ else
+ { //camera is below water, clip plane points down
+ pnorm = LLVector3(0,0,-1);
+ pd = height;
+ plane.setVec(pnorm, pd);
+ water_clip = 1;
+ }
+
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //generate planar reflection map
+
+ //disable occlusion culling for reflection map for now
+ S32 occlusion = LLPipeline::sUseOcclusion;
+ LLPipeline::sUseOcclusion = 0;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glClearColor(0,0,0,0);
+ mWaterRef.bindTarget();
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
+ gGL.setColorMask(true, true);
+ mWaterRef.clear();
+ gGL.setColorMask(true, false);
+
+ mWaterRef.getViewport(gGLViewport);
+
+ stop_glerror();
+
+ gGL.pushMatrix();
+
+ mat.set_scale(glh::vec3f(1,1,-1));
+ mat.set_translate(glh::vec3f(0,0,height*2.f));
+
+ glh::matrix4f current = glh_get_current_modelview();
+
+ mat = current * mat;
+
+ glh_set_current_modelview(mat);
+ gGL.loadMatrix(mat.m);
+
+ LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
+
+ glh::matrix4f inv_mat = mat.inverse();
+
+ glh::vec3f origin(0,0,0);
+ inv_mat.mult_matrix_vec(origin);
+
+ camera.setOrigin(origin.v);
+
+ glCullFace(GL_FRONT);
+
+ static LLCullResult ref_result;
+
+ if (LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ //initial sky pass (no user clip plane)
+ { //mask out everything but the sky
+ gPipeline.pushRenderTypeMask();
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
+ static LLCullResult result;
+ updateCull(camera, result);
+ stateSort(camera, result);
+
+ renderGeom(camera, TRUE);
+
+ gPipeline.popRenderTypeMask();
+ }
+
+ gPipeline.pushRenderTypeMask();
+
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
+ S32 detail = RenderReflectionDetail;
+ if (detail > 0)
+ { //mask out selected geometry based on reflection detail
+ if (detail < 4)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
+ if (detail < 3)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ if (detail < 2)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
+ }
+ }
+ }
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ LLGLDisable cull(GL_CULL_FACE);
+ updateCull(camera, ref_result, -water_clip, &plane);
+ stateSort(camera, ref_result);
+ }
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
+ {
+ if (RenderReflectionDetail > 0)
+ {
+ gPipeline.grabReferences(ref_result);
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ renderGeom(camera);
+ }
+ }
+
+ gPipeline.popRenderTypeMask();
+ }
+ glCullFace(GL_BACK);
+ gGL.popMatrix();
+ mWaterRef.flush();
+ glh_set_current_modelview(current);
+ LLPipeline::sUseOcclusion = occlusion;
+ }
+
+ camera.setOrigin(camera_in.getOrigin());
+ //render distortion map
+ static BOOL last_update = TRUE;
+ if (last_update)
+ {
+ camera.setFar(camera_in.getFar());
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ END_RENDER_TYPES);
+ stop_glerror();
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
+
+ if (LLPipeline::sUnderWaterRender)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ END_RENDER_TYPES);
+ }
+ LLViewerCamera::updateFrustumPlanes(camera);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLColor4& col = LLDrawPoolWater::sWaterFogColor;
+ glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+ mWaterDis.bindTarget();
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ mWaterDis.getViewport(gGLViewport);
+
+ if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ //clip out geometry on the same side of water as the camera
+ mat = glh_get_current_modelview();
+ LLPlane plane(-pnorm, -(pd+pad));
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ static LLCullResult result;
+ updateCull(camera, result, water_clip, &plane);
+ stateSort(camera, result);
+
+ gGL.setColorMask(true, true);
+ mWaterDis.clear();
+ gGL.setColorMask(true, false);
+
+ renderGeom(camera);
+
+ }
+
+ LLPipeline::sUnderWaterRender = FALSE;
+ mWaterDis.flush();
+ }
+ last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
+
+ LLRenderTarget::unbindTarget();
+
+ LLPipeline::sReflectionRender = FALSE;
+
+ if (!LLRenderTarget::sUseFBO)
+ {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ glClearColor(0.f, 0.f, 0.f, 0.f);
+ gViewerWindow->setup3DViewport();
+ gPipeline.popRenderTypeMask();
+ LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
+ LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
+ LLPlane npnorm(-pnorm, -pd);
+ LLViewerCamera::getInstance()->setUserClipPlane(npnorm);
+
+ LLGLState::checkStates();
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+ }
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ }
+}
+
+glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
+{
+ glh::matrix4f ret;
+
+ LLVector3 dirN;
+ LLVector3 upN;
+ LLVector3 lftN;
+
+ lftN = dir % up;
+ lftN.normVec();
+
+ upN = lftN % dir;
+ upN.normVec();
+
+ dirN = dir;
+ dirN.normVec();
+
+ ret.m[ 0] = lftN[0];
+ ret.m[ 1] = upN[0];
+ ret.m[ 2] = -dirN[0];
+ ret.m[ 3] = 0.f;
+
+ ret.m[ 4] = lftN[1];
+ ret.m[ 5] = upN[1];
+ ret.m[ 6] = -dirN[1];
+ ret.m[ 7] = 0.f;
+
+ ret.m[ 8] = lftN[2];
+ ret.m[ 9] = upN[2];
+ ret.m[10] = -dirN[2];
+ ret.m[11] = 0.f;
+
+ ret.m[12] = -(lftN*pos);
+ ret.m[13] = -(upN*pos);
+ ret.m[14] = dirN*pos;
+ ret.m[15] = 1.f;
+
+ return ret;
+}
+
+glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
+{
+ glh::matrix4f ret;
+ ret.m[ 0] = 2/(max[0]-min[0]);
+ ret.m[ 4] = 0;
+ ret.m[ 8] = 0;
+ ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
+
+ ret.m[ 1] = 0;
+ ret.m[ 5] = 2/(max[1]-min[1]);
+ ret.m[ 9] = 0;
+ ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
+
+ ret.m[ 2] = 0;
+ ret.m[ 6] = 0;
+ ret.m[10] = 2/(max[2]-min[2]);
+ ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
+
+ ret.m[ 3] = 0;
+ ret.m[ 7] = 0;
+ ret.m[11] = 0;
+ ret.m[15] = 1;
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
+static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
+static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
+
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
+{
+ LLFastTimer t(FTM_SHADOW_RENDER);
+
+ //clip out geometry on the same side of water as the camera
+ S32 occlude = LLPipeline::sUseOcclusion;
+ if (!use_occlusion)
+ {
+ LLPipeline::sUseOcclusion = 0;
+ }
+ LLPipeline::sShadowRender = TRUE;
+
+ U32 types[] = {
+ LLRenderPass::PASS_SIMPLE,
+ LLRenderPass::PASS_FULLBRIGHT,
+ LLRenderPass::PASS_SHINY,
+ LLRenderPass::PASS_BUMP,
+ LLRenderPass::PASS_FULLBRIGHT_SHINY
+ };
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.bind();
+ }
+
+ updateCull(shadow_cam, result);
+ stateSort(shadow_cam, result);
+
+ //generate shadow map
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(proj.m);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLModelView);
+
+ stop_glerror();
+ gGLLastMatrix = NULL;
+
+ {
+ //LLGLDepthTest depth(GL_TRUE);
+ //glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ stop_glerror();
+
+ //glCullFace(GL_FRONT);
+
+ LLVertexBuffer::unbind();
+
+ {
+ if (!use_shader)
+ { //occlusion program is general purpose depth-only no-textures
+ gOcclusionProgram.bind();
+ }
+
+ gGL.diffuseColor4f(1,1,1,1);
+ gGL.setColorMask(false, false);
+
+ LLFastTimer ftm(FTM_SHADOW_SIMPLE);
+ gGL.getTexUnit(0)->disable();
+ for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+ {
+ renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+ }
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ if (!use_shader)
+ {
+ gOcclusionProgram.unbind();
+ }
+ }
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ renderGeomShadow(shadow_cam);
+ gDeferredShadowProgram.bind();
+ }
+ else
+ {
+ renderGeomShadow(shadow_cam);
+ }
+
+ {
+ LLFastTimer ftm(FTM_SHADOW_ALPHA);
+ gDeferredShadowAlphaMaskProgram.bind();
+ gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_TEXTURE_INDEX;
+
+ renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
+ renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
+ renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE);
+ gDeferredTreeShadowProgram.bind();
+ gDeferredTreeShadowProgram.setMinimumAlpha(0.598f);
+ renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+ }
+
+ //glCullFace(GL_BACK);
+
+ gDeferredShadowProgram.bind();
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ doOcclusion(shadow_cam);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ }
+
+ gGL.setColorMask(true, true);
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ gGLLastMatrix = NULL;
+
+ LLPipeline::sUseOcclusion = occlude;
+ LLPipeline::sShadowRender = FALSE;
+}
+
+static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
+BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
+{
+ LLFastTimer t(FTM_VISIBLE_CLOUD);
+ //get point cloud of intersection of frust and min, max
+
+ if (getVisibleExtents(camera, min, max))
+ {
+ return FALSE;
+ }
+
+ //get set of planes on bounding box
+ LLPlane bp[] = {
+ LLPlane(min, LLVector3(-1,0,0)),
+ LLPlane(min, LLVector3(0,-1,0)),
+ LLPlane(min, LLVector3(0,0,-1)),
+ LLPlane(max, LLVector3(1,0,0)),
+ LLPlane(max, LLVector3(0,1,0)),
+ LLPlane(max, LLVector3(0,0,1))};
+
+ //potential points
+ std::vector<LLVector3> pp;
+
+ //add corners of AABB
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
+
+ //add corners of camera frustum
+ for (U32 i = 0; i < 8; i++)
+ {
+ pp.push_back(camera.mAgentFrustum[i]);
+ }
+
+
+ //bounding box line segments
+ U32 bs[] =
+ {
+ 0,1,
+ 1,3,
+ 3,2,
+ 2,0,
+
+ 4,5,
+ 5,7,
+ 7,6,
+ 6,4,
+
+ 0,4,
+ 1,5,
+ 3,7,
+ 2,6
+ };
+
+ for (U32 i = 0; i < 12; i++)
+ { //for each line segment in bounding box
+ for (U32 j = 0; j < 6; j++)
+ { //for each plane in camera frustum
+ const LLPlane& cp = camera.getAgentPlane(j);
+ const LLVector3& v1 = pp[bs[i*2+0]];
+ const LLVector3& v2 = pp[bs[i*2+1]];
+ LLVector3 n;
+ cp.getVector3(n);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ //camera frustum line segments
+ const U32 fs[] =
+ {
+ 0,1,
+ 1,2,
+ 2,3,
+ 3,0,
+
+ 4,5,
+ 5,6,
+ 6,7,
+ 7,4,
+
+ 0,4,
+ 1,5,
+ 2,6,
+ 3,7
+ };
+
+ LLVector3 center = (max+min)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+
+ for (U32 i = 0; i < 12; i++)
+ {
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLVector3& v1 = pp[fs[i*2+0]+8];
+ const LLVector3& v2 = pp[fs[i*2+1]+8];
+ const LLPlane& cp = bp[j];
+ LLVector3 n;
+ cp.getVector3(n);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
+ max+LLVector3(0.05f,0.05f,0.05f) };
+
+ for (U32 i = 0; i < pp.size(); ++i)
+ {
+ bool found = true;
+
+ const F32* p = pp[i].mV;
+
+ for (U32 j = 0; j < 3; ++j)
+ {
+ if (p[j] < ext[0].mV[j] ||
+ p[j] > ext[1].mV[j])
+ {
+ found = false;
+ break;
+ }
+ }
+
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLPlane& cp = camera.getAgentPlane(j);
+ F32 dist = cp.dist(pp[i]);
+ if (dist > 0.05f) //point is above some plane, not contained
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ fp.push_back(pp[i]);
+ }
+ }
+
+ if (fp.empty())
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
+{
+ if (obj && obj->getVolume())
+ {
+ for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
+ {
+ renderHighlight(*iter, fade);
+ }
+
+ LLDrawable* drawable = obj->mDrawable;
+ if (drawable)
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ if (face)
+ {
+ face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
+ }
+ }
+ }
+ }
+}
+
+void LLPipeline::generateHighlight(LLCamera& camera)
+{
+ //render highlighted object as white into offscreen render target
+ if (mHighlightObject.notNull())
+ {
+ mHighlightSet.insert(HighlightItem(mHighlightObject));
+ }
+
+ if (!mHighlightSet.empty())
+ {
+ F32 transition = gFrameIntervalSeconds/RenderHighlightFadeTime;
+
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ mHighlight.bindTarget();
+ disableLights();
+ gGL.setColorMask(true, true);
+ mHighlight.clear();
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
+ {
+ std::set<HighlightItem>::iterator cur_iter = iter++;
+
+ if (cur_iter->mItem.isNull())
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+
+ if (cur_iter->mItem == mHighlightObject)
+ {
+ cur_iter->incrFade(transition);
+ }
+ else
+ {
+ cur_iter->incrFade(-transition);
+ if (cur_iter->mFade <= 0.f)
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+ }
+
+ renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
+ }
+
+ mHighlight.flush();
+ gGL.setColorMask(true, false);
+ gViewerWindow->setup3DViewport();
+ }
+}
+
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+ if (!sRenderDeferred || RenderShadowDetail <= 0)
+ {
+ return;
+ }
+
+ BOOL skip_avatar_update = FALSE;
+ if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
+ {
+
+ skip_avatar_update = TRUE;
+ }
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
+ }
+
+ F64 last_modelview[16];
+ F64 last_projection[16];
+ for (U32 i = 0; i < 16; i++)
+ { //store last_modelview of world camera
+ last_modelview[i] = gGLLastModelView[i];
+ last_projection[i] = gGLLastProjection[i];
+ }
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ END_RENDER_TYPES);
+
+ gGL.setColorMask(false, false);
+
+ //get sun view matrix
+
+ //store current projection/modelview matrix
+ glh::matrix4f saved_proj = glh_get_current_projection();
+ glh::matrix4f saved_view = glh_get_current_modelview();
+ glh::matrix4f inv_view = saved_view.inverse();
+
+ glh::matrix4f view[6];
+ glh::matrix4f proj[6];
+
+ //clip contains parallel split distances for 3 splits
+ LLVector3 clip = RenderShadowClipPlanes;
+
+ //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
+
+ //far clip on last split is minimum of camera view distance and 128
+ mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
+
+ clip = RenderShadowOrthoClipPlanes;
+ mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
+
+ //currently used for amount to extrude frusta corners for constructing shadow frusta
+ LLVector3 n = RenderShadowNearDist;
+ //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+
+ //put together a universal "near clip" plane for shadow frusta
+ LLPlane shadow_near_clip;
+ {
+ LLVector3 p = gAgent.getPositionAgent();
+ p += mSunDir * RenderFarClip*2.f;
+ shadow_near_clip.setVec(p, mSunDir);
+ }
+
+ LLVector3 lightDir = -mSunDir;
+ lightDir.normVec();
+
+ glh::vec3f light_dir(lightDir.mV);
+
+ //create light space camera matrix
+
+ LLVector3 at = lightDir;
+
+ LLVector3 up = camera.getAtAxis();
+
+ if (fabsf(up*lightDir) > 0.75f)
+ {
+ up = camera.getUpAxis();
+ }
+
+ /*LLVector3 left = up%at;
+ up = at%left;*/
+
+ up.normVec();
+ at.normVec();
+
+
+ LLCamera main_camera = camera;
+
+ F32 near_clip = 0.f;
+ {
+ //get visible point cloud
+ std::vector<LLVector3> fp;
+
+ main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
+
+ LLVector3 min,max;
+ getVisiblePointCloud(main_camera,min,max,fp);
+
+ if (fp.empty())
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[0] = main_camera;
+ mShadowExtents[0][0] = min;
+ mShadowExtents[0][1] = max;
+
+ mShadowFrustPoints[0].clear();
+ mShadowFrustPoints[1].clear();
+ mShadowFrustPoints[2].clear();
+ mShadowFrustPoints[3].clear();
+ }
+ popRenderTypeMask();
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+ }
+
+ return;
+ }
+
+ //get good split distances for frustum
+ for (U32 i = 0; i < fp.size(); ++i)
+ {
+ glh::vec3f v(fp[i].mV);
+ saved_view.mult_matrix_vec(v);
+ fp[i].setVec(v.v);
+ }
+
+ min = fp[0];
+ max = fp[0];
+
+ //get camera space bounding box
+ for (U32 i = 1; i < fp.size(); ++i)
+ {
+ update_min_max(min, max, fp[i]);
+ }
+
+ near_clip = -max.mV[2];
+ F32 far_clip = -min.mV[2]*2.f;
+
+ //far_clip = llmin(far_clip, 128.f);
+ far_clip = llmin(far_clip, camera.getFar());
+
+ F32 range = far_clip-near_clip;
+
+ LLVector3 split_exp = RenderShadowSplitExponent;
+
+ F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
+
+ da = powf(da, split_exp.mV[2]);
+
+
+ F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ F32 x = (F32)(i+1)/4.f;
+ x = powf(x, sxp);
+ mSunClipPlanes.mV[i] = near_clip+range*x;
+ }
+ }
+
+ // convenience array of 4 near clip plane distances
+ F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
+
+
+ if (mSunDiffuse == LLColor4::black)
+ { //sun diffuse is totally black, shadows don't matter
+ LLGLDepthTest depth(GL_TRUE);
+
+ for (S32 j = 0; j < 4; j++)
+ {
+ mShadow[j].bindTarget();
+ mShadow[j].clear();
+ mShadow[j].flush();
+ }
+ }
+ else
+ {
+ for (S32 j = 0; j < 4; j++)
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustPoints[j].clear();
+ }
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
+
+ //restore render matrices
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ LLVector3 eye = camera.getOrigin();
+
+ //camera used for shadow cull/render
+ LLCamera shadow_cam;
+
+ //create world space camera frustum for this split
+ shadow_cam = camera;
+ shadow_cam.setFar(16.f);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ LLVector3* frust = shadow_cam.mAgentFrustum;
+
+ LLVector3 pn = shadow_cam.getAtAxis();
+
+ LLVector3 min, max;
+
+ //construct 8 corners of split frustum section
+ for (U32 i = 0; i < 4; i++)
+ {
+ LLVector3 delta = frust[i+4]-eye;
+ delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
+ delta.normVec();
+ F32 dp = delta*pn;
+ frust[i] = eye + (delta*dist[j]*0.95f)/dp;
+ frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
+ }
+
+ shadow_cam.calcAgentFrustumPlanes(frust);
+ shadow_cam.mFrustumCornerDist = 0.f;
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[j] = shadow_cam;
+ }
+
+ std::vector<LLVector3> fp;
+
+ if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
+ {
+ //no possible shadow receivers
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = LLVector3();
+ mShadowExtents[j][1] = LLVector3();
+ mShadowCamera[j+4] = shadow_cam;
+ }
+
+ mShadow[j].bindTarget();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mShadow[j].clear();
+ }
+ mShadow[j].flush();
+
+ mShadowError.mV[j] = 0.f;
+ mShadowFOV.mV[j] = 0.f;
+
+ continue;
+ }
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = min;
+ mShadowExtents[j][1] = max;
+ mShadowFrustPoints[j] = fp;
+ }
+
+
+ //find a good origin for shadow projection
+ LLVector3 origin;
+
+ //get a temporary view projection
+ view[j] = look(camera.getOrigin(), lightDir, -up);
+
+ std::vector<LLVector3> wpf;
+
+ for (U32 i = 0; i < fp.size(); i++)
+ {
+ glh::vec3f p = glh::vec3f(fp[i].mV);
+ view[j].mult_matrix_vec(p);
+ wpf.push_back(LLVector3(p.v));
+ }
+
+ min = wpf[0];
+ max = wpf[0];
+
+ for (U32 i = 0; i < fp.size(); ++i)
+ { //get AABB in camera space
+ update_min_max(min, max, wpf[i]);
+ }
+
+ // Construct a perspective transform with perspective along y-axis that contains
+ // points in wpf
+ //Known:
+ // - far clip plane
+ // - near clip plane
+ // - points in frustum
+ //Find:
+ // - origin
+
+ //get some "interesting" points of reference
+ LLVector3 center = (min+max)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+ LLVector3 near_center = center;
+ near_center.mV[1] += size.mV[1]*2.f;
+
+
+ //put all points in wpf in quadrant 0, reletive to center of min/max
+ //get the best fit line using least squares
+ F32 bfm = 0.f;
+ F32 bfb = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ wpf[i] -= center;
+ wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
+ wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
+ }
+
+ if (!wpf.empty())
+ {
+ F32 sx = 0.f;
+ F32 sx2 = 0.f;
+ F32 sy = 0.f;
+ F32 sxy = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ sx += wpf[i].mV[0];
+ sx2 += wpf[i].mV[0]*wpf[i].mV[0];
+ sy += wpf[i].mV[1];
+ sxy += wpf[i].mV[0]*wpf[i].mV[1];
+ }
+
+ bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
+ bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
+ }
+
+ {
+ // best fit line is y=bfm*x+bfb
+
+ //find point that is furthest to the right of line
+ F32 off_x = -1.f;
+ LLVector3 lp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ //y = bfm*x+bfb
+ //x = (y-bfb)/bfm
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+
+ lx = wpf[i].mV[0]-lx;
+
+ if (off_x < lx)
+ {
+ off_x = lx;
+ lp = wpf[i];
+ }
+ }
+
+ //get line with slope bfm through lp
+ // bfb = y-bfm*x
+ bfb = lp.mV[1]-bfm*lp.mV[0];
+
+ //calculate error
+ mShadowError.mV[j] = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+ mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
+ }
+
+ mShadowError.mV[j] /= wpf.size();
+ mShadowError.mV[j] /= size.mV[0];
+
+ if (mShadowError.mV[j] > RenderShadowErrorCutoff)
+ { //just use ortho projection
+ mShadowFOV.mV[j] = -1.f;
+ origin.clearVec();
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //origin is where line x = 0;
+ origin.setVec(0,bfb,0);
+
+ F32 fovz = 1.f;
+ F32 fovx = 1.f;
+
+ LLVector3 zp;
+ LLVector3 xp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ if (fovz > -atz.mV[1])
+ {
+ zp = wpf[i];
+ fovz = -atz.mV[1];
+ }
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ if (fovx > -atx.mV[1])
+ {
+ fovx = -atx.mV[1];
+ xp = wpf[i];
+ }
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ F32 cutoff = llmin((F32) RenderShadowFOVCutoff, 1.4f);
+
+ mShadowFOV.mV[j] = fovx;
+
+ if (fovx < cutoff && fovz > cutoff)
+ {
+ //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
+ F32 d = zp.mV[2]/tan(cutoff);
+ F32 ny = zp.mV[1] + fabsf(d);
+
+ origin.mV[1] = ny;
+
+ fovz = 1.f;
+ fovx = 1.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ fovz = llmin(fovz, -atz.mV[1]);
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ fovx = llmin(fovx, -atx.mV[1]);
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ mShadowFOV.mV[j] = cutoff;
+ }
+
+
+ origin += center;
+
+ F32 ynear = -(max.mV[1]-origin.mV[1]);
+ F32 yfar = -(min.mV[1]-origin.mV[1]);
+
+ if (ynear < 0.1f) //keep a sensible near clip plane
+ {
+ F32 diff = 0.1f-ynear;
+ origin.mV[1] += diff;
+ ynear += diff;
+ yfar += diff;
+ }
+
+ if (fovx > cutoff)
+ { //just use ortho projection
+ origin.clearVec();
+ mShadowError.mV[j] = -1.f;
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //get perspective projection
+ view[j] = view[j].inverse();
+
+ glh::vec3f origin_agent(origin.mV);
+
+ //translate view to origin
+ view[j].mult_matrix_vec(origin_agent);
+
+ eye = LLVector3(origin_agent.v);
+
+ if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustOrigin[j] = eye;
+ }
+
+ view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
+
+ F32 fx = 1.f/tanf(fovx);
+ F32 fz = 1.f/tanf(fovz);
+
+ proj[j] = glh::matrix4f(-fx, 0, 0, 0,
+ 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
+ 0, 0, -fz, 0,
+ 0, -1.f, 0, 0);
+ }
+ }
+ }
+
+ //shadow_cam.setFar(128.f);
+ shadow_cam.setOriginAndLookAt(eye, up, center);
+
+ shadow_cam.setOrigin(0,0,0);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+ shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = mShadowModelview[j].m[i];
+ gGLLastProjection[i] = mShadowProjection[j].m[i];
+ }
+
+ mShadowModelview[j] = view[j];
+ mShadowProjection[j] = proj[j];
+
+
+ mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
+
+ stop_glerror();
+
+ mShadow[j].bindTarget();
+ mShadow[j].getViewport(gGLViewport);
+ mShadow[j].clear();
+
+ {
+ static LLCullResult result[4];
+
+ //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+ renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
+ }
+
+ mShadow[j].flush();
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+ mShadowCamera[j+4] = shadow_cam;
+ }
+ }
+ }
+
+
+ //hack to disable projector shadows
+ bool gen_shadow = RenderShadowDetail > 1;
+
+ if (gen_shadow)
+ {
+ F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
+
+ //update shadow targets
+ for (U32 i = 0; i < 2; i++)
+ { //for each current shadow
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+
+ if (mShadowSpotLight[i].notNull() &&
+ (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+ mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+ { //keep this spotlight
+ mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+ }
+ else
+ { //fade out this light
+ mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+
+ if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+ { //faded out, grab one of the pending spots (whichever one isn't already taken)
+ if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+ }
+ else
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+ }
+ }
+ }
+ }
+
+ for (S32 i = 0; i < 2; i++)
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ if (mShadowSpotLight[i].isNull())
+ {
+ continue;
+ }
+
+ LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+
+ if (!volume)
+ {
+ mShadowSpotLight[i] = NULL;
+ continue;
+ }
+
+ LLDrawable* drawable = mShadowSpotLight[i];
+
+ LLVector3 params = volume->getSpotLightParams();
+ F32 fov = params.mV[0];
+
+ //get agent->light space matrix (modelview)
+ LLVector3 center = drawable->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+
+ //get near clip plane
+ LLVector3 scale = volume->getScale();
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = center+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+
+ view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+
+ view[i+4] = view[i+4].inverse();
+
+ //get perspective matrix
+ F32 near_clip = dist+0.01f;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = dist+volume->getLightRadius()*1.5f;
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[i+4]);
+ glh_set_current_projection(proj[i+4]);
+
+ mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
+
+ for (U32 j = 0; j < 16; j++)
+ {
+ gGLLastModelView[j] = mShadowModelview[i+4].m[j];
+ gGLLastProjection[j] = mShadowProjection[i+4].m[j];
+ }
+
+ mShadowModelview[i+4] = view[i+4];
+ mShadowProjection[i+4] = proj[i+4];
+
+ LLCamera shadow_cam = camera;
+ shadow_cam.setFar(far_clip);
+ shadow_cam.setOrigin(origin);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ stop_glerror();
+
+ mShadow[i+4].bindTarget();
+ mShadow[i+4].getViewport(gGLViewport);
+ mShadow[i+4].clear();
+
+ static LLCullResult result[2];
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+
+ renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+
+ mShadow[i+4].flush();
+ }
+ }
+ else
+ { //no spotlight shadows
+ mShadowSpotLight[0] = mShadowSpotLight[1] = NULL;
+ }
+
+
+ if (!CameraOffset)
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+ }
+ else
+ {
+ glh_set_current_modelview(view[1]);
+ glh_set_current_projection(proj[1]);
+ gGL.loadMatrix(view[1].m);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.loadMatrix(proj[1].m);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ }
+ gGL.setColorMask(true, false);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = last_modelview[i];
+ gGLLastProjection[i] = last_projection[i];
+ }
+
+ popRenderTypeMask();
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+ }
+}
+
+void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
+{
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!group->isDead() &&
+ (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
+ gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
+ group->mDrawMap.find(type) != group->mDrawMap.end())
+ {
+ pass->renderGroup(group,type,mask,texture);
+ }
+ }
+}
+
+void LLPipeline::generateImpostor(LLVOAvatar* avatar)
+{
+ LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ static LLCullResult result;
+ result.clear();
+ grabReferences(result);
+
+ if (!avatar || !avatar->mDrawable)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ bool muted = avatar->isVisuallyMuted();
+
+ pushRenderTypeMask();
+
+ if (muted)
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ }
+ else
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ END_RENDER_TYPES);
+ }
+
+ S32 occlusion = sUseOcclusion;
+ sUseOcclusion = 0;
+ sReflectionRender = sRenderDeferred ? FALSE : TRUE;
+ sShadowRender = TRUE;
+ sImpostorRender = TRUE;
+
+ LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
+ markVisible(avatar->mDrawable, *viewer_camera);
+ LLVOAvatar::sUseImpostors = FALSE;
+
+ LLVOAvatar::attachment_map_t::iterator iter;
+ for (iter = avatar->mAttachmentPoints.begin();
+ iter != avatar->mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject* attached_object = (*attachment_iter))
+ {
+ markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+ }
+ }
+ }
+
+ stateSort(*LLViewerCamera::getInstance(), result);
+
+ const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
+ LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
+
+ LLCamera camera = *viewer_camera;
+
+ camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
+
+ LLVector2 tdim;
+
+
+ LLVector4a half_height;
+ half_height.setSub(ext[1], ext[0]);
+ half_height.mul(0.5f);
+
+ LLVector4a left;
+ left.load3(camera.getLeftAxis().mV);
+ left.mul(left);
+ left.normalize3fast();
+
+ LLVector4a up;
+ up.load3(camera.getUpAxis().mV);
+ up.mul(up);
+ up.normalize3fast();
+
+ tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
+ tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+
+ F32 distance = (pos-camera.getOrigin()).length();
+ F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
+ F32 aspect = tdim.mV[0]/tdim.mV[1];
+ glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
+ glh_set_current_projection(persp);
+ gGL.loadMatrix(persp.m);
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ glh::matrix4f mat;
+ camera.getOpenGLTransform(mat.m);
+
+ mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
+
+ gGL.loadMatrix(mat.m);
+ glh_set_current_modelview(mat);
+
+ glClearColor(0.0f,0.0f,0.0f,0.0f);
+ gGL.setColorMask(true, true);
+
+ // get the number of pixels per angle
+ F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
+
+ //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
+ U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
+ U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
+
+ if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
+ resY != avatar->mImpostor.getHeight())
+ {
+ avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ addDeferredAttachments(avatar->mImpostor);
+ }
+
+ gGL.getTexUnit(0)->bind(&avatar->mImpostor);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ avatar->mImpostor.bindTarget();
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ avatar->mImpostor.clear();
+ renderGeomDeferred(camera);
+ renderGeomPostDeferred(camera);
+ }
+ else
+ {
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, resX, resY);
+ avatar->mImpostor.clear();
+ renderGeom(camera);
+ }
+
+ { //create alpha mask based on depth buffer (grey out if muted)
+ if (LLPipeline::sRenderDeferred)
+ {
+ GLuint buff = GL_COLOR_ATTACHMENT0;
+ glDrawBuffersARB(1, &buff);
+ }
+
+ LLGLDisable blend(GL_BLEND);
+
+ if (muted)
+ {
+ gGL.setColorMask(true, true);
+ }
+ else
+ {
+ gGL.setColorMask(false, true);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ gGL.flush();
+
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ static const F32 clip_plane = 0.99999f;
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.bind();
+ }
+
+ gGL.color4ub(64,64,64,255);
+ gGL.begin(LLRender::QUADS);
+ gGL.vertex3f(-1, -1, clip_plane);
+ gGL.vertex3f(1, -1, clip_plane);
+ gGL.vertex3f(1, 1, clip_plane);
+ gGL.vertex3f(-1, 1, clip_plane);
+ gGL.end();
+ gGL.flush();
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gUIProgram.unbind();
+ }
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ }
+
+ avatar->mImpostor.flush();
+
+ avatar->setImpostorDim(tdim);
+
+ LLVOAvatar::sUseImpostors = TRUE;
+ sUseOcclusion = occlusion;
+ sReflectionRender = FALSE;
+ sImpostorRender = FALSE;
+ sShadowRender = FALSE;
+ popRenderTypeMask();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ avatar->mNeedsImpostorUpdate = FALSE;
+ avatar->cacheImpostorValues();
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+}
+
+BOOL LLPipeline::hasRenderBatches(const U32 type) const
+{
+ return sCull->getRenderMapSize(type) > 0;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
+{
+ return sCull->beginRenderMap(type);
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
+{
+ return sCull->endRenderMap(type);
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
+{
+ return sCull->beginAlphaGroups();
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
+{
+ return sCull->endAlphaGroups();
+}
+
+BOOL LLPipeline::hasRenderType(const U32 type) const
+{
+ // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
+ // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
+ // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
+ return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
+}
+
+void LLPipeline::setRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = TRUE;
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ return TRUE;
+ }
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ return FALSE;
+}
+
+void LLPipeline::pushRenderTypeMask()
+{
+ std::string cur_mask;
+ cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.push(cur_mask);
+}
+
+void LLPipeline::popRenderTypeMask()
+{
+ if (mRenderTypeEnableStack.empty())
+ {
+ llerrs << "Depleted render type stack." << llendl;
+ }
+
+ memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.pop();
+}
+
+void LLPipeline::andRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ BOOL tmp[NUM_RENDER_TYPES];
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ tmp[i] = FALSE;
+ }
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ tmp[type] = TRUE;
+ }
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = tmp[i];
+ }
+
+}
+
+void LLPipeline::clearRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = FALSE;
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+void LLPipeline::addDebugBlip(const LLVector3& position, const LLColor4& color)
+{
+ DebugBlip blip(position, color);
+ mDebugBlips.push_back(blip);
+}
+
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index eabcc68916..d5d58235a4 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -140,7 +140,11 @@ with the same filename but different name <texture name="Command_MiniMap_Icon" file_name="toolbar_icons/mini_map.png" preload="true" /> <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> <texture name="Command_Outbox_Icon" file_name="toolbar_icons/outbox.png" preload="true" /> + <texture name="Command_Pathfinding_Icon" file_name="toolbar_icons/land.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> + <texture name="Command_PF_Basic_Icon" file_name="toolbar_icons/land.png" preload="true" /> + <texture name="Command_PF_Characters_Icon" file_name="toolbar_icons/land.png" preload="true" /> + <texture name="Command_PF_Linksets_Icon" file_name="toolbar_icons/land.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> <texture name="Command_Preferences_Icon" file_name="toolbar_icons/preferences.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml new file mode 100644 index 0000000000..7af40bbff6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_tear_off="false" + height="213" + layout="topleft" + name="floater_pathfinding_basic" + help_topic="floater_pathfinding_basic" + reuse_instance="false" + save_rect="false" + single_instance="true" + title="Basic pathfinding setup" + width="312"> + <floater.string name="status_pathfinding_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="status_unable_to_change_state">Unable to change modes successfully.</floater.string> + <floater.string name="status_querying_state">Checking status ...</floater.string> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + name="status_label" + top="8" + width="289"> + </text> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + name="unfreeze_label" + top_pad="4" + width="289"> + Allow object / terrain changes: + </text> + <button + follows="left|top" + height="22" + label="Unfreeze" + layout="topleft" + name="enter_unfrozen_mode" + width="116"/> + <text + height="82" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + line_spacing.multiple="1.5" + left="15" + name="freeze_label" + top_pad="23" + width="289"> + In unfrozen mode, you can move and make changes to objects and terrain. When you are finished, click the Freeze button. It may require a few minutes to process your changes. + </text> + <button + follows="left|top" + height="22" + label="Freeze" + layout="topleft" + name="enter_frozen_mode" + top_pad="0" + width="116"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml new file mode 100644 index 0000000000..e9d58c7a33 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_resize="true" + can_tear_off="false" + height="273" + width="635" + min_height="273" + min_width="635" + layout="topleft" + name="floater_pathfinding_characters" + help_topic="floater_pathfinding_characters" + reuse_instance="true" + save_rect="false" + single_instance="true" + title="Pathfinding characters"> + <floater.string name="characters_messaging_initial"></floater.string> + <floater.string name="characters_messaging_fetch_starting">Building query for pathfinding characters ...</floater.string> + <floater.string name="characters_messaging_fetch_inprogress">Querying for pathfinding characters ...</floater.string> + <floater.string name="characters_messaging_fetch_inprogress_multi_request">Querying for pathfinding characters (already in progress) ...</floater.string> + <floater.string name="characters_messaging_fetch_received">Loading pathfinding characters data from response ...</floater.string> + <floater.string name="characters_messaging_fetch_error">Error detected while querying for pathfinding characters</floater.string> + <floater.string name="characters_messaging_complete_none_found">No pathfinding characters</floater.string> + <floater.string name="characters_messaging_complete_available">[NUM_SELECTED] characters selected out of [NUM_TOTAL]</floater.string> + <floater.string name="characters_messaging_service_not_available">Required capability is not available in current region</floater.string> + <floater.string name="character_cpu_time">[CPU_TIME] µs</floater.string> + <scroll_list + column_padding="0" + draw_heading="true" + follows="all" + height="135" + layout="topleft" + left="18" + top="10" + multi_select="true" + name="pathfinding_characters" + width="600"> + <scroll_list.columns + label="Name" + name="name" + dynamic_width="true" /> + <scroll_list.columns + label="Description" + name="description" + width="172" /> + <scroll_list.columns + label="Owner" + name="owner" + width="141" /> + <scroll_list.columns + label="CPU" + name="cpu_time" + width="60" /> + <scroll_list.columns + label="Altitude" + name="altitude" + width="64" /> + </scroll_list> + <text + height="26" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + name="characters_status" + top="161" + width="240"> + Characters: + </text> + <button + follows="right|bottom" + height="21" + label="Refresh list" + layout="topleft" + name="refresh_characters_list" + top="161" + left="257" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select all" + layout="topleft" + name="select_all_characters" + top="161" + left="378" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select none" + layout="topleft" + name="select_none_characters" + top="161" + left="502" + width="115"/> + <view_border + bevel_style="none" + follows="left|right|bottom" + height="0" + layout="topleft" + name="horiz_separator" + top="196" + left="20" + width="600"/> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|bottom" + layout="topleft" + name="actions_label" + top_pad="12" + width="242"> + Actions on selected characters: + </text> + <check_box + height="19" + follows="left|bottom" + label="Show beacon" + layout="topleft" + name="show_beacon" + top="208" + left="259" + width="90" /> + <button + follows="left|bottom" + height="22" + label="Take" + layout="topleft" + name="take_characters" + top="232" + left="17" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Take copy" + layout="topleft" + name="take_copy_characters" + top="232" + left="119" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Return" + layout="topleft" + name="return_characters" + top="233" + left="220" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Delete" + layout="topleft" + name="delete_characters" + top="233" + left="322" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Teleport me to it" + layout="topleft" + name="teleport_to_character" + tool_tip="Enabled only when one character is selected." + top="233" + left="420" + width="159"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml new file mode 100644 index 0000000000..dd31a71e0f --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml @@ -0,0 +1,466 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_tear_off="false" + height="352" + layout="topleft" + name="floater_pathfinding_console" + help_topic="floater_pathfinding_console" + reuse_instance="true" + save_rect="true" + single_instance="true" + title="Pathfinding edit / test" + width="456"> + <floater.string name="navmesh_status_unknown"></floater.string> + <floater.string name="navmesh_status_library_not_implemented">Cannot find pathing library implementation.</floater.string> + <floater.string name="navmesh_status_region_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="navmesh_status_downloading">Downloading the navmesh ...</floater.string> + <floater.string name="navmesh_status_updating">The navmesh has changed on the server. Downloading the latest navmesh ...</floater.string> + <floater.string name="navmesh_status_has_navmesh">Navmesh received.</floater.string> + <floater.string name="navmesh_status_error">Unable to download navmesh successfully.</floater.string> + <floater.string name="pathing_choose_start_and_end_points">Please choose start and end points.</floater.string> + <floater.string name="pathing_choose_start_point">Please choose start point.</floater.string> + <floater.string name="pathing_choose_end_point">Please choose end point.</floater.string> + <floater.string name="pathing_path_valid">Path is shown in blue.</floater.string> + <floater.string name="navmesh_update_needed">Region boundary hit, navmesh may not be accurate. Update.</floater.string> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + top="9" + width="208"> + Show: + </text> + <check_box + height="19" + label="Navmesh" + layout="topleft" + left="14" + name="show_navmesh" + top_pad="7" + width="90" /> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="35" + width="208"> + Show walkability map: + </text> + <combo_box + height="19" + layout="topleft" + left="34" + name="show_heatmap_mode" + top_pad="8" + width="156"> + <combo_box.item + label="None" + name="show_heatmap_mode_none" + value="0" /> + <combo_box.item + label="Character type A" + name="show_heatmap_mode_a" + value="1" /> + <combo_box.item + label="Character type B" + name="show_heatmap_mode_b" + value="2" /> + <combo_box.item + label="Character type C" + name="show_heatmap_mode_c" + value="3" /> + <combo_box.item + label="Character type D" + name="show_heatmap_mode_d" + value="4" /> + </combo_box> + <check_box + height="19" + label="Walkables" + layout="topleft" + left="14" + name="show_walkables" + top_pad="10" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Material volumes" + layout="topleft" + left="14" + name="show_material_volumes" + top_pad="4" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Static obstacles" + layout="topleft" + left="14" + name="show_static_obstacles" + top_pad="4" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Exclusion volumes" + layout="topleft" + left="14" + name="show_exclusion_volumes" + top_pad="4" + width="90" /> + <check_box + height="19" + label="World" + layout="topleft" + left="14" + name="show_world" + top_pad="4" + width="90" /> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="14" + height="0" + width="200" + top_pad="12" + visible="true" /> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + height="73" + width="200"> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + layout="topleft" + left="0" + top_pad="5" + width="200"> + Status + </text> + <text + height="40" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="0" + name="pathfinding_status" + top_pad="8" + width="200"> + </text> + </panel> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="14" + height="0" + width="200" + top_pad="0" + visible="true" /> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + layout="topleft" + left="14" + top_pad="18" + width="105"> + Lost characters? + </text> + <button + follows="left|top" + height="21" + label="Characters..." + layout="topleft" + name="view_characters_floater" + left_pad="0" + width="96"/> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="230" + top="35" + height="305" + width="214" + visible="true" /> + <tab_container + follows="left|top" + layout="topleft" + tab_position="top" + name="edit_test_tab_container" + left="227" + top="14" + height="327" + width="218"> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + name="edit_panel" + left="1" + label="Edit"> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + name="unfreeze_label" + left="16" + top_pad="16" + height="13" + width="190"> + Allow object / terrain changes: + </text> + <button + follows="left|top" + height="22" + left="16" + enabled="false" + label="Unfreeze" + layout="topleft" + name="enter_unfrozen_mode" + top_pad="5" + width="116"/> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + name="edit_linksets_label" + top_pad="23" + height="13" + width="190"> + Edit linkset attributes: + </text> + <button + follows="left|top" + height="22" + left="16" + label="Linksets..." + layout="topleft" + name="view_and_edit_linksets" + top_pad="5" + width="116"/> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + line_spacing.multiple="1.5" + name="freeze_label" + top_pad="23" + height="26" + width="190"> + Prevent object / terrain changes and update the navmesh: + </text> + <button + follows="left|top" + height="22" + left="16" + enabled="false" + label="Freeze" + layout="topleft" + name="enter_frozen_mode" + top_pad="9" + width="116"/> + </panel> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + left="1" + name="test_panel" + label="Test"> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + top_pad="14" + width="190"> + Character width + </text> + <slider + decimal_digits="1" + height="14" + increment="0.1" + layout="topleft" + follows="left|top" + max_val="2" + min_val="0.2" + name="character_width" + top_pad="5" + value="1" + width="145" /> + <text + height="14" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + top_pad="-14" + left_pad="0" + width="20"> + m + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="-165" + top_pad="9" + width="190"> + Character type + </text> + <radio_group + follows="top|left" + height="20" + layout="topleft" + left_delta="0" + name="character_type" + top_delta="18" + value="1" + width="190"> + <radio_item + label="A" + height="14" + width="30" + value="1" + name="character_type_a"/> + <radio_item + label="B" + height="14" + width="30" + layout="topleft" + top="4" + left="50" + value="2" + name="character_type_b"/> + <radio_item + label="C" + height="14" + width="30" + layout="topleft" + top="4" + left="100" + value="3" + name="character_type_c"/> + <radio_item + label="D" + height="14" + width="30" + layout="topleft" + top="4" + left="150" + value="4" + name="character_type_d"/> + </radio_group> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="-190" + top_pad="12" + width="190"> + Ctrl-click to select start point. + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + top_pad="5" + width="190"> + Shift-click to select end point. + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + name="path_test_status" + top_pad="11" + width="190"> + </text> + <button + follows="left|top" + height="22" + label="Clear path" + layout="topleft" + name="clear_path" + top_pad="27" + width="96"/> + </panel> + </tab_container> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml new file mode 100644 index 0000000000..d00b85f5d7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml @@ -0,0 +1,512 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_resize="true" + can_tear_off="false" + height="382" + width="950" + min_height="382" + min_width="950" + layout="topleft" + name="floater_pathfinding_linksets" + help_topic="floater_pathfinding_linksets" + reuse_instance="true" + save_rect="false" + single_instance="true" + title="Pathfinding linksets"> + <floater.string name="linksets_messaging_initial"></floater.string> + <floater.string name="linksets_messaging_get_inprogress">Querying for pathfinding linksets ...</floater.string> + <floater.string name="linksets_messaging_get_error">Error detected while querying for pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_set_inprogress">Modifying selected pathfinding linksets ...</floater.string> + <floater.string name="linksets_messaging_set_error">Error detected while modifying selected pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_complete_none_found">No pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_complete_available">[NUM_SELECTED] linksets selected out of [NUM_TOTAL]</floater.string> + <floater.string name="linksets_messaging_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="linkset_terrain_name">[Terrain]</floater.string> + <floater.string name="linkset_terrain_description">--</floater.string> + <floater.string name="linkset_terrain_land_impact">--</floater.string> + <floater.string name="linkset_terrain_dist_from_you">--</floater.string> + <floater.string name="linkset_use_walkable">Walkable</floater.string> + <floater.string name="linkset_use_static_obstacle">Static obstacle</floater.string> + <floater.string name="linkset_use_dynamic_obstacle">Movable obstacle</floater.string> + <floater.string name="linkset_use_material_volume">Material volume</floater.string> + <floater.string name="linkset_use_exclusion_volume">Exclusion volume</floater.string> + <floater.string name="linkset_use_dynamic_phantom">Movable phantom</floater.string> + <floater.string name="linkset_is_terrain">[unmodifiable]</floater.string> + <floater.string name="linkset_is_restricted_state">[restricted]</floater.string> + <floater.string name="linkset_choose_use">Choose linkset use...</floater.string> + <panel + border="false" + bevel_style="none" + follows="left|top|right|bottom" + layout="topleft" + height="226" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="20" + top_pad="14" + width="67"> + Filter by: + </text> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="0" + width="62"> + Name + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|top" + height="20" + layout="topleft" + left_pad="0" + top_pad="-18" + max_length_bytes="10" + name="filter_by_name" + width="105" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="22" + top_pad="-15" + width="88"> + Description + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|top" + height="20" + layout="topleft" + left_pad="0" + top_pad="-17" + max_length_bytes="10" + name="filter_by_description" + width="145" /> + <combo_box + height="20" + layout="topleft" + follows="left|top" + name="filter_by_linkset_use" + left_pad="32" + top_pad="-20" + width="199"> + <combo_box.item + label="Filter by linkset use..." + name="filter_by_linkset_use_none" + value="0" /> + <combo_box.item + label="Walkable" + name="filter_by_linkset_use_walkable" + value="1" /> + <combo_box.item + label="Static obstacle" + name="filter_by_linkset_use_static_obstacle" + value="2" /> + <combo_box.item + label="Movable obstacle" + name="filter_by_linkset_use_dynamic_obstacle" + value="3" /> + <combo_box.item + label="Material volume" + name="filter_by_linkset_use_material_volume" + value="4" /> + <combo_box.item + label="Exclusion volume" + name="filter_by_linkset_use_exclusion_volume" + value="5" /> + <combo_box.item + label="Movable phantom" + name="filter_by_linkset_use_dynamic_phantom" + value="6" /> + </combo_box> + <button + follows="right|top" + height="21" + label="Apply" + layout="topleft" + name="apply_filters" + top_pad="-21" + left_pad="31" + width="73"/> + <button + follows="right|top" + height="21" + label="Clear" + layout="topleft" + name="clear_filters" + top_pad="-21" + left_pad="8" + width="73"/> + <scroll_list + column_padding="0" + draw_heading="true" + follows="all" + height="135" + layout="topleft" + left="18" + top_pad="15" + multi_select="true" + name="pathfinding_linksets" + width="910"> + <scroll_list.columns + label="Name (root prim)" + name="name" + dynamic_width="true" /> + <scroll_list.columns + label="Description (root prim)" + name="description" + width="192" /> + <scroll_list.columns + label="Land impact" + name="land_impact" + width="88" /> + <scroll_list.columns + label="Dist from you" + name="dist_from_you" + width="97" /> + <scroll_list.columns + label="Linkset use" + name="linkset_use" + width="210" /> + <scroll_list.columns + label="A %" + name="a_percent" + width="41" /> + <scroll_list.columns + label="B %" + name="b_percent" + width="41" /> + <scroll_list.columns + label="C %" + name="c_percent" + width="41" /> + <scroll_list.columns + label="D %" + name="d_percent" + width="41" /> + </scroll_list> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + name="linksets_status" + top_pad="17" + width="549"> + Linksets: + </text> + <button + follows="right|bottom" + height="21" + label="Refresh list" + layout="topleft" + name="refresh_linksets_list" + top_pad="-16" + left_pad="0" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select all" + layout="topleft" + name="select_all_linksets" + top_pad="-21" + left_pad="8" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select none" + layout="topleft" + name="select_none_linksets" + top_pad="-21" + left_pad="8" + width="115"/> + </panel> + <view_border + bevel_style="none" + follows="left|bottom|right" + height="0" + layout="topleft" + name="horiz_separator" + top_pad="0" + left="18" + width="912"/> + <panel + border="false" + bevel_style="none" + follows="left|right|bottom" + layout="topleft" + left="0" + height="67" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + left="18" + follows="left|bottom|right" + layout="topleft" + top_pad="8" + width="580"> + Actions on selected linksets (If a linkset is removed from the world, its attributes will be lost): + </text> + <check_box + height="19" + follows="left|bottom" + label="Show beacon" + layout="topleft" + name="show_beacon" + left_pad="0" + top_pad="-16" + width="90" /> + <button + follows="left|bottom" + height="21" + label="Take" + layout="topleft" + name="take_linksets" + top_pad="9" + left="18" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Take copy" + layout="topleft" + name="take_copy_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Return" + layout="topleft" + name="return_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Delete" + layout="topleft" + name="delete_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Teleport me to it" + layout="topleft" + name="teleport_me_to_linkset" + top_pad="-21" + left_pad="6" + width="160"/> + </panel> + <view_border + bevel_style="none" + follows="left|bottom|right" + height="0" + layout="topleft" + name="horiz_separator" + top_pad="0" + left="18" + width="912"/> + <panel + border="false" + bevel_style="none" + follows="left|right|bottom" + layout="topleft" + left="0" + height="75" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + left="18" + top_pad="8" + width="912"> + Edit attributes of selected linksets and press the button to apply changes + </text> + <combo_box + height="20" + layout="topleft" + follows="left|top" + name="edit_linkset_use" + left="18" + top_pad="17" + width="199"> + </combo_box> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="walkability_coefficients_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="36" + top_pad="-17" + width="110"> + Walkability: + </text> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_a_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="0" + width="18"> + A + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_a_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_b_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + B + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_b_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_c_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + C + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_c_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_d_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + D + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_d_value" + width="45" /> + <button + follows="right|bottom" + height="21" + label="Apply changes" + layout="topleft" + name="apply_edit_values" + top_pad="-21" + left_pad="40" + width="140"/> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 1d11abcf73..fb1709f28d 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -681,6 +681,7 @@ <menu_item_check.on_enable function="Build.Enabled" /> </menu_item_check> + <menu create_jump_keys="true" label="Select Build Tool" @@ -937,7 +938,45 @@ </menu_item_call> </menu> - <menu_item_separator/> + <menu + create_jump_keys="true" + label="Pathfinding" + name="Pathfinding" + tear_off="false"> + <menu_item_call + label="Basic setup..." + name="pathfinding_basic_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_basic" /> + </menu_item_call> + <menu_item_call + label="Edit / test..." + name="pathfinding_console_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_console" /> + </menu_item_call> + <menu_item_call + label="Linksets..." + name="pathfinding_linksets_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_linksets" /> + <menu_item_call.on_enable + function="Tools.EnableLinksets" /> + </menu_item_call> + <menu_item_call + label="Characters..." + name="pathfinding_characters_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_characters" /> + </menu_item_call> + </menu> + + + <menu_item_separator/> <menu create_jump_keys="true" @@ -1123,6 +1162,14 @@ <menu_item_call.on_visible function="File.VisibleUploadModel"/> </menu_item_call> + <menu_item_call + label="BuildNavMeshTest" + layout="topleft" + name="BuildNavMesh"> + <menu_item_call.on_click + function="File.UploadNavMesh" + parameter="" /> + </menu_item_call> <menu_item_call label="Bulk (L$[COST] per file)..." layout="topleft" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 59dd17ea9d..5faafecef7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7663,7 +7663,20 @@ The site at '<nolink>[HOST_NAME]</nolink>' in realm ' notext="Cancel" ignoretext="Confirm before hiding UI"/> </notification> - + + <notification + icon="alertmodal.tga" + name="PathfindingLinksets_SetLinksetUseMismatchOnRestricted" + type="alertmodal"> + Some selected linksets cannot be set to be '[REQUESTED_TYPE]' because of permission restrictions on the linkset. These linksets will be set to be '[RESTRICTED_TYPE]' instead. + <tag>confirm</tag> + <usetemplate + ignoretext="Do you wish to proceed?" + name="okcancelignore" + notext="Cancel" + yestext="OK"/> + </notification> + <global name="UnsupportedGLRequirements"> You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 9752652679..749f0e9ad9 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3698,7 +3698,11 @@ Try enclosing path to the editor with double quotes. <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> <string name="Command_Outbox_Label">Merchant outbox</string> + <string name="Command_Pathfinding_Label">Pathfinding</string> <string name="Command_People_Label">People</string> + <string name="Command_PF_Basic_Label">Pathfinding Basic</string> + <string name="Command_PF_Characters_Label">Pathfinding Characters</string> + <string name="Command_PF_Linksets_Label">Pathfinding Linksets</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> <string name="Command_Preferences_Label">Preferences</string> @@ -3724,7 +3728,11 @@ Try enclosing path to the editor with double quotes. <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> <string name="Command_Outbox_Tooltip">Transfer items to your marketplace for sale</string> + <string name="Command_Pathfinding_Tooltip">Information about pathfinding</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> + <string name="Command_PF_Basic_Tooltip">Manipulation of pathfinding frozen/unfrozen state</string> + <string name="Command_PF_Characters_Tooltip">Manipulation of pathfinding characters</string> + <string name="Command_PF_Linksets_Tooltip">Manipulation of pathfinding linksets</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> <string name="Command_Preferences_Tooltip">Preferences</string> |