diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c2458b098..6a6f7c222 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -127,7 +127,7 @@ if (LINUX) -pthread ) - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_FORTIFY_SOURCE=2 ") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 ") # Don't catch SIGCHLD in our base application class for the viewer # some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index df10f984a..98906d3d4 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -484,7 +484,9 @@ LLJoint* LLKeyframeMotion::getJoint(U32 index) index = (S32)mJointStates.size() - 1; // LLJoint* joint = mJointStates[index]->getJoint(); - llassert_always (joint); + if(!joint) { + LL_WARNS_ONCE("Animation") << "Missing joint index:"<< index << " ID:" << mID << " Name:" << mName << LL_ENDL; + } return joint; } diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 40ae4a0a8..c1f925428 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -554,7 +554,7 @@ bool LLApp::isQuitting() // static bool LLApp::isExiting() { - return isQuitting() || isError(); + return isQuitting() || isError() || isStopped(); } void LLApp::disableCrashlogger() diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index db72aa19b..89c831d29 100644 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -40,7 +40,9 @@ namespace LLInitParam { const U8* my_addr = reinterpret_cast(this); const U8* block_addr = reinterpret_cast(enclosing_block); - mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr); + U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); + mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; + mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; } // @@ -112,6 +114,35 @@ namespace LLInitParam std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); } + void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) + { + // create a copy of the param descriptor in mAllParams + // so other data structures can store a pointer to it + mAllParams.push_back(in_param); + ParamDescriptorPtr param(mAllParams.back()); + + std::string name(char_name); + if ((size_t)param->mParamHandle > mMaxParamOffset) + { + llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; + } + + if (name.empty()) + { + mUnnamedParams.push_back(param); + } + else + { + // don't use insert, since we want to overwrite existing entries + mNamedParams[name] = param; + } + + if (param->mValidationFunc) + { + mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); + } + } + BlockDescriptor::BlockDescriptor() : mMaxParamOffset(0), mInitializationState(UNINITIALIZED), @@ -150,7 +181,8 @@ namespace LLInitParam bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) { - if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true)) + Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); + if (!deserializeBlock(p, range, true)) { if (!silent) { @@ -196,12 +228,7 @@ namespace LLInitParam if (serialize_func) { const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - // each param descriptor remembers its serial number - // so we can inspect the same param under different names - // and see that it has the same number - name_stack.push_back(std::make_pair("", true)); serialize_func(*param, parser, name_stack, diff_param); - name_stack.pop_back(); } } @@ -295,7 +322,7 @@ namespace LLInitParam return true; } - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored) + bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) { BlockDescriptor& block_data = mostDerivedBlockDescriptor(); bool names_left = name_stack_range.first != name_stack_range.second; @@ -308,15 +335,12 @@ namespace LLInitParam { const std::string& top_name = name_stack_range.first->first; - ParamDescriptor::deserialize_func_t deserialize_func = NULL; - Param* paramp = NULL; - BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); if (found_it != block_data.mNamedParams.end()) { // find pointer to member parameter from offset table - paramp = getParamFromHandle(found_it->second->mParamHandle); - deserialize_func = found_it->second->mDeserializeFunc; + Param* paramp = getParamFromHandle(found_it->second->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); ++new_name_stack.first; @@ -358,36 +382,6 @@ namespace LLInitParam return false; } - //static - void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name) - { - // create a copy of the param descriptor in mAllParams - // so other data structures can store a pointer to it - block_data.mAllParams.push_back(in_param); - ParamDescriptorPtr param(block_data.mAllParams.back()); - - std::string name(char_name); - if ((size_t)param->mParamHandle > block_data.mMaxParamOffset) - { - llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; - } - - if (name.empty()) - { - block_data.mUnnamedParams.push_back(param); - } - else - { - // don't use insert, since we want to overwrite existing entries - block_data.mNamedParams[name] = param; - } - - if (param->mValidationFunc) - { - block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); - } - } - void BaseBlock::addSynonym(Param& param, const std::string& synonym) { BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -460,7 +454,7 @@ namespace LLInitParam if (merge_func) { Param* paramp = getParamFromHandle((*it)->mParamHandle); - llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle); + llassert(paramp->getEnclosingBlockOffset() == (*it)->mParamHandle); some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); } } diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index b79417f96..7870fd750 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -38,6 +38,71 @@ #include "llerror.h" #include "llstl.h" +namespace LLTypeTags +{ + template + struct TypeTagBase + { + typedef void is_tag_t; + typedef INNER_TYPE inner_t; + static const int SORT_ORDER=_SORT_ORDER; + }; + + template + struct GreaterThan + { + static const bool value = VAL1 > VAL2; + }; + + template::value > + struct Swap + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct Swap + { + typedef typename REST::template Cons::value_t>::value_t value_t; + }; + + template + struct IsSortable + { + static const bool value = false; + }; + + template + struct IsSortable + { + static const bool value = true; + }; + + template::value> + struct InsertInto + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct InsertInto + { + typedef typename Swap::value_t value_t; + }; + + template::value> + struct Sorted + { + typedef T value_t; + }; + + template + struct Sorted + { + typedef typename InsertInto::value_t>::value_t value_t; + }; +} + namespace LLInitParam { // used to indicate no matching value to a given name when parsing @@ -45,6 +110,8 @@ namespace LLInitParam template const T& defaultValue() { static T value; return value; } + // wraps comparison operator between any 2 values of the same type + // specialize to handle cases where equality isn't defined well, or at all template ::value > struct ParamCompare { @@ -79,24 +146,123 @@ namespace LLInitParam // helper functions and classes typedef ptrdiff_t param_handle_t; + struct IS_A_BLOCK {}; + struct NOT_BLOCK {}; + + // these templates allow us to distinguish between template parameters + // that derive from BaseBlock and those that don't + template + struct IsBlock + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock + { + typedef IS_A_BLOCK value_t; + }; + + // ParamValue class directly manages the wrapped value + // by holding on to a copy (scalar params) + // or deriving from it (blocks) + // has specializations for custom value behavior + // and "tag" values like Lazy and Atomic + template::value_t> + class ParamValue + { + typedef ParamValue self_t; + + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue(): mValue() {} + ParamValue(const default_value_t& other) : mValue(other) {} + + void setValue(const value_t& val) + { + mValue = val; + } + + const value_t& getValue() const + { + return mValue; + } + + T& getValue() + { + return mValue; + } + + protected: + T mValue; + }; + + template + class ParamValue + : public T + { + typedef ParamValue self_t; + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue() + : T(), + mValidated(false) + {} + + ParamValue(const default_value_t& other) + : T(other), + mValidated(false) + {} + + void setValue(const value_t& val) + { + *this = val; + } + + const value_t& getValue() const + { + return *this; + } + + T& getValue() + { + return *this; + } + + protected: + mutable bool mValidated; // lazy validation flag + }; + // empty default implementation of key cache // leverages empty base class optimization template class TypeValues + : public ParamValue::value_t> { private: struct Inaccessable{}; public: typedef std::map value_name_map_t; typedef Inaccessable name_t; + typedef TypeValues type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValues(const typename param_value_t::value_t& val) + : param_value_t(val) + {} void setValueName(const std::string& key) {} std::string getValueName() const { return ""; } - std::string calcValueName(const T& value) const { return ""; } + std::string calcValueName(const value_t& value) const { return ""; } void clearValueName() const {} - static bool getValueFromName(const std::string& name, T& value) + static bool getValueFromName(const std::string& name, value_t& value) { return false; } @@ -111,15 +277,39 @@ namespace LLInitParam return NULL; } + void assignNamedValue(const Inaccessable& name) + {} + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + static value_name_map_t* getValueNames() {return NULL;} }; - template > + // helper class to implement name value lookups + // and caching of last used name + template , bool IS_SPECIALIZED = true > class TypeValuesHelper + : public ParamValue::value_t> { + typedef TypeValuesHelper self_t; public: typedef typename std::map value_name_map_t; typedef std::string name_t; + typedef self_t type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValuesHelper(const typename param_value_t::value_t& val) + : param_value_t(val) + {} //TODO: cache key by index to save on param block size void setValueName(const std::string& value_name) @@ -132,7 +322,7 @@ namespace LLInitParam return mValueName; } - std::string calcValueName(const T& value) const + std::string calcValueName(const value_t& value) const { value_name_map_t* map = getValueNames(); for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end(); @@ -153,7 +343,7 @@ namespace LLInitParam mValueName.clear(); } - static bool getValueFromName(const std::string& name, T& value) + static bool getValueFromName(const std::string& name, value_t& value) { value_name_map_t* map = getValueNames(); typename value_name_map_t::iterator found_it = map->find(name); @@ -195,24 +385,94 @@ namespace LLInitParam return &sValues; } - static void declare(const std::string& name, const T& value) + static void declare(const std::string& name, const value_t& value) { (*getValueNames())[name] = value; } + void operator ()(const std::string& name) + { + *this = name; + } + + void assignNamedValue(const std::string& name) + { + if (getValueFromName(name, param_value_t::getValue())) + { + setValueName(name); + } + } + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + protected: - static void getName(const std::string& name, const T& value) + static void getName(const std::string& name, const value_t& value) {} mutable std::string mValueName; }; + // string types can support custom named values, but need + // to disambiguate in code between a string that is a named value + // and a string that is a name + template + class TypeValuesHelper + : public TypeValuesHelper + { + public: + typedef TypeValuesHelper self_t; + typedef TypeValuesHelper base_t; + typedef std::string value_t; + typedef std::string name_t; + typedef self_t type_value_t; + + TypeValuesHelper(const std::string& val) + : base_t(val) + {} + + void operator ()(const std::string& name) + { + *this = name; + } + + self_t& operator =(const std::string& name) + { + if (base_t::getValueFromName(name, ParamValue::getValue())) + { + base_t::setValueName(name); + } + else + { + ParamValue::setValue(name); + } + return *this; + } + + operator const value_t&() const + { + return ParamValue::getValue(); + } + + const value_t& operator()() const + { + return ParamValue::getValue(); + } + + }; + + // parser base class with mechanisms for registering readers/writers/inspectors of different types class LL_COMMON_API Parser { LOG_CLASS(Parser); - public: - typedef std::vector > name_stack_t; typedef std::pair name_stack_range_t; typedef std::vector possible_values_t; @@ -225,62 +485,6 @@ namespace LLInitParam typedef std::map parser_write_func_map_t; typedef std::map parser_inspect_func_map_t; - private: - template::value> - struct ReaderWriter - { - static bool read(T& param, Parser* parser) - { - parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(T)); - if (found_it != parser->mParserReadFuncs->end()) - { - return found_it->second(*parser, (void*)¶m); - } - return false; - } - - static bool write(const T& param, Parser* parser, name_stack_t& name_stack) - { - parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(T)); - if (found_it != parser->mParserWriteFuncs->end()) - { - return found_it->second(*parser, (const void*)¶m, name_stack); - } - return false; - } - }; - - // read enums as ints - template - struct ReaderWriter - { - static bool read(T& param, Parser* parser) - { - // read all enums as ints - parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(S32)); - if (found_it != parser->mParserReadFuncs->end()) - { - S32 value; - if (found_it->second(*parser, (void*)&value)) - { - param = (T)value; - return true; - } - } - return false; - } - - static bool write(const T& param, Parser* parser, name_stack_t& name_stack) - { - parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(S32)); - if (found_it != parser->mParserWriteFuncs->end()) - { - return found_it->second(*parser, (const void*)¶m, name_stack); - } - return false; - } - }; - public: Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) @@ -292,15 +496,47 @@ namespace LLInitParam virtual ~Parser(); - template bool readValue(T& param) - { - return ReaderWriter::read(param, this); - } + template bool readValue(T& param, typename boost::disable_if >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + + return false; + } + + template bool readValue(T& param, typename boost::enable_if >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + else + { + found_it = mParserReadFuncs->find(&typeid(S32)); + if (found_it != mParserReadFuncs->end()) + { + S32 int_value; + bool parsed = found_it->second(*this, (void*)&int_value); + param = (T)int_value; + return parsed; + } + } + return false; + } template bool writeValue(const T& param, name_stack_t& name_stack) - { - return ReaderWriter::write(param, this, name_stack); - } + { + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + if (found_it != mParserWriteFuncs->end()) + { + return found_it->second(*this, (const void*)¶m, name_stack); + } + return false; + } // dispatch inspection to registered inspection functions, for each parameter in a param block template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) @@ -352,7 +588,7 @@ namespace LLInitParam }; typedef bool(*merge_func_t)(Param&, const Param&, bool); - typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool); + typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param); typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); typedef bool(*validation_func_t)(const Param*); @@ -397,6 +633,7 @@ namespace LLInitParam } EInitializationState; void aggregateBlockData(BlockDescriptor& src_block_data); + void addParam(ParamDescriptorPtr param, const char* name); typedef boost::unordered_map param_map_t; typedef std::vector param_list_t; @@ -412,48 +649,58 @@ namespace LLInitParam class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed }; - class LL_COMMON_API BaseBlock - { - public: //TODO: implement in terms of owned_ptr template - class Lazy + class LazyValue { public: - Lazy() + LazyValue() : mPtr(NULL) {} - ~Lazy() + ~LazyValue() { delete mPtr; } - Lazy(const Lazy& other) + LazyValue(const T& value) { - if (other.mPtr) - { - mPtr = new T(*other.mPtr); - } - else - { - mPtr = NULL; - } - } + mPtr = new T(value); + } - Lazy& operator = (const Lazy& other) + LazyValue(const LazyValue& other) + : mPtr(NULL) + { + *this = other; + } + + LazyValue& operator = (const LazyValue& other) + { + if (!other.mPtr) { - if (other.mPtr) + delete mPtr; + mPtr = NULL; + } + else + { + if (!mPtr) { mPtr = new T(*other.mPtr); } else { - mPtr = NULL; + *mPtr = *(other.mPtr); + } } return *this; } + bool operator==(const LazyValue& other) const + { + if (empty() || other.empty()) return false; + return *mPtr == *other.mPtr; + } + bool empty() const { return mPtr == NULL; @@ -461,18 +708,29 @@ namespace LLInitParam void set(const T& other) { - delete mPtr; + if (!mPtr) + { mPtr = new T(other); } + else + { + *mPtr = other; + } + } const T& get() const { - return ensureInstance(); + return *ensureInstance(); } T& get() { - return ensureInstance(); + return *ensureInstance(); + } + + operator const T&() const + { + return get(); } private: @@ -487,13 +745,50 @@ namespace LLInitParam } private: - // if you get a compilation error with this, that means you are using a forward declared struct for T - // unfortunately, the type traits we rely on don't work with forward declared typed - //static const int dummy = sizeof(T); mutable T* mPtr; }; + // root class of all parameter blocks + + class LL_COMMON_API BaseBlock + { + public: + // lift block tags into baseblock namespace so derived classes do not need to qualify them + typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; + typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; + + template + struct Sequential : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Sequential > value_t; }; + template struct Cons > { typedef Sequential value_t; }; + }; + + template + struct Atomic : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Atomic > value_t; }; + template struct Cons > { typedef Atomic value_t; }; + }; + + template::value_t > + struct Lazy : public LLTypeTags::TypeTagBase + { + template struct Cons + { + typedef Lazy, BLOCK_T> value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + }; + // "Multiple" constraint types, put here in root class to avoid ambiguity during use struct AnyAmount { @@ -559,12 +854,12 @@ namespace LLInitParam // Blocks can override this to do custom tracking of changes virtual void paramChanged(const Param& changed_param, bool user_provided) {} - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } // take all provided params from other and apply to self bool overwriteFrom(const BaseBlock& other) @@ -578,10 +873,17 @@ namespace LLInitParam return false; } - static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name); - ParamDescriptorPtr findParamDescriptor(const Param& param); + // take all provided params from other and apply to self + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + protected: void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); @@ -590,25 +892,11 @@ namespace LLInitParam { return mergeBlock(block_data, source, overwrite); } - // take all provided params from other and apply to self - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); - - static BlockDescriptor& selfBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } private: const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; }; - template - struct ParamCompare, false > - { - static bool equals(const BaseBlock::Lazy& a, const BaseBlock::Lazy& b) { return !a.empty() || !b.empty(); } - }; - class LL_COMMON_API Param { public: @@ -632,261 +920,73 @@ namespace LLInitParam // store pointer to enclosing block as offset to reduce space and allow for quick copying BaseBlock& enclosingBlock() const - { + { const U8* my_addr = reinterpret_cast(this); // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class return *const_cast (reinterpret_cast - (my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset)); + (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); + } + + U32 getEnclosingBlockOffset() const + { + return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; } private: friend class BaseBlock; - U32 mEnclosingBlockOffset:31; - U32 mIsProvided:1; + //24 bits for member offset field and 1 bit for provided flag + U16 mEnclosingBlockOffsetLow; + U8 mEnclosingBlockOffsetHigh:7; + U8 mIsProvided:1; }; - // these templates allow us to distinguish between template parameters - // that derive from BaseBlock and those that don't - template - struct IsBlock - { - static const bool value = false; - struct EmptyBase {}; - typedef EmptyBase base_class_t; - }; - - template - struct IsBlock - { - static const bool value = true; - typedef BaseBlock base_class_t; - }; - - template - struct IsBlock, typename T::baseblock_base_class_t > - { - static const bool value = true; - typedef BaseBlock base_class_t; - }; - - template::value> - class ParamValue : public NAME_VALUE_LOOKUP - { - public: - typedef const T& value_assignment_t; - typedef T value_t; - typedef ParamValue self_t; - - ParamValue(): mValue() {} - ParamValue(value_assignment_t other) : mValue(other) {} - - void setValue(value_assignment_t val) - { - mValue = val; - } - - value_assignment_t getValue() const - { - return mValue; - } - - T& getValue() - { - return mValue; - } - - operator value_assignment_t() const - { - return mValue; - } - - value_assignment_t operator()() const - { - return mValue; - } - - void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) - { - *this = name; - } - - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) - { - if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue)) - { - setValueName(name); - } - - return *this; - } - - protected: - T mValue; - }; - - template - class ParamValue - : public T, - public NAME_VALUE_LOOKUP - { - public: - typedef const T& value_assignment_t; - typedef T value_t; - typedef ParamValue self_t; - - ParamValue() - : T(), - mValidated(false) - {} - - ParamValue(value_assignment_t other) - : T(other), - mValidated(false) - {} - - void setValue(value_assignment_t val) - { - *this = val; - } - - value_assignment_t getValue() const - { - return *this; - } - - T& getValue() - { - return *this; - } - - operator value_assignment_t() const - { - return *this; - } - - value_assignment_t operator()() const - { - return *this; - } - - void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) - { - *this = name; - } - - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) - { - if (NAME_VALUE_LOOKUP::getValueFromName(name, *this)) - { - setValueName(name); - } - - return *this; - } - - protected: - mutable bool mValidated; // lazy validation flag - }; - - template - class ParamValue - : public NAME_VALUE_LOOKUP - { - public: - typedef const std::string& value_assignment_t; - typedef std::string value_t; - typedef ParamValue self_t; - - ParamValue(): mValue() {} - ParamValue(value_assignment_t other) : mValue(other) {} - - void setValue(value_assignment_t val) - { - if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue)) - { - NAME_VALUE_LOOKUP::setValueName(val); - } - else - { - mValue = val; - } - } - - value_assignment_t getValue() const - { - return mValue; - } - - std::string& getValue() - { - return mValue; - } - - operator value_assignment_t() const - { - return mValue; - } - - value_assignment_t operator()() const - { - return mValue; - } - - protected: - std::string mValue; - }; - - template > struct ParamIterator { - typedef typename std::vector >::const_iterator const_iterator; - typedef typename std::vector >::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::iterator iterator; }; - // specialize for custom parsing/decomposition of specific classes - // e.g. TypedParam has left, top, right, bottom, etc... + // wrapper for parameter with a known type + // specialized to handle 4 cases: + // simple "scalar" value + // parameter that is itself a block + // multiple scalar values, stored in a vector + // multiple blocks, stored in a vector template, bool HAS_MULTIPLE_VALUES = false, - bool VALUE_IS_BLOCK = IsBlock >::value> + typename VALUE_IS_BLOCK = typename IsBlock::value_t> >::value_t> class TypedParam : public Param, - public ParamValue + public NAME_VALUE_LOOKUP::type_value_t { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename param_value_t::value_assignment_t value_assignment_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; + typedef typename param_value_t::value_t value_t; - using param_value_t::operator(); + using named_value_t::operator(); - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) { if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } - - this->setValue(value); } bool isProvided() const { return Param::anyProvided(); } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast(param); // no further names in stack, attempt to parse value now @@ -895,9 +995,9 @@ namespace LLInitParam std::string name; // try to parse a known named value - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + && named_value_t::getValueFromName(name, typed_param.getValue())) { typed_param.setValueName(name); typed_param.setProvided(); @@ -941,7 +1041,9 @@ namespace LLInitParam if (!parser.writeValue(typed_param.getValue(), name_stack)) { std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); - if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key)) + if (calculated_key.size() + && (!diff_param + || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key))) { parser.writeValue(calculated_key, name_stack); } @@ -954,22 +1056,23 @@ namespace LLInitParam // tell parser about our actual type parser.inspectValue(name_stack, min_count, max_count, NULL); // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (name_value_lookup_t::getPossibleValues()) + if (named_value_t::getPossibleValues()) { - parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); } } - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const value_t& val, bool flag_as_provided = true) { - param_value_t::clearValueName(); + named_value_t::clearValueName(); this->setValue(val); setProvided(flag_as_provided); } - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + self_t& operator =(const typename named_value_t::name_t& name) { - return static_cast(param_value_t::operator =(name)); + named_value_t::assignNamedValue(name); + return *this; } protected: @@ -994,41 +1097,47 @@ namespace LLInitParam } return false; } + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; // parameter that is a block template - class TypedParam + class TypedParam : public Param, - public ParamValue + public NAME_VALUE_LOOKUP::type_value_t { + protected: + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: - typedef ParamValue param_value_t; - typedef typename param_value_t::value_assignment_t value_assignment_t; - typedef TypedParam self_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; + using named_value_t::operator(); + typedef typename param_value_t::value_t value_t; - using param_value_t::operator(); - - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr), - param_value_t(value) + named_value_t(value) { if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast(param); @@ -1036,9 +1145,9 @@ namespace LLInitParam { // try to parse a known named value std::string name; - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + && named_value_t::getValueFromName(name, typed_param.getValue())) { typed_param.setValueName(name); typed_param.setProvided(); @@ -1070,9 +1179,9 @@ namespace LLInitParam std::string key = typed_param.getValueName(); if (!key.empty()) { - if (!parser.writeValue(key, name_stack)) + if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) { - return; + parser.writeValue(key, name_stack); } } else @@ -1083,8 +1192,16 @@ namespace LLInitParam static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - // I am a param that is also a block, so just recurse into my contents const self_t& typed_param = static_cast(param); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + typed_param.inspectBlock(parser, name_stack, min_count, max_count); } @@ -1102,32 +1219,34 @@ namespace LLInitParam } // assign block contents to this param-that-is-a-block - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const value_t& val, bool flag_as_provided = true) { this->setValue(val); - param_value_t::clearValueName(); + named_value_t::clearValueName(); // force revalidation of block // next call to isProvided() will update provision status based on validity param_value_t::mValidated = false; setProvided(flag_as_provided); } - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + self_t& operator =(const typename named_value_t::name_t& name) { - return static_cast(param_value_t::operator =(name)); + named_value_t::assignNamedValue(name); + return *this; } // propagate changed status up to enclosing block /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) { param_value_t::paramChanged(changed_param, user_provided); + if (user_provided) { // a child param has been explicitly changed // so *some* aspect of this block is now provided param_value_t::mValidated = false; setProvided(); - param_value_t::clearValueName(); + named_value_t::clearValueName(); } else { @@ -1151,7 +1270,7 @@ namespace LLInitParam if (src_typed_param.anyProvided()) { - if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::selfBlockDescriptor(), src_typed_param, overwrite)) + if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) { dst_typed_param.clearValueName(); dst_typed_param.setProvided(true); @@ -1160,56 +1279,72 @@ namespace LLInitParam } return false; } + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; - // container of non-block parameters + // list of non-block parameters template - class TypedParam + class TypedParam : public Param { - public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename std::vector container_t; - typedef const container_t& value_assignment_t; + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef container_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: typedef typename param_value_t::value_t value_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr) { std::copy(value.begin(), value.end(), std::back_inserter(mValues)); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); + } } bool isProvided() const { return Param::anyProvided(); } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); self_t& typed_param = static_cast(param); value_t value; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + ++new_name_stack_range.first; + } + // no further names in stack, attempt to parse value now if (name_stack_range.first == name_stack_range.second) { std::string name; // try to parse a known named value - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, value)) + && named_value_t::getValueFromName(name, value)) { typed_param.add(value); typed_param.mValues.back().setValueName(name); @@ -1227,14 +1362,14 @@ namespace LLInitParam static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) { const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided() || name_stack.empty()) return; + if (!typed_param.isProvided()) return; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; ++it) { std::string key = it->getValueName(); - name_stack.back().second = true; + name_stack.push_back(std::make_pair(std::string(), true)); if(key.empty()) // not parsed via name values, write out value directly @@ -1256,19 +1391,21 @@ namespace LLInitParam break; } } + + name_stack.pop_back(); } } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { parser.inspectValue(name_stack, min_count, max_count, NULL); - if (name_value_lookup_t::getPossibleValues()) + if (named_value_t::getPossibleValues()) { - parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); } } - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const container_t& val, bool flag_as_provided = true) { mValues = val; setProvided(flag_as_provided); @@ -1276,26 +1413,24 @@ namespace LLInitParam param_value_t& add() { - mValues.push_back(param_value_t(value_t())); + mValues.push_back(value_t()); Param::setProvided(); return mValues.back(); } self_t& add(const value_t& item) { - param_value_t param_value; - param_value.setValue(item); - mValues.push_back(param_value); + mValues.push_back(item); setProvided(); return *this; } - self_t& add(const typename name_value_lookup_t::name_t& name) + self_t& add(const typename named_value_t::name_t& name) { value_t value; // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value)) + if (named_value_t::getValueFromName(name, value)) { add(value); mValues.back().setValueName(name); @@ -1305,9 +1440,9 @@ namespace LLInitParam } // implicit conversion - operator value_assignment_t() const { return mValues; } + operator const container_t&() const { return mValues; } // explicit conversion - value_assignment_t operator()() const { return mValues; } + const container_t& operator()() const { return mValues; } typedef typename container_t::iterator iterator; typedef typename container_t::const_iterator const_iterator; @@ -1348,62 +1483,79 @@ namespace LLInitParam } container_t mValues; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; - // container of block parameters + // list of block parameters template - class TypedParam + class TypedParam : public Param { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef container_t default_value_t; + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename std::vector container_t; - typedef const container_t& value_assignment_t; typedef typename param_value_t::value_t value_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr) { std::copy(value.begin(), value.end(), back_inserter(mValues)); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } } bool isProvided() const { return Param::anyProvided(); } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); self_t& typed_param = static_cast(param); bool new_value = false; + bool new_array_value = false; - if (new_name || typed_param.mValues.empty()) + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + new_array_value = new_name_stack_range.first->second; + ++new_name_stack_range.first; + } + + if (new_name || new_array_value || typed_param.mValues.empty()) { new_value = true; typed_param.mValues.push_back(value_t()); } - param_value_t& value = typed_param.mValues.back(); if (name_stack_range.first == name_stack_range.second) { // try to parse a known named value std::string name; - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, value.getValue())) + && named_value_t::getValueFromName(name, value.getValue())) { typed_param.mValues.back().setValueName(name); typed_param.setProvided(); @@ -1412,9 +1564,13 @@ namespace LLInitParam } // attempt to parse block... - if(value.deserializeBlock(parser, name_stack_range, new_name)) + if(value.deserializeBlock(parser, new_name_stack_range, new_name)) { typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } return true; } @@ -1430,13 +1586,13 @@ namespace LLInitParam static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) { const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided() || name_stack.empty()) return; + if (!typed_param.isProvided()) return; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; ++it) { - name_stack.back().second = true; + name_stack.push_back(std::make_pair(std::string(), true)); std::string key = it->getValueName(); if (!key.empty()) @@ -1449,16 +1605,27 @@ namespace LLInitParam { it->serializeBlock(parser, name_stack, NULL); } + + name_stack.pop_back(); } } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - // I am a vector of blocks, so describe my contents recursively - param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count); + const param_value_t& value_param = param_value_t(value_t()); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); } - void set(value_assignment_t val, bool flag_as_provided = true) + value_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + void set(const container_t& val, bool flag_as_provided = true) { mValues = val; setProvided(flag_as_provided); @@ -1478,12 +1645,12 @@ namespace LLInitParam return *this; } - self_t& add(const typename name_value_lookup_t::name_t& name) + self_t& add(const typename named_value_t::name_t& name) { value_t value; // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value)) + if (named_value_t::getValueFromName(name, value)) { add(value); mValues.back().setValueName(name); @@ -1492,12 +1659,10 @@ namespace LLInitParam } // implicit conversion - operator value_assignment_t() const { return mValues; } + operator const container_t&() const { return mValues; } // explicit conversion - value_assignment_t operator()() const { return mValues; } + const container_t& operator()() const { return mValues; } - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; iterator begin() { return mValues.begin(); } iterator end() { return mValues.end(); } const_iterator begin() const { return mValues.begin(); } @@ -1544,6 +1709,20 @@ namespace LLInitParam } container_t mValues; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; template @@ -1558,13 +1737,13 @@ namespace LLInitParam // take all provided params from other and apply to self bool overwriteFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self bool fillFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); } bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) @@ -1582,7 +1761,7 @@ namespace LLInitParam bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) { mCurChoice = other.mCurChoice; - return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite); + return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); } // clear out old choice when param has changed @@ -1603,38 +1782,38 @@ namespace LLInitParam base_block_t::paramChanged(changed_param, user_provided); } - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } protected: ChoiceBlock() : mCurChoice(0) { - BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); } // Alternatives are mutually exclusive wrt other Alternatives in the same block. // One alternative in a block will always have isChosen() == true. // At most one alternative in a block will have isProvided() == true. - template > + template ::type_value_t > class Alternative : public TypedParam { + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: friend class ChoiceBlock; - typedef Alternative self_t; - typedef TypedParam >::value> super_t; - typedef typename super_t::value_assignment_t value_assignment_t; - using super_t::operator =; - explicit Alternative(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1), + explicit Alternative(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), mOriginalValue(val) { // assign initial choice to first declared option - DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr); - if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) + DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); + if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) { if(blockp->mCurChoice == 0) { @@ -1648,31 +1827,31 @@ namespace LLInitParam static_cast(Param::enclosingBlock()).paramChanged(*this, true); } - void chooseAs(value_assignment_t val) + void chooseAs(const value_t& val) { super_t::set(val); } - void operator =(value_assignment_t val) + void operator =(const value_t& val) { super_t::set(val); } - void operator()(typename super_t::value_assignment_t val) + void operator()(const value_t& val) { super_t::set(val); } - operator value_assignment_t() const + operator const value_t&() const { return (*this)(); } - value_assignment_t operator()() const + const value_t& operator()() const { if (static_cast(Param::enclosingBlock()).getCurrentChoice() == this) { - return super_t::getValue(); + return super_t::getValue(); } return mOriginalValue; } @@ -1683,11 +1862,11 @@ namespace LLInitParam } private: - T mOriginalValue; + default_value_t mOriginalValue; }; - protected: - static BlockDescriptor& selfBlockDescriptor() + public: + static BlockDescriptor& getBlockDescriptor() { static BlockDescriptor sBlockDescriptor; return sBlockDescriptor; @@ -1707,6 +1886,8 @@ namespace LLInitParam : public BASE_BLOCK { typedef Block self_t; + + protected: typedef Block block_t; public: @@ -1715,80 +1896,82 @@ namespace LLInitParam // take all provided params from other and apply to self bool overwriteFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self bool fillFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); } - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } protected: Block() { //#pragma message("Parsing LLInitParam::Block") - BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); } // // Nested classes for declaring parameters // - template > + template ::type_value_t > class Optional : public TypedParam { - public: - typedef TypedParam >::value> super_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: using super_t::operator(); using super_t::operator =; - explicit Optional(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1) + explicit Optional(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) { //#pragma message("Parsing LLInitParam::Block::Optional") } - Optional& operator =(value_assignment_t val) + Optional& operator =(const value_t& val) { this->set(val); return *this; } - DERIVED_BLOCK& operator()(value_assignment_t val) + DERIVED_BLOCK& operator()(const value_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); } }; - template > + template ::type_value_t > class Mandatory : public TypedParam { - public: - typedef TypedParam >::value> super_t; + typedef TypedParam super_t; typedef Mandatory self_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: using super_t::operator(); using super_t::operator =; // mandatory parameters require a name to be parseable - explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1) + explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) {} - Mandatory& operator =(value_assignment_t val) + Mandatory& operator =(const value_t& val) { this->set(val); return *this; } - DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + DERIVED_BLOCK& operator()(const value_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); @@ -1802,28 +1985,29 @@ namespace LLInitParam }; - template > + template ::type_value_t > class Multiple : public TypedParam { - public: - typedef TypedParam >::value> super_t; + typedef TypedParam super_t; typedef Multiple self_t; typedef typename super_t::container_t container_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef typename super_t::value_t value_t; + + public: typedef typename super_t::iterator iterator; typedef typename super_t::const_iterator const_iterator; explicit Multiple(const char* name = "") - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) {} - Multiple& operator =(value_assignment_t val) + Multiple& operator =(const container_t& val) { set(val); return *this; } - DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + DERIVED_BLOCK& operator()(const container_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); @@ -1836,13 +2020,15 @@ namespace LLInitParam } }; - class Deprecated : public Param + // can appear in data files, but will ignored during parsing + // cannot read or write in code + class Ignored : public Param { public: - explicit Deprecated(const char* name) - : Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr) + explicit Ignored(const char* name) + : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) { - BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor(); + BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( @@ -1853,11 +2039,11 @@ namespace LLInitParam NULL, NULL, 0, S32_MAX)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + block_descriptor.addParam(param_descriptor, name); } } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { if (name_stack_range.first == name_stack_range.second) { @@ -1870,19 +2056,46 @@ namespace LLInitParam } }; - // different semantics for documentation purposes, but functionally identical - typedef Deprecated Ignored; + // can appear in data files, or be written to in code, but data will be ignored + // cannot be read in code + class Deprecated : public Ignored + { + public: + explicit Deprecated(const char* name) : Ignored(name) {} - protected: - static BlockDescriptor& selfBlockDescriptor() + // dummy writer interfaces + template + Deprecated& operator =(const T& val) + { + // do nothing + return *this; + } + + template + DERIVED_BLOCK& operator()(const T& val) + { + // do nothing + return static_cast(Param::enclosingBlock()); + } + + template + void set(const T& val, bool flag_as_provided = true) + { + // do nothing + } + }; + + public: + static BlockDescriptor& getBlockDescriptor() { static BlockDescriptor sBlockDescriptor; return sBlockDescriptor; } - template + protected: + template void changeDefault(TypedParam& param, - typename TypedParam::value_assignment_t value) + const typename TypedParam::value_t& value) { if (!param.isProvided()) { @@ -1892,204 +2105,420 @@ namespace LLInitParam }; - template - class BatchBlock - : public Block + template + struct IsBlock, BLOCK_T >, void> { - public: - typedef BatchBlock self_t; - typedef Block super_t; + typedef IS_A_BLOCK value_t; + }; - BatchBlock() + template + struct IsBlock, BLOCK_T >, void> + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + + template + struct InnerMostType + { + typedef T value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue(), + mValidated(false) {} - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + ParamValue(const default_value_t& value) + : mValue(value), + mValidated(false) + {} + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) { if (new_name) { - // reset block - *static_cast(this) = defaultBatchValue(); + resetToDefault(); } - return super_t::deserializeBlock(p, name_stack_range, new_name); + return mValue.deserializeBlock(p, name_stack_range, new_name); } - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const { - if (overwrite) + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + mValue.serializeBlock(p, name_stack, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + if ((overwrite && source_provided) // new values coming in on top or... + || (!overwrite && !dst_provided)) // values being pushed under with nothing already there { - *static_cast(this) = defaultBatchValue(); - // merge individual parameters into destination - return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite); + // clear away what is there and take the new stuff as a whole + resetToDefault(); + return mValue.mergeBlock(block_data, source.getValue(), overwrite); } - return false; + + + return mValue.mergeBlock(block_data, source.getValue(), overwrite); } - protected: - static const DERIVED_BLOCK& defaultBatchValue() + + bool validateBlock(bool emit_errors = true) const { - static DERIVED_BLOCK default_value; - return default_value; + return mValue.validateBlock(emit_errors); } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + + mutable bool mValidated; // lazy validation flag + + private: + void resetToDefault() + { + static T default_value; + mValue = default_value; + } + + T mValue; }; - // FIXME: this specialization is not currently used, as it only matches against the BatchBlock base class - // and not the derived class with the actual params - template - class ParamValue , - NAME_VALUE_LOOKUP, - true> - : public NAME_VALUE_LOOKUP, - protected BatchBlock + template + class ParamValue , IS_A_BLOCK> { + typedef ParamValue , IS_A_BLOCK> self_t; + public: - typedef BatchBlock block_t; - typedef const BatchBlock& value_assignment_t; - typedef block_t value_t; + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; ParamValue() - : block_t(), + : mValue(), + mValidated(false) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + ParamValue(const default_value_t& value) + : mValue(value), + mValidated(false) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (new_name) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + if (name_stack_range.first == name_stack_range.second + && mCurParam != getBlockDescriptor().mAllParams.end()) + { + // deserialize to mCurParam + ParamDescriptor& pd = *(*mCurParam); + ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; + Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); + + if (deserialize_func + && paramp + && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + ++mCurParam; + return true; + } + else + { + return false; + } + } + else + { + return mValue.deserializeBlock(p, name_stack_range, new_name); + } + } + + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + { + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + mValue.serializeBlock(p, name_stack, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + mutable bool mValidated; // lazy validation flag + + private: + + BlockDescriptor::all_params_list_t::iterator mCurParam; + T mValue; + }; + + template + class ParamValue , NOT_BLOCK> + : public T + { + typedef ParamValue , NOT_BLOCK> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : T(), mValidated(false) {} - ParamValue(value_assignment_t other) - : block_t(other), + ParamValue(const default_value_t& value) + : T(value.getValue()), mValidated(false) - { - } + {} - void setValue(value_assignment_t val) - { - *this = val; - } - - value_assignment_t getValue() const - { - return *this; - } - - BatchBlock& getValue() - { - return *this; - } - - operator value_assignment_t() const - { - return *this; - } - - value_assignment_t operator()() const - { - return *this; - } - - protected: mutable bool mValidated; // lazy validation flag }; - template - class ParamValue , - TypeValues, - IS_BLOCK> - : public IsBlock::base_class_t + template + class ParamValue , BLOCK_T> { + typedef ParamValue , BLOCK_T> self_t; + public: - typedef ParamValue , TypeValues, false> self_t; - typedef const T& value_assignment_t; - typedef T value_t; + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; ParamValue() : mValue(), mValidated(false) {} - ParamValue(value_assignment_t other) + ParamValue(const default_value_t& other) : mValue(other), mValidated(false) {} - void setValue(value_assignment_t val) + ParamValue(const T& value) + : mValue(value), + mValidated(false) + {} + + void setValue(const value_t& val) { mValue.set(val); } - value_assignment_t getValue() const + const value_t& getValue() const { - return mValue.get(); + return mValue.get().getValue(); } - T& getValue() + value_t& getValue() { - return mValue.get(); + return mValue.get().getValue(); } - operator value_assignment_t() const - { - return mValue.get(); - } - - value_assignment_t operator()() const - { - return mValue.get(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) { return mValue.get().deserializeBlock(p, name_stack_range, new_name); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const { if (mValue.empty()) return; - - mValue.get().serializeBlock(p, name_stack, diff_block); + + const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) + ? &(diff_block->mValue.get().getValue()) + : NULL; + mValue.get().serializeBlock(p, name_stack, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { - if (mValue.empty()) return false; - return mValue.get().inspectBlock(p, name_stack, min_count, max_count); } - protected: + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.empty() || mValue.get().validateBlock(emit_errors); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + mutable bool mValidated; // lazy validation flag private: - BaseBlock::Lazy mValue; + LazyValue mValue; + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; + + ParamValue() + : mValue(), + mValidated(false) + {} + + ParamValue(const default_value_t& other) + : mValue(other), + mValidated(false) + {} + + ParamValue(const T& value) + : mValue(value), + mValidated(false) + {} + + void setValue(const value_t& val) + { + mValue.set(val); + } + + const value_t& getValue() const + { + return mValue.get().getValue(); + } + + value_t& getValue() + { + return mValue.get().getValue(); + } + + mutable bool mValidated; // lazy validation flag + + private: + LazyValue mValue; }; template <> - class ParamValue , - false> - : public TypeValues, - public BaseBlock + class ParamValue + : public BaseBlock { public: - typedef ParamValue, false> self_t; - typedef const LLSD& value_assignment_t; + typedef LLSD value_t; + typedef LLSD default_value_t; ParamValue() : mValidated(false) {} - ParamValue(value_assignment_t other) + ParamValue(const default_value_t& other) : mValue(other), mValidated(false) {} - void setValue(value_assignment_t val) { mValue = val; } + void setValue(const value_t& val) { mValue = val; } - value_assignment_t getValue() const { return mValue; } + const value_t& getValue() const { return mValue; } LLSD& getValue() { return mValue; } - operator value_assignment_t() const { return mValue; } - value_assignment_t operator()() const { return mValue; } - - // block param interface - LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); + LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { @@ -2108,8 +2537,7 @@ namespace LLInitParam template class CustomParamValue - : public Block > >, - public TypeValues + : public Block > { public: typedef enum e_value_age @@ -2119,20 +2547,21 @@ namespace LLInitParam BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative } EValueAge; - typedef ParamValue > derived_t; + typedef ParamValue derived_t; typedef CustomParamValue self_t; typedef Block block_t; - typedef const T& value_assignment_t; + typedef T default_value_t; typedef T value_t; + typedef void baseblock_base_class_t; - CustomParamValue(const T& value = T()) + CustomParamValue(const default_value_t& value = T()) : mValue(value), mValueAge(VALUE_AUTHORITATIVE), mValidated(false) {} - bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name) + bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { derived_t& typed_param = static_cast(*this); // try to parse direct value T @@ -2143,8 +2572,6 @@ namespace LLInitParam typed_param.mValueAge = VALUE_AUTHORITATIVE; typed_param.updateBlockFromValue(false); - typed_param.clearValueName(); - return true; } } @@ -2158,18 +2585,8 @@ namespace LLInitParam const derived_t& typed_param = static_cast(*this); const derived_t* diff_param = static_cast(diff_block); - std::string key = typed_param.getValueName(); - - // first try to write out name of name/value pair - if (!key.empty()) - { - if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) - { - parser.writeValue(key, name_stack); - } - } // then try to serialize value directly - else if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) + if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) { if (!parser.writeValue(typed_param.getValue(), name_stack)) @@ -2199,19 +2616,6 @@ namespace LLInitParam } } - bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - // first, inspect with actual type... - parser.inspectValue(name_stack, min_count, max_count, NULL); - if (TypeValues::getPossibleValues()) - { - //...then inspect with possible string values... - parser.inspectValue(name_stack, min_count, max_count, TypeValues::getPossibleValues()); - } - // then recursively inspect contents... - return block_t::inspectBlock(parser, name_stack, min_count, max_count); - } - bool validateBlock(bool emit_errors = true) const { if (mValueAge == VALUE_NEEDS_UPDATE) @@ -2219,7 +2623,6 @@ namespace LLInitParam if (block_t::validateBlock(emit_errors)) { // clear stale keyword associated with old value - TypeValues::clearValueName(); mValueAge = BLOCK_AUTHORITATIVE; static_cast(const_cast(this))->updateValueFromBlock(); return true; @@ -2249,17 +2652,15 @@ namespace LLInitParam } } - void setValue(value_assignment_t val) + void setValue(const value_t& val) { - derived_t& typed_param = static_cast(*this); // set param version number to be up to date, so we ignore block contents mValueAge = VALUE_AUTHORITATIVE; mValue = val; - typed_param.clearValueName(); static_cast(this)->updateBlockFromValue(false); } - value_assignment_t getValue() const + const value_t& getValue() const { validateBlock(true); return mValue; @@ -2271,20 +2672,10 @@ namespace LLInitParam return mValue; } - operator value_assignment_t() const - { - return getValue(); - } - - value_assignment_t operator()() const - { - return getValue(); - } - protected: // use this from within updateValueFromBlock() to set the value without making it authoritative - void updateValue(value_assignment_t value) + void updateValue(const value_t& value) { mValue = value; } diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 0e29873bb..9f4460a98 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser: { bool new_traversal = it->second; - LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - - if (child_sd->isArray()) + LLSD* child_sd; + if (it->first.empty()) { + child_sd = sd_to_write; + if (child_sd->isUndefined()) + { + *child_sd = LLSD::emptyArray(); + } if (new_traversal) { // write to new element at end @@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser: } else { - if (new_traversal - && child_sd->isDefined() - && !child_sd->isArray()) - { - // copy child contents into first element of an array - LLSD new_array = LLSD::emptyArray(); - new_array.append(*child_sd); - // assign array to slot that previously held the single value - *child_sd = new_array; - // return next element in that array - sd_to_write = &((*child_sd)[1]); - } - else - { - sd_to_write = child_sd; - } + sd_to_write = &(*sd_to_write)[it->first]; } it->second = false; } @@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI it != sd.endArray(); ++it) { - stack.back().second = true; + stack.push_back(make_pair(std::string(), true)); readSDValues(cb, *it, stack); + stack.pop_back(); } } else if (sd.isUndefined()) @@ -313,8 +303,14 @@ namespace LLInitParam { // LLSD specialization // block param interface - bool ParamValue, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) + bool ParamValue::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) { + if (name_stack.first == name_stack.second + && p.readValue(mValue)) + { + return true; + } + LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); LLSD::String string; @@ -328,15 +324,18 @@ namespace LLInitParam } //static - void ParamValue, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) + void ParamValue::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) { p.writeValue(sd.asString(), name_stack); } - void ParamValue, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const + void ParamValue::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const { - // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - Parser::name_stack_t stack; - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); + // attempt to write LLSD out directly + if (!p.writeValue(mValue, name_stack)) + { + // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack); + } } } diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 3626c88ea..2c1842a74 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -1112,6 +1112,13 @@ std::string LLFontGL::nameFromFont(const LLFontGL* fontp) return fontp->mFontDescriptor.getName(); } + +// static +std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) +{ + return fontp->getFontDesc().getSize(); +} + // static std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align) { @@ -1228,6 +1235,41 @@ LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) return sFontRegistry->getFont(desc); } +// static +LLFontGL* LLFontGL::getFontByName(const std::string& name) +{ + // check for most common fonts first + if (name == "SANSSERIF") + { + return getFontSansSerif(); + } + else if (name == "SANSSERIF_SMALL") + { + return getFontSansSerifSmall(); + } + else if (name == "SANSSERIF_BIG") + { + return getFontSansSerifBig(); + } + else if (name == "SMALL" || name == "OCRA") + { + // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? + // Does "SMALL" mean "SERIF"? + return getFontMonospace(); + } + else + { + return NULL; + } +} + +//static +LLFontGL* LLFontGL::getFontDefault() +{ + return getFontSansSerif(); // Fallback to sans serif as default font +} + + // static std::string LLFontGL::getFontPathSystem() { diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index f83a72f73..776727888 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -171,7 +171,9 @@ public: // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" static U8 getStyleFromString(const std::string &style); static std::string getStringFromStyle(U8 style); + static std::string nameFromFont(const LLFontGL* fontp); + static std::string sizeFromFont(const LLFontGL* fontp); static std::string nameFromHAlign(LLFontGL::HAlign align); static LLFontGL::HAlign hAlignFromName(const std::string& name); @@ -201,6 +203,9 @@ public: static LLFontGL* getFontSansSerifBold(); static LLFontGL* getFontExtChar(); static LLFontGL* getFont(const LLFontDescriptor& desc); + // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" + static LLFontGL* getFontByName(const std::string& name); + static LLFontGL* getFontDefault(); // default fallback font static std::string getFontPathLocal(); static std::string getFontPathSystem(); diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 843789ae1..fbb456eed 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1177,6 +1177,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("depth_cutoff"); mReservedUniforms.push_back("norm_cutoff"); mReservedUniforms.push_back("shadow_target_width"); + mReservedUniforms.push_back("downsampled_depth_scale"); llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1); @@ -1195,6 +1196,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("dof_height"); mReservedUniforms.push_back("depthMap"); + mReservedUniforms.push_back("depthMapDownsampled"); mReservedUniforms.push_back("shadowMap0"); mReservedUniforms.push_back("shadowMap1"); mReservedUniforms.push_back("shadowMap2"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index c13485b71..7dccf47b1 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -136,6 +136,7 @@ public: DEFERRED_DEPTH_CUTOFF, DEFERRED_NORM_CUTOFF, DEFERRED_SHADOW_TARGET_WIDTH, + DEFERRED_DOWNSAMPLED_DEPTH_SCALE, FXAA_TC_SCALE, FXAA_RCP_SCREEN_RES, @@ -152,6 +153,7 @@ public: DOF_HEIGHT, DEFERRED_DEPTH, + DEFERRED_DOWNSAMPLED_DEPTH, DEFERRED_SHADOW0, DEFERRED_SHADOW1, DEFERRED_SHADOW2, diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 90b313d45..fecdce432 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -40,68 +40,56 @@ #include "llcontrol.h" #include "llui.h" #include "lluictrlfactory.h" - -const F32 RESOLUTION_BUMP = 1.f; +#include "lluiimage.h" static LLRegisterWidget r("icon"); -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ) +LLIconCtrl::Params::Params() +: image("image_name"), + color("color"), +// use_draw_context_alpha("use_draw_context_alpha", true), + scale_image("scale_image"), + min_width("min_width", 0), + min_height("min_height", 0) +{} + +LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) +: LLUICtrl(p), + mColor(p.color()), + mImagep(p.image), +// mUseDrawContextAlpha(p.use_draw_context_alpha), + mPriority(0), + mMinWidth(p.min_width), + mMinHeight(p.min_height) { - setImage( image_id ); - setTabStop(FALSE); + if (mImagep.notNull()) + { + LLUICtrl::setValue(mImagep->getName()); + } + setTabStop(false); } -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name) +LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name, const S32& min_width, const S32& min_height) : LLUICtrl(name, rect, FALSE, // mouse opaque NULL, FOLLOWS_LEFT | FOLLOWS_TOP), mColor( LLColor4::white ), - mImageName(image_name) + mPriority(0), + mMinWidth(min_width), + mMinHeight(min_height) { - setImage( image_name ); + setValue( image_name ); setTabStop(FALSE); } - LLIconCtrl::~LLIconCtrl() { mImagep = NULL; } -void LLIconCtrl::setImage(const std::string& image_name) -{ - //RN: support UUIDs masquerading as strings - if (LLUUID::validate(image_name)) - { - mImageID = LLUUID(image_name); - - setImage(mImageID); - } - else - { - mImageName = image_name; - mImagep = LLUI::getUIImage(image_name); - mImageID.setNull(); - } -} - -void LLIconCtrl::setImage(const LLUUID& image_id) -{ - mImageName.clear(); - mImagep = LLUI::getUIImageByID(image_id); - mImageID = image_id; -} - - void LLIconCtrl::draw() { if( mImagep.notNull() ) @@ -120,23 +108,40 @@ void LLIconCtrl::setAlpha(F32 alpha) } // virtual +// value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value ) { - if (value.isUUID()) + LLSD tvalue(value); + if (value.isString() && LLUUID::validate(value.asString())) { - setImage(value.asUUID()); + //RN: support UUIDs masquerading as strings + tvalue = LLSD(LLUUID(value.asString())); + } + LLUICtrl::setValue(tvalue); + if (tvalue.isUUID()) + { + mImagep = LLUI::getUIImageByID(tvalue.asUUID(), mPriority); } else { - setImage(value.asString()); + mImagep = LLUI::getUIImage(tvalue.asString(), mPriority); + } + + if (mImagep.notNull() + && mImagep->getImage().notNull() + && mMinWidth + && mMinHeight) + { + mImagep->getImage()->setKnownDrawSize(llmax(mMinWidth, mImagep->getWidth()), llmax(mMinHeight, mImagep->getHeight())); } } -// virtual -LLSD LLIconCtrl::getValue() const +std::string LLIconCtrl::getImageName() const { - LLSD ret = getImage(); - return ret; + if (getValue().isString()) + return getValue().asString(); + else + return std::string(); } // virtual @@ -146,11 +151,14 @@ LLXMLNodePtr LLIconCtrl::getXML(bool save_children) const node->setName(LL_ICON_CTRL_TAG); - if (mImageName != "") + if (!getImageName().empty()) { - node->createChild("image_name", TRUE)->setStringValue(mImageName); + node->createChild("image_name", TRUE)->setStringValue(getImageName()); } + if (mMinWidth) node->createChild("min_width", true)->setIntValue(mMinWidth); + if (mMinHeight) node->createChild("min_height", true)->setIntValue(mMinHeight); + node->createChild("color", TRUE)->setFloatValue(4, mColor.mV); return node; @@ -170,7 +178,18 @@ LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory * LLColor4 color(LLColor4::white); LLUICtrlFactory::getAttributeColor(node,"color", color); - LLIconCtrl* icon = new LLIconCtrl("icon", rect, image_name); + S32 min_width = 0, min_height = 0; + if (node->hasAttribute("min_width")) + { + node->getAttributeS32("min_width", min_width); + } + + if (node->hasAttribute("min_height")) + { + node->getAttributeS32("min_height", min_height); + } + + LLIconCtrl* icon = new LLIconCtrl("icon", rect, image_name, min_width, min_height); icon->setColor(color); diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 2506fb209..16f4c4238 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -49,33 +49,55 @@ class LLIconCtrl : public LLUICtrl { public: - LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id); - LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name); + struct Params : public LLInitParam::Block + { + Optional image; + Optional color; +// Optional use_draw_context_alpha; + Optional min_width, + min_height; + Ignored scale_image; + + Params(); + }; +protected: + LLIconCtrl(const Params&); + friend class LLUICtrlFactory; + +public: + LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name, const S32& min_width = 0, const S32& min_height = 0); virtual ~LLIconCtrl(); // llview overrides virtual void draw(); - void setImage(const std::string& image_name); - void setImage(const LLUUID& image_name); - const LLUUID &getImage() const { return mImageID; } - std::string getImageName() const { return mImageName; } - - // Takes a UUID, wraps get/setImage + // lluictrl overrides virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; /*virtual*/ void setAlpha(F32 alpha); + std::string getImageName() const; + void setColor(const LLColor4& color) { mColor = color; } + void setImage(LLPointer image) { mImagep = image; } + const LLPointer getImage() { return mImagep; } virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); +protected: + S32 mPriority; + + //the output size of the icon image if set. + S32 mMinWidth, + mMinHeight; + + // If set to true (default), use the draw context transparency. + // If false, will use transparency returned by getCurrentTransparency(). See STORM-698. + //bool mUseDrawContextAlpha; + private: LLColor4 mColor; - std::string mImageName; - LLUUID mImageID; LLPointer mImagep; }; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 400d80d64..f066ef6dc 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1508,8 +1508,9 @@ LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, un // Allow LLNotifications::add, LLNotifications::cancel and LLNotifications::update // to be called from any thread. -struct UpdateItem +class UpdateItem { +public: char const* sigtype; LLNotificationPtr pNotif; UpdateItem(char const* st, LLNotificationPtr const& np) : sigtype(st), pNotif(np) { } diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index be15bd406..4fda9d77e 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -96,7 +96,7 @@ int const access_increment = 1000; static void log_sStringTemplates_accesses(void) { - llinfos << "LLTrans::getString/findString called " << sStringTemplates_accesses << " in total." << llendl; + lldebugs << "LLTrans::getString/findString called " << sStringTemplates_accesses << " in total." << llendl; } //static diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 5a68c9efe..aab2df83f 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -313,3 +313,227 @@ void LLUI::setQAMode(BOOL b) LLUI::sQAMode = b; } +namespace LLInitParam +{ + ParamValue::ParamValue(const LLUIColor& color) + : super_t(color), + red("red"), + green("green"), + blue("blue"), + alpha("alpha"), + control("") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + if (control.isProvided() && !control().empty()) + { + updateValue(LLUI::sColorsGroup->controlExists(control) ? LLUI::sColorsGroup->getColor(control) : LLUI::sConfigGroup->getColor(control)); // Singu Note: Most of our colors will be in sColorsGroup (skin), but some may be moved to settings for users. + } + else + { + updateValue(LLColor4(red, green, blue, alpha)); + } + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + LLColor4 color = getValue(); + red.set(color.mV[VRED], make_block_authoritative); + green.set(color.mV[VGREEN], make_block_authoritative); + blue.set(color.mV[VBLUE], make_block_authoritative); + alpha.set(color.mV[VALPHA], make_block_authoritative); + control.set("", make_block_authoritative); + } + + bool ParamCompare::equals(const LLFontGL* a, const LLFontGL* b) + { + return !(a->getFontDesc() < b->getFontDesc()) + && !(b->getFontDesc() < a->getFontDesc()); + } + + ParamValue::ParamValue(const LLFontGL* fontp) + : super_t(fontp), + name("name"), + size("size"), + style("style") + { + if (!fontp) + { + updateValue(LLFontGL::getFontDefault()); + } + addSynonym(name, ""); + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + const LLFontGL* res_fontp = LLFontGL::getFontByName(name); + if (res_fontp) + { + updateValue(res_fontp); + return; + } + + U8 fontstyle = 0; + fontstyle = LLFontGL::getStyleFromString(style()); + LLFontDescriptor desc(name(), size(), fontstyle); + const LLFontGL* fontp = LLFontGL::getFont(desc); + if (fontp) + { + updateValue(fontp); + } + else + { + updateValue(LLFontGL::getFontDefault()); + } + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + if (getValue()) + { + name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative); + size.set(LLFontGL::sizeFromFont(getValue()), make_block_authoritative); + style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), make_block_authoritative); + } + } + + ParamValue::ParamValue(const LLRect& rect) + : super_t(rect), + left("left"), + top("top"), + right("right"), + bottom("bottom"), + width("width"), + height("height") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + LLRect rect; + + //calculate from params + // prefer explicit left and right + if (left.isProvided() && right.isProvided()) + { + rect.mLeft = left; + rect.mRight = right; + } + // otherwise use width along with specified side, if any + else if (width.isProvided()) + { + // only right + width provided + if (right.isProvided()) + { + rect.mRight = right; + rect.mLeft = right - width; + } + else // left + width, or just width + { + rect.mLeft = left; + rect.mRight = left + width; + } + } + // just left, just right, or none + else + { + rect.mLeft = left; + rect.mRight = right; + } + + // prefer explicit bottom and top + if (bottom.isProvided() && top.isProvided()) + { + rect.mBottom = bottom; + rect.mTop = top; + } + // otherwise height along with specified side, if any + else if (height.isProvided()) + { + // top + height provided + if (top.isProvided()) + { + rect.mTop = top; + rect.mBottom = top - height; + } + // bottom + height or just height + else + { + rect.mBottom = bottom; + rect.mTop = bottom + height; + } + } + // just bottom, just top, or none + else + { + rect.mBottom = bottom; + rect.mTop = top; + } + updateValue(rect); + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + // because of the ambiguity in specifying a rect by position and/or dimensions + // we use the lowest priority pairing so that any valid pairing in xui + // will override those calculated from the rect object + // in this case, that is left+width and bottom+height + LLRect& value = getValue(); + + right.set(value.mRight, false); + left.set(value.mLeft, make_block_authoritative); + width.set(value.getWidth(), make_block_authoritative); + + top.set(value.mTop, false); + bottom.set(value.mBottom, make_block_authoritative); + height.set(value.getHeight(), make_block_authoritative); + } + + ParamValue::ParamValue(const LLCoordGL& coord) + : super_t(coord), + x("x"), + y("y") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + updateValue(LLCoordGL(x, y)); + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + x.set(getValue().mX, make_block_authoritative); + y.set(getValue().mY, make_block_authoritative); + } + + + void TypeValues::declareValues() + { + declare("left", LLFontGL::LEFT); + declare("right", LLFontGL::RIGHT); + declare("center", LLFontGL::HCENTER); + } + + void TypeValues::declareValues() + { + declare("top", LLFontGL::TOP); + declare("center", LLFontGL::VCENTER); + declare("baseline", LLFontGL::BASELINE); + declare("bottom", LLFontGL::BOTTOM); + } + + void TypeValues::declareValues() + { + declare("none", LLFontGL::NO_SHADOW); + declare("hard", LLFontGL::DROP_SHADOW); + declare("soft", LLFontGL::DROP_SHADOW_SOFT); + } +} + diff --git a/indra/llui/llui.h b/indra/llui/llui.h index aede0f859..1d3d7b33e 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -32,12 +32,18 @@ #include "llcontrol.h" #include "llcoord.h" #include "v2math.h" +#include "llinitparam.h" #include "llregistry.h" #include "llrender2dutils.h" #include "llpointer.h" +#include "lluicolor.h" #include "lluiimage.h" #include +// for initparam specialization +#include "llfontgl.h" + + // LLUIFactory #include "llsd.h" @@ -504,4 +510,99 @@ protected: template T* LLParamBlock::sBlock = NULL; + +namespace LLInitParam +{ + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional left, + top, + right, + bottom, + width, + height; + + ParamValue(const LLRect& value); + + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + + public: + Optional red, + green, + blue, + alpha; + Optional control; + + ParamValue(const LLUIColor& color); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional name, + size, + style; + + ParamValue(const LLFontGL* value); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct ParamCompare + { + static bool equals(const LLFontGL* a, const LLFontGL* b); + }; + + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional x, + y; + + ParamValue(const LLCoordGL& val); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; +} + #endif diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 56bac0e92..a44367725 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -31,7 +31,6 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "lluictrl.h" #include "llfocusmgr.h" @@ -39,10 +38,69 @@ static LLRegisterWidget r("ui_ctrl"); -// NOTE: the LLFocusableElement implementation has been moved to llfocusmgr.cpp, to mirror the header where the class is defined. +LLUICtrl::CallbackParam::CallbackParam() +: name("name"), + function_name("function"), + parameter("parameter"), + control_name("control") // Shortcut to control -> "control_name" for backwards compatability +{ + addSynonym(parameter, "userdata"); +} -LLUICtrl::LLUICtrl() : - mViewModel(LLViewModelPtr(new LLViewModel)), +LLUICtrl::EnableControls::EnableControls() +: enabled("enabled_control"), + disabled("disabled_control") +{} + +LLUICtrl::ControlVisibility::ControlVisibility() +: visible("visibility_control"), + invisible("invisibility_control") +{ + addSynonym(visible, "visiblity_control"); + addSynonym(invisible, "invisiblity_control"); +} + +LLUICtrl::Params::Params() +: tab_stop("tab_stop", true), + chrome("chrome", false), + requests_front("requests_front", false), + label("label"), + initial_value("value"), + init_callback("init_callback"), + commit_callback("commit_callback"), + validate_callback("validate_callback"), + mouseenter_callback("mouseenter_callback"), + mouseleave_callback("mouseleave_callback"), + control_name("control_name"), + font("font", LLFontGL::getFontSansSerif()), + font_halign("halign"), + font_valign("valign"), + length("length"), // ignore LLXMLNode cruft + type("type") // ignore LLXMLNode cruft +{ + addSynonym(initial_value, "initial_value"); +} + +// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp. + +//static +const LLUICtrl::Params& LLUICtrl::getDefaultParams() +{ + // Singu Note: We diverge here, not using LLUICtrlFactory::getDefaultParams + static const Params p; + return p; +} + + +LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) +: LLView(p), + mIsChrome(FALSE), + mRequestsFront(p.requests_front), + mTabStop(TRUE), + mTentative(FALSE), + mViewModel(viewmodel), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), mMakeVisibleControlVariable(NULL), mMakeInvisibleControlVariable(NULL), mCommitSignal(NULL), @@ -54,22 +112,110 @@ LLUICtrl::LLUICtrl() : mRightMouseDownSignal(NULL), mRightMouseUpSignal(NULL), mDoubleClickSignal(NULL), - mTentative(FALSE), - mTabStop(TRUE), - mIsChrome(FALSE), mCommitOnReturn(FALSE) { } +void LLUICtrl::initFromParams(const Params& p) +{ + LLView::initFromParams(p); + + mRequestsFront = p.requests_front; + + setIsChrome(p.chrome); + if(p.enabled_controls.isProvided()) + { + if (p.enabled_controls.enabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.enabled); + if (control) + setEnabledControlVariable(control); + } + else if(p.enabled_controls.disabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.disabled); + if (control) + setDisabledControlVariable(control); + } + } + if(p.controls_visibility.isProvided()) + { + if (p.controls_visibility.visible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.visible); + if (control) + setMakeVisibleControlVariable(control); + } + else if (p.controls_visibility.invisible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.invisible); + if (control) + setMakeInvisibleControlVariable(control); + } + } + + setTabStop(p.tab_stop); + + if (p.initial_value.isProvided() + && !p.control_name.isProvided()) + { + setValue(p.initial_value); + } + + if (p.commit_callback.isProvided()) + { + setCommitCallback(initCommitCallback(p.commit_callback)); + } + + if (p.validate_callback.isProvided()) + { + setValidateCallback(initEnableCallback(p.validate_callback)); + } + + if (p.init_callback.isProvided()) + { + if (p.init_callback.function.isProvided()) + { + p.init_callback.function()(this, p.init_callback.parameter); + } + else + { + commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); + if (initfunc) + { + (*initfunc)(this, p.init_callback.parameter); + } + } + } + + if(p.mouseenter_callback.isProvided()) + { + setMouseEnterCallback(initCommitCallback(p.mouseenter_callback)); + } + + if(p.mouseleave_callback.isProvided()) + { + setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback)); + } +} + LLUICtrl::LLUICtrl(const std::string& name, const LLRect rect, BOOL mouse_opaque, commit_callback_t commit_callback, U32 reshape) : // can't make this automatically follow top and left, breaks lots // of buttons in the UI. JC 7/20/2002 LLView( name, rect, mouse_opaque, reshape ), + mIsChrome(FALSE), + mRequestsFront(false), + mTabStop( TRUE ), + mTentative( FALSE ), + mViewModel(LLViewModelPtr(new LLViewModel)), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), + mMakeVisibleControlVariable(NULL), + mMakeInvisibleControlVariable(NULL), mCommitSignal(NULL), mValidateSignal(NULL), - mViewModel(LLViewModelPtr(new LLViewModel)), mMouseEnterSignal(NULL), mMouseLeaveSignal(NULL), mMouseDownSignal(NULL), @@ -77,9 +223,6 @@ LLUICtrl::LLUICtrl(const std::string& name, const LLRect rect, BOOL mouse_opaque mRightMouseDownSignal(NULL), mRightMouseUpSignal(NULL), mDoubleClickSignal(NULL), - mTentative( FALSE ), - mTabStop( TRUE ), - mIsChrome(FALSE), mCommitOnReturn(FALSE) { if(commit_callback) @@ -107,6 +250,66 @@ LLUICtrl::~LLUICtrl() delete mDoubleClickSignal; } +void default_commit_handler(LLUICtrl* ctrl, const LLSD& param) +{} + +bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param) +{ + return true; +} + + +LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb) +{ + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), _1, cb.parameter); + else + return cb.function(); + } + else + { + std::string function_name = cb.function_name; + commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), _1, cb.parameter); + else + return commit_signal_t::slot_type(*func); + } + else if (!function_name.empty()) + { + llwarns << "No callback found for: '" << function_name << "' in control: " << getName() << llendl; + } + } + return default_commit_handler; +} + +LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb) +{ + // Set the callback function + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), this, cb.parameter); + else + return cb.function(); + } + else + { + enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), this, cb.parameter); + else + return enable_signal_t::slot_type(*func); + } + } + return default_enable_handler; +} // virtual void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask) @@ -130,6 +333,7 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask) BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLView::handleMouseDown(x,y,mask); + if (mMouseDownSignal) { (*mMouseDownSignal)(this,x,y,mask); @@ -227,6 +431,66 @@ LLViewModel* LLUICtrl::getViewModel() const return mViewModel; } +//virtual +BOOL LLUICtrl::postBuild() +{ + // + // Find all of the children that want to be in front and move them to the front + // + + if (getChildCount() > 0) + { + std::vector childrenToMoveToFront; + + for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) + { + LLUICtrl* uictrl = dynamic_cast(*child_it); + + if (uictrl && uictrl->mRequestsFront) + { + childrenToMoveToFront.push_back(uictrl); + } + } + + for (std::vector::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it) + { + sendChildToFront(*it); + } + } + + return LLView::postBuild(); +} + +void LLUICtrl::setEnabledControlVariable(LLControlVariable* control) +{ + if (mEnabledControlVariable) + { + mEnabledControlConnection.disconnect(); // disconnect current signal + mEnabledControlVariable = NULL; + } + if (control) + { + mEnabledControlVariable = control; + mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled"))); + setEnabled(mEnabledControlVariable->getValue().asBoolean()); + } +} + +void LLUICtrl::setDisabledControlVariable(LLControlVariable* control) +{ + if (mDisabledControlVariable) + { + mDisabledControlConnection.disconnect(); // disconnect current signal + mDisabledControlVariable = NULL; + } + if (control) + { + mDisabledControlVariable = control; + mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled"))); + setEnabled(!(mDisabledControlVariable->getValue().asBoolean())); + } +} + void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control) { if (mMakeVisibleControlVariable) @@ -262,7 +526,17 @@ bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle handle, LLUICtrl* ctrl = handle.get(); if (ctrl) { - if (type == "visible") + if (type == "enabled") + { + ctrl->setEnabled(newvalue.asBoolean()); + return true; + } + else if(type =="disabled") + { + ctrl->setEnabled(!newvalue.asBoolean()); + return true; + } + else if (type == "visible") { ctrl->setVisible(newvalue.asBoolean()); return true; @@ -383,7 +657,6 @@ void LLUICtrl::setIsChrome(BOOL is_chrome) // virtual BOOL LLUICtrl::getIsChrome() const { - LLView* parent_ctrl = getParent(); while(parent_ctrl) { @@ -533,6 +806,7 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields) return FALSE; } + BOOL LLUICtrl::focusNextItem(BOOL text_fields_only) { // this assumes that this method is called on the focus root. @@ -618,6 +892,8 @@ void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) setTabStop(has_tab_stop); + node->getAttributeBOOL("requests_front", mRequestsFront); + std::string str = node->getName()->mString; std::string attrib_str; LLXMLNodePtr child_node; @@ -667,6 +943,20 @@ void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) } LLView::initFromXML(node, parent); + if (node->getAttributeString("enabled_control", attrib_str)) + { + LLControlVariable* control = findControl(attrib_str); + if (control) + setEnabledControlVariable(control); + } + + if (node->getAttributeString("disabled_control", attrib_str)) + { + LLControlVariable* control = findControl(attrib_str); + if (control) + setDisabledControlVariable(control); + } + if(node->getAttributeString("visibility_control",attrib_str) || node->getAttributeString("visiblity_control",attrib_str)) { LLControlVariable* control = findControl(attrib_str); @@ -727,6 +1017,7 @@ boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::functionconnect(boost::bind(cb, _2)); } + // virtual void LLUICtrl::setTentative(BOOL b) { @@ -756,6 +1047,16 @@ void LLUICtrl::setMinValue(LLSD min_value) void LLUICtrl::setMaxValue(LLSD max_value) { } +boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb) +{ + return setCommitCallback(initCommitCallback(cb)); +} + +boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb) +{ + return setValidateCallback(initEnableCallback(cb)); +} + boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) { if (!mCommitSignal) mCommitSignal = new commit_signal_t(); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index ba6acc98e..aae767e1a 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -34,13 +34,13 @@ #ifndef LL_LLUICTRL_H #define LL_LLUICTRL_H -#include "llview.h" #include "llrect.h" #include "llsd.h" #include #include #include "llinitparam.h" +#include "llview.h" #include "llviewmodel.h" // *TODO move dependency to .cpp file class LLUICtrl @@ -49,20 +49,102 @@ class LLUICtrl public: typedef boost::function commit_callback_t; typedef boost::signals2::signal commit_signal_t; + // *TODO: add xml support for this type of signal in the future typedef boost::signals2::signal mouse_signal_t; + typedef boost::function enable_callback_t; typedef boost::signals2::signal enable_signal_t; - LLUICtrl(); + struct CallbackParam : public LLInitParam::Block + { + Ignored name; + + Optional function_name; + Optional parameter; + + Optional control_name; + + CallbackParam(); + }; + + struct CommitCallbackParam : public LLInitParam::Block + { + Optional function; + }; + + // also used for visible callbacks + struct EnableCallbackParam : public LLInitParam::Block + { + Optional function; + }; + + struct EnableControls : public LLInitParam::ChoiceBlock + { + Alternative enabled; + Alternative disabled; + + EnableControls(); + }; + struct ControlVisibility : public LLInitParam::ChoiceBlock + { + Alternative visible; + Alternative invisible; + + ControlVisibility(); + }; + struct Params : public LLInitParam::Block + { + Optional label; + Optional tab_stop, + chrome, + requests_front; + Optional initial_value; + + Optional init_callback, + commit_callback; + Optional validate_callback; + + Optional mouseenter_callback, + mouseleave_callback; + + Optional control_name; + Optional enabled_controls; + Optional controls_visibility; + + // font params + Optional font; + Optional font_halign; + Optional font_valign; + + // cruft from LLXMLNode implementation + Ignored type, + length; + + Params(); + }; + + /*virtual*/ ~LLUICtrl(); + + void initFromParams(const Params& p); + static const Params& getDefaultParams(); + LLUICtrl(const Params& p = getDefaultParams(), + const LLViewModelPtr& viewmodel=LLViewModelPtr(new LLViewModel)); + // Singu Note: This constructor is deprecated: LLUICtrl( const std::string& name, const LLRect rect = LLRect(), BOOL mouse_opaque = TRUE, commit_callback_t commit_callback = NULL, U32 reshape=FOLLOWS_NONE); - /*virtual*/ ~LLUICtrl(); + + commit_signal_t::slot_type initCommitCallback(const CommitCallbackParam& cb); + enable_signal_t::slot_type initEnableCallback(const EnableCallbackParam& cb); // We need this virtual so we can override it with derived versions virtual LLViewModel* getViewModel() const; // We shouldn't ever need to set this directly //virtual void setViewModel(const LLViewModelPtr&); + + virtual BOOL postBuild(); + +public: // LLView interface /*virtual*/ void initFromXML(LLXMLNodePtr node, LLView* parent); /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const; @@ -87,6 +169,9 @@ public: virtual class LLCtrlSelectionInterface* getSelectionInterface(); virtual class LLCtrlListInterface* getListInterface(); virtual class LLCtrlScrollInterface* getScrollInterface(); + + void setEnabledControlVariable(LLControlVariable* control); + void setDisabledControlVariable(LLControlVariable* control); void setMakeVisibleControlVariable(LLControlVariable* control); void setMakeInvisibleControlVariable(LLControlVariable* control); @@ -113,6 +198,9 @@ public: // Default to no-op: virtual void onTabInto(); + + // Clear any user-provided input (text in a text editor, checked checkbox, + // selected radio button, etc.). Defaults to no-op. virtual void clear(); virtual void setColor(const LLColor4& color); virtual void setAlpha(F32 alpha); @@ -121,7 +209,7 @@ public: BOOL focusNextItem(BOOL text_entry_only); BOOL focusPrevItem(BOOL text_entry_only); - virtual BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); + BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); BOOL focusLastItem(BOOL prefer_text_fields = FALSE); // Non Virtuals @@ -136,10 +224,13 @@ public: void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } + boost::signals2::connection setCommitCallback(const CommitCallbackParam& cb); + boost::signals2::connection setValidateCallback(const EnableCallbackParam& cb); + //Start using these! boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ); - + boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ); @@ -192,14 +283,19 @@ protected: LLViewModelPtr mViewModel; + LLControlVariable* mEnabledControlVariable; + boost::signals2::connection mEnabledControlConnection; + LLControlVariable* mDisabledControlVariable; + boost::signals2::connection mDisabledControlConnection; LLControlVariable* mMakeVisibleControlVariable; boost::signals2::connection mMakeVisibleControlConnection; LLControlVariable* mMakeInvisibleControlVariable; boost::signals2::connection mMakeInvisibleControlConnection; private: - BOOL mTabStop; BOOL mIsChrome; + BOOL mRequestsFront; + BOOL mTabStop; BOOL mTentative; bool mCommitOnReturn; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2a70a1c8f..8b3a3524a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -17,7 +17,7 @@ Type Boolean Value - 1 + 0 PhoenixIMAnnounceStealFocus @@ -223,13 +223,13 @@ zmm_mlfov Comment - 1=Normal, Under 1 Zoom Out, Over 1 Zoom in + Adjusted when scrolling back and forth while holding rightclick in mouselook (Zoomed in < 1.037 < Zoomed out) Persist 1 Type F32 Value - 1 + 0.5 AllowLargeSounds @@ -763,6 +763,39 @@ Value 0 + LiruMouselookHidesFloaters + + Comment + Whether or not floaters open during third person will be hidden while in mouselook + Persist + 1 + Type + Boolean + Value + 1 + + LiruMouselookHidesMenubar + + Comment + Whether or not the main menu bar will be hidden in mouselook + Persist + 1 + Type + Boolean + Value + 1 + + LiruMouselookHidesNotices + + Comment + Whether or not notices will be hidden in mouselook + Persist + 1 + Type + Boolean + Value + 0 + LiruMouselookMenu Comment @@ -6153,6 +6186,28 @@ This should be as low as possible, but too low may break functionality Value 1 + EnableNongestureSounds + + Comment + Play sounds from non-gestures + Persist + 1 + Type + Boolean + Value + 1 + + EnableNongestureSoundsSelf + + Comment + Play sounds from your non-gestures when EnableNongestureSounds is false. (Useless otherwise) + Persist + 1 + Type + Boolean + Value + 1 + EnableMouselook Comment diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index 998c3ff37..5fb2c4826 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -229,5 +229,16 @@ Value 1 + SHRenderSSAOResolutionScale + + Comment + SSAO resolution scale. Valid values: 0.01-1.0 + Persist + 1 + Type + F32 + Value + .5 + diff --git a/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl new file mode 100644 index 000000000..64c4e41cf --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl @@ -0,0 +1,140 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +//#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +VARYING vec2 vary_fragcoord; + +uniform sampler2DRect depthMapDownsampled; +uniform sampler2DRect normalMap; +uniform sampler2D noiseMap; + +uniform vec2 screen_res; +uniform mat4 inv_proj; + +uniform float downsampled_depth_scale; + +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; + +vec3 decode_normal (vec2 enc) +{ + vec2 fenc = enc*4-2; + float f = dot(fenc,fenc); + float g = sqrt(1-f/4); + vec3 n; + n.xy = fenc*g; + n.z = 1-f/2; + return n; +} + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2DRect(depthMapDownsampled, pos_screen.xy*downsampled_depth_scale).r; + vec2 sc = pos_screen.xy*2.0; + sc /= screen_res; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec2 getKern(int i) +{ + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * (0.125*0.125*.9+.1); + kern[1] = vec2(1.0, 0.0) * (0.250*0.250*.9+.1); + kern[2] = vec2(0.0, 1.0) * (0.375*0.375*.9+.1); + kern[3] = vec2(0.0, -1.0) * (0.500*0.500*.9+.1); + kern[4] = vec2(0.7071, 0.7071) * (0.625*0.625*.9+.1); + kern[5] = vec2(-0.7071, -0.7071) * (0.750*0.750*.9+.1); + kern[6] = vec2(-0.7071, 0.7071) * (0.875*0.875*.9+.1); + kern[7] = vec2(0.7071, -0.7071) * (1.000*1.000*.9+.1); + + return kern[i]; +} + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm) +{ + vec2 pos_screen = vary_fragcoord.xy; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; + + // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. + float points = 1.0; + float angle_hidden = 0.0; + + // use a kernel scale that diminishes with distance. + // a scale of less than 32 is just wasting good samples, though. + float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); + + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; + + vec3 diff = samppos_world - pos.xyz; + + if (diff.z < ssao_factor && diff.z != 0.0) + { + float dist = length(diff); + float angrel = max(0.0, dot(norm.xyz, diff/dist)); + float distrel = 1.0/(1.0+dist*dist); + float samplehidden = min(angrel, distrel); + + angle_hidden += (samplehidden); + points += 1.0; + } + } + + angle_hidden /= points; + float rtn = (1.0 - angle_hidden); + return (rtn * rtn) * (rtn * rtn); //Pow2 to increase darkness to match previous behavior. +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec3 norm = texture2DRect(normalMap, pos_screen).xyz; + norm = decode_normal(norm.xy); + + frag_color = vec4(calcAmbientOcclusion(pos,norm),0,0,0); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index 35362cabb..b1cacf8b0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -51,7 +51,6 @@ uniform float max_y; uniform vec4 glow; uniform float scene_light_strength; uniform mat3 env_mat; -uniform mat3 ssao_effect_mat; uniform vec3 sun_dir; @@ -312,7 +311,7 @@ void setAtmosAttenuation(vec3 v) vary_AtmosAttenuation = v; } -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { +void calcAtmospherics(vec3 inPositionEye) { vec3 P = inPositionEye; setPositionEye(P); @@ -373,16 +372,6 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { //increase ambient when there are more clouds vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5; - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - //haze color setAdditiveColor( vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient) @@ -568,7 +557,7 @@ void main() vec3 norm = vary_norm; - calcAtmospherics(pos.xyz, 1.0); + calcAtmospherics(pos.xyz); vec2 abnormal = encode_normal(norm.xyz); norm.xyz = decode_normal(abnormal.xy); diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 369a014fb..80c0c6e7b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -38,7 +38,7 @@ uniform sampler2DRect lightMap; uniform float dist_factor; uniform float blur_size; uniform vec2 delta; -uniform vec3 kern[4]; +//uniform vec3 kern[4]; uniform float kern_scale; VARYING vec2 vary_fragcoord; @@ -46,8 +46,14 @@ VARYING vec2 vary_fragcoord; uniform mat4 inv_proj; uniform vec2 screen_res; -vec3 getKern(int i) +vec2 getKern(int i) { + vec2 kern[4]; + + kern[0] = vec2(0.3989422804,0.1994711402); + kern[1] = vec2(0.2419707245,0.1760326634); + kern[2] = vec2(0.0539909665,0.1209853623); + kern[3] = vec2(0.0044318484,0.0647587978); return kern[i]; } @@ -102,33 +108,37 @@ void main() // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large vec2 tc_v = fract(0.5 * tc.xy); // we now have floor(mod(tc,2.0))*0.5 float tc_mod = 2.0 * abs(tc_v.x - tc_v.y); // diff of x,y makes checkerboard - tc += ( (tc_mod - 0.5) * getKern(1).z * dlt * 0.5 ); + tc += ( (tc_mod - 0.5) * dlt * 0.5 ); for (int i = 1; i < 4; i++) { - vec2 samptc = (tc + getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc + i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2DRect(lightMap, samptc)*weight; + defined_weight += weight.xy; } } for (int i = 1; i < 4; i++) { - vec2 samptc = (tc - getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc - i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2DRect(lightMap, samptc)*weight; + defined_weight += weight.xy; } } col /= defined_weight.xyxx; - col.y *= col.y; // delinearize SSAO effect post-blur + //col.y *= col.y; // delinearize SSAO effect post-blur // Singu note: Performed pre-blur as to remove blur requirement frag_color = col; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl new file mode 100644 index 000000000..9b6355fb9 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl @@ -0,0 +1,41 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +//#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect depthMap; + +VARYING vec2 vary_fragcoord; + +void main() +{ + gl_FragDepth = texture2DRect(depthMap, vary_fragcoord.xy).r; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl index d7abc457d..c1d0ee266 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl @@ -134,7 +134,6 @@ uniform float max_y; uniform vec4 glow; uniform float scene_light_strength; uniform mat3 env_mat; -uniform mat3 ssao_effect_mat; uniform vec3 sun_dir; @@ -335,7 +334,7 @@ void setAtmosAttenuation(vec3 v) vary_AtmosAttenuation = v; } -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { +void calcAtmospherics(vec3 inPositionEye) { vec3 P = inPositionEye; setPositionEye(P); @@ -396,16 +395,6 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { //increase ambient when there are more clouds vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5; - /* decrease value and saturation (that in HSV, not HSL) for occluded areas - * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html - * // The following line of code performs the equivalent of: - * float ambAlpha = tmpAmbient.a; - * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis - * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue); - * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha); - */ - tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - //haze color setAdditiveColor( vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient) @@ -677,7 +666,7 @@ void main() vec3 col = vec3(0.0f,0.0f,0.0f); float bloom = 0.0; - calcAtmospherics(pos.xyz, 1.0); + calcAtmospherics(pos.xyz); vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index 7e149fae8..a0e5958eb 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -64,7 +64,6 @@ uniform vec4 glow; uniform float global_gamma; uniform float scene_light_strength; uniform mat3 env_mat; -uniform float ssao_effect; uniform vec3 sun_dir; VARYING vec2 vary_fragcoord; @@ -238,7 +237,7 @@ vec4 applyWaterFogDeferred(vec3 pos, vec4 color) } #endif -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { +void calcAtmospherics(vec3 inPositionEye) { vec3 P = inPositionEye; setPositionEye(P); @@ -305,9 +304,6 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * temp2.x + tmpAmbient))); - // decrease value for occluded areas - tmpAmbient = vec4(mix(ssao_effect * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - //brightness of surface both sunlight and ambient setSunlitColor(vec3(sunlight * .5)); setAmblitColor(vec3(tmpAmbient * .25)); @@ -408,7 +404,7 @@ void main() float final_da = max(0.0,da); final_da = min(final_da, 1.0f); final_da = pow(final_da, 1.0/1.3); - calcAtmospherics(pos.xyz, 1.0); + calcAtmospherics(pos.xyz); col = atmosAmbient(vec3(0)); float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl index a1ae08bb6..a0e1af439 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -31,120 +31,19 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -//class 1 -- no shadow, SSAO only - -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2D noiseMap; - - -// Inputs -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; - VARYING vec2 vary_fragcoord; -uniform mat4 inv_proj; +uniform sampler2DRect depthMapDownsampled; +uniform sampler2DRect depthMap; + +uniform sampler2DRect diffuseRect; +uniform float downsampled_depth_scale; uniform vec2 screen_res; -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - -vec3 decode_normal (vec2 enc) -{ - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; - - vec3 diff = samppos_world - pos.xyz; - - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; - - float rtn = (1.0 - angle_hidden); - - return (rtn * rtn); -} - void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - - //try doing an unproject here - - vec4 pos = getPosition(pos_screen); - - vec3 norm = texture2DRect(normalMap, pos_screen).xyz; - norm = decode_normal(norm.xy); - +{ frag_color[0] = 1.0; - frag_color[1] = calcAmbientOcclusion(pos, norm); - frag_color[2] = 1.0; + frag_color[1] = texture2DRect(diffuseRect,vary_fragcoord.xy*downsampled_depth_scale).r; + frag_color[2] = 1.0; frag_color[3] = 1.0; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 2be812200..9b3b9ed5a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -32,6 +32,7 @@ out vec4 frag_color; //class 2 -- shadows and SSAO +uniform sampler2DRect diffuseRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; uniform sampler2DShadow shadowMap0; @@ -40,16 +41,12 @@ uniform sampler2DShadow shadowMap2; uniform sampler2DShadow shadowMap3; uniform sampler2DShadow shadowMap4; uniform sampler2DShadow shadowMap5; -uniform sampler2D noiseMap; +//uniform sampler2D noiseMap; // Inputs uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; VARYING vec2 vary_fragcoord; @@ -66,6 +63,8 @@ uniform float shadow_offset; uniform float spot_shadow_bias; uniform float spot_shadow_offset; +uniform float downsampled_depth_scale; + vec2 encode_normal(vec3 n) { float f = sqrt(8 * n.z + 8); @@ -96,61 +95,6 @@ vec4 getPosition(vec2 pos_screen) return pos; } -vec2 getKern(int i) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - return kern[i]; -} - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 pos_screen = vary_fragcoord.xy; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; - - vec3 diff = samppos_world - pos.xyz; - - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; - float rtn = (1.0 - angle_hidden); - return (rtn * rtn); -} - float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; @@ -301,7 +245,7 @@ void main() } frag_color[0] = shadow; - frag_color[1] = calcAmbientOcclusion(pos, norm); + frag_color[1] = texture2DRect(diffuseRect,vary_fragcoord*downsampled_depth_scale); spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 081e3b65f..599ee5496 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -52,6 +52,7 @@ #include "llmoveview.h" #include "llchatbar.h" #include "llnotificationsutil.h" +#include "llnotify.h" // For hiding notices(gNotifyBoxView) in mouselook #include "llparcel.h" #include "llrendersphere.h" #include "llsdmessage.h" @@ -2043,6 +2044,8 @@ void LLAgent::endAnimationUpdateUI() gMenuBarView->setVisible(TRUE); gStatusBar->setVisibleForMouselook(true); + // Show notices + gNotifyBoxView->setVisible(true); LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); @@ -2053,7 +2056,7 @@ void LLAgent::endAnimationUpdateUI() } // Only pop if we have pushed... - if (TRUE == mViewsPushed) + if (mViewsPushed) { LLFloaterView::skip_list_t skip_list; skip_list.insert(LLFloaterMap::getInstance()); @@ -2134,9 +2137,11 @@ void LLAgent::endAnimationUpdateUI() if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) { // hide menus - gMenuBarView->setVisible(FALSE); + gMenuBarView->setVisible(!gSavedSettings.getBOOL("LiruMouselookHidesMenubar")); gStatusBar->setVisibleForMouselook(false); + if (gSavedSettings.getBOOL("LiruMouselookHidesNotices")) + gNotifyBoxView->setVisible(false); // clear out camera lag effect gAgentCamera.clearCameraLag(); @@ -2146,7 +2151,7 @@ void LLAgent::endAnimationUpdateUI() LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset); - mViewsPushed = TRUE; + mViewsPushed = gSavedSettings.getBOOL("LiruMouselookHidesFloaters"); if (mMouselookModeInSignal) { @@ -2155,9 +2160,12 @@ void LLAgent::endAnimationUpdateUI() // hide all floaters except the mini map - LLFloaterView::skip_list_t skip_list; - skip_list.insert(LLFloaterMap::getInstance()); - gFloaterView->pushVisibleAll(FALSE, skip_list); + if (mViewsPushed) // Singu Note: Only hide if the setting is true. + { + LLFloaterView::skip_list_t skip_list; + skip_list.insert(LLFloaterMap::getInstance()); + gFloaterView->pushVisibleAll(FALSE, skip_list); + } if( gMorphView ) { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6449b376d..5d9da37c8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2972,14 +2972,17 @@ void LLAppViewer::removeMarkerFile(bool leave_logout_marker) mMarkerFile.close() ; LLAPRFile::remove( mMarkerFileName ); } - if (mLogoutMarkerFile != NULL && !leave_logout_marker) + if (mLogoutMarkerFile != NULL) { - LLAPRFile::remove( mLogoutMarkerFileName ); - mLogoutMarkerFile = NULL; - } - else - { - LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; + if(!leave_logout_marker) + { + LLAPRFile::remove( mLogoutMarkerFileName ); + mLogoutMarkerFile = NULL; + } + else + { + LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL; + } } } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 3e2dc4308..0a2a7f1c0 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -221,7 +221,7 @@ void LLDrawPoolAlpha::endRenderPass( S32 pass ) LLFastTimer t(FTM_RENDER_ALPHA); LLRenderPass::endRenderPass(pass); - if(gPipeline.canUseWindLightShaders()) + if(mVertexShaderLevel > 0) //Singu Note: Unbind if shaders are enabled at all, not just windlight atmospherics.. { LLGLSLShader::bindNoShader(); } diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index e6b8167ff..5f1a0f47c 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -1252,26 +1252,35 @@ void LLFloaterAvatarList::setFocusAvatar(const LLUUID& id) } } +// Simple function to decrement iterators, wrapping back if needed +template +T prev_iter(const T& cur, const T& begin, const T& end) +{ + return ((cur == begin) ? end : cur) - 1; +} + template void decrement_focus_target(T begin, T end, BOOL marked_only) { - T iter = begin; - while(iter != end && !(*iter)->isFocused()) ++iter; - if(iter == end) - return; - T prev_iter = iter; - while(prev_iter != begin) + for (T iter = begin; iter != end; ++iter) { - const LLAvatarListEntry& entry = *((--prev_iter)->get()); - if(entry.isInList() && (entry.isMarked() || !marked_only) && gAgentCamera.lookAtObject(entry.getID(), false)) + LLAvatarListEntry& old = *(iter->get()); + if (!old.isFocused()) continue; + for (T prev = prev_iter(iter, begin, end); prev != iter; prev = prev_iter(prev, begin, end)) { - (*iter)->setFocus(FALSE); - (*prev_iter)->setFocus(TRUE); - gAgentCamera.lookAtObject((*prev_iter)->getID(), false); - return; + LLAvatarListEntry& entry = *(prev->get()); + if (!entry.isInList()) continue; + if (marked_only && !entry.isMarked()) continue; + if (gAgentCamera.lookAtObject(entry.getID(), false)) + { + old.setFocus(false); + entry.setFocus(true); + return; + } } + // Nothing else to focus + break; } - gAgentCamera.lookAtObject((*iter)->getID(), false); } void LLFloaterAvatarList::focusOnPrev(BOOL marked_only) diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 095034be9..303b985c7 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -418,6 +418,7 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) std::string fullname; BOOL have_name = LLAvatarNameCache::getPNSName(agent_id, fullname); + if (!have_name) gCacheName->getFullName(agent_id, fullname); LLSD element; element["id"] = agent_id; @@ -426,9 +427,11 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) friend_column["value"] = fullname; friend_column["font"] = "SANSSERIF"; friend_column["font-style"] = "NORMAL"; + /* Singu TODO: Liru will fix this up to actually work later static const LLCachedControl sDefaultColor(gColors, "DefaultListText"); static const LLCachedControl sMutedColor("AscentMutedColor"); - friend_column["color"] = ll_sd_from_color4(LLAvatarActions::isBlocked(agent_id) ? sMutedColor : sDefaultColor); + friend_column["color"] = LLAvatarActions::isBlocked(agent_id) ? sMutedColor : sDefaultColor; + */ LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS]; online_status_column["column"] = "icon_online_status"; @@ -503,6 +506,7 @@ BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationsh std::string fullname; BOOL have_name = LLAvatarNameCache::getPNSName(agent_id, fullname); + if (!have_name) gCacheName->getFullName(agent_id, fullname); // Name of the status icon to use std::string statusIcon; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1902f115d..16c33c6b5 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4275,7 +4275,7 @@ void LLModelPreview::updateStatusMessages() std::string img = lod_status_image[upload_status[lod]]; LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); icon->setVisible(true); - icon->setImage(img); + icon->setValue(img); if (upload_status[lod] >= 2) { @@ -4286,7 +4286,7 @@ void LLModelPreview::updateStatusMessages() { mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); icon = mFMP->getChild("lod_status_message_icon"); - icon->setImage(img); + icon->setValue(img); } updateLodControls(lod); diff --git a/indra/newview/llgroupnotify.cpp b/indra/newview/llgroupnotify.cpp index ca9c834f8..5d31f8acb 100644 --- a/indra/newview/llgroupnotify.cpp +++ b/indra/newview/llgroupnotify.cpp @@ -163,7 +163,7 @@ LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject, { icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+ICON_WIDTH, y-ICON_WIDTH), - group_insignia); + group_insignia.asString()); } else { diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index efdafd28e..abae430f6 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1390,7 +1390,7 @@ void LLFloaterIMPanel::sendTypingState(bool typing) return; // Don't want to send typing indicators to multiple people, potentially too // much network traffic. Only send in person-to-person IMs. - if (mSessionType == P2P_SESSION) return; + if (mSessionType != P2P_SESSION) return; std::string name; gAgent.buildFullname(name); diff --git a/indra/newview/llmediaremotectrl.cpp b/indra/newview/llmediaremotectrl.cpp index b5841d2f4..c044496dc 100644 --- a/indra/newview/llmediaremotectrl.cpp +++ b/indra/newview/llmediaremotectrl.cpp @@ -293,7 +293,7 @@ void LLMediaRemoteCtrl::enableMediaButtons() mMusicIcon->setColor(music_icon_color); if(!media_icon_name.empty()) { - media_icon->setImage(media_icon_name); + media_icon->setValue(media_icon_name); } media_play_btn->setEnabled(play_media_enabled); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index d7bac5e12..fb558b3da 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -266,7 +266,7 @@ public: ~LLMeshLODResponder() { - if (!LLApp::isQuitting()) + if (!LLApp::isExiting()) { if (!mProcessed) { diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 39c86e307..74c591f1e 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -310,7 +310,7 @@ void LLPanelGroupNotices::setItem(LLPointer inv_item) inv_item->getFlags(), item_is_multi ); - mCreateInventoryIcon->setImage(icon_name); + mCreateInventoryIcon->setValue(icon_name); mCreateInventoryIcon->setVisible(TRUE); std::stringstream ss; @@ -541,7 +541,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType, LLInventoryType::IT_TEXTURE); - mViewInventoryIcon->setImage(icon_name); + mViewInventoryIcon->setValue(icon_name); mViewInventoryIcon->setVisible(TRUE); std::stringstream ss; diff --git a/indra/newview/llpanelnetwork.cpp b/indra/newview/llpanelnetwork.cpp index 95b91731b..05821a8a8 100644 --- a/indra/newview/llpanelnetwork.cpp +++ b/indra/newview/llpanelnetwork.cpp @@ -118,12 +118,7 @@ LLPanelNetwork::~LLPanelNetwork() void LLPanelNetwork::apply() { - U32 cache_size = (U32)childGetValue("cache_size").asInteger(); - if (gSavedSettings.getU32("CacheSize") != cache_size) - { - onClickClearCache(this); - gSavedSettings.setU32("CacheSize", cache_size); - } + gSavedSettings.setU32("CacheSize", childGetValue("cache_size").asInteger()); gSavedSettings.setF32("ThrottleBandwidthKBPS", childGetValue("max_bandwidth").asReal()); gSavedSettings.setF32("HTTPThrottleBandwidth", childGetValue("tex_bandwidth").asReal()); gSavedSettings.setBOOL("ImagePipelineUseHTTP", childGetValue("http_textures")); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index bb2b9c539..31bf42abd 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -51,6 +51,8 @@ const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024; const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate) +static std::queue sgDelayedPurgeQueue; + class LLTextureCacheWorker : public LLWorkerClass { friend class LLTextureCache; @@ -1541,6 +1543,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) llinfos << "The entire texture cache is cleared." << llendl; } +void LLTextureCache::performDelayedPurge() +{ + LLMutexLock lock(&mHeaderMutex); + while(!sgDelayedPurgeQueue.empty()) + { + removeFromCache(sgDelayedPurgeQueue.front()); + sgDelayedPurgeQueue.pop(); + if (mTexturesSizeTotal < sCacheMaxTexturesSize) + { + break; + } + } +} + void LLTextureCache::purgeTextures(bool validate) { if (mReadOnly) @@ -1558,6 +1574,9 @@ void LLTextureCache::purgeTextures(bool validate) llinfos << "TEXTURE CACHE: Purging." << llendl; + std::queue empty; + std::swap(sgDelayedPurgeQueue, empty); + // Read the entries list std::vector entries; U32 num_entries = openAndReadEntries(entries); @@ -1567,8 +1586,8 @@ void LLTextureCache::purgeTextures(bool validate) } // Use mTexturesSizeMap to collect UUIDs of textures with bodies - typedef std::set > time_idx_set_t; - std::set > time_idx_set; + typedef std::vector > time_idx_set_t; + time_idx_set_t time_idx_set; for (size_map_t::iterator iter1 = mTexturesSizeMap.begin(); iter1 != mTexturesSizeMap.end(); ++iter1) { @@ -1578,7 +1597,7 @@ void LLTextureCache::purgeTextures(bool validate) if (iter2 != mHeaderIDMap.end()) { S32 idx = iter2->second; - time_idx_set.insert(std::make_pair(entries[idx].mTime, idx)); + time_idx_set.push_back(std::make_pair(entries[idx].mTime, idx)); // llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl; } else @@ -1587,6 +1606,8 @@ void LLTextureCache::purgeTextures(bool validate) } } } + + std::sort(time_idx_set.begin(), time_idx_set.end()); // Validate 1/256th of the files on startup U32 validate_idx = 0; @@ -1637,7 +1658,14 @@ void LLTextureCache::purgeTextures(bool validate) purge_count++; LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; cache_size -= entries[idx].mBodySize; - removeEntry(idx, entries[idx], filename) ; + if(validate) + { + removeEntry(idx, entries[idx], filename); + } + else + { + sgDelayedPurgeQueue.push(entries[idx].mID); + } } } @@ -1791,7 +1819,7 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio delete responder; return LLWorkerThread::nullHandle(); } - if (mDoPurge) + if (sgDelayedPurgeQueue.empty() && mDoPurge) { // NOTE: This may cause an occasional hiccup, // but it really needs to be done on the control thread @@ -1799,6 +1827,7 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio purgeTextures(false); mDoPurge = FALSE; } + performDelayedPurge(); LLMutexLock lock(&mWorkersMutex); LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, data, datasize, 0, diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index ac6ac0227..2715ef2c4 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -146,6 +146,7 @@ private: void setDirNames(ELLPath location); void readHeaderCache(); void clearCorruptedCache(); + void performDelayedPurge(); void purgeAllTextures(bool purge_directories); void purgeTextures(bool validate); LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset); diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 1a66b2489..842ffc7f9 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -94,10 +94,10 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible) switch (badge) { default: - case BADGE_OK: child->setImage(std::string("badge_ok.j2c")); break; - case BADGE_NOTE: child->setImage(std::string("badge_note.j2c")); break; - case BADGE_WARN: child->setImage(std::string("badge_warn.j2c")); break; - case BADGE_ERROR: child->setImage(std::string("badge_error.j2c")); break; + case BADGE_OK: child->setValue(std::string("badge_ok.j2c")); break; + case BADGE_NOTE: child->setValue(std::string("badge_note.j2c")); break; + case BADGE_WARN: child->setValue(std::string("badge_warn.j2c")); break; + case BADGE_ERROR: child->setValue(std::string("badge_error.j2c")); break; } } } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 23e407d40..c8f2d4c9a 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -693,6 +693,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("SHRenderSSAOResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2)); gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2)); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7c2c5a898..a27bbedb4 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5287,10 +5287,19 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from gestures if they are not enabled. - if (object_id == owner_id && !gSavedSettings.getBOOL("EnableGestureSounds")) + if (object_id == owner_id) { - // Don't mute own gestures, if they're not muted. - if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableGestureSoundsSelf")) + if (!gSavedSettings.getBOOL("EnableGestureSounds")) + { + // Don't mute own gestures, if they're not muted. + if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableGestureSoundsSelf")) + return; + } + } + else if (!gSavedSettings.getBOOL("EnableNongestureSounds")) + { + // Don't mute own non-gestures, if they're not muted. + if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableNongestureSoundsSelf")) return; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 6df2a4f28..93b4e6b5a 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -206,6 +206,8 @@ LLGLSLShader gDeferredLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShaderArray gDeferredMultiLightProgram[16]; LLGLSLShader gDeferredSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredMultiSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredSSAOProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredDownsampleDepthNearestProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSunProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredBlurLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSoftenProgram(LLViewerShaderMgr::SHADER_DEFERRED); @@ -1336,6 +1338,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredSunProgram.createShader(NULL, NULL); } + if(gSavedSettings.getBOOL("RenderDeferredSSAO")) + { + if (success) + { + gDeferredSSAOProgram.mName = "Deferred Ambient Occlusion Shader"; + gDeferredSSAOProgram.mShaderFiles.clear(); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/SSAOF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSSAOProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSSAOProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredDownsampleDepthNearestProgram.mName = "Deferred Nearest Downsample Depth Shader"; + gDeferredDownsampleDepthNearestProgram.mShaderFiles.clear(); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/downsampleDepthNearestF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredDownsampleDepthNearestProgram.createShader(NULL, NULL); + } + } + if (success) { gDeferredBlurLightProgram.mName = "Deferred Blur Light Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 320c25828..99374c31a 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -313,6 +313,8 @@ extern LLGLSLShaderArray gDeferredMultiLig extern LLGLSLShader gDeferredSpotLightProgram; extern LLGLSLShader gDeferredMultiSpotLightProgram; extern LLGLSLShader gDeferredSunProgram; +extern LLGLSLShader gDeferredSSAOProgram; +extern LLGLSLShader gDeferredDownsampleDepthNearestProgram; extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index a1fbd85a3..10c924225 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1270,7 +1270,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mNeedsCreateTexture = FALSE; if (mRawImage.isNull()) { - llerrs << "LLViewerTexture trying to create texture with no Raw Image" << llendl; + llwarns << "LLViewerTexture trying to create texture with no Raw Image" << llendl; } // llinfos << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", // mRawDiscardLevel, @@ -1712,7 +1712,7 @@ bool LLViewerFetchedTexture::updateFetch() } if (mIsMissingAsset) { - llassert_always(!mHasFetcher); + llassert(!mHasFetcher); return false; // skip } if (!mLoadedCallbackList.empty() && mRawImage.notNull()) @@ -1942,8 +1942,8 @@ bool LLViewerFetchedTexture::updateFetch() mHasFetcher = FALSE; } } - - llassert_always(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid)); + + llassert(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid)); return mIsFetching ? true : false; } diff --git a/indra/newview/llvoiceremotectrl.cpp b/indra/newview/llvoiceremotectrl.cpp index 1863020f9..7566db6b1 100644 --- a/indra/newview/llvoiceremotectrl.cpp +++ b/indra/newview/llvoiceremotectrl.cpp @@ -154,7 +154,7 @@ void LLVoiceRemoteCtrl::draw() LLIconCtrl* icon = mVoiceVolIcon; if (icon) { - icon->setImage(talk_blip_image); + icon->setValue(talk_blip_image); } LLFloater* voice_floater = LLFloaterChatterBox::getInstance()->getCurrentVoiceFloater(); @@ -185,7 +185,7 @@ void LLVoiceRemoteCtrl::draw() LLIconCtrl* voice_channel_icon = findChild("voice_channel_icon"); if (voice_channel_icon && voice_floater) { - voice_channel_icon->setImage(voice_floater->getString("voice_icon")); + voice_channel_icon->setValue(voice_floater->getString("voice_icon")); } if (voice_channel_bg) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index e6aec53bb..7d2095334 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -207,11 +207,11 @@ LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); -static LLStaticHashedString sTint("tint"); -static LLStaticHashedString sAmbiance("ambiance"); -static LLStaticHashedString sAlphaScale("alpha_scale"); +//static LLStaticHashedString sTint("tint"); +//static LLStaticHashedString sAmbiance("ambiance"); +//static LLStaticHashedString sAlphaScale("alpha_scale"); static LLStaticHashedString sNormMat("norm_mat"); -static LLStaticHashedString sOffset("offset"); +//static LLStaticHashedString sOffset("offset"); static LLStaticHashedString sScreenRes("screenRes"); static LLStaticHashedString sDelta("delta"); static LLStaticHashedString sDistFactor("dist_factor"); @@ -796,12 +796,15 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mSampleBuffer.release(); mScreen.release(); + mDeferredDownsampledDepth.release(); + if (LLPipeline::sRenderDeferred) { - S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO"); - BOOL RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField"); + static const LLCachedControl shadow_detail("RenderShadowDetail",0); + static const LLCachedControl ssao ("RenderDeferredSSAO",false); + static const LLCachedControl RenderDepthOfField("RenderDepthOfField",false); static const LLCachedControl RenderShadowResolutionScale("RenderShadowResolutionScale",1.0f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); const U32 occlusion_divisor = 3; @@ -835,6 +838,11 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) 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; + if(ssao) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if( scale < 1.f && !mDeferredDownsampledDepth.allocate(llceil(F32(resX)*scale), llceil(F32(resY)*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE) ) return false; + } } else { @@ -901,6 +909,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mScreen.release(); mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first mDeferredDepth.release(); + mDeferredDownsampledDepth.release(); mOcclusionDepth.release(); if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; @@ -1022,6 +1031,7 @@ void LLPipeline::releaseScreenBuffers() mPhysicsDisplay.release(); mDeferredScreen.release(); mDeferredDepth.release(); + mDeferredDownsampledDepth.release(); mDeferredLight.release(); mOcclusionDepth.release(); @@ -7648,6 +7658,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n static const LLCachedControl RenderSpotShadowBias("RenderSpotShadowBias",0.f); static const LLCachedControl RenderEdgeDepthCutoff("RenderEdgeDepthCutoff",.01f); static const LLCachedControl RenderEdgeNormCutoff("RenderEdgeNormCutoff",.25f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); if (noise_map == 0xFFFFFFFF) { @@ -7677,10 +7688,21 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + S32 channel2 = shader.enableTexture(LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH, mDeferredDepth.getUsage()); channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); - if (channel > -1) + if (channel > -1 || channel2 >= -1) { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel > -1) + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel2 > -1) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if(scale < 1.f) + gGL.getTexUnit(channel2)->bind(&mDeferredDownsampledDepth, TRUE); + else + gGL.getTexUnit(channel2)->bind(&mDeferredDepth, TRUE); //Bind full res depth instead, as downsampling is disabled if scale == 1.f + } + //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); stop_glerror(); @@ -7774,21 +7796,24 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); - F32 mat[16*6]; - for (U32 i = 0; i < 16; i++) + if(shader.getUniformLocation(LLShaderMgr::DEFERRED_SHADOW_MATRIX) >= 0) { - 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]; + 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(); } - shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); - - stop_glerror(); - channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); if (channel > -1) { @@ -7844,6 +7869,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); } + + shader.uniform1f(LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH_SCALE, llclamp(RenderSSAOResolutionScale.get(),.01f,1.f)); } static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); @@ -7867,6 +7894,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); @@ -7933,6 +7961,54 @@ void LLPipeline::renderDeferredLighting() gGL.pushMatrix(); gGL.loadIdentity(); + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + + LLGLDisable blend(GL_BLEND); + + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) + { + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram, 0); + gDeferredDownsampleDepthNearestProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); + } + + //Run SSAO + { + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram, 0); + if(ssao_scale < 1.f) + { + glViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + gDeferredSSAOProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + } + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); + } + } + if (RenderDeferredSSAO || RenderShadowDetail > 0) { mDeferredLight.bindTarget(); @@ -7944,7 +8020,7 @@ void LLPipeline::renderDeferredLighting() mDeferredLight.clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + /*glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); const U32 slice = 32; F32 offset[slice*3]; @@ -7978,8 +8054,18 @@ void LLPipeline::renderDeferredLighting() } } - gDeferredSunProgram.uniform3fv(sOffset, slice, offset); + gDeferredSunProgram.uniform3fv(sOffset, slice, offset);*/ + gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); + + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } { LLGLDisable blend(GL_BLEND); @@ -7988,6 +8074,11 @@ void LLPipeline::renderDeferredLighting() mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); stop_glerror(); } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } unbindDeferredShader(gDeferredSunProgram); } @@ -8106,6 +8197,9 @@ void LLPipeline::renderDeferredLighting() gPipeline.pushRenderTypeMask(); gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS + LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::END_RENDER_TYPES); @@ -8500,6 +8594,7 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); @@ -8560,6 +8655,54 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) gGL.pushMatrix(); gGL.loadIdentity(); + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + + LLGLDisable blend(GL_BLEND); + + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) + { + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram, 0); + gDeferredDownsampleDepthNearestProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); + } + + //Run SSAO + { + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram, 0); + if(ssao_scale < 1.f) + { + glViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + gDeferredSSAOProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredDownsampledDepth.getWidth()/ssao_scale, mDeferredDownsampledDepth.getHeight()/ssao_scale); + } + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + { + LLGLDepthTest depth(GL_FALSE); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); + } + } + if (RenderDeferredSSAO || RenderShadowDetail > 0) { mDeferredLight.bindTarget(); @@ -8571,7 +8714,7 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) mDeferredLight.clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + /*glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); const U32 slice = 32; F32 offset[slice*3]; @@ -8590,9 +8733,18 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) } } - gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset); + gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset);*/ gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight()); + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + { LLGLDisable blend(GL_BLEND); LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); @@ -8600,6 +8752,11 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); stop_glerror(); } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } unbindDeferredShader(gDeferredSunProgram); } @@ -8656,7 +8813,10 @@ void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) gPipeline.pushRenderTypeMask(); gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif + LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, LLPipeline::END_RENDER_TYPES); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 453512d80..6a7d7479d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -615,6 +615,7 @@ public: LLRenderTarget mFXAABuffer; LLRenderTarget mEdgeMap; LLRenderTarget mDeferredDepth; + LLRenderTarget mDeferredDownsampledDepth; LLRenderTarget mOcclusionDepth; LLRenderTarget mDeferredLight; LLMultisampleBuffer mSampleBuffer; diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml index 32ad53d84..aadd1526c 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml @@ -5,6 +5,10 @@ + UI Hidden in mouselook: + + + Movement Options: @@ -13,7 +17,8 @@ Camera Follow Distance: - + +