From 78e3d61b982723f268bee00d0acb9f11f08c0834 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 28 Nov 2013 21:07:25 -0600 Subject: [PATCH 01/22] Remove ambient occlusion darkening from all deferred shaders except the one that actually calculates occlusion values.. (aka every shader except class2/softenLightF.glsl) --- .../shaders/class1/deferred/alphaF.glsl | 15 ++------------- .../shaders/class1/deferred/materialF.glsl | 15 ++------------- .../shaders/class1/deferred/softenLightF.glsl | 8 ++------ 3 files changed, 6 insertions(+), 32 deletions(-) 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/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); From f3ca4b6e344b33bdddde6d768a204d9a97ed2d67 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sun, 1 Dec 2013 00:33:04 -0500 Subject: [PATCH 02/22] Fix Issue 1222 by changing the default Field of View for mouselook zoom Smooth scroll changes the meaning of the numbers, unfortunately.. so for those who haven't figured out how to customize their mouselook zoom, this'll hafta do. Also clarified the description of the debug. SV-1222 #close Fixed up, will require a reset of the debug setting "zmm_mlfov", clean install, or just scroll to modify it. --- indra/newview/app_settings/settings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 60420a247..3989bfa37 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -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 From bbb55b0b4daa89997cc1fb71d0c8dd945bb0444f Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sun, 1 Dec 2013 11:56:45 -0500 Subject: [PATCH 03/22] LLUICtrl support for "enabled_control" and "disabled_control" attributes from upstream. --- indra/llui/lluictrl.cpp | 62 ++++++++++++++++++++++++++++++++++++++++- indra/llui/lluictrl.h | 7 +++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 56bac0e92..a791c9c48 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -43,6 +43,8 @@ static LLRegisterWidget r("ui_ctrl"); LLUICtrl::LLUICtrl() : mViewModel(LLViewModelPtr(new LLViewModel)), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), mMakeVisibleControlVariable(NULL), mMakeInvisibleControlVariable(NULL), mCommitSignal(NULL), @@ -67,6 +69,10 @@ LLUICtrl::LLUICtrl(const std::string& name, const LLRect rect, BOOL mouse_opaque : // 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 ), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), + mMakeVisibleControlVariable(NULL), + mMakeInvisibleControlVariable(NULL), mCommitSignal(NULL), mValidateSignal(NULL), mViewModel(LLViewModelPtr(new LLViewModel)), @@ -227,6 +233,36 @@ LLViewModel* LLUICtrl::getViewModel() const return mViewModel; } +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 +298,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; @@ -667,6 +713,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); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index ba6acc98e..bdf290ba4 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -87,6 +87,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); @@ -192,6 +195,10 @@ protected: LLViewModelPtr mViewModel; + LLControlVariable* mEnabledControlVariable; + boost::signals2::connection mEnabledControlConnection; + LLControlVariable* mDisabledControlVariable; + boost::signals2::connection mDisabledControlConnection; LLControlVariable* mMakeVisibleControlVariable; boost::signals2::connection mMakeVisibleControlConnection; LLControlVariable* mMakeInvisibleControlVariable; From 9723a45e72833ce40e3ba5241af50cdd5895f26c Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sun, 1 Dec 2013 15:58:24 -0500 Subject: [PATCH 04/22] Modernize LLIconCtrl Adds min_height and min_width attributes Adds mPriority for controlling priority with which to call LLUI::getUIImage* Moves specialized setImage()s into setValue Removes mImageName and mImageID, value is stored in base as LLSD now --- indra/llui/lliconctrl.cpp | 99 ++++++++++++------------- indra/llui/lliconctrl.h | 24 +++--- indra/newview/llfloatermodelpreview.cpp | 4 +- indra/newview/llgroupnotify.cpp | 2 +- indra/newview/llmediaremotectrl.cpp | 2 +- indra/newview/llpanelgroupnotices.cpp | 4 +- indra/newview/llviewchildren.cpp | 8 +- indra/newview/llvoiceremotectrl.cpp | 4 +- 8 files changed, 72 insertions(+), 75 deletions(-) diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 90b313d45..e5b53ba38 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -40,68 +40,32 @@ #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 ) -{ - setImage( image_id ); - 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 +84,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 +127,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 +154,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..79f08a795 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -49,33 +49,35 @@ 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); + 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; + private: LLColor4 mColor; - std::string mImageName; - LLUUID mImageID; LLPointer mImagep; }; 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/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/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/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/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) From 23958965aa9aa8cbb2c84866dd552c8bf924a41b Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 2 Dec 2013 00:27:50 -0500 Subject: [PATCH 05/22] LLInitParam/LLUI Params enhancement Specialized param handling for common linden types And pre-viewer-interesting modernized llinitparam.* (includes llsdparam.cpp update) --- indra/llcommon/llinitparam.cpp | 82 +- indra/llcommon/llinitparam.h | 1731 ++++++++++++++++++++------------ indra/llcommon/llsdparam.cpp | 51 +- indra/llrender/llfontgl.cpp | 42 + indra/llrender/llfontgl.h | 5 + indra/llui/llui.cpp | 224 +++++ indra/llui/llui.h | 101 ++ 7 files changed, 1496 insertions(+), 740 deletions(-) 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 010dcf940..72ae548cd 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -1046,6 +1046,13 @@ std::string LLFontGL::nameFromFont(const LLFontGL* fontp) return fontp->getFontDesc().getName(); } + +// static +std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) +{ + return fontp->getFontDesc().getSize(); +} + // static std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align) { @@ -1162,6 +1169,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 9476382eb..0bb69fa68 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/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 From 4116ac75f6e599127cb317ad0e8e31cb131dbeb5 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 2 Dec 2013 20:17:48 -0500 Subject: [PATCH 06/22] LLUICtrl Params Also adds support for requests_front boolean attribute to lluictrl from upstream --- indra/llui/lluictrl.cpp | 265 ++++++++++++++++++++++++++++++++++++++-- indra/llui/lluictrl.h | 101 ++++++++++++++- 2 files changed, 348 insertions(+), 18 deletions(-) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index a791c9c48..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,67 @@ 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), @@ -56,26 +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), @@ -83,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) @@ -113,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) @@ -136,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); @@ -233,6 +431,36 @@ 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) @@ -429,7 +657,6 @@ void LLUICtrl::setIsChrome(BOOL is_chrome) // virtual BOOL LLUICtrl::getIsChrome() const { - LLView* parent_ctrl = getParent(); while(parent_ctrl) { @@ -579,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. @@ -664,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; @@ -787,6 +1017,7 @@ boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::functionconnect(boost::bind(cb, _2)); } + // virtual void LLUICtrl::setTentative(BOOL b) { @@ -816,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 bdf290ba4..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; @@ -116,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); @@ -124,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 @@ -139,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 ); @@ -205,8 +293,9 @@ protected: boost::signals2::connection mMakeInvisibleControlConnection; private: - BOOL mTabStop; BOOL mIsChrome; + BOOL mRequestsFront; + BOOL mTabStop; BOOL mTentative; bool mCommitOnReturn; From b4d089650797f3a972fd5f0fd9bb02d0b45387ba Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 2 Dec 2013 20:30:59 -0500 Subject: [PATCH 07/22] Fixups to mistakes of the past. --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llfloaterfriends.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3989bfa37..295393d41 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -223,7 +223,7 @@ zmm_mlfov Comment - Adjusted when scrolling back and forth while holding rightclick in mouselook (Zoomed in < 1.037 < Zoomed out) + Adjusted when scrolling back and forth while holding rightclick in mouselook (Zoomed in < 1.037 < Zoomed out) Persist 1 Type diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index b8f155914..4d7091c56 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -426,9 +426,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"] = LLAvatarActions::isBlocked(agent_id) ? sMutedColor : sDefaultColor; + */ LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS]; online_status_column["column"] = "icon_online_status"; From 8fb281289967c5332ed61ba262633730603b754b Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 2 Dec 2013 20:45:07 -0500 Subject: [PATCH 08/22] LLIconCtrl Params --- indra/llui/lliconctrl.cpp | 24 ++++++++++++++++++++++++ indra/llui/lliconctrl.h | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index e5b53ba38..fecdce432 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -44,6 +44,30 @@ static LLRegisterWidget r("icon"); +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) +{ + if (mImagep.notNull()) + { + LLUICtrl::setValue(mImagep->getName()); + } + setTabStop(false); +} LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name, const S32& min_width, const S32& min_height) : LLUICtrl(name, diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 79f08a795..16f4c4238 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -48,6 +48,22 @@ class LLUICtrlFactory; class LLIconCtrl : public LLUICtrl { +public: + 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(); @@ -76,6 +92,10 @@ protected: 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; LLPointer mImagep; From f988cd36b642bbb0967bb65a163917ae734643e9 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Mon, 2 Dec 2013 22:45:44 -0500 Subject: [PATCH 09/22] Attempt to fix Issue 1264: Vacant lines in Friends list --- indra/newview/llfloaterfriends.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 4d7091c56..955af629d 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; @@ -505,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; From 062973aaaf4a4cc6a83da507ec99607f861dbf1f Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 6 Dec 2013 08:43:28 -0500 Subject: [PATCH 10/22] Default SinguOffsetScrollKeys to false and expose it in Camera prefs. Adds "Scrolling with control and/or shift held adjusts camera position" to Input & Camera prefs --- indra/newview/app_settings/settings.xml | 2 +- .../skins/default/xui/en-us/panel_preferences_input.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9224dbd5a..ed558e669 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 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..cdbc28c25 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 @@ -13,7 +13,8 @@ Camera Follow Distance: - + + From 36d8df602c14049e6c5a44df6aef7eaee96d0411 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 6 Dec 2013 13:10:12 -0500 Subject: [PATCH 11/22] [Radar] Feature request: Have Focus Next/Prev wrap around when it reaches the end --- indra/newview/llfloateravatarlist.cpp | 35 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 13 deletions(-) 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) From a59940c592c2d738e1787e56148240b1e9c83848 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sun, 8 Dec 2013 14:21:39 -0500 Subject: [PATCH 12/22] Fix Issue 1273: Typing in Group Chat opens IM Window for other participants Broken logic, my bad. --- indra/newview/llimpanel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From e182173ee29235a777da980c5586e766e16bb022 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Mon, 9 Dec 2013 03:39:47 +0100 Subject: [PATCH 13/22] Fatal paranoia cure --- indra/llcharacter/llkeyframemotion.cpp | 4 +++- indra/newview/llappviewer.cpp | 17 ++++++++++------- indra/newview/llviewertexture.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 12 deletions(-) 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/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/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; } From 64e7be0321e9505a31ef7f2533976cef80e8ed38 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Mon, 9 Dec 2013 08:35:21 +0100 Subject: [PATCH 14/22] This should make the cache-full situation a lot more benign I should be ashamed of myself, i took ugly, terrible code and uglied it up even more. --- indra/newview/llpanelnetwork.cpp | 7 +----- indra/newview/lltexturecache.cpp | 39 ++++++++++++++++++++++++++++---- indra/newview/lltexturecache.h | 1 + 3 files changed, 36 insertions(+), 11 deletions(-) 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); From 13f26e6b5ade569477742cfd41a56a847fcf0d07 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Tue, 10 Dec 2013 15:56:07 -0500 Subject: [PATCH 15/22] Feature request: Add EnableNongestureSounds as an opposite to gesture mute --- indra/newview/app_settings/settings.xml | 22 ++++++++++++++++++++++ indra/newview/llviewermessage.cpp | 15 ++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ed558e669..6b6ab0ab0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6153,6 +6153,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/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; } From c5adb01ed952df2b0ea47f5ca9700bf49ee6e9e3 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Tue, 10 Dec 2013 23:11:07 +0100 Subject: [PATCH 16/22] Stop occasional crash during shutdown --- indra/llcommon/llapp.cpp | 2 +- indra/newview/llmeshrepository.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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) { From edabdcf7248590e257f6b08d836ad7778f16cfc6 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Wed, 11 Dec 2013 15:57:05 -0500 Subject: [PATCH 17/22] log_sStringTemplates_accesses now spews lldebugs, not llinfos --- indra/llui/lltrans.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 7da8b012e62a5ec4ae0219ac2c8d93ac0cc41bf3 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 13 Dec 2013 02:19:57 -0600 Subject: [PATCH 18/22] Pulled SSAO out into its own shader to support running at a lower-than-native framebuffer resolution (defaults at half-resolution [SHRenderSSAOResolutionScale=.5] ). This doesn't improve the slow ssao/shadow softening, however, as that bit remains unchanged. --- indra/llrender/llshadermgr.cpp | 2 + indra/llrender/llshadermgr.h | 2 + indra/newview/app_settings/settings_sh.xml | 11 + .../shaders/class1/deferred/SSAOF.glsl | 140 ++++++++++++ .../shaders/class1/deferred/blurLightF.glsl | 34 ++- .../deferred/downsampleDepthNearestF.glsl | 41 ++++ .../class1/deferred/sunLightSSAOF.glsl | 117 +--------- .../class2/deferred/sunLightSSAOF.glsl | 66 +----- indra/newview/llviewercontrol.cpp | 1 + indra/newview/llviewershadermgr.cpp | 25 +++ indra/newview/llviewershadermgr.h | 2 + indra/newview/pipeline.cpp | 210 +++++++++++++++--- indra/newview/pipeline.h | 1 + 13 files changed, 445 insertions(+), 207 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl 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/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/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/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/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/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/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; From 9014d56957496257c6d803d81b412414aff52d2f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 13 Dec 2013 02:21:54 -0600 Subject: [PATCH 19/22] Fix 'setBuffer: Shader consumption mismatches data provision.' error in LLPipeline::updateCull. Issue caused by LLDrawPoolAlpha not unbinding shaders when only basic shaders are enabled. https://code.google.com/p/singularity-viewer/issues/detail?id=1281 --- indra/newview/lldrawpoolalpha.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); } From 2642a1c3ffee1442319aab57200b744b53c82a93 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sat, 14 Dec 2013 00:00:52 -0500 Subject: [PATCH 20/22] [Warnings] Fix class/struct inconsistency. --- indra/llui/llnotifications.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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) { } From b22cc2c2fab36deff7e2639a30c4a2c55a7413ea Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sat, 14 Dec 2013 00:05:10 -0500 Subject: [PATCH 21/22] [Warnings] Fixed warning: "_FORTIFY_SOURCE" redefined [enabled by default] --- indra/cmake/00-Common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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! From 649c29674c63ef39551f75570862941ed889b443 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Sat, 14 Dec 2013 20:48:48 -0500 Subject: [PATCH 22/22] Feature Request: User control over which UI will become hidden when going into mouselook. Adds three checkboxes to input and camera preferences: Floaters, Notices, and Menubar Should satisfy Issue 462. SV-462 #close Done~ --- indra/newview/app_settings/settings.xml | 33 +++++++++++++++++++ indra/newview/llagent.cpp | 20 +++++++---- .../xui/en-us/panel_preferences_input.xml | 4 +++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6b6ab0ab0..8b3a3524a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -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 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/skins/default/xui/en-us/panel_preferences_input.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_input.xml index cdbc28c25..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: