From da3002bd0c25cfe922db1e40e46e48de9201501f Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <gavriliuk@gmail.com>
Date: Sun, 12 Feb 2023 13:37:08 +0100
Subject: SL-18964 Move creating of LLViewerFetchedTexture::sSmokeImagep to
 LLDrawPoolAlpha::renderDebugAlpha()

---
 indra/newview/lldrawpoolalpha.cpp | 7 +++++++
 indra/newview/llviewertexture.cpp | 4 ++++
 2 files changed, 11 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 6c1abb24c9..d4797321bb 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -280,6 +280,13 @@ void LLDrawPoolAlpha::renderDebugAlpha()
 	{
         gHighlightProgram.bind();
         gGL.diffuseColor4f(1, 0, 0, 1);
+
+        // SL-18964 : The creating of this texture was moved here from LLViewerTextureManager::init() to make the texture transparent before adding to cache
+        if (!LLViewerFetchedTexture::sSmokeImagep)
+        {
+            LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
+            LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
+        }
         LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f);
         gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index e3ac56d0d3..0d82aced23 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -402,8 +402,12 @@ void LLViewerTextureManager::init()
 	LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
 	LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER);
 
+#if 0
+	// When called first time after clearing cache this call creates (and adds to cache) an opaque texture instead of transparent
+	// SL-18964 : The creating of this texture was moved to LLDrawPoolAlpha::renderDebugAlpha()
  	LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
 	LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
+#endif
 
 	image_raw = new LLImageRaw(32,32,3);
 	data = image_raw->getData();
-- 
cgit v1.2.3


From 23a781317a12e7e46124a05efd1a6849a39438b3 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Feb 2023 02:45:58 +0200
Subject: SL-19196 Nearby chat bar moves down every time it gains focus

---
 indra/newview/llfloaterimnearbychat.cpp | 2 ++
 indra/newview/llfloaterimsessiontab.cpp | 6 ++++++
 indra/newview/llfloaterimsessiontab.h   | 1 +
 3 files changed, 9 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index f1807f1c5b..0d2c6d8e4c 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -108,6 +108,8 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd)
 	mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing));
 	mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing));
 	mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing));
+
+    mMinFloaterHeight = EXPANDED_MIN_HEIGHT;
 }
 
 //static
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 78271369d2..af4e7f5aff 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -92,6 +92,8 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
     mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2));
     mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2));
     mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing));
+
+    mMinFloaterHeight = getMinHeight();
 }
 
 LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
@@ -934,10 +936,13 @@ void LLFloaterIMSessionTab::reshapeFloater(bool collapse)
 		S32 height = mContentPanel->getRect().getHeight() + mToolbarPanel->getRect().getHeight()
 			+ mChatLayoutPanel->getRect().getHeight() - mChatLayoutPanelHeight + 2;
 		floater_rect.mTop -= height;
+
+        setResizeLimits(getMinWidth(), floater_rect.getHeight());
 	}
 	else
 	{
 		floater_rect.mTop = floater_rect.mBottom + mFloaterHeight;
+        setResizeLimits(getMinWidth(), mMinFloaterHeight);
 	}
 
 	enableResizeCtrls(true, true, !collapse);
@@ -962,6 +967,7 @@ void LLFloaterIMSessionTab::restoreFloater()
 		setShape(floater_rect, true);
 		mBodyStack->updateLayout();
 		mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));
+        setResizeLimits(getMinWidth(), mMinFloaterHeight);
 		setMessagePaneExpanded(true);
 		saveCollapsedState();
 		mInputEditor->enableSingleLineMode(false);
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index 9f00917647..d478922617 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -152,6 +152,7 @@ protected:
 
 	bool mMessagePaneExpanded;
 	bool mIsParticipantListExpanded;
+    S32 mMinFloaterHeight;
 
 
 	LLIMModel::LLIMSession* mSession;
-- 
cgit v1.2.3


From 53c33ebf993a4c0424bd5ae8f5e9c42b528dc5e5 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <gavriliuk@gmail.com>
Date: Thu, 16 Feb 2023 02:11:46 +0100
Subject: SL-18246 Highlight 100% transparent faces for scripted objects

---
 indra/newview/llvovolume.cpp | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2e7ccc8334..108f5cd1d3 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5850,15 +5850,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						}
 						else
 						{
-                            if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
-                            { //only treat as alpha in the pipeline if < 100% transparent
-                                drawablep->setState(LLDrawable::HAS_ALPHA);
-                                add_face(sAlphaFaces, alpha_count, facep);
-                            }
-                            else if (LLDrawPoolAlpha::sShowDebugAlpha)
-                            {
-                                add_face(sAlphaFaces, alpha_count, facep);
-                            }
+							if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f)
+							{ //only treat as alpha in the pipeline if < 100% transparent
+								drawablep->setState(LLDrawable::HAS_ALPHA);
+								add_face(sAlphaFaces, alpha_count, facep);
+							}
+							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
+								gPipeline.sRenderHighlight &&
+								(LLPipeline::getRenderScriptedBeacons() || LLPipeline::getRenderScriptedTouchBeacons()) &&
+								drawablep->getVObj() && drawablep->getVObj()->flagScripted())
+							{ //draw the transparent face for debugging purposes using a custom texture
+								add_face(sAlphaFaces, alpha_count, facep);
+							}
 						}
 					}
 					else
-- 
cgit v1.2.3


From fe21f3fdf1e98eb2393449963f6bfd97b1885d44 Mon Sep 17 00:00:00 2001
From: Maxim Nikolenko <maximnproductengine@lindenlab.com>
Date: Thu, 23 Feb 2023 11:58:17 +0200
Subject: SL-19252 Remove "#ifdef _CORY_TESTING" code

---
 indra/newview/llfilepicker.cpp     | 34 ----------------------------------
 indra/newview/llfilepicker.h       |  6 ------
 indra/newview/llviewermenu.cpp     |  4 ----
 indra/newview/llviewermenufile.cpp |  7 -------
 indra/newview/llvovolume.cpp       |  4 ++--
 5 files changed, 2 insertions(+), 53 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index e3a695fc79..7379ac0da4 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -55,9 +55,6 @@ LLFilePicker LLFilePicker::sInstance;
 #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
 #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0"
 #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
-#ifdef _CORY_TESTING
-#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
-#endif
 #define XML_FILTER L"XML files (*.xml)\0*.xml\0"
 #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
 #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
@@ -197,12 +194,6 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 		mOFN.lpstrFilter = COLLADA_FILTER \
 			L"\0";
 		break;
-#ifdef _CORY_TESTING
-	case FFLOAD_GEOMETRY:
-		mOFN.lpstrFilter = GEOMETRY_FILTER \
-			L"\0";
-		break;
-#endif
 	case FFLOAD_XML:
 		mOFN.lpstrFilter = XML_FILTER \
 			L"\0";
@@ -480,18 +471,6 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,
 			L"XAF Anim File (*.xaf)\0*.xaf\0" \
 			L"\0";
 		break;
-#ifdef _CORY_TESTING
-	case FFSAVE_GEOMETRY:
-		if (filename.empty())
-		{
-			wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE);	/*Flawfinder: ignore*/
-		}
-		mOFN.lpstrDefExt = L"slg";
-		mOFN.lpstrFilter =
-			L"SLG SL Geometry File (*.slg)\0*.slg\0" \
-			L"\0";
-		break;
-#endif
 	case FFSAVE_XML:
 		if (filename.empty())
 		{
@@ -624,11 +603,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF
         case FFLOAD_COLLADA:
             allowedv->push_back("dae");
             break;
-#ifdef _CORY_TESTING
-        case FFLOAD_GEOMETRY:
-            allowedv->push_back("slg");
-            break;
-#endif
         case FFLOAD_XML:
             allowedv->push_back("xml");
             break;
@@ -727,14 +701,6 @@ bool	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena
 			creator = "\?\?\?\?";
 			extension = "xaf";
 			break;
-
-#ifdef _CORY_TESTING
-		case FFSAVE_GEOMETRY:
-			type = "\?\?\?\?";
-			creator = "\?\?\?\?";
-			extension = "slg";
-			break;
-#endif	
 			
 		case FFSAVE_XML:
 			type = "\?\?\?\?";
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index 73baeca1c0..8f2274024c 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -77,9 +77,6 @@ public:
 		FFLOAD_WAV = 2,
 		FFLOAD_IMAGE = 3,
 		FFLOAD_ANIM = 4,
-#ifdef _CORY_TESTING
-		FFLOAD_GEOMETRY = 5,
-#endif
 		FFLOAD_XML = 6,
 		FFLOAD_SLOBJECT = 7,
 		FFLOAD_RAW = 8,
@@ -99,9 +96,6 @@ public:
 		FFSAVE_BMP = 5,
 		FFSAVE_AVI = 6,
 		FFSAVE_ANIM = 7,
-#ifdef _CORY_TESTING
-		FFSAVE_GEOMETRY = 8,
-#endif
 		FFSAVE_XML = 9,
 		FFSAVE_COLLADA = 10,
 		FFSAVE_RAW = 11,
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index a0223a5dbb..8177353083 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -276,10 +276,6 @@ void handle_object_owner_permissive(void*);
 void handle_object_lock(void*);
 void handle_object_asset_ids(void*);
 void force_take_copy(void*);
-#ifdef _CORY_TESTING
-void force_export_copy(void*);
-void force_import_geometry(void*);
-#endif
 
 void handle_force_parcel_owner_to_me(void*);
 void handle_force_parcel_to_content(void*);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index fdf1d04c09..f9ec1115a6 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -277,9 +277,6 @@ void LLMediaFilePicker::notify(const std::vector<std::string>& filenames)
 static std::string SOUND_EXTENSIONS = "wav";
 static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
 static std::string ANIM_EXTENSIONS =  "bvh anim";
-#ifdef _CORY_TESTING
-static std::string GEOMETRY_EXTENSIONS = "slg";
-#endif
 static std::string XML_EXTENSIONS = "xml";
 static std::string SLOBJECT_EXTENSIONS = "slobject";
 #endif
@@ -301,10 +298,6 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 		return SLOBJECT_EXTENSIONS;
 	case LLFilePicker::FFLOAD_MODEL:
 		return MODEL_EXTENSIONS;
-#ifdef _CORY_TESTING
-	case LLFilePicker::FFLOAD_GEOMETRY:
-		return GEOMETRY_EXTENSIONS;
-#endif
 	case LLFilePicker::FFLOAD_XML:
 	    return XML_EXTENSIONS;
     case LLFilePicker::FFLOAD_ALL:
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 108f5cd1d3..b910c4f93c 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5856,9 +5856,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
 							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
-								gPipeline.sRenderHighlight &&
+								(gPipeline.sRenderHighlight &&
 								(LLPipeline::getRenderScriptedBeacons() || LLPipeline::getRenderScriptedTouchBeacons()) &&
-								drawablep->getVObj() && drawablep->getVObj()->flagScripted())
+								drawablep->getVObj() && drawablep->getVObj()->flagScripted()))
 							{ //draw the transparent face for debugging purposes using a custom texture
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
-- 
cgit v1.2.3


From a6ea3fa741c90b4fe88550085f9a6b52d71447fd Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <gavriliuk@gmail.com>
Date: Mon, 27 Feb 2023 08:15:29 +0100
Subject: SL-18882: Show diffuse non-alpha textures opaque on editing

---
 indra/llprimitive/llmaterial.cpp | 18 +++++++++---------
 indra/llprimitive/llmaterial.h   |  2 +-
 indra/newview/llvovolume.cpp     |  7 ++++---
 3 files changed, 14 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
index a219ac1450..fa22145972 100644
--- a/indra/llprimitive/llmaterial.cpp
+++ b/indra/llprimitive/llmaterial.cpp
@@ -426,18 +426,18 @@ bool LLMaterial::operator != (const LLMaterial& rhs) const
 }
 
 
-U32 LLMaterial::getShaderMask(U32 alpha_mode)
+U32 LLMaterial::getShaderMask(U32 alpha_mode, BOOL is_alpha)
 { //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
-    U32 ret = 0;
 
-    //two least significant bits are "diffuse alpha mode"
-    if (alpha_mode != DIFFUSE_ALPHA_MODE_DEFAULT)
+	//two least significant bits are "diffuse alpha mode"
+	U32 ret = alpha_mode;
+    if (ret == DIFFUSE_ALPHA_MODE_DEFAULT)
     {
-        ret = alpha_mode;
-    }
-    else
-    {
-        ret = getDiffuseAlphaMode();
+		ret = getDiffuseAlphaMode();
+		if (ret == DIFFUSE_ALPHA_MODE_BLEND && !is_alpha)
+		{
+			ret = DIFFUSE_ALPHA_MODE_NONE;
+		}
     }
 
     llassert(ret < SHADER_COUNT);
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
index d58b7ee812..d92ef1dfba 100644
--- a/indra/llprimitive/llmaterial.h
+++ b/indra/llprimitive/llmaterial.h
@@ -126,7 +126,7 @@ public:
     bool        operator == (const LLMaterial& rhs) const;
     bool        operator != (const LLMaterial& rhs) const;
 
-    U32         getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT);
+    U32         getShaderMask(U32 alpha_mode, BOOL is_alpha);
 
 protected:
     LLUUID      mNormalID;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index b910c4f93c..086e751965 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5295,13 +5295,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	if (mat)
 	{
+		BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) || (facep->getTextureEntry()->getColor().mV[3] < 0.999f) ? TRUE : FALSE;
 		if (type == LLRenderPass::PASS_ALPHA)
 		{
-			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND);
+			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, is_alpha);
 		}
 		else
 		{
-			shader_mask = mat->getShaderMask();
+			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha);
 		}
 	}
 
@@ -6676,7 +6677,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 						LLRenderPass::PASS_NORMSPEC_EMISSIVE,
 					};
 
-					U32 mask = mat->getShaderMask();
+					U32 mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT, is_alpha);
 
 					llassert(mask < sizeof(pass)/sizeof(U32));
 
-- 
cgit v1.2.3


From 0e837fbaad136722fbad4b59e1402df2af8e4ea4 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <gavriliuk@gmail.com>
Date: Mon, 27 Feb 2023 21:46:54 +0100
Subject: Fix formatting in indra/newview/llpanelface.* files

---
 indra/newview/llpanelface.cpp |  131 +++--
 indra/newview/llpanelface.h   | 1129 ++++++++++++++++++++---------------------
 2 files changed, 627 insertions(+), 633 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 178aba11a3..cbb87f63bb 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -831,7 +831,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 { //set state of UI to match state of texture entry(ies)  (calls setEnabled, setValue, etc, but NOT setVisible)
 	LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
 
-	if( objectp
+	if (objectp
 		&& objectp->getPCode() == LL_PCODE_VOLUME
 		&& objectp->permModify())
 	{
@@ -854,7 +854,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		}
 
 		LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
-		if(radio_mat_type)
+		if (radio_mat_type)
 		{
 		    if (radio_mat_type->getSelectedIndex() < MATTYPE_DIFFUSE)
 		    {
@@ -871,10 +871,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings"));
 		updateVisibility();
 
-		bool identical				= true;	// true because it is anded below
-      bool identical_diffuse	= false;
-      bool identical_norm		= false;
-      bool identical_spec		= false;
+		bool identical			= true;	// true because it is anded below
+		bool identical_diffuse	= false;
+		bool identical_norm		= false;
+		bool identical_spec		= false;
 
 		LLTextureCtrl*	texture_ctrl = getChild<LLTextureCtrl>("texture control");
 		LLTextureCtrl*	shinytexture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
@@ -888,12 +888,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		{
 			getChildView("color label")->setEnabled(editable);
 		}
-		LLColorSwatchCtrl*	color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
+		LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
 
-		LLColor4 color					= LLColor4::white;
-		bool		identical_color	= false;
+		LLColor4 color = LLColor4::white;
+		bool identical_color = false;
 
-		if(color_swatch)
+		if (color_swatch)
 		{
 			LLSelectedTE::getColor(color, identical_color);
 			LLColor4 prev_color = color_swatch->get();
@@ -927,7 +927,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 		LLCtrlSelectionInterface* combobox_shininess = childGetSelectionInterface("combobox shininess");
 		if (combobox_shininess)
-				{
+		{
 			combobox_shininess->selectNthItem((S32)shiny);
 		}
 
@@ -947,8 +947,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 		getChild<LLUICtrl>("shinycolorswatch")->setTentative(!identical_spec);
 					
 		LLColorSwatchCtrl*	mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
-		if(mShinyColorSwatch)
-					{
+		if (mShinyColorSwatch)
+		{
 			mShinyColorSwatch->setValid(editable);
 			mShinyColorSwatch->setEnabled( editable );
 			mShinyColorSwatch->setCanApplyImmediately( editable );
@@ -956,7 +956,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 		U8 bumpy = 0;
 		// Bumpy
-						{
+		{
 			bool identical_bumpy = false;
 			LLSelectedTE::getBumpmap(bumpy,identical_bumpy);
 
@@ -966,18 +966,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
 
 			if (combobox_bumpiness)
-							{
+			{
 				combobox_bumpiness->selectNthItem((S32)bumpy);
-							}
+			}
 			else
-							{
+			{
 				LL_WARNS() << "failed childGetSelectionInterface for 'combobox bumpiness'" << LL_ENDL;
-							}
+			}
 
 			getChildView("combobox bumpiness")->setEnabled(editable);
 			getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical_bumpy);
 			getChildView("label bumpiness")->setEnabled(editable);
-						}
+		}
 
 		// Texture
 		{
@@ -991,25 +991,25 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			bool identical_image_format = false;
 			LLSelectedTE::getImageFormat(image_format, identical_image_format);
             
-         mIsAlpha = FALSE;
-         switch (image_format)
-         {
-               case GL_RGBA:
-               case GL_ALPHA:
-               {
-                  mIsAlpha = TRUE;
-               }
-               break;
-
-               case GL_RGB: break;
-               default:
-               {
-                  LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
-					}
-               break;
+			mIsAlpha = FALSE;
+			switch (image_format)
+			{
+				case GL_RGBA:
+				case GL_ALPHA:
+				{
+					mIsAlpha = TRUE;
+				}
+				break;
+
+				case GL_RGB: break;
+				default:
+				{
+					LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
 				}
+				break;
+			}
 
-			if(LLViewerMedia::getInstance()->textureHasMedia(id))
+			if (LLViewerMedia::getInstance()->textureHasMedia(id))
 			{
 				getChildView("button align")->setEnabled(editable);
 			}
@@ -1046,7 +1046,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 			updateAlphaControls();
 
 			if (texture_ctrl)
-				{
+			{
 				if (identical_diffuse)
 				{
 					texture_ctrl->setTentative(FALSE);
@@ -1060,8 +1060,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					texture_ctrl->setBakeTextureEnabled(TRUE);
 				}
 				else if (id.isNull())
-					{
-						// None selected
+				{
+					// None selected
 					texture_ctrl->setTentative(FALSE);
 					texture_ctrl->setEnabled(FALSE);
 					texture_ctrl->setImageAssetID(LLUUID::null);
@@ -1071,10 +1071,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					getChildView("label maskcutoff")->setEnabled(FALSE);
 
 					texture_ctrl->setBakeTextureEnabled(false);
-					}
-					else
-					{
-						// Tentative: multiple selected with different textures
+				}
+				else
+				{
+					// Tentative: multiple selected with different textures
 					texture_ctrl->setTentative(TRUE);
 					texture_ctrl->setEnabled(editable);
 					texture_ctrl->setImageAssetID(id);
@@ -1085,7 +1085,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					
 					texture_ctrl->setBakeTextureEnabled(TRUE);
 				}
-				
 			}
 
 			if (shinytexture_ctrl)
@@ -1343,15 +1342,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				combobox_texgen->selectNthItem(((S32)selected_texgen) >> 1);
 			}
 			else
-				{
+			{
 				LL_WARNS() << "failed childGetSelectionInterface for 'combobox texgen'" << LL_ENDL;
-				}
+			}
 
 			getChildView("combobox texgen")->setEnabled(editable);
 			getChild<LLUICtrl>("combobox texgen")->setTentative(!identical);
 			getChildView("tex gen")->setEnabled(editable);
-
-			}
+		}
 
 		{
 			U8 fullbright_flag = 0;
@@ -1380,7 +1378,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 			LLComboBox*	mComboTexGen = getChild<LLComboBox>("combobox texgen");
 			if (mComboTexGen)
-		{
+			{
 				S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
 				BOOL enabled = editable && (index != 1);
 				BOOL identical_repeats = true;
@@ -1390,26 +1388,26 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				LLSelectMgr::getInstance()->setTextureChannel(LLRender::eTexIndex(material_type));
 
 				switch (material_type)
-			{
+				{
 					default:
 					case MATTYPE_DIFFUSE:
-				{
+					{
 						enabled = editable && !id.isNull();
 						identical_repeats = identical_diff_repeats;
 						repeats = repeats_diff;
-				}
+					}
 					break;
 
 					case MATTYPE_SPECULAR:
-			{
+					{
 						enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()));
 						identical_repeats = identical_spec_repeats;
 						repeats = repeats_spec;
-			}
+					}
 					break;
 
 					case MATTYPE_NORMAL:
-			{
+					{
 						enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()));
 						identical_repeats = identical_norm_repeats;
 						repeats = repeats_norm;
@@ -1458,14 +1456,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					if (!mIsAlpha)
 					{ // ... unless there is no alpha channel in the texture, in which case alpha mode MUST ebe none
 						alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-				}
+					}
 
 					combobox_alphamode->selectNthItem(alpha_mode);
-			}
-			else
-			{
+				}
+				else
+				{
 					LL_WARNS() << "failed childGetSelectionInterface for 'combobox alphamode'" << LL_ENDL;
-			}
+				}
 				getChild<LLUICtrl>("maskcutoff")->setValue(material->getAlphaMaskCutoff());
 				updateAlphaControls();
 
@@ -1477,15 +1475,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 				texture_ctrl->setImageAssetID(material->getSpecularID());
 
 				if (!material->getSpecularID().isNull() && (shiny == SHINY_TEXTURE))
-			{
+				{
 					material->getSpecularOffset(offset_x,offset_y);
 					material->getSpecularRepeat(repeat_x,repeat_y);
 
 					if (identical_planar_texgen)
-			{
+					{
 						repeat_x *= 2.0f;
 						repeat_y *= 2.0f;
-			}
+					}
 
 					rot = material->getSpecularRotation();
 					getChild<LLUICtrl>("shinyScaleU")->setValue(repeat_x);
@@ -1497,7 +1495,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 					getChild<LLUICtrl>("environment")->setValue(material->getEnvironmentIntensity());
 
 					updateShinyControls(!material->getSpecularID().isNull(), true);
-		}
+				}
 
 				// Assert desired colorswatch color to match material AFTER updateShinyControls
 				// to avoid getting overwritten with the default on some UI state changes.
@@ -1559,14 +1557,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 
 		// Disable non-UICtrls
 		LLTextureCtrl*	texture_ctrl = getChild<LLTextureCtrl>("texture control"); 
-		if(texture_ctrl)
+		if (texture_ctrl)
 		{
 			texture_ctrl->setImageAssetID( LLUUID::null );
 			texture_ctrl->setEnabled( FALSE );  // this is a LLUICtrl, but we don't want it to have keyboard focus so we add it as a child, not a ctrl.
 // 			texture_ctrl->setValid(FALSE);
 		}
 		LLColorSwatchCtrl* mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
-		if(mColorSwatch)
+		if (mColorSwatch)
 		{
 			mColorSwatch->setEnabled( FALSE );			
 			mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
@@ -1609,7 +1607,6 @@ void LLPanelFace::updateCopyTexButton()
                                                     && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1));
     std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
     mMenuClipboardTexture->setToolTip(tooltip);
-
 }
 
 void LLPanelFace::refresh()
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 44bc442bbb..787eb0c51b 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -1,566 +1,563 @@
-/** 
- * @file llpanelface.h
- * @brief Panel in the tools floater for editing face textures, colors, etc.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPANELFACE_H
-#define LL_LLPANELFACE_H
-
-#include "v4color.h"
-#include "llpanel.h"
-#include "llmaterial.h"
-#include "llmaterialmgr.h"
-#include "lltextureentry.h"
-#include "llselectmgr.h"
-
-class LLButton;
-class LLCheckBoxCtrl;
-class LLColorSwatchCtrl;
-class LLComboBox;
-class LLInventoryItem;
-class LLLineEditor;
-class LLSpinCtrl;
-class LLTextBox;
-class LLTextureCtrl;
-class LLUICtrl;
-class LLViewerObject;
-class LLFloater;
-class LLMaterialID;
-class LLMediaCtrl;
-class LLMenuButton;
-
-// Represents an edit for use in replicating the op across one or more materials in the selection set.
-//
-// The apply function optionally performs the edit which it implements
-// as a functor taking Data that calls member func MaterialFunc taking SetValueType
-// on an instance of the LLMaterial class.
-//
-// boost who?
-//
-template<
-	typename DataType,
-	typename SetValueType,
-	void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
-class LLMaterialEditFunctor
-{
-public:
-	LLMaterialEditFunctor(const DataType& data) : _data(data) {}
-	virtual ~LLMaterialEditFunctor() {}
-	virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
-	DataType _data;
-};
-
-template<
-	typename DataType,
-	DataType (LLMaterial::*MaterialGetFunc)() >
-class LLMaterialGetFunctor
-{
-public:
-	LLMaterialGetFunctor() {}
-	virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
-};
-
-template<
-	typename DataType,
-	DataType (LLTextureEntry::*TEGetFunc)() >
-class LLTEGetFunctor
-{
-public:
-	LLTEGetFunctor() {}
-	virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
-};
-
-class LLPanelFace : public LLPanel
-{
-public:
-	virtual BOOL	postBuild();
-	LLPanelFace();
-	virtual ~LLPanelFace();
-
-	void			refresh();
-    void			refreshMedia();
-    void			unloadMedia();
-
-    /*virtual*/ void draw();
-
-	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
-	{
-		LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
-		llassert_always(new_material);
-
-		// Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
-		//
-		new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
-		return new_material;
-	}
-
-	LLRender::eTexIndex getTextureChannelToEdit();
-
-protected:
-    void			navigateToTitleMedia(const std::string url);
-    bool			selectedMediaEditable();
-    void			clearMediaSettings();
-    void			updateMediaSettings();
-    void			updateMediaTitle();
-
-	void			getState();
-
-	void			sendTexture();			// applies and sends texture
-	void			sendTextureInfo();		// applies and sends texture scale, offset, etc.
-	void			sendColor();			// applies and sends color
-	void			sendAlpha();			// applies and sends transparency
-	void			sendBump(U32 bumpiness);				// applies and sends bump map
-	void			sendTexGen();				// applies and sends bump map
-	void			sendShiny(U32 shininess);			// applies and sends shininess
-	void			sendFullbright();		// applies and sends full bright
-	void        sendGlow();
-	void			sendMedia();
-    void            alignTestureLayer();
-
-    void            updateCopyTexButton();
-
-	// this function is to return TRUE if the drag should succeed.
-	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
-
-	void 	onCommitTexture(const LLSD& data);
-	void 	onCancelTexture(const LLSD& data);
-	void 	onSelectTexture(const LLSD& data);
-	void 	onCommitSpecularTexture(const LLSD& data);
-	void 	onCancelSpecularTexture(const LLSD& data);
-	void 	onSelectSpecularTexture(const LLSD& data);
-	void 	onCommitNormalTexture(const LLSD& data);
-	void 	onCancelNormalTexture(const LLSD& data);
-	void 	onSelectNormalTexture(const LLSD& data);
-	void 	onCommitColor(const LLSD& data);
-	void 	onCommitShinyColor(const LLSD& data);
-	void 	onCommitAlpha(const LLSD& data);
-	void 	onCancelColor(const LLSD& data);
-	void 	onCancelShinyColor(const LLSD& data);
-	void 	onSelectColor(const LLSD& data);
-	void 	onSelectShinyColor(const LLSD& data);
-
-	void 	onCloseTexturePicker(const LLSD& data);
-
-    static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
-    static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
-
-	// Make UI reflect state of currently selected material (refresh)
-	// and UI mode (e.g. editing normal map v diffuse map)
-	//
-	// @param force_set_values forces spinners to set value even if they are focused
-	void updateUI(bool force_set_values = false);
-
-	// Convenience func to determine if all faces in selection have
-	// identical planar texgen settings during edits
-	// 
-	bool isIdenticalPlanarTexgen();
-
-	// Callback funcs for individual controls
-	//
-	static void		onCommitTextureInfo(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureScaleX(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureScaleY(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureRot(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureOffsetX(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureOffsetY(LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialBumpyScaleX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyScaleY(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyRot(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyOffsetX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyOffsetY(	LLUICtrl* ctrl, void* userdata);
-
-	static void		syncRepeatX(LLPanelFace* self, F32 scaleU);
-	static void		syncRepeatY(LLPanelFace* self, F32 scaleV);
-	static void		syncOffsetX(LLPanelFace* self, F32 offsetU);
-	static void		syncOffsetY(LLPanelFace* self, F32 offsetV);
-	static void 	syncMaterialRot(LLPanelFace* self, F32 rot, int te = -1);
-
-	static void		onCommitMaterialShinyScaleX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyScaleY(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyRot(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyOffsetX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyOffsetY(	LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialGloss(			LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialEnv(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialMaskCutoff(	LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
-	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
-	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
-	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
-	static void		onClickAutoFix(void*);
-    static void		onAlignTexture(void*);
-
-public: // needs to be accessible to selection manager
-    void            onCopyColor(); // records all selected faces
-    void            onPasteColor(); // to specific face
-    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
-    void            onCopyTexture();
-    void            onPasteTexture();
-    void            onPasteTexture(LLViewerObject* objectp, S32 te);
-
-protected:
-    void            menuDoToSelected(const LLSD& userdata);
-    bool            menuEnableItem(const LLSD& userdata);
-
-	static F32     valueGlow(LLViewerObject* object, S32 face);
-
-	
-
-private:
-
-	bool		isAlpha() { return mIsAlpha; }
-
-	// Convenience funcs to keep the visual flack to a minimum
-	//
-	LLUUID	getCurrentNormalMap();
-	LLUUID	getCurrentSpecularMap();
-	U32		getCurrentShininess();
-	U32		getCurrentBumpiness();
-	U8			getCurrentDiffuseAlphaMode();
-	U8			getCurrentAlphaMaskCutoff();
-	U8			getCurrentEnvIntensity();
-	U8			getCurrentGlossiness();
-	F32		getCurrentBumpyRot();
-	F32		getCurrentBumpyScaleU();
-	F32		getCurrentBumpyScaleV();
-	F32		getCurrentBumpyOffsetU();
-	F32		getCurrentBumpyOffsetV();
-	F32		getCurrentShinyRot();
-	F32		getCurrentShinyScaleU();
-	F32		getCurrentShinyScaleV();
-	F32		getCurrentShinyOffsetU();
-	F32		getCurrentShinyOffsetV();
-
-    LLComboBox *mComboMatMedia;
-    LLMediaCtrl *mTitleMedia;
-    LLTextBox *mTitleMediaText;
-
-	// Update visibility of controls to match current UI mode
-	// (e.g. materials vs media editing)
-	//
-	// Do NOT call updateUI from within this function.
-	//
-	void updateVisibility();
-
-	// Hey look everyone, a type-safe alternative to copy and paste! :)
-	//
-
-	// Update material parameters by applying 'edit_func' to selected TEs
-	//
-	template<
-		typename DataType,
-		typename SetValueType,
-		void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
-	static void edit(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())
-	{
-		LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
-		struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
-		{
-			LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {}
-			virtual ~LLSelectedTEEditMaterial() {};
-			virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
-			{
-				if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID()))
-				{
-					LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
-					llassert_always(new_material);
-
-					// Determine correct alpha mode for current diffuse texture
-					// (i.e. does it have an alpha channel that makes alpha mode useful)
-					//
-					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
-					// need to get per-face answer to this question for sane alpha mode retention on updates.
-					//					
-					bool is_alpha_face = object->isImageAlphaBlended(face);
-
-					// need to keep this original answer for valid comparisons in logic below
-					//
-					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-					
-					U8 default_alpha_mode = original_default_alpha_mode;
-
-					if (!current_material.isNull())
-					{
-						default_alpha_mode = current_material->getDiffuseAlphaMode();
-					}
-
-					// Insure we don't inherit the default of blend by accident...
-					// this will be stomped by a legit request to change the alpha mode by the apply() below
-					//
-					new_material->setDiffuseAlphaMode(default_alpha_mode);
-
-					// Do "It"!
-					//
-					_edit->apply(new_material);
-
-					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
-					LLUUID	new_normal_map_id		= new_material->getNormalID();
-					LLUUID	new_spec_map_id		= new_material->getSpecularID();
-
-					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
-					{
-						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
-					}
-
-					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
-					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
-
-					if (!is_need_material)
-					{
-						LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
-						LLMaterialMgr::getInstance()->remove(object->getID(),face);
-						new_material = NULL;
-					}
-					else
-					{
-						LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
-						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
-					}
-
-					object->setTEMaterialParams(face, new_material);
-					return new_material;
-				}
-				return NULL;
-			}
-			LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >*	_edit;
-			LLPanelFace *_panel;
-			const LLUUID & _only_for_object_id;
-		} editor(p, &edit, only_for_object_id);
-		LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te);
-	}
-
-	template<
-		typename DataType,
-		typename ReturnType,
-		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
-	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
-	{
-		DataType data_value;
-		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
-		{
-			GetTEMaterialVal(DataType default_value) : _default(default_value) {}
-			virtual ~GetTEMaterialVal() {}
-
-			DataType get(LLViewerObject* object, S32 face)
-			{
-				DataType ret = _default;
-				LLMaterialPtr material_ptr;
-				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
-				if (tep)
-				{
-					material_ptr = tep->getMaterialParams();
-					if (!material_ptr.isNull())
-					{
-						ret = (material_ptr->*(MaterialGetFunc))();
-					}
-				}
-				return ret;
-			}
-			DataType _default;
-		} GetFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
-		data_to_return = data_value;
-	}
-
-	template<
-		typename DataType,
-		typename ReturnType, // some kids just have to different...
-		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
-	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
-	{
-		DataType data_value;
-		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
-		{
-			GetTEVal(DataType default_value) : _default(default_value) {}
-			virtual ~GetTEVal() {}
-
-			DataType get(LLViewerObject* object, S32 face) {
-				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
-				return tep ? ((tep->*(TEGetFunc))()) : _default;
-			}
-			DataType _default;
-		} GetTEValFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
-		data_to_return = data_value;
-	}
-
-	// Update vis and enabling of specific subsets of controls based on material params
-	// (e.g. hide the spec controls if no spec texture is applied)
-	//
-	void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
-	void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
-	void updateAlphaControls();
-
-	/*
-	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
-	 * If agent selects texture which is not allowed to be applied for the currently selected object,
-	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
-	 */
-    void onTextureSelectionChanged(LLInventoryItem* itemp);
-
-    LLMenuButton*   mMenuClipboardColor;
-    LLMenuButton*   mMenuClipboardTexture;
-
-	bool mIsAlpha;
-	
-	/* These variables interlock processing of materials updates sent to
-	 * the sim.  mUpdateInFlight is set to flag that an update has been
-	 * sent to the sim and not acknowledged yet, and cleared when an
-	 * update is received from the sim.  mUpdatePending is set when
-	 * there's an update in flight and another UI change has been made
-	 * that needs to be sent as a materials update, and cleared when the
-	 * update is sent.  This prevents the sim from getting spammed with
-	 * update messages when, for example, the user holds down the
-	 * up-arrow on a spinner, and avoids running afoul of its throttle.
-	 */
-	bool mUpdateInFlight;
-    bool mUpdatePending;
-
-    LLSD            mClipboardParams;
-
-    LLSD mMediaSettings;
-    bool mNeedMediaTitle;
-
-public:
-	#if defined(DEF_GET_MAT_STATE)
-		#undef DEF_GET_MAT_STATE
-	#endif
-
-	#if defined(DEF_GET_TE_STATE)
-		#undef DEF_GET_TE_STATE
-	#endif
-
-	#if defined(DEF_EDIT_MAT_STATE)
-		DEF_EDIT_MAT_STATE
-	#endif
-
-    // Accessors for selected TE material state
-    //
-    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance)                                           \
-        static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)          \
-        {                                                                                                                                           \
-            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
-        }
-
-    // Mutators for selected TE material
-    //
-    #define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc)                                                              \
-        static void MaterialMemberFunc(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())     \
-        {                                                                                                                           \
-            edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id);                         \
-        }
-
-    // Accessors for selected TE state proper (legacy settings etc)
-    //
-    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance)                                        \
-        static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)      \
-        {                                                                                                                                       \
-            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
-        }
-
-	class LLSelectedTEMaterial
-	{
-	public:
-		static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
-		static void getMaxSpecularRepeats(F32& repeats, bool& identical);
-		static void getMaxNormalRepeats(F32& repeats, bool& identical);
-		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
-
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
-
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
-
-		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
-		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
-
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
-
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
-
-		DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
-		DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
-
-		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
-		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
-		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
-	};
-
-	class LLSelectedTE
-	{
-	public:
-
-		static void getFace(class LLFace*& face_to_return, bool& identical_face);
-		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
-		static void getTexId(LLUUID& id, bool& identical);
-		static void getObjectScaleS(F32& scale_s, bool& identical);
-		static void getObjectScaleT(F32& scale_t, bool& identical);
-		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
-
-		DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
-		DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
-		DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
-		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
-		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
-	};
-};
-
-#endif
-
+/** 
+ * @file llpanelface.h
+ * @brief Panel in the tools floater for editing face textures, colors, etc.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELFACE_H
+#define LL_LLPANELFACE_H
+
+#include "v4color.h"
+#include "llpanel.h"
+#include "llmaterial.h"
+#include "llmaterialmgr.h"
+#include "lltextureentry.h"
+#include "llselectmgr.h"
+
+class LLButton;
+class LLCheckBoxCtrl;
+class LLColorSwatchCtrl;
+class LLComboBox;
+class LLInventoryItem;
+class LLLineEditor;
+class LLSpinCtrl;
+class LLTextBox;
+class LLTextureCtrl;
+class LLUICtrl;
+class LLViewerObject;
+class LLFloater;
+class LLMaterialID;
+class LLMediaCtrl;
+class LLMenuButton;
+
+// Represents an edit for use in replicating the op across one or more materials in the selection set.
+//
+// The apply function optionally performs the edit which it implements
+// as a functor taking Data that calls member func MaterialFunc taking SetValueType
+// on an instance of the LLMaterial class.
+//
+// boost who?
+//
+template<
+	typename DataType,
+	typename SetValueType,
+	void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+class LLMaterialEditFunctor
+{
+public:
+	LLMaterialEditFunctor(const DataType& data) : _data(data) {}
+	virtual ~LLMaterialEditFunctor() {}
+	virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
+	DataType _data;
+};
+
+template<
+	typename DataType,
+	DataType (LLMaterial::*MaterialGetFunc)() >
+class LLMaterialGetFunctor
+{
+public:
+	LLMaterialGetFunctor() {}
+	virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
+};
+
+template<
+	typename DataType,
+	DataType (LLTextureEntry::*TEGetFunc)() >
+class LLTEGetFunctor
+{
+public:
+	LLTEGetFunctor() {}
+	virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
+};
+
+class LLPanelFace : public LLPanel
+{
+public:
+	virtual BOOL	postBuild();
+	LLPanelFace();
+	virtual ~LLPanelFace();
+
+	void			refresh();
+    void			refreshMedia();
+    void			unloadMedia();
+
+    /*virtual*/ void draw();
+
+	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
+	{
+		LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+		llassert_always(new_material);
+
+		// Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
+		//
+		new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
+		return new_material;
+	}
+
+	LLRender::eTexIndex getTextureChannelToEdit();
+
+protected:
+    void			navigateToTitleMedia(const std::string url);
+    bool			selectedMediaEditable();
+    void			clearMediaSettings();
+    void			updateMediaSettings();
+    void			updateMediaTitle();
+
+	void			getState();
+
+	void			sendTexture();			// applies and sends texture
+	void			sendTextureInfo();		// applies and sends texture scale, offset, etc.
+	void			sendColor();			// applies and sends color
+	void			sendAlpha();			// applies and sends transparency
+	void			sendBump(U32 bumpiness);				// applies and sends bump map
+	void			sendTexGen();				// applies and sends bump map
+	void			sendShiny(U32 shininess);			// applies and sends shininess
+	void			sendFullbright();		// applies and sends full bright
+	void			sendGlow();
+    void            alignTestureLayer();
+
+    void            updateCopyTexButton();
+
+	// this function is to return TRUE if the drag should succeed.
+	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
+
+	void 	onCommitTexture(const LLSD& data);
+	void 	onCancelTexture(const LLSD& data);
+	void 	onSelectTexture(const LLSD& data);
+	void 	onCommitSpecularTexture(const LLSD& data);
+	void 	onCancelSpecularTexture(const LLSD& data);
+	void 	onSelectSpecularTexture(const LLSD& data);
+	void 	onCommitNormalTexture(const LLSD& data);
+	void 	onCancelNormalTexture(const LLSD& data);
+	void 	onSelectNormalTexture(const LLSD& data);
+	void 	onCommitColor(const LLSD& data);
+	void 	onCommitShinyColor(const LLSD& data);
+	void 	onCommitAlpha(const LLSD& data);
+	void 	onCancelColor(const LLSD& data);
+	void 	onCancelShinyColor(const LLSD& data);
+	void 	onSelectColor(const LLSD& data);
+	void 	onSelectShinyColor(const LLSD& data);
+
+	void 	onCloseTexturePicker(const LLSD& data);
+
+    static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
+    static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
+
+	// Make UI reflect state of currently selected material (refresh)
+	// and UI mode (e.g. editing normal map v diffuse map)
+	//
+	// @param force_set_values forces spinners to set value even if they are focused
+	void updateUI(bool force_set_values = false);
+
+	// Convenience func to determine if all faces in selection have
+	// identical planar texgen settings during edits
+	// 
+	bool isIdenticalPlanarTexgen();
+
+	// Callback funcs for individual controls
+	//
+	static void		onCommitTextureInfo(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureScaleX(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureScaleY(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureRot(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureOffsetX(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureOffsetY(LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialBumpyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		syncRepeatX(LLPanelFace* self, F32 scaleU);
+	static void		syncRepeatY(LLPanelFace* self, F32 scaleV);
+	static void		syncOffsetX(LLPanelFace* self, F32 offsetU);
+	static void		syncOffsetY(LLPanelFace* self, F32 offsetV);
+	static void 	syncMaterialRot(LLPanelFace* self, F32 rot, int te = -1);
+
+	static void		onCommitMaterialShinyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialGloss(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialEnv(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialMaskCutoff(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
+	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
+	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
+	static void		onClickAutoFix(void*);
+    static void		onAlignTexture(void*);
+
+public: // needs to be accessible to selection manager
+    void            onCopyColor(); // records all selected faces
+    void            onPasteColor(); // to specific face
+    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
+    void            onCopyTexture();
+    void            onPasteTexture();
+    void            onPasteTexture(LLViewerObject* objectp, S32 te);
+
+protected:
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
+	static F32     valueGlow(LLViewerObject* object, S32 face);
+
+	
+
+private:
+	bool		isAlpha() { return mIsAlpha; }
+
+	// Convenience funcs to keep the visual flack to a minimum
+	//
+	LLUUID	getCurrentNormalMap();
+	LLUUID	getCurrentSpecularMap();
+	U32		getCurrentShininess();
+	U32		getCurrentBumpiness();
+	U8		getCurrentDiffuseAlphaMode();
+	U8		getCurrentAlphaMaskCutoff();
+	U8		getCurrentEnvIntensity();
+	U8		getCurrentGlossiness();
+	F32		getCurrentBumpyRot();
+	F32		getCurrentBumpyScaleU();
+	F32		getCurrentBumpyScaleV();
+	F32		getCurrentBumpyOffsetU();
+	F32		getCurrentBumpyOffsetV();
+	F32		getCurrentShinyRot();
+	F32		getCurrentShinyScaleU();
+	F32		getCurrentShinyScaleV();
+	F32		getCurrentShinyOffsetU();
+	F32		getCurrentShinyOffsetV();
+
+    LLComboBox *mComboMatMedia;
+    LLMediaCtrl *mTitleMedia;
+    LLTextBox *mTitleMediaText;
+
+	// Update visibility of controls to match current UI mode
+	// (e.g. materials vs media editing)
+	//
+	// Do NOT call updateUI from within this function.
+	//
+	void updateVisibility();
+
+	// Hey look everyone, a type-safe alternative to copy and paste! :)
+	//
+
+	// Update material parameters by applying 'edit_func' to selected TEs
+	//
+	template<
+		typename DataType,
+		typename SetValueType,
+		void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+	static void edit(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())
+	{
+		LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
+		struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
+		{
+			LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {}
+			virtual ~LLSelectedTEEditMaterial() {};
+			virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
+			{
+				if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID()))
+				{
+					LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
+					llassert_always(new_material);
+
+					// Determine correct alpha mode for current diffuse texture
+					// (i.e. does it have an alpha channel that makes alpha mode useful)
+					//
+					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
+					// need to get per-face answer to this question for sane alpha mode retention on updates.
+					//					
+					bool is_alpha_face = object->isImageAlphaBlended(face);
+
+					// need to keep this original answer for valid comparisons in logic below
+					//
+					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+					
+					U8 default_alpha_mode = original_default_alpha_mode;
+
+					if (!current_material.isNull())
+					{
+						default_alpha_mode = current_material->getDiffuseAlphaMode();
+					}
+
+					// Insure we don't inherit the default of blend by accident...
+					// this will be stomped by a legit request to change the alpha mode by the apply() below
+					//
+					new_material->setDiffuseAlphaMode(default_alpha_mode);
+
+					// Do "It"!
+					//
+					_edit->apply(new_material);
+
+					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
+					LLUUID	new_normal_map_id		= new_material->getNormalID();
+					LLUUID	new_spec_map_id			= new_material->getSpecularID();
+
+					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
+					{
+						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					}
+
+					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
+					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
+
+					if (!is_need_material)
+					{
+						LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
+						LLMaterialMgr::getInstance()->remove(object->getID(),face);
+						new_material = NULL;
+					}
+					else
+					{
+						LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
+						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
+					}
+
+					object->setTEMaterialParams(face, new_material);
+					return new_material;
+				}
+				return NULL;
+			}
+			LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >*	_edit;
+			LLPanelFace *_panel;
+			const LLUUID & _only_for_object_id;
+		} editor(p, &edit, only_for_object_id);
+		LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te);
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType,
+		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
+	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+	{
+		DataType data_value;
+		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEMaterialVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEMaterialVal() {}
+
+			DataType get(LLViewerObject* object, S32 face)
+			{
+				DataType ret = _default;
+				LLMaterialPtr material_ptr;
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				if (tep)
+				{
+					material_ptr = tep->getMaterialParams();
+					if (!material_ptr.isNull())
+					{
+						ret = (material_ptr->*(MaterialGetFunc))();
+					}
+				}
+				return ret;
+			}
+			DataType _default;
+		} GetFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
+		data_to_return = data_value;
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType, // some kids just have to different...
+		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
+	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+	{
+		DataType data_value;
+		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEVal() {}
+
+			DataType get(LLViewerObject* object, S32 face) {
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				return tep ? ((tep->*(TEGetFunc))()) : _default;
+			}
+			DataType _default;
+		} GetTEValFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
+		data_to_return = data_value;
+	}
+
+	// Update vis and enabling of specific subsets of controls based on material params
+	// (e.g. hide the spec controls if no spec texture is applied)
+	//
+	void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateAlphaControls();
+
+	/*
+	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
+	 * If agent selects texture which is not allowed to be applied for the currently selected object,
+	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
+	 */
+    void onTextureSelectionChanged(LLInventoryItem* itemp);
+
+    LLMenuButton*   mMenuClipboardColor;
+    LLMenuButton*   mMenuClipboardTexture;
+
+	bool mIsAlpha;
+	
+	/* These variables interlock processing of materials updates sent to
+	 * the sim.  mUpdateInFlight is set to flag that an update has been
+	 * sent to the sim and not acknowledged yet, and cleared when an
+	 * update is received from the sim.  mUpdatePending is set when
+	 * there's an update in flight and another UI change has been made
+	 * that needs to be sent as a materials update, and cleared when the
+	 * update is sent.  This prevents the sim from getting spammed with
+	 * update messages when, for example, the user holds down the
+	 * up-arrow on a spinner, and avoids running afoul of its throttle.
+	 */
+	bool mUpdateInFlight;
+    bool mUpdatePending;
+
+    LLSD            mClipboardParams;
+
+    LLSD mMediaSettings;
+    bool mNeedMediaTitle;
+
+public:
+	#if defined(DEF_GET_MAT_STATE)
+		#undef DEF_GET_MAT_STATE
+	#endif
+
+	#if defined(DEF_GET_TE_STATE)
+		#undef DEF_GET_TE_STATE
+	#endif
+
+	#if defined(DEF_EDIT_MAT_STATE)
+		DEF_EDIT_MAT_STATE
+	#endif
+
+    // Accessors for selected TE material state
+    //
+    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance)                                           \
+        static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)          \
+        {                                                                                                                                           \
+            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
+        }
+
+    // Mutators for selected TE material
+    //
+    #define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc)                                                              \
+        static void MaterialMemberFunc(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())     \
+        {                                                                                                                           \
+            edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id);                         \
+        }
+
+    // Accessors for selected TE state proper (legacy settings etc)
+    //
+    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance)                                        \
+        static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)      \
+        {                                                                                                                                       \
+            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
+        }
+
+	class LLSelectedTEMaterial
+	{
+	public:
+		static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
+		static void getMaxSpecularRepeats(F32& repeats, bool& identical);
+		static void getMaxNormalRepeats(F32& repeats, bool& identical);
+		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
+
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
+
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
+
+		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
+		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
+
+		DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
+		DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
+
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
+		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
+	};
+
+	class LLSelectedTE
+	{
+	public:
+		static void getFace(class LLFace*& face_to_return, bool& identical_face);
+		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
+		static void getTexId(LLUUID& id, bool& identical);
+		static void getObjectScaleS(F32& scale_s, bool& identical);
+		static void getObjectScaleT(F32& scale_t, bool& identical);
+		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
+
+		DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
+		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
+		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
+	};
+};
+
+#endif
+
-- 
cgit v1.2.3


From 3daccc5d2344404af1b3501c35b7cff96468602f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 23 Feb 2023 22:43:53 +0200
Subject: SL-19209 WIP Switch MS Bing to MS Azure

---
 indra/newview/lltranslate.cpp | 117 +++++++++++++++++++++++++++++++-----------
 1 file changed, 88 insertions(+), 29 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index a2c696c762..3e6bf4fe82 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -41,7 +41,7 @@
 #include "llurlregistry.h"
 
 
-static const std::string BING_NOTRANSLATE_OPENING_TAG("<div class=\"notranslate\">");
+static const std::string BING_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
 static const std::string BING_NOTRANSLATE_CLOSING_TAG("</div>");
 
 /**
@@ -113,6 +113,14 @@ public:
 
     void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc);
     void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+
+    virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const = 0;
+    virtual LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                       LLCore::HttpRequest::ptr_t request,
+                                       LLCore::HttpOptions::ptr_t options,
+                                       LLCore::HttpHeaders::ptr_t headers,
+                                       const std::string & url,
+                                       const std::string & msg) const = 0;
 };
 
 void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
@@ -184,8 +192,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LLVersionInfo::instance().getPatch(),
         LLVersionInfo::instance().getBuild());
 
-    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
-    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+    initHttpHeader(httpHeaders, user_agent);
     httpOpts->setSSLVerifyPeer(false);
 
     std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg);
@@ -194,8 +201,10 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
         return;
     }
+    LL_INFOS() << "Message: " << msg << LL_ENDL;
+    LL_INFOS() << "Requesting: " << url << LL_ENDL;
 
-    LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+    LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg);
 
     if (LLApp::isQuitting())
     {
@@ -280,6 +289,14 @@ public:
 
     /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
 
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url,
+        const std::string & msg) const override;
+
 private:
     static void parseErrorResponse(
         const Json::Value& root,
@@ -417,31 +434,55 @@ void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::
         this, LLTranslate::SERVICE_GOOGLE, key, fnc));
 }
 
+/*virtual*/
+void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const
+{
+    headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+}
+
+LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url,
+    const std::string & msg) const
+{
+    return adapter->getRawAndSuspend(request, url, options, headers);
+}
 
 //=========================================================================
 /// Microsoft Translator v2 API handler.
-class LLBingTranslationHandler : public LLTranslationAPIHandler
+class LLAzureTranslationHandler : public LLTranslationAPIHandler
 {
-    LOG_CLASS(LLBingTranslationHandler);
+    LOG_CLASS(LLAzureTranslationHandler);
 
 public:
-    /*virtual*/ std::string getTranslateURL(
+    std::string getTranslateURL(
         const std::string &from_lang,
         const std::string &to_lang,
-        const std::string &text) const;
-    /*virtual*/ std::string getKeyVerificationURL(
-        const std::string &key) const;
-    /*virtual*/ bool parseResponse(
+        const std::string &text) const override;
+    std::string getKeyVerificationURL(
+        const std::string &key) const override;
+    bool parseResponse(
         int& status,
         const std::string& body,
         std::string& translation,
         std::string& detected_lang,
-        std::string& err_msg) const;
-    /*virtual*/ bool isConfigured() const;
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
 
-    /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_BING; }
+    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_BING; }
 
-    /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+    void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) override;
+
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url,
+        const std::string & msg) const override;
 private:
     static std::string getAPIKey();
     static std::string getAPILanguageCode(const std::string& lang);
@@ -450,23 +491,20 @@ private:
 
 //-------------------------------------------------------------------------
 // virtual
-std::string LLBingTranslationHandler::getTranslateURL(
+std::string LLAzureTranslationHandler::getTranslateURL(
 	const std::string &from_lang,
 	const std::string &to_lang,
 	const std::string &text) const
 {
-	std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
-		+ getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang);
-	if (!from_lang.empty())
-	{
-		url += "&from=" + getAPILanguageCode(from_lang);
-	}
+    // Global service. Alternatively regional services exist.
+	std::string url = std::string("https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=")
+		+ getAPILanguageCode(to_lang) + "&Subscription-Key=" + getAPIKey();
     return url;
 }
 
 
 // virtual
-std::string LLBingTranslationHandler::getKeyVerificationURL(
+std::string LLAzureTranslationHandler::getKeyVerificationURL(
 	const std::string& key) const
 {
 	std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
@@ -475,7 +513,7 @@ std::string LLBingTranslationHandler::getKeyVerificationURL(
 }
 
 // virtual
-bool LLBingTranslationHandler::parseResponse(
+bool LLAzureTranslationHandler::parseResponse(
 	int& status,
 	const std::string& body,
 	std::string& translation,
@@ -521,30 +559,51 @@ bool LLBingTranslationHandler::parseResponse(
 }
 
 // virtual
-bool LLBingTranslationHandler::isConfigured() const
+bool LLAzureTranslationHandler::isConfigured() const
 {
 	return !getAPIKey().empty();
 }
 
 // static
-std::string LLBingTranslationHandler::getAPIKey()
+std::string LLAzureTranslationHandler::getAPIKey()
 {
 	return gSavedSettings.getString("BingTranslateAPIKey");
 }
 
 // static
-std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang)
+std::string LLAzureTranslationHandler::getAPILanguageCode(const std::string& lang)
 {
 	return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
 }
 
 /*virtual*/
-void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLAzureTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
 {
     LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, 
         this, LLTranslate::SERVICE_BING, key, fnc));
 }
 
+/*virtual*/
+void LLAzureTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const
+{
+    headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_JSON);
+    // Token based autorization exists
+    //headers->append("Ocp-Apim-Subscription-Key", getAPIKey());
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+}
+
+LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url,
+    const std::string & msg) const
+{
+    LLSD body;
+    body["text"] = "Hello, what is your name?";
+    return adapter->postJsonAndSuspend(request, url, body, headers);
+}
+
 //=========================================================================
 /*static*/
 void LLTranslate::translateMessage(const std::string &from_lang, const std::string &to_lang,
@@ -652,7 +711,7 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
 {
 	static LLGoogleTranslationHandler google;
-	static LLBingTranslationHandler bing;
+	static LLAzureTranslationHandler bing;
 
 	if (service == SERVICE_GOOGLE)
 	{
-- 
cgit v1.2.3


From 3fc3627f2d27b181269416f346f29d6451f7009a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 24 Feb 2023 11:59:48 +0200
Subject: SL-19209 WIP Switch MS Bing to MS Azure #2

---
 indra/newview/app_settings/settings.xml            |  17 +-
 indra/newview/llfloatertranslationsettings.cpp     | 120 +++++---
 indra/newview/llfloatertranslationsettings.h       |  18 +-
 indra/newview/lltranslate.cpp                      | 317 +++++++++++++++------
 indra/newview/lltranslate.h                        |  14 +-
 .../xui/en/floater_translation_settings.xml        |  95 ++++--
 6 files changed, 420 insertions(+), 161 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 411f77e6a7..ddd4f57f3f 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12929,13 +12929,13 @@
     <key>TranslationService</key>
     <map>
       <key>Comment</key>
-      <string>Translation API to use. (google|bing)</string>
+      <string>Translation API to use. (google|azure)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-      <string>bing</string>
+      <string>azure</string>
     </map>
     <key>GoogleTranslateAPIKey</key>
     <map>
@@ -12951,7 +12951,7 @@
     <key>BingTranslateAPIKey</key>
     <map>
       <key>Comment</key>
-      <string>Bing AppID to use with the Microsoft Translator API</string>
+      <string>(Deprecated) Bing AppID to use with the Microsoft Translator API</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -12959,6 +12959,17 @@
       <key>Value</key>
       <string></string>
     </map>
+    <key>AzureTranslateAPIKey</key>
+    <map>
+      <key>Comment</key>
+      <string>Azure Translation service data to use with the MS Azure Translator API</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <string></string>
+    </map>
     <key>TutorialURL</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 082bb888b1..45f46aacf5 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -45,14 +45,7 @@
 LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
 :	LLFloater(key)
 ,	mMachineTranslationCB(NULL)
-,	mLanguageCombo(NULL)
-,	mTranslationServiceRadioGroup(NULL)
-,	mBingAPIKeyEditor(NULL)
-,	mGoogleAPIKeyEditor(NULL)
-,	mBingVerifyBtn(NULL)
-,	mGoogleVerifyBtn(NULL)
-,	mOKBtn(NULL)
-,	mBingKeyVerified(false)
+,	mAzureKeyVerified(false)
 ,	mGoogleKeyVerified(false)
 {
 }
@@ -63,9 +56,11 @@ BOOL LLFloaterTranslationSettings::postBuild()
 	mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox");
 	mLanguageCombo = getChild<LLComboBox>("translate_language_combo");
 	mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg");
-	mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key");
+    mAzureAPIEndpointEditor = getChild<LLComboBox>("azure_api_endpoint_combo");
+	mAzureAPIKeyEditor = getChild<LLLineEditor>("azure_api_key");
+    mAzureAPIRegionEditor = getChild<LLLineEditor>("azure_api_region");
 	mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key");
-	mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn");
+	mAzureVerifyBtn = getChild<LLButton>("verify_azure_api_key_btn");
 	mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn");
 	mOKBtn = getChild<LLButton>("ok_btn");
 
@@ -73,11 +68,17 @@ BOOL LLFloaterTranslationSettings::postBuild()
 	mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
 	mOKBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnOK, this));
 	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false));
-	mBingVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnBingVerify, this));
+	mAzureVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnAzureVerify, this));
 	mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this));
 
-	mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
-	mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onBingKeyEdited, this), NULL);
+	mAzureAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+	mAzureAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
+    mAzureAPIRegionEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+    mAzureAPIRegionEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
+
+    mAzureAPIEndpointEditor->setFocusLostCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this));
+    mAzureAPIEndpointEditor->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this));
+
 	mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
 	mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL);
 
@@ -92,17 +93,27 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE);
 	mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE);
 
-	std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey");
-	if (!bing_key.empty())
+	LLSD azure_key = gSavedSettings.getLLSD("AzureTranslateAPIKey");
+	if (azure_key.isMap())
 	{
-		mBingAPIKeyEditor->setText(bing_key);
-		mBingAPIKeyEditor->setTentative(FALSE);
-		verifyKey(LLTranslate::SERVICE_BING, bing_key, false);
+		mAzureAPIKeyEditor->setText(azure_key["id"].asString());
+		mAzureAPIKeyEditor->setTentative(false);
+        if (azure_key.has("region"))
+        {
+            mAzureAPIRegionEditor->setText(azure_key["region"].asString());
+            mAzureAPIRegionEditor->setTentative(false);
+        }
+        else
+        {
+            mAzureAPIRegionEditor->setTentative(true);
+        }
+        mAzureAPIEndpointEditor->setValue(azure_key["endpoint"]);
+		verifyKey(LLTranslate::SERVICE_AZURE, azure_key, false);
 	}
 	else
 	{
-		mBingAPIKeyEditor->setTentative(TRUE);
-		mBingKeyVerified = FALSE;
+		mAzureAPIKeyEditor->setTentative(TRUE);
+		mAzureKeyVerified = FALSE;
 	}
 
 	std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey");
@@ -121,14 +132,14 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	updateControlsEnabledState();
 }
 
-void LLFloaterTranslationSettings::setBingVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert)
 {
 	if (alert)
 	{
-		showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified");
+		showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified");
 	}
 
-	mBingKeyVerified = ok;
+	mAzureKeyVerified = ok;
 	updateControlsEnabledState();
 }
 
@@ -148,9 +159,19 @@ std::string LLFloaterTranslationSettings::getSelectedService() const
 	return mTranslationServiceRadioGroup->getSelectedValue().asString();
 }
 
-std::string LLFloaterTranslationSettings::getEnteredBingKey() const
+LLSD LLFloaterTranslationSettings::getEnteredAzureKey() const
 {
-	return mBingAPIKeyEditor->getTentative() ? LLStringUtil::null : mBingAPIKeyEditor->getText();
+    LLSD key;
+    if (!mAzureAPIKeyEditor->getTentative())
+    {
+        key["endpoint"] = mAzureAPIEndpointEditor->getValue();
+        key["id"] = mAzureAPIKeyEditor->getText();
+        if (!mAzureAPIRegionEditor->getTentative())
+        {
+            key["region"] = mAzureAPIRegionEditor->getText();
+        }
+    }
+	return key;
 }
 
 std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
@@ -170,27 +191,31 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
 	// Enable/disable controls based on the checkbox value.
 	bool on = mMachineTranslationCB->getValue().asBoolean();
 	std::string service = getSelectedService();
-	bool bing_selected = service == "bing";
+	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
 
 	mTranslationServiceRadioGroup->setEnabled(on);
 	mLanguageCombo->setEnabled(on);
 
-	getChild<LLTextBox>("bing_api_key_label")->setEnabled(on);
-	mBingAPIKeyEditor->setEnabled(on);
+	getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on);
+	mAzureAPIEndpointEditor->setEnabled(on);
+    getChild<LLTextBox>("azure_api_key_label")->setEnabled(on);
+    mAzureAPIKeyEditor->setEnabled(on);
+    getChild<LLTextBox>("azure_api_region_label")->setEnabled(on);
+    mAzureAPIRegionEditor->setEnabled(on);
 
 	getChild<LLTextBox>("google_api_key_label")->setEnabled(on);
 	mGoogleAPIKeyEditor->setEnabled(on);
 
-	mBingAPIKeyEditor->setEnabled(on && bing_selected);
+	mAzureAPIKeyEditor->setEnabled(on && azure_selected);
 	mGoogleAPIKeyEditor->setEnabled(on && google_selected);
 
-	mBingVerifyBtn->setEnabled(on && bing_selected &&
-		!mBingKeyVerified && !getEnteredBingKey().empty());
+	mAzureVerifyBtn->setEnabled(on && azure_selected &&
+		!mAzureKeyVerified && getEnteredAzureKey().isMap());
 	mGoogleVerifyBtn->setEnabled(on && google_selected &&
 		!mGoogleKeyVerified && !getEnteredGoogleKey().empty());
 
-	bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified);
+	bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified);
 	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 
 	mOKBtn->setEnabled(!on || service_verified);
@@ -210,8 +235,8 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
 
     switch (service)
     {
-    case LLTranslate::SERVICE_BING:
-        floater->setBingVerified(ok, alert);
+    case LLTranslate::SERVICE_AZURE:
+        floater->setAzureVerified(ok, alert);
         break;
     case LLTranslate::SERVICE_GOOGLE:
         floater->setGoogleVerified(ok, alert);
@@ -220,7 +245,7 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
 }
 
 
-void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert)
+void LLFloaterTranslationSettings::verifyKey(int service, const LLSD& key, bool alert)
 {
     LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
         boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
@@ -239,11 +264,14 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
 	}
 }
 
-void LLFloaterTranslationSettings::onBingKeyEdited()
+void LLFloaterTranslationSettings::onAzureKeyEdited()
 {
-	if (mBingAPIKeyEditor->isDirty())
+	if (mAzureAPIKeyEditor->isDirty()
+        || mAzureAPIRegionEditor->isDirty()
+        || mAzureAPIEndpointEditor->getValue().isString())
 	{
-		setBingVerified(false, false);
+        // todo: verify mAzureAPIEndpointEditor url
+		setAzureVerified(false, false);
 	}
 }
 
@@ -255,12 +283,12 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited()
 	}
 }
 
-void LLFloaterTranslationSettings::onBtnBingVerify()
+void LLFloaterTranslationSettings::onBtnAzureVerify()
 {
-	std::string key = getEnteredBingKey();
-	if (!key.empty())
+	LLSD key = getEnteredAzureKey();
+	if (key.isMap())
 	{
-		verifyKey(LLTranslate::SERVICE_BING, key);
+		verifyKey(LLTranslate::SERVICE_AZURE, key);
 	}
 }
 
@@ -269,16 +297,16 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify()
 	std::string key = getEnteredGoogleKey();
 	if (!key.empty())
 	{
-		verifyKey(LLTranslate::SERVICE_GOOGLE, key);
+		verifyKey(LLTranslate::SERVICE_GOOGLE, LLSD(key));
 	}
 }
 void LLFloaterTranslationSettings::onClose(bool app_quitting)
 {
 	std::string service = gSavedSettings.getString("TranslationService");
-	bool bing_selected = service == "bing";
+	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
 
-	bool service_verified = (bing_selected && mBingKeyVerified) || (google_selected && mGoogleKeyVerified);
+	bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified);
 	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 
 }
@@ -287,7 +315,7 @@ void LLFloaterTranslationSettings::onBtnOK()
 	gSavedSettings.setBOOL("TranslateChat", mMachineTranslationCB->getValue().asBoolean());
 	gSavedSettings.setString("TranslateLanguage", mLanguageCombo->getSelectedValue().asString());
 	gSavedSettings.setString("TranslationService", getSelectedService());
-	gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey());
+	gSavedSettings.setLLSD("AzureTranslateAPIKey", getEnteredAzureKey());
 	gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey());
 
 	closeFloater(false);
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index 2a15eacded..52523f4d4a 100644
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -42,22 +42,22 @@ public:
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& key);
 
-	void setBingVerified(bool ok, bool alert);
+	void setAzureVerified(bool ok, bool alert);
 	void setGoogleVerified(bool ok, bool alert);
 	void onClose(bool app_quitting);
 
 private:
 	std::string getSelectedService() const;
-	std::string getEnteredBingKey() const;
+	LLSD getEnteredAzureKey() const;
 	std::string getEnteredGoogleKey() const;
 	void showAlert(const std::string& msg_name) const;
 	void updateControlsEnabledState();
-	void verifyKey(int service, const std::string& key, bool alert = true);
+    void verifyKey(int service, const LLSD& key, bool alert = true);
 
 	void onEditorFocused(LLFocusableElement* control);
-	void onBingKeyEdited();
+	void onAzureKeyEdited();
 	void onGoogleKeyEdited();
-	void onBtnBingVerify();
+	void onBtnAzureVerify();
 	void onBtnGoogleVerify();
 	void onBtnOK();
 
@@ -65,14 +65,16 @@ private:
 
 	LLCheckBoxCtrl* mMachineTranslationCB;
 	LLComboBox* mLanguageCombo;
-	LLLineEditor* mBingAPIKeyEditor;
+    LLComboBox* mAzureAPIEndpointEditor;;
+	LLLineEditor* mAzureAPIKeyEditor;
+    LLLineEditor* mAzureAPIRegionEditor;
 	LLLineEditor* mGoogleAPIKeyEditor;
 	LLRadioGroup* mTranslationServiceRadioGroup;
-	LLButton* mBingVerifyBtn;
+	LLButton* mAzureVerifyBtn;
 	LLButton* mGoogleVerifyBtn;
 	LLButton* mOKBtn;
 
-	bool mBingKeyVerified;
+	bool mAzureKeyVerified;
 	bool mGoogleKeyVerified;
 };
 
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 3e6bf4fe82..706b4cc6ee 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -80,7 +80,18 @@ public:
     * @param[in]  key  Key to verify.
     */
     virtual std::string getKeyVerificationURL(
-        const std::string &key) const = 0;
+        const LLSD &key) const = 0;
+
+    /**
+    * Check API verification response.
+    *
+    * @param[out] bool  true if valid.
+    * @param[in]  response
+    * @param[in]  status
+    */
+    virtual bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const = 0;
 
     /**
     * Parse translation response.
@@ -105,22 +116,28 @@ public:
 
     virtual LLTranslate::EService getCurrentService() = 0;
 
-    virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
+    virtual void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
     virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
 
 
     virtual ~LLTranslationAPIHandler() {}
 
-    void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc);
+    void verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc);
     void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
 
     virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const = 0;
+    virtual void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const = 0;
     virtual LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
                                        LLCore::HttpRequest::ptr_t request,
                                        LLCore::HttpOptions::ptr_t options,
                                        LLCore::HttpHeaders::ptr_t headers,
                                        const std::string & url,
                                        const std::string & msg) const = 0;
+    virtual LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const = 0;
 };
 
 void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
@@ -130,8 +147,7 @@ void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::strin
 
 }
 
-
-void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD key, LLTranslate::KeyVerificationResult_fn fnc)
 {
     LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
     LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
@@ -148,8 +164,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::
         LLVersionInfo::instance().getPatch(),
         LLVersionInfo::instance().getBuild());
 
-    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
-    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+    initHttpHeader(httpHeaders, user_agent, key);
 
     httpOpts->setFollowRedirects(true);
     httpOpts->setSSLVerifyPeer(false);
@@ -161,17 +176,22 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::
         return;
     }
 
-    LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+    LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url);
 
     LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
     LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
 
     bool bOk = true;
-    if (!status)
+    int parseResult = status.getType();
+    if (!checkVerificationResponse(httpResults, parseResult))
+    {
         bOk = false;
+    }
 
     if (!fnc.empty())
+    {
         fnc(service, bOk);
+    }
 }
 
 void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg,
@@ -192,7 +212,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LLVersionInfo::instance().getPatch(),
         LLVersionInfo::instance().getBuild());
 
-    initHttpHeader(httpHeaders, user_agent);
+    initHttpHeader(httpHeaders, user_agent);
     httpOpts->setSSLVerifyPeer(false);
 
     std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg);
@@ -251,6 +271,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
     }
     else
     {
+        if (err_msg.empty() && httpResults.has("error_body"))
+        {
+            err_msg = httpResults["error_body"].asString();
+        }
+
         if (err_msg.empty())
         {
             err_msg = LLTrans::getString("TranslationResponseParseError");
@@ -271,25 +296,29 @@ class LLGoogleTranslationHandler : public LLTranslationAPIHandler
     LOG_CLASS(LLGoogleTranslationHandler);
 
 public:
-    /*virtual*/ std::string getTranslateURL(
+    std::string getTranslateURL(
         const std::string &from_lang,
         const std::string &to_lang,
-        const std::string &text) const;
-    /*virtual*/ std::string getKeyVerificationURL(
-        const std::string &key) const;
-    /*virtual*/ bool parseResponse(
+        const std::string &text) const override;
+    std::string getKeyVerificationURL(
+        const LLSD &key) const override;
+    bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const override;
+    bool parseResponse(
         int& status,
         const std::string& body,
         std::string& translation,
         std::string& detected_lang,
-        std::string& err_msg) const;
-    /*virtual*/ bool isConfigured() const;
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
 
-    /*virtual*/ LLTranslate::EService getCurrentService() { return LLTranslate::EService::SERVICE_GOOGLE; }
+    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_GOOGLE; }
 
-    /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+    void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override;
 
     void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override;
     LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
         LLCore::HttpRequest::ptr_t request,
         LLCore::HttpOptions::ptr_t options,
@@ -297,6 +326,12 @@ public:
         const std::string & url,
         const std::string & msg) const override;
 
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const override;
+
 private:
     static void parseErrorResponse(
         const Json::Value& root,
@@ -328,13 +363,21 @@ std::string LLGoogleTranslationHandler::getTranslateURL(
 
 // virtual
 std::string LLGoogleTranslationHandler::getKeyVerificationURL(
-	const std::string& key) const
+	const LLSD& key) const
 {
-	std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
-		+ key + "&target=en";
+    std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+        + key.asString() +"&target=en";
     return url;
 }
 
+//virtual
+bool LLGoogleTranslationHandler::checkVerificationResponse(
+    const LLSD &response,
+    int status) const
+{
+    return status == HTTP_OK;
+}
+
 // virtual
 bool LLGoogleTranslationHandler::parseResponse(
 	int& status,
@@ -424,11 +467,12 @@ bool LLGoogleTranslationHandler::parseTranslation(
 // static
 std::string LLGoogleTranslationHandler::getAPIKey()
 {
-	return gSavedSettings.getString("GoogleTranslateAPIKey");
+    static LLCachedControl<std::string> google_key(gSavedSettings, "GoogleTranslateAPIKey");
+	return google_key;
 }
 
 /*virtual*/ 
-void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLGoogleTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc)
 {
     LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
         this, LLTranslate::SERVICE_GOOGLE, key, fnc));
@@ -441,6 +485,16 @@ void LLGoogleTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t heade
     headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
 }
 
+/*virtual*/
+void LLGoogleTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD &key) const
+{
+    headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+}
+
 LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
     LLCore::HttpRequest::ptr_t request,
     LLCore::HttpOptions::ptr_t options,
@@ -451,6 +505,15 @@ LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorou
     return adapter->getRawAndSuspend(request, url, options, headers);
 }
 
+LLSD LLGoogleTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url) const
+{
+    return adapter->getAndSuspend(request, url, options, headers);
+}
+
 //=========================================================================
 /// Microsoft Translator v2 API handler.
 class LLAzureTranslationHandler : public LLTranslationAPIHandler
@@ -463,7 +526,10 @@ public:
         const std::string &to_lang,
         const std::string &text) const override;
     std::string getKeyVerificationURL(
-        const std::string &key) const override;
+        const LLSD &key) const override;
+    bool checkVerificationResponse(
+        const LLSD &response,
+        int status) const override;
     bool parseResponse(
         int& status,
         const std::string& body,
@@ -472,19 +538,26 @@ public:
         std::string& err_msg) const override;
     bool isConfigured() const override;
 
-    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_BING; }
+    LLTranslate::EService getCurrentService() override { return LLTranslate::EService::SERVICE_AZURE; }
 
-    void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) override;
+    void verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc) override;
 
     void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD &key) const override;
     LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
         LLCore::HttpRequest::ptr_t request,
         LLCore::HttpOptions::ptr_t options,
         LLCore::HttpHeaders::ptr_t headers,
         const std::string & url,
         const std::string & msg) const override;
+
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+        LLCore::HttpRequest::ptr_t request,
+        LLCore::HttpOptions::ptr_t options,
+        LLCore::HttpHeaders::ptr_t headers,
+        const std::string & url) const override;
 private:
-    static std::string getAPIKey();
+    static LLSD getAPIKey();
     static std::string getAPILanguageCode(const std::string& lang);
 
 };
@@ -496,22 +569,49 @@ std::string LLAzureTranslationHandler::getTranslateURL(
 	const std::string &to_lang,
 	const std::string &text) const
 {
-    // Global service. Alternatively regional services exist.
-	std::string url = std::string("https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=")
-		+ getAPILanguageCode(to_lang) + "&Subscription-Key=" + getAPIKey();
+    std::string url;
+    LLSD key = getAPIKey();
+    if (key.isMap())
+    {
+        std::string endpoint = key["endpoint"].asString();
+        // todo: validate url
+        if (*endpoint.rbegin() != '/')
+        {
+            endpoint += "/";
+        }
+        url = endpoint + std::string("translate?api-version=3.0&to=")
+            + getAPILanguageCode(to_lang);
+    }
     return url;
 }
 
 
 // virtual
 std::string LLAzureTranslationHandler::getKeyVerificationURL(
-	const std::string& key) const
+	const LLSD& key) const
 {
-	std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
-		+ key;
+    std::string url;
+    if (key.isMap())
+    {
+        std::string endpoint = key["endpoint"].asString();
+        // todo: validate url
+        if (*endpoint.rbegin() != '/')
+        {
+            endpoint += "/";
+        }
+        url = endpoint + std::string("translate?api-version=3.0&to=en");
+    }
     return url;
 }
 
+//virtual
+bool LLAzureTranslationHandler::checkVerificationResponse(
+    const LLSD &response,
+    int status) const
+{
+    return status == HTTP_BAD_REQUEST; // would have been 401 if id was wrong
+}
+
 // virtual
 bool LLAzureTranslationHandler::parseResponse(
 	int& status,
@@ -522,52 +622,71 @@ bool LLAzureTranslationHandler::parseResponse(
 {
 	if (status != HTTP_OK)
 	{
-		static const std::string MSG_BEGIN_MARKER = "Message: ";
-		size_t begin = body.find(MSG_BEGIN_MARKER);
-		if (begin != std::string::npos)
-		{
-			begin += MSG_BEGIN_MARKER.size();
-		}
-		else
-		{
-			begin = 0;
-			err_msg.clear();
-		}
-		size_t end = body.find("</p>", begin);
-		err_msg = body.substr(begin, end-begin);
-		LLStringUtil::replaceString(err_msg, "&#xD;", ""); // strip CR
 		return false;
 	}
 
-	// Sample response: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string>
-	size_t begin = body.find(">");
-	if (begin == std::string::npos || begin >= (body.size() - 1))
-	{
-		begin = 0;
-	}
-	else
-	{
-		++begin;
-	}
+    //Example:
+    // "[{\"detectedLanguage\":{\"language\":\"en\",\"score\":1.0},\"translations\":[{\"text\":\"Hello, what is your name?\",\"to\":\"en\"}]}]"
 
-	size_t end = body.find("</string>", begin);
+    Json::Value root;
+    Json::Reader reader;
 
-	detected_lang = ""; // unsupported by this API
-	translation = body.substr(begin, end-begin);
-	LLStringUtil::replaceString(translation, "&#xD;", ""); // strip CR
-	return true;
+    if (!reader.parse(body, root))
+    {
+        err_msg = reader.getFormatedErrorMessages();
+        return false;
+    }
+
+    if (!root.isArray()) // empty response? should not happen
+    {
+        return false;
+    }
+
+    // Request succeeded, extract translation from the response.
+
+    const Json::Value& data = root[0U];
+    if (!data.isObject()
+        || !data.isMember("detectedLanguage")
+        || !data.isMember("translations"))
+    {
+        return false;
+    }
+
+    const Json::Value& detectedLanguage = data["detectedLanguage"];
+    if (!detectedLanguage.isObject() || !detectedLanguage.isMember("language"))
+    {
+        return false;
+    }
+    detected_lang = detectedLanguage["language"].asString();
+
+    const Json::Value& translations = data["translations"];
+    if (!translations.isArray() || translations.size() == 0)
+    {
+        return false;
+    }
+
+    const Json::Value& first = translations[0U];
+    if (!first.isObject() || !first.isMember("text"))
+    {
+        return false;
+    }
+
+    translation = first["text"].asString();
+
+    return true;
 }
 
 // virtual
 bool LLAzureTranslationHandler::isConfigured() const
 {
-	return !getAPIKey().empty();
+	return !getAPIKey().isMap();
 }
 
 // static
-std::string LLAzureTranslationHandler::getAPIKey()
+LLSD LLAzureTranslationHandler::getAPIKey()
 {
-	return gSavedSettings.getString("BingTranslateAPIKey");
+    static LLCachedControl<LLSD> azure_key(gSavedSettings, "AzureTranslateAPIKey");
+	return azure_key;
 }
 
 // static
@@ -577,19 +696,38 @@ std::string LLAzureTranslationHandler::getAPILanguageCode(const std::string& lan
 }
 
 /*virtual*/
-void LLAzureTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+void LLAzureTranslationHandler::verifyKey(const LLSD &key, LLTranslate::KeyVerificationResult_fn fnc)
 {
-    LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, 
-        this, LLTranslate::SERVICE_BING, key, fnc));
+    LLCoros::instance().launch("Azure /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, 
+        this, LLTranslate::SERVICE_AZURE, key, fnc));
+}
+/*virtual*/
+void LLAzureTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent) const
+{
+    initHttpHeader(headers, user_agent, getAPIKey());
 }
 
 /*virtual*/
-void LLAzureTranslationHandler::initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const
+void LLAzureTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD &key) const
 {
     headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_JSON);
-    // Token based autorization exists
-    //headers->append("Ocp-Apim-Subscription-Key", getAPIKey());
     headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+    if (key.has("id"))
+    {
+        // Token based autorization
+        headers->append("Ocp-Apim-Subscription-Key", key["id"].asString());
+    }
+    if (key.has("region"))
+    {
+        // ex: "westeurope"
+        headers->append("Ocp-Apim-Subscription-Region", key["region"].asString());
+    }
 }
 
 LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
@@ -599,9 +737,26 @@ LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorout
     const std::string & url,
     const std::string & msg) const
 {
-    LLSD body;
-    body["text"] = "Hello, what is your name?";
-    return adapter->postJsonAndSuspend(request, url, body, headers);
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "[{\"text\":\"";
+    outs << msg;
+    outs << "\"}]";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
+LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+    LLCore::HttpRequest::ptr_t request,
+    LLCore::HttpOptions::ptr_t options,
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string & url) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "[{\"intentionally_invalid_400\"}]";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
 }
 
 //=========================================================================
@@ -616,7 +771,7 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri
 
 std::string LLTranslate::addNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_BING)
+    if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
     {
         return mesg;
     }
@@ -637,7 +792,7 @@ std::string LLTranslate::addNoTranslateTags(std::string mesg)
 
 std::string LLTranslate::removeNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_BING)
+    if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
     {
         return mesg;
     }
@@ -667,7 +822,7 @@ std::string LLTranslate::removeNoTranslateTags(std::string mesg)
 }
 
 /*static*/
-void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc)
+void LLTranslate::verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc)
 {
     LLTranslationAPIHandler& handler = getHandler(service);
 
@@ -696,7 +851,7 @@ bool LLTranslate::isTranslationConfigured()
 // static
 LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 {
-	EService service = SERVICE_BING;
+	EService service = SERVICE_AZURE;
 
 	std::string service_str = gSavedSettings.getString("TranslationService");
 	if (service_str == "google")
@@ -711,12 +866,12 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
 {
 	static LLGoogleTranslationHandler google;
-	static LLAzureTranslationHandler bing;
+	static LLAzureTranslationHandler azure;
 
 	if (service == SERVICE_GOOGLE)
 	{
 		return google;
 	}
 
-	return bing;
+	return azure;
 }
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index e0722fbd83..870fd54441 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -55,7 +55,7 @@ class LLTranslate
 public :
 
 	typedef enum e_service {
-		SERVICE_BING,
+		SERVICE_AZURE,
 		SERVICE_GOOGLE,
 	} EService;
 
@@ -74,12 +74,12 @@ public :
     static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure);
 
     /**
-	 * Verify given API key of a translation service.
-	 *
-	 * @param receiver  Object to pass verification result to.
-	 * @param key       Key to verify.
-	 */
-    static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc);
+     * Verify given API key of a translation service.
+     *
+     * @param receiver  Object to pass verification result to.
+     * @param key       Key to verify.
+     */
+    static void verifyKey(EService service, const LLSD &key, KeyVerificationResult_fn fnc);
 
 	/**
 	 * @return translation target language
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index a212ce7889..b0e47798e9 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  legacy_header_height="18"
- height="310"
+ height="370"
  layout="topleft"
  name="floater_translation_settings"
  help_topic="translation_settings"
@@ -9,10 +9,10 @@
  title="CHAT TRANSLATION SETTINGS"
  width="485">
 
- <string name="bing_api_key_not_verified">Bing appID not verified. Please try again.</string>
+ <string name="azure_api_key_not_verified">Azure service identifier not verified. Please try again.</string>
  <string name="google_api_key_not_verified">Google API key not verified. Please try again.</string>
 
- <string name="bing_api_key_verified">Bing appID verified.</string>
+ <string name="azure_api_key_verified">Azure service identifier verified.</string>
  <string name="google_api_key_verified">Google API key verified.</string>
 
  <check_box
@@ -128,25 +128,67 @@
 
  <radio_group
   follows="top|left"
-  height="80"
+  height="140"
   layout="topleft"
   left_delta="10"
   name="translation_service_rg"
   top_pad="20"
   width="320">
   <radio_item
-   initial_value="bing"
-   label="Bing Translator"
+   initial_value="azure"
+   label="Azure Translator"
    layout="topleft"
-   name="bing" />
+   name="azure" />
   <radio_item
    initial_value="google"
    label="Google Translate"
    layout="topleft"
    name="google"
-   top_pad="55" />
+   top_pad="115" />
  </radio_group>
 
+  <text
+   type="string"
+   length="1"
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="70"
+   name="azure_api_endoint_label"
+   top_pad="-115"
+   width="85">
+    Endpoint:
+  </text>
+  
+ <combo_box
+   allow_text_entry="true"
+   follows="left|top"
+   name="azure_api_endpoint_combo"
+   height="23"
+   left_pad="10"
+   right="-10"
+   top_delta="-4"
+   max_chars="512"
+   value="https://api.cognitive.microsofttranslator.com"
+   combo_button.scale_image="true">
+   <combo_box.item
+     label="https://api.cognitive.microsofttranslator.com"
+     name="global"
+     value="https://api.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-apc.cognitive.microsofttranslator.com"
+     name="api-apc"
+     value="https://api-apc.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-eur.cognitive.microsofttranslator.com"
+     name="api-eur"
+     value="https://api-eur.cognitive.microsofttranslator.com" />
+   <combo_box.item
+     label="https://api-nam.cognitive.microsofttranslator.com"
+     name="api-nam"
+     value="https://api-nam.cognitive.microsofttranslator.com" />
+  </combo_box>
+
  <text
   type="string"
   length="1"
@@ -154,20 +196,20 @@
   height="20"
   layout="topleft"
   left="70"
-  name="bing_api_key_label"
-  top_pad="-55"
+  name="azure_api_key_label"
+  top_pad="10"
   width="85">
-  Bing [http://www.bing.com/developers/createapp.aspx AppID]:
+  Azure Key:
   </text>
  <line_editor
-  default_text="Enter Bing AppID and click &quot;Verify&quot;"
+  default_text="Enter Translator Key and click &quot;Verify&quot;"
   follows="top|left"
   height="20"
   layout="topleft"
   left_pad="10"
   max_length_chars="50"
   top_delta="-4"
-  name="bing_api_key"
+  name="azure_api_key"
   width="210" />
  <button
   follows="left|top"
@@ -175,9 +217,30 @@
   label="Verify"
   layout="topleft"
   left_pad="10"
-  name="verify_bing_api_key_btn"
+  name="verify_azure_api_key_btn"
   top_delta="-2"
-  width="90" />	
+  width="90" />
+  <text
+   type="string"
+   length="1"
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="70"
+   name="azure_api_region_label"
+   top_pad="10"
+   width="85">
+    Region:
+  </text>
+  <line_editor
+   follows="top|left"
+   height="20"
+   layout="topleft"
+   left_pad="10"
+   max_length_chars="50"
+   top_delta="-4"
+   name="azure_api_region"
+   width="210" />
 
  <text
   follows="top|right"
@@ -186,7 +249,7 @@
   left="70"
   length="1"
   name="google_api_key_label"
-  top_pad="50"
+  top_pad="55"
   type="string"
   width="85">
   Google [http://code.google.com/apis/language/translate/v2/getting_started.html#auth API key]:
-- 
cgit v1.2.3


From f7210db06ee677231b93b750c205cd0317a9901f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 28 Feb 2023 00:13:31 +0200
Subject: SL-19209 Switch MS Bing to MS Azure #3

---
 indra/newview/llfloatertranslationsettings.cpp     |  29 ++--
 indra/newview/llfloatertranslationsettings.h       |   8 +-
 indra/newview/lltranslate.cpp                      | 168 ++++++++++++++++-----
 indra/newview/lltranslate.h                        |   2 +-
 .../xui/en/floater_translation_settings.xml        |  19 ++-
 5 files changed, 168 insertions(+), 58 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 45f46aacf5..c99de47da0 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -132,22 +132,22 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	updateControlsEnabledState();
 }
 
-void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setAzureVerified(bool ok, bool alert, S32 status)
 {
 	if (alert)
 	{
-		showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified");
+		showAlert(ok ? "azure_api_key_verified" : "azure_api_key_not_verified", status);
 	}
 
 	mAzureKeyVerified = ok;
 	updateControlsEnabledState();
 }
 
-void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert)
+void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 status)
 {
 	if (alert)
 	{
-		showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified");
+		showAlert(ok ? "google_api_key_verified" : "google_api_key_not_verified", status);
 	}
 
 	mGoogleKeyVerified = ok;
@@ -179,10 +179,15 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
 	return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText();
 }
 
-void LLFloaterTranslationSettings::showAlert(const std::string& msg_name) const
+void LLFloaterTranslationSettings::showAlert(const std::string& msg_name, S32 status) const
 {
+    LLStringUtil::format_map_t string_args;
+    // For now just show an http error code, whole 'reason' string might be added later
+    string_args["[STATUS]"] = llformat("%d", status);
+    std::string message = getString(msg_name, string_args);
+
 	LLSD args;
-	args["MESSAGE"] = getString(msg_name);
+	args["MESSAGE"] = message;
 	LLNotificationsUtil::add("GenericAlert", args);
 }
 
@@ -222,7 +227,7 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
 }
 
 /*static*/
-void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert)
+void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert, S32 status)
 {
     LLFloaterTranslationSettings* floater =
         LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
@@ -236,10 +241,10 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
     switch (service)
     {
     case LLTranslate::SERVICE_AZURE:
-        floater->setAzureVerified(ok, alert);
+        floater->setAzureVerified(ok, alert, status);
         break;
     case LLTranslate::SERVICE_GOOGLE:
-        floater->setGoogleVerified(ok, alert);
+        floater->setGoogleVerified(ok, alert, status);
         break;
     }
 }
@@ -248,7 +253,7 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
 void LLFloaterTranslationSettings::verifyKey(int service, const LLSD& key, bool alert)
 {
     LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
-        boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
+        boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert, _3));
 }
 
 void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
@@ -271,7 +276,7 @@ void LLFloaterTranslationSettings::onAzureKeyEdited()
         || mAzureAPIEndpointEditor->getValue().isString())
 	{
         // todo: verify mAzureAPIEndpointEditor url
-		setAzureVerified(false, false);
+		setAzureVerified(false, false, 0);
 	}
 }
 
@@ -279,7 +284,7 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited()
 {
 	if (mGoogleAPIKeyEditor->isDirty())
 	{
-		setGoogleVerified(false, false);
+		setGoogleVerified(false, false, 0);
 	}
 }
 
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index 52523f4d4a..f039d90e27 100644
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -42,15 +42,15 @@ public:
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void onOpen(const LLSD& key);
 
-	void setAzureVerified(bool ok, bool alert);
-	void setGoogleVerified(bool ok, bool alert);
+	void setAzureVerified(bool ok, bool alert, S32 status);
+	void setGoogleVerified(bool ok, bool alert, S32 status);
 	void onClose(bool app_quitting);
 
 private:
 	std::string getSelectedService() const;
 	LLSD getEnteredAzureKey() const;
 	std::string getEnteredGoogleKey() const;
-	void showAlert(const std::string& msg_name) const;
+	void showAlert(const std::string& msg_name, S32 status) const;
 	void updateControlsEnabledState();
     void verifyKey(int service, const LLSD& key, bool alert = true);
 
@@ -61,7 +61,7 @@ private:
 	void onBtnGoogleVerify();
 	void onBtnOK();
 
-    static void setVerificationStatus(int service, bool alert, bool ok);
+    static void setVerificationStatus(int service, bool alert, bool ok, S32 status);
 
 	LLCheckBoxCtrl* mMachineTranslationCB;
 	LLComboBox* mLanguageCombo;
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 706b4cc6ee..b0c4418ae9 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -41,8 +41,8 @@
 #include "llurlregistry.h"
 
 
-static const std::string BING_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
-static const std::string BING_NOTRANSLATE_CLOSING_TAG("</div>");
+static const std::string AZURE_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">");
+static const std::string AZURE_NOTRANSLATE_CLOSING_TAG("</div>");
 
 /**
 * Handler of an HTTP machine translation service.
@@ -103,6 +103,7 @@ public:
     * @param[out]    err_msg       Error message (in case of error).
     */
     virtual bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
@@ -176,6 +177,13 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD
         return;
     }
 
+    std::string::size_type delim_pos = url.find("://");
+    if (delim_pos == std::string::npos)
+    {
+        LL_INFOS("Translate") << "URL is missing a scheme" << LL_ENDL;
+        return;
+    }
+
     LLSD result = verifyAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url);
 
     LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
@@ -190,7 +198,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, LLSD
 
     if (!fnc.empty())
     {
-        fnc(service, bOk);
+        fnc(service, bOk, parseResult);
     }
 }
 
@@ -221,8 +229,8 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
         return;
     }
-    LL_INFOS() << "Message: " << msg << LL_ENDL;
-    LL_INFOS() << "Requesting: " << url << LL_ENDL;
+    LL_DEBUGS("Translate") << "Message: " << msg << LL_ENDL;
+    LL_DEBUGS("Translate") << "Requesting: " << url << LL_ENDL;
 
     LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg);
 
@@ -245,7 +253,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
 
     try
     {
-        res = this->parseResponse(parseResult, body, translation, detected_lang, err_msg);
+        res = this->parseResponse(httpResults, parseResult, body, translation, detected_lang, err_msg);
     }
     catch (std::out_of_range&)
     {
@@ -306,6 +314,7 @@ public:
         const LLSD &response,
         int status) const override;
     bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
@@ -380,6 +389,7 @@ bool LLGoogleTranslationHandler::checkVerificationResponse(
 
 // virtual
 bool LLGoogleTranslationHandler::parseResponse(
+    const LLSD& http_response,
 	int& status,
 	const std::string& body,
 	std::string& translation,
@@ -531,6 +541,7 @@ public:
         const LLSD &response,
         int status) const override;
     bool parseResponse(
+        const LLSD& http_response,
         int& status,
         const std::string& body,
         std::string& translation,
@@ -557,6 +568,8 @@ public:
         LLCore::HttpHeaders::ptr_t headers,
         const std::string & url) const override;
 private:
+    static std::string parseErrorResponse(
+        const std::string& body);
     static LLSD getAPIKey();
     static std::string getAPILanguageCode(const std::string& lang);
 
@@ -574,7 +587,7 @@ std::string LLAzureTranslationHandler::getTranslateURL(
     if (key.isMap())
     {
         std::string endpoint = key["endpoint"].asString();
-        // todo: validate url
+
         if (*endpoint.rbegin() != '/')
         {
             endpoint += "/";
@@ -594,7 +607,6 @@ std::string LLAzureTranslationHandler::getKeyVerificationURL(
     if (key.isMap())
     {
         std::string endpoint = key["endpoint"].asString();
-        // todo: validate url
         if (*endpoint.rbegin() != '/')
         {
             endpoint += "/";
@@ -609,11 +621,48 @@ bool LLAzureTranslationHandler::checkVerificationResponse(
     const LLSD &response,
     int status) const
 {
-    return status == HTTP_BAD_REQUEST; // would have been 401 if id was wrong
+    if (status == HTTP_UNAUTHORIZED)
+    {
+        LL_DEBUGS("Translate") << "Key unathorised" << LL_ENDL;
+        return false;
+    }
+
+    if (status == HTTP_NOT_FOUND)
+    {
+        LL_DEBUGS("Translate") << "Either endpoint doesn't have requested resource" << LL_ENDL;
+        return false;
+    }
+
+    if (status != HTTP_BAD_REQUEST)
+    {
+        LL_DEBUGS("Translate") << "Unexpected error code" << LL_ENDL;
+        return false;
+    }
+
+    if (!response.has("error_body"))
+    {
+        LL_DEBUGS("Translate") << "Unexpected response, no error returned" << LL_ENDL;
+        return false;
+    }
+
+    // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+    // But for now just verify response is a valid json with an error
+
+    Json::Value root;
+    Json::Reader reader;
+
+    if (!reader.parse(response["error_body"].asString(), root))
+    {
+        LL_DEBUGS("Translate") << "Failed to parse error_body:" << reader.getFormatedErrorMessages() << LL_ENDL;
+        return false;
+    }
+
+    return true;
 }
 
 // virtual
 bool LLAzureTranslationHandler::parseResponse(
+    const LLSD& http_response,
 	int& status,
 	const std::string& body,
 	std::string& translation,
@@ -622,6 +671,8 @@ bool LLAzureTranslationHandler::parseResponse(
 {
 	if (status != HTTP_OK)
 	{
+        if (http_response.has("error_body"))
+        err_msg = parseErrorResponse(http_response["error_body"].asString());
 		return false;
 	}
 
@@ -682,6 +733,36 @@ bool LLAzureTranslationHandler::isConfigured() const
 	return !getAPIKey().isMap();
 }
 
+//static
+std::string LLAzureTranslationHandler::parseErrorResponse(
+    const std::string& body)
+{
+    // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
+    // But for now just verify response is a valid json with an error
+
+    Json::Value root;
+    Json::Reader reader;
+
+    if (!reader.parse(body, root))
+    {
+        return std::string();
+    }
+
+    if (!root.isObject() || !root.isMember("error"))
+    {
+        return std::string();
+    }
+
+    const Json::Value& error_map = root["error"];
+
+    if (!error_map.isObject() || !error_map.isMember("message"))
+    {
+        return std::string();
+    }
+
+    return error_map["message"].asString();
+}
+
 // static
 LLSD LLAzureTranslationHandler::getAPIKey()
 {
@@ -771,54 +852,65 @@ void LLTranslate::translateMessage(const std::string &from_lang, const std::stri
 
 std::string LLTranslate::addNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
+    if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
     {
         return mesg;
     }
 
-    std::string upd_msg(mesg);
-    LLUrlMatch match;
-    S32 dif = 0;
-    //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
-    while (LLUrlRegistry::instance().findUrl(mesg, match))
+    if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
     {
-        upd_msg.insert(dif + match.getStart(), BING_NOTRANSLATE_OPENING_TAG);
-        upd_msg.insert(dif + BING_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, BING_NOTRANSLATE_CLOSING_TAG);
-        mesg.erase(match.getStart(), match.getEnd() - match.getStart());
-        dif += match.getEnd() - match.getStart() + BING_NOTRANSLATE_OPENING_TAG.size() + BING_NOTRANSLATE_CLOSING_TAG.size();
+        // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation
+        std::string upd_msg(mesg);
+        LLUrlMatch match;
+        S32 dif = 0;
+        //surround all links (including SLURLs) with 'no-translate' tags to prevent unnecessary translation
+        while (LLUrlRegistry::instance().findUrl(mesg, match))
+        {
+            upd_msg.insert(dif + match.getStart(), AZURE_NOTRANSLATE_OPENING_TAG);
+            upd_msg.insert(dif + AZURE_NOTRANSLATE_OPENING_TAG.size() + match.getEnd() + 1, AZURE_NOTRANSLATE_CLOSING_TAG);
+            mesg.erase(match.getStart(), match.getEnd() - match.getStart());
+            dif += match.getEnd() - match.getStart() + AZURE_NOTRANSLATE_OPENING_TAG.size() + AZURE_NOTRANSLATE_CLOSING_TAG.size();
+        }
+        return upd_msg;
     }
-    return upd_msg;
+    return mesg;
 }
 
 std::string LLTranslate::removeNoTranslateTags(std::string mesg)
 {
-    if (getPreferredHandler().getCurrentService() != SERVICE_AZURE)
+    if (getPreferredHandler().getCurrentService() == SERVICE_GOOGLE)
     {
         return mesg;
     }
-    std::string upd_msg(mesg);
-    LLUrlMatch match;
-    S32 opening_tag_size = BING_NOTRANSLATE_OPENING_TAG.size();
-    S32 closing_tag_size = BING_NOTRANSLATE_CLOSING_TAG.size();
-    S32 dif = 0;
-    //remove 'no-translate' tags we added to the links before
-    while (LLUrlRegistry::instance().findUrl(mesg, match))
+
+    if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
     {
-        if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == BING_NOTRANSLATE_OPENING_TAG)
+        std::string upd_msg(mesg);
+        LLUrlMatch match;
+        S32 opening_tag_size = AZURE_NOTRANSLATE_OPENING_TAG.size();
+        S32 closing_tag_size = AZURE_NOTRANSLATE_CLOSING_TAG.size();
+        S32 dif = 0;
+        //remove 'no-translate' tags we added to the links before
+        while (LLUrlRegistry::instance().findUrl(mesg, match))
         {
-            upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
-            dif -= opening_tag_size;
-
-            if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == BING_NOTRANSLATE_CLOSING_TAG)
+            if (upd_msg.substr(dif + match.getStart() - opening_tag_size, opening_tag_size) == AZURE_NOTRANSLATE_OPENING_TAG)
             {
-                upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
-                dif -= closing_tag_size - 1;
+                upd_msg.erase(dif + match.getStart() - opening_tag_size, opening_tag_size);
+                dif -= opening_tag_size;
+
+                if (upd_msg.substr(dif + match.getEnd() + 1, closing_tag_size) == AZURE_NOTRANSLATE_CLOSING_TAG)
+                {
+                    upd_msg.replace(dif + match.getEnd() + 1, closing_tag_size, " ");
+                    dif -= closing_tag_size - 1;
+                }
             }
+            mesg.erase(match.getStart(), match.getUrl().size());
+            dif += match.getUrl().size();
         }
-        mesg.erase(match.getStart(), match.getUrl().size());
-        dif += match.getUrl().size();
+        return upd_msg;
     }
-    return upd_msg;
+
+    return mesg;
 }
 
 /*static*/
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 870fd54441..1de5c02f74 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -59,7 +59,7 @@ public :
 		SERVICE_GOOGLE,
 	} EService;
 
-    typedef boost::function<void(EService, bool)> KeyVerificationResult_fn;
+    typedef boost::function<void(EService, bool, S32)> KeyVerificationResult_fn;
     typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn;
     typedef boost::function<void(int, std::string)> TranslationFailure_fn;
 
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index b0e47798e9..d095451685 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -9,8 +9,8 @@
  title="CHAT TRANSLATION SETTINGS"
  width="485">
 
- <string name="azure_api_key_not_verified">Azure service identifier not verified. Please try again.</string>
- <string name="google_api_key_not_verified">Google API key not verified. Please try again.</string>
+ <string name="azure_api_key_not_verified">Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again.</string>
+ <string name="google_api_key_not_verified">Google API key not verified. Status: [STATUS]. Please check your key and try again.</string>
 
  <string name="azure_api_key_verified">Azure service identifier verified.</string>
  <string name="google_api_key_verified">Google API key verified.</string>
@@ -147,6 +147,19 @@
    top_pad="115" />
  </radio_group>
 
+  <text
+   follows="top|right"
+   height="20"
+   layout="topleft"
+   left="185"
+   length="1"
+   name="google_links_text"
+   top_pad="-142"
+   type="string"
+   width="100">
+    [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup]
+  </text>
+
   <text
    type="string"
    length="1"
@@ -155,7 +168,7 @@
    layout="topleft"
    left="70"
    name="azure_api_endoint_label"
-   top_pad="-115"
+   top_pad="8"
    width="85">
     Endpoint:
   </text>
-- 
cgit v1.2.3


From b2a06908859caa3d816ab1791fe2062142e2ccce Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 28 Feb 2023 00:51:25 +0200
Subject: SL-19209 Add default text for region field

---
 indra/newview/llfloatertranslationsettings.cpp                      | 5 +++--
 indra/newview/lltranslate.cpp                                       | 4 +---
 indra/newview/skins/default/xui/en/floater_translation_settings.xml | 1 +
 3 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index c99de47da0..e14227f490 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -94,11 +94,11 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE);
 
 	LLSD azure_key = gSavedSettings.getLLSD("AzureTranslateAPIKey");
-	if (azure_key.isMap())
+	if (azure_key.isMap() && !azure_key["id"].asString().empty())
 	{
 		mAzureAPIKeyEditor->setText(azure_key["id"].asString());
 		mAzureAPIKeyEditor->setTentative(false);
-        if (azure_key.has("region"))
+        if (azure_key.has("region") && !azure_key["region"].asString().empty())
         {
             mAzureAPIRegionEditor->setText(azure_key["region"].asString());
             mAzureAPIRegionEditor->setTentative(false);
@@ -113,6 +113,7 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 	else
 	{
 		mAzureAPIKeyEditor->setTentative(TRUE);
+        mAzureAPIRegionEditor->setTentative(true);
 		mAzureKeyVerified = FALSE;
 	}
 
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index b0c4418ae9..f84c660c0d 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -229,8 +229,6 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
         return;
     }
-    LL_DEBUGS("Translate") << "Message: " << msg << LL_ENDL;
-    LL_DEBUGS("Translate") << "Requesting: " << url << LL_ENDL;
 
     LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg);
 
@@ -646,7 +644,7 @@ bool LLAzureTranslationHandler::checkVerificationResponse(
     }
 
     // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}"
-    // But for now just verify response is a valid json with an error
+    // But for now just verify response is a valid json
 
     Json::Value root;
     Json::Reader reader;
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index d095451685..a5154d99ec 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -246,6 +246,7 @@
     Region:
   </text>
   <line_editor
+   default_text="Can be left empty for global services"
    follows="top|left"
    height="20"
    layout="topleft"
-- 
cgit v1.2.3


From 89afd1cd4838022267f117efb65939c04c35f3da Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 28 Feb 2023 17:43:44 +0200
Subject: D580 Fix coding policy failures

---
 indra/newview/llpanelface.h | 1126 +++++++++++++++++++++----------------------
 1 file changed, 563 insertions(+), 563 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 787eb0c51b..aaf8eddaf7 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -1,563 +1,563 @@
-/** 
- * @file llpanelface.h
- * @brief Panel in the tools floater for editing face textures, colors, etc.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPANELFACE_H
-#define LL_LLPANELFACE_H
-
-#include "v4color.h"
-#include "llpanel.h"
-#include "llmaterial.h"
-#include "llmaterialmgr.h"
-#include "lltextureentry.h"
-#include "llselectmgr.h"
-
-class LLButton;
-class LLCheckBoxCtrl;
-class LLColorSwatchCtrl;
-class LLComboBox;
-class LLInventoryItem;
-class LLLineEditor;
-class LLSpinCtrl;
-class LLTextBox;
-class LLTextureCtrl;
-class LLUICtrl;
-class LLViewerObject;
-class LLFloater;
-class LLMaterialID;
-class LLMediaCtrl;
-class LLMenuButton;
-
-// Represents an edit for use in replicating the op across one or more materials in the selection set.
-//
-// The apply function optionally performs the edit which it implements
-// as a functor taking Data that calls member func MaterialFunc taking SetValueType
-// on an instance of the LLMaterial class.
-//
-// boost who?
-//
-template<
-	typename DataType,
-	typename SetValueType,
-	void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
-class LLMaterialEditFunctor
-{
-public:
-	LLMaterialEditFunctor(const DataType& data) : _data(data) {}
-	virtual ~LLMaterialEditFunctor() {}
-	virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
-	DataType _data;
-};
-
-template<
-	typename DataType,
-	DataType (LLMaterial::*MaterialGetFunc)() >
-class LLMaterialGetFunctor
-{
-public:
-	LLMaterialGetFunctor() {}
-	virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
-};
-
-template<
-	typename DataType,
-	DataType (LLTextureEntry::*TEGetFunc)() >
-class LLTEGetFunctor
-{
-public:
-	LLTEGetFunctor() {}
-	virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
-};
-
-class LLPanelFace : public LLPanel
-{
-public:
-	virtual BOOL	postBuild();
-	LLPanelFace();
-	virtual ~LLPanelFace();
-
-	void			refresh();
-    void			refreshMedia();
-    void			unloadMedia();
-
-    /*virtual*/ void draw();
-
-	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
-	{
-		LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
-		llassert_always(new_material);
-
-		// Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
-		//
-		new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
-		return new_material;
-	}
-
-	LLRender::eTexIndex getTextureChannelToEdit();
-
-protected:
-    void			navigateToTitleMedia(const std::string url);
-    bool			selectedMediaEditable();
-    void			clearMediaSettings();
-    void			updateMediaSettings();
-    void			updateMediaTitle();
-
-	void			getState();
-
-	void			sendTexture();			// applies and sends texture
-	void			sendTextureInfo();		// applies and sends texture scale, offset, etc.
-	void			sendColor();			// applies and sends color
-	void			sendAlpha();			// applies and sends transparency
-	void			sendBump(U32 bumpiness);				// applies and sends bump map
-	void			sendTexGen();				// applies and sends bump map
-	void			sendShiny(U32 shininess);			// applies and sends shininess
-	void			sendFullbright();		// applies and sends full bright
-	void			sendGlow();
-    void            alignTestureLayer();
-
-    void            updateCopyTexButton();
-
-	// this function is to return TRUE if the drag should succeed.
-	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
-
-	void 	onCommitTexture(const LLSD& data);
-	void 	onCancelTexture(const LLSD& data);
-	void 	onSelectTexture(const LLSD& data);
-	void 	onCommitSpecularTexture(const LLSD& data);
-	void 	onCancelSpecularTexture(const LLSD& data);
-	void 	onSelectSpecularTexture(const LLSD& data);
-	void 	onCommitNormalTexture(const LLSD& data);
-	void 	onCancelNormalTexture(const LLSD& data);
-	void 	onSelectNormalTexture(const LLSD& data);
-	void 	onCommitColor(const LLSD& data);
-	void 	onCommitShinyColor(const LLSD& data);
-	void 	onCommitAlpha(const LLSD& data);
-	void 	onCancelColor(const LLSD& data);
-	void 	onCancelShinyColor(const LLSD& data);
-	void 	onSelectColor(const LLSD& data);
-	void 	onSelectShinyColor(const LLSD& data);
-
-	void 	onCloseTexturePicker(const LLSD& data);
-
-    static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
-    static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
-
-	// Make UI reflect state of currently selected material (refresh)
-	// and UI mode (e.g. editing normal map v diffuse map)
-	//
-	// @param force_set_values forces spinners to set value even if they are focused
-	void updateUI(bool force_set_values = false);
-
-	// Convenience func to determine if all faces in selection have
-	// identical planar texgen settings during edits
-	// 
-	bool isIdenticalPlanarTexgen();
-
-	// Callback funcs for individual controls
-	//
-	static void		onCommitTextureInfo(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureScaleX(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureScaleY(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureRot(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureOffsetX(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTextureOffsetY(LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialBumpyScaleX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyScaleY(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyRot(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyOffsetX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialBumpyOffsetY(	LLUICtrl* ctrl, void* userdata);
-
-	static void		syncRepeatX(LLPanelFace* self, F32 scaleU);
-	static void		syncRepeatY(LLPanelFace* self, F32 scaleV);
-	static void		syncOffsetX(LLPanelFace* self, F32 offsetU);
-	static void		syncOffsetY(LLPanelFace* self, F32 offsetV);
-	static void 	syncMaterialRot(LLPanelFace* self, F32 rot, int te = -1);
-
-	static void		onCommitMaterialShinyScaleX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyScaleY(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyRot(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyOffsetX(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialShinyOffsetY(	LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialGloss(			LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialEnv(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialMaskCutoff(	LLUICtrl* ctrl, void* userdata);
-
-	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
-	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata);
-	static void 	onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata);
-	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
-	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
-	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
-	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
-	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
-	static void		onClickAutoFix(void*);
-    static void		onAlignTexture(void*);
-
-public: // needs to be accessible to selection manager
-    void            onCopyColor(); // records all selected faces
-    void            onPasteColor(); // to specific face
-    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
-    void            onCopyTexture();
-    void            onPasteTexture();
-    void            onPasteTexture(LLViewerObject* objectp, S32 te);
-
-protected:
-    void            menuDoToSelected(const LLSD& userdata);
-    bool            menuEnableItem(const LLSD& userdata);
-
-	static F32     valueGlow(LLViewerObject* object, S32 face);
-
-	
-
-private:
-	bool		isAlpha() { return mIsAlpha; }
-
-	// Convenience funcs to keep the visual flack to a minimum
-	//
-	LLUUID	getCurrentNormalMap();
-	LLUUID	getCurrentSpecularMap();
-	U32		getCurrentShininess();
-	U32		getCurrentBumpiness();
-	U8		getCurrentDiffuseAlphaMode();
-	U8		getCurrentAlphaMaskCutoff();
-	U8		getCurrentEnvIntensity();
-	U8		getCurrentGlossiness();
-	F32		getCurrentBumpyRot();
-	F32		getCurrentBumpyScaleU();
-	F32		getCurrentBumpyScaleV();
-	F32		getCurrentBumpyOffsetU();
-	F32		getCurrentBumpyOffsetV();
-	F32		getCurrentShinyRot();
-	F32		getCurrentShinyScaleU();
-	F32		getCurrentShinyScaleV();
-	F32		getCurrentShinyOffsetU();
-	F32		getCurrentShinyOffsetV();
-
-    LLComboBox *mComboMatMedia;
-    LLMediaCtrl *mTitleMedia;
-    LLTextBox *mTitleMediaText;
-
-	// Update visibility of controls to match current UI mode
-	// (e.g. materials vs media editing)
-	//
-	// Do NOT call updateUI from within this function.
-	//
-	void updateVisibility();
-
-	// Hey look everyone, a type-safe alternative to copy and paste! :)
-	//
-
-	// Update material parameters by applying 'edit_func' to selected TEs
-	//
-	template<
-		typename DataType,
-		typename SetValueType,
-		void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
-	static void edit(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())
-	{
-		LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
-		struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
-		{
-			LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {}
-			virtual ~LLSelectedTEEditMaterial() {};
-			virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
-			{
-				if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID()))
-				{
-					LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
-					llassert_always(new_material);
-
-					// Determine correct alpha mode for current diffuse texture
-					// (i.e. does it have an alpha channel that makes alpha mode useful)
-					//
-					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
-					// need to get per-face answer to this question for sane alpha mode retention on updates.
-					//					
-					bool is_alpha_face = object->isImageAlphaBlended(face);
-
-					// need to keep this original answer for valid comparisons in logic below
-					//
-					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-					
-					U8 default_alpha_mode = original_default_alpha_mode;
-
-					if (!current_material.isNull())
-					{
-						default_alpha_mode = current_material->getDiffuseAlphaMode();
-					}
-
-					// Insure we don't inherit the default of blend by accident...
-					// this will be stomped by a legit request to change the alpha mode by the apply() below
-					//
-					new_material->setDiffuseAlphaMode(default_alpha_mode);
-
-					// Do "It"!
-					//
-					_edit->apply(new_material);
-
-					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
-					LLUUID	new_normal_map_id		= new_material->getNormalID();
-					LLUUID	new_spec_map_id			= new_material->getSpecularID();
-
-					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
-					{
-						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
-					}
-
-					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
-					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
-
-					if (!is_need_material)
-					{
-						LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
-						LLMaterialMgr::getInstance()->remove(object->getID(),face);
-						new_material = NULL;
-					}
-					else
-					{
-						LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
-						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
-					}
-
-					object->setTEMaterialParams(face, new_material);
-					return new_material;
-				}
-				return NULL;
-			}
-			LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >*	_edit;
-			LLPanelFace *_panel;
-			const LLUUID & _only_for_object_id;
-		} editor(p, &edit, only_for_object_id);
-		LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te);
-	}
-
-	template<
-		typename DataType,
-		typename ReturnType,
-		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
-	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
-	{
-		DataType data_value;
-		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
-		{
-			GetTEMaterialVal(DataType default_value) : _default(default_value) {}
-			virtual ~GetTEMaterialVal() {}
-
-			DataType get(LLViewerObject* object, S32 face)
-			{
-				DataType ret = _default;
-				LLMaterialPtr material_ptr;
-				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
-				if (tep)
-				{
-					material_ptr = tep->getMaterialParams();
-					if (!material_ptr.isNull())
-					{
-						ret = (material_ptr->*(MaterialGetFunc))();
-					}
-				}
-				return ret;
-			}
-			DataType _default;
-		} GetFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
-		data_to_return = data_value;
-	}
-
-	template<
-		typename DataType,
-		typename ReturnType, // some kids just have to different...
-		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
-	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
-	{
-		DataType data_value;
-		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
-		{
-			GetTEVal(DataType default_value) : _default(default_value) {}
-			virtual ~GetTEVal() {}
-
-			DataType get(LLViewerObject* object, S32 face) {
-				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
-				return tep ? ((tep->*(TEGetFunc))()) : _default;
-			}
-			DataType _default;
-		} GetTEValFunc(default_value);
-		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
-		data_to_return = data_value;
-	}
-
-	// Update vis and enabling of specific subsets of controls based on material params
-	// (e.g. hide the spec controls if no spec texture is applied)
-	//
-	void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
-	void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
-	void updateAlphaControls();
-
-	/*
-	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
-	 * If agent selects texture which is not allowed to be applied for the currently selected object,
-	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
-	 */
-    void onTextureSelectionChanged(LLInventoryItem* itemp);
-
-    LLMenuButton*   mMenuClipboardColor;
-    LLMenuButton*   mMenuClipboardTexture;
-
-	bool mIsAlpha;
-	
-	/* These variables interlock processing of materials updates sent to
-	 * the sim.  mUpdateInFlight is set to flag that an update has been
-	 * sent to the sim and not acknowledged yet, and cleared when an
-	 * update is received from the sim.  mUpdatePending is set when
-	 * there's an update in flight and another UI change has been made
-	 * that needs to be sent as a materials update, and cleared when the
-	 * update is sent.  This prevents the sim from getting spammed with
-	 * update messages when, for example, the user holds down the
-	 * up-arrow on a spinner, and avoids running afoul of its throttle.
-	 */
-	bool mUpdateInFlight;
-    bool mUpdatePending;
-
-    LLSD            mClipboardParams;
-
-    LLSD mMediaSettings;
-    bool mNeedMediaTitle;
-
-public:
-	#if defined(DEF_GET_MAT_STATE)
-		#undef DEF_GET_MAT_STATE
-	#endif
-
-	#if defined(DEF_GET_TE_STATE)
-		#undef DEF_GET_TE_STATE
-	#endif
-
-	#if defined(DEF_EDIT_MAT_STATE)
-		DEF_EDIT_MAT_STATE
-	#endif
-
-    // Accessors for selected TE material state
-    //
-    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance)                                           \
-        static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)          \
-        {                                                                                                                                           \
-            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
-        }
-
-    // Mutators for selected TE material
-    //
-    #define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc)                                                              \
-        static void MaterialMemberFunc(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())     \
-        {                                                                                                                           \
-            edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id);                         \
-        }
-
-    // Accessors for selected TE state proper (legacy settings etc)
-    //
-    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance)                                        \
-        static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)      \
-        {                                                                                                                                       \
-            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
-        }
-
-	class LLSelectedTEMaterial
-	{
-	public:
-		static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
-		static void getMaxSpecularRepeats(F32& repeats, bool& identical);
-		static void getMaxNormalRepeats(F32& repeats, bool& identical);
-		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
-
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
-		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
-
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
-		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
-
-		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
-		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
-
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
-		DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
-
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
-		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
-
-		DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
-		DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
-
-		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
-		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
-		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
-	};
-
-	class LLSelectedTE
-	{
-	public:
-		static void getFace(class LLFace*& face_to_return, bool& identical_face);
-		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
-		static void getTexId(LLUUID& id, bool& identical);
-		static void getObjectScaleS(F32& scale_s, bool& identical);
-		static void getObjectScaleT(F32& scale_t, bool& identical);
-		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
-
-		DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
-		DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
-		DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
-		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
-		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
-		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
-		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
-	};
-};
-
-#endif
-
+/** 
+ * @file llpanelface.h
+ * @brief Panel in the tools floater for editing face textures, colors, etc.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELFACE_H
+#define LL_LLPANELFACE_H
+
+#include "v4color.h"
+#include "llpanel.h"
+#include "llmaterial.h"
+#include "llmaterialmgr.h"
+#include "lltextureentry.h"
+#include "llselectmgr.h"
+
+class LLButton;
+class LLCheckBoxCtrl;
+class LLColorSwatchCtrl;
+class LLComboBox;
+class LLInventoryItem;
+class LLLineEditor;
+class LLSpinCtrl;
+class LLTextBox;
+class LLTextureCtrl;
+class LLUICtrl;
+class LLViewerObject;
+class LLFloater;
+class LLMaterialID;
+class LLMediaCtrl;
+class LLMenuButton;
+
+// Represents an edit for use in replicating the op across one or more materials in the selection set.
+//
+// The apply function optionally performs the edit which it implements
+// as a functor taking Data that calls member func MaterialFunc taking SetValueType
+// on an instance of the LLMaterial class.
+//
+// boost who?
+//
+template<
+	typename DataType,
+	typename SetValueType,
+	void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+class LLMaterialEditFunctor
+{
+public:
+	LLMaterialEditFunctor(const DataType& data) : _data(data) {}
+	virtual ~LLMaterialEditFunctor() {}
+	virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
+	DataType _data;
+};
+
+template<
+	typename DataType,
+	DataType (LLMaterial::*MaterialGetFunc)() >
+class LLMaterialGetFunctor
+{
+public:
+	LLMaterialGetFunctor() {}
+	virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
+};
+
+template<
+	typename DataType,
+	DataType (LLTextureEntry::*TEGetFunc)() >
+class LLTEGetFunctor
+{
+public:
+	LLTEGetFunctor() {}
+	virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
+};
+
+class LLPanelFace : public LLPanel
+{
+public:
+	virtual BOOL	postBuild();
+	LLPanelFace();
+	virtual ~LLPanelFace();
+
+	void			refresh();
+    void			refreshMedia();
+    void			unloadMedia();
+
+    /*virtual*/ void draw();
+
+	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
+	{
+		LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+		llassert_always(new_material);
+
+		// Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
+		//
+		new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
+		return new_material;
+	}
+
+	LLRender::eTexIndex getTextureChannelToEdit();
+
+protected:
+    void			navigateToTitleMedia(const std::string url);
+    bool			selectedMediaEditable();
+    void			clearMediaSettings();
+    void			updateMediaSettings();
+    void			updateMediaTitle();
+
+	void			getState();
+
+	void			sendTexture();			// applies and sends texture
+	void			sendTextureInfo();		// applies and sends texture scale, offset, etc.
+	void			sendColor();			// applies and sends color
+	void			sendAlpha();			// applies and sends transparency
+	void			sendBump(U32 bumpiness);				// applies and sends bump map
+	void			sendTexGen();				// applies and sends bump map
+	void			sendShiny(U32 shininess);			// applies and sends shininess
+	void			sendFullbright();		// applies and sends full bright
+	void			sendGlow();
+    void            alignTestureLayer();
+
+    void            updateCopyTexButton();
+
+	// this function is to return TRUE if the drag should succeed.
+	static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
+
+	void 	onCommitTexture(const LLSD& data);
+	void 	onCancelTexture(const LLSD& data);
+	void 	onSelectTexture(const LLSD& data);
+	void 	onCommitSpecularTexture(const LLSD& data);
+	void 	onCancelSpecularTexture(const LLSD& data);
+	void 	onSelectSpecularTexture(const LLSD& data);
+	void 	onCommitNormalTexture(const LLSD& data);
+	void 	onCancelNormalTexture(const LLSD& data);
+	void 	onSelectNormalTexture(const LLSD& data);
+	void 	onCommitColor(const LLSD& data);
+	void 	onCommitShinyColor(const LLSD& data);
+	void 	onCommitAlpha(const LLSD& data);
+	void 	onCancelColor(const LLSD& data);
+	void 	onCancelShinyColor(const LLSD& data);
+	void 	onSelectColor(const LLSD& data);
+	void 	onSelectShinyColor(const LLSD& data);
+
+	void 	onCloseTexturePicker(const LLSD& data);
+
+    static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
+    static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
+
+	// Make UI reflect state of currently selected material (refresh)
+	// and UI mode (e.g. editing normal map v diffuse map)
+	//
+	// @param force_set_values forces spinners to set value even if they are focused
+	void updateUI(bool force_set_values = false);
+
+	// Convenience func to determine if all faces in selection have
+	// identical planar texgen settings during edits
+	// 
+	bool isIdenticalPlanarTexgen();
+
+	// Callback funcs for individual controls
+	//
+	static void		onCommitTextureInfo(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureScaleX(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureScaleY(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureRot(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureOffsetX(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTextureOffsetY(LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialBumpyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		syncRepeatX(LLPanelFace* self, F32 scaleU);
+	static void		syncRepeatY(LLPanelFace* self, F32 scaleV);
+	static void		syncOffsetX(LLPanelFace* self, F32 offsetU);
+	static void		syncOffsetY(LLPanelFace* self, F32 offsetV);
+	static void 	syncMaterialRot(LLPanelFace* self, F32 rot, int te = -1);
+
+	static void		onCommitMaterialShinyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialGloss(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialEnv(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialMaskCutoff(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata);
+	static void 	onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata);
+	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
+	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
+	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
+	static void		onClickAutoFix(void*);
+    static void		onAlignTexture(void*);
+
+public: // needs to be accessible to selection manager
+    void            onCopyColor(); // records all selected faces
+    void            onPasteColor(); // to specific face
+    void            onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
+    void            onCopyTexture();
+    void            onPasteTexture();
+    void            onPasteTexture(LLViewerObject* objectp, S32 te);
+
+protected:
+    void            menuDoToSelected(const LLSD& userdata);
+    bool            menuEnableItem(const LLSD& userdata);
+
+	static F32     valueGlow(LLViewerObject* object, S32 face);
+
+	
+
+private:
+	bool		isAlpha() { return mIsAlpha; }
+
+	// Convenience funcs to keep the visual flack to a minimum
+	//
+	LLUUID	getCurrentNormalMap();
+	LLUUID	getCurrentSpecularMap();
+	U32		getCurrentShininess();
+	U32		getCurrentBumpiness();
+	U8		getCurrentDiffuseAlphaMode();
+	U8		getCurrentAlphaMaskCutoff();
+	U8		getCurrentEnvIntensity();
+	U8		getCurrentGlossiness();
+	F32		getCurrentBumpyRot();
+	F32		getCurrentBumpyScaleU();
+	F32		getCurrentBumpyScaleV();
+	F32		getCurrentBumpyOffsetU();
+	F32		getCurrentBumpyOffsetV();
+	F32		getCurrentShinyRot();
+	F32		getCurrentShinyScaleU();
+	F32		getCurrentShinyScaleV();
+	F32		getCurrentShinyOffsetU();
+	F32		getCurrentShinyOffsetV();
+
+    LLComboBox *mComboMatMedia;
+    LLMediaCtrl *mTitleMedia;
+    LLTextBox *mTitleMediaText;
+
+	// Update visibility of controls to match current UI mode
+	// (e.g. materials vs media editing)
+	//
+	// Do NOT call updateUI from within this function.
+	//
+	void updateVisibility();
+
+	// Hey look everyone, a type-safe alternative to copy and paste! :)
+	//
+
+	// Update material parameters by applying 'edit_func' to selected TEs
+	//
+	template<
+		typename DataType,
+		typename SetValueType,
+		void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+	static void edit(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())
+	{
+		LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
+		struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
+		{
+			LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {}
+			virtual ~LLSelectedTEEditMaterial() {};
+			virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
+			{
+				if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID()))
+				{
+					LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
+					llassert_always(new_material);
+
+					// Determine correct alpha mode for current diffuse texture
+					// (i.e. does it have an alpha channel that makes alpha mode useful)
+					//
+					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
+					// need to get per-face answer to this question for sane alpha mode retention on updates.
+					//					
+					bool is_alpha_face = object->isImageAlphaBlended(face);
+
+					// need to keep this original answer for valid comparisons in logic below
+					//
+					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+					
+					U8 default_alpha_mode = original_default_alpha_mode;
+
+					if (!current_material.isNull())
+					{
+						default_alpha_mode = current_material->getDiffuseAlphaMode();
+					}
+
+					// Insure we don't inherit the default of blend by accident...
+					// this will be stomped by a legit request to change the alpha mode by the apply() below
+					//
+					new_material->setDiffuseAlphaMode(default_alpha_mode);
+
+					// Do "It"!
+					//
+					_edit->apply(new_material);
+
+					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
+					LLUUID	new_normal_map_id		= new_material->getNormalID();
+					LLUUID	new_spec_map_id			= new_material->getSpecularID();
+
+					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
+					{
+						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					}
+
+					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
+					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
+
+					if (!is_need_material)
+					{
+						LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
+						LLMaterialMgr::getInstance()->remove(object->getID(),face);
+						new_material = NULL;
+					}
+					else
+					{
+						LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
+						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
+					}
+
+					object->setTEMaterialParams(face, new_material);
+					return new_material;
+				}
+				return NULL;
+			}
+			LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >*	_edit;
+			LLPanelFace *_panel;
+			const LLUUID & _only_for_object_id;
+		} editor(p, &edit, only_for_object_id);
+		LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te);
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType,
+		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
+	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+	{
+		DataType data_value;
+		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEMaterialVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEMaterialVal() {}
+
+			DataType get(LLViewerObject* object, S32 face)
+			{
+				DataType ret = _default;
+				LLMaterialPtr material_ptr;
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				if (tep)
+				{
+					material_ptr = tep->getMaterialParams();
+					if (!material_ptr.isNull())
+					{
+						ret = (material_ptr->*(MaterialGetFunc))();
+					}
+				}
+				return ret;
+			}
+			DataType _default;
+		} GetFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
+		data_to_return = data_value;
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType, // some kids just have to different...
+		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
+	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+	{
+		DataType data_value;
+		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEVal() {}
+
+			DataType get(LLViewerObject* object, S32 face) {
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				return tep ? ((tep->*(TEGetFunc))()) : _default;
+			}
+			DataType _default;
+		} GetTEValFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
+		data_to_return = data_value;
+	}
+
+	// Update vis and enabling of specific subsets of controls based on material params
+	// (e.g. hide the spec controls if no spec texture is applied)
+	//
+	void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateAlphaControls();
+
+	/*
+	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
+	 * If agent selects texture which is not allowed to be applied for the currently selected object,
+	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
+	 */
+    void onTextureSelectionChanged(LLInventoryItem* itemp);
+
+    LLMenuButton*   mMenuClipboardColor;
+    LLMenuButton*   mMenuClipboardTexture;
+
+	bool mIsAlpha;
+	
+	/* These variables interlock processing of materials updates sent to
+	 * the sim.  mUpdateInFlight is set to flag that an update has been
+	 * sent to the sim and not acknowledged yet, and cleared when an
+	 * update is received from the sim.  mUpdatePending is set when
+	 * there's an update in flight and another UI change has been made
+	 * that needs to be sent as a materials update, and cleared when the
+	 * update is sent.  This prevents the sim from getting spammed with
+	 * update messages when, for example, the user holds down the
+	 * up-arrow on a spinner, and avoids running afoul of its throttle.
+	 */
+	bool mUpdateInFlight;
+    bool mUpdatePending;
+
+    LLSD            mClipboardParams;
+
+    LLSD mMediaSettings;
+    bool mNeedMediaTitle;
+
+public:
+	#if defined(DEF_GET_MAT_STATE)
+		#undef DEF_GET_MAT_STATE
+	#endif
+
+	#if defined(DEF_GET_TE_STATE)
+		#undef DEF_GET_TE_STATE
+	#endif
+
+	#if defined(DEF_EDIT_MAT_STATE)
+		DEF_EDIT_MAT_STATE
+	#endif
+
+    // Accessors for selected TE material state
+    //
+    #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance)                                           \
+        static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)          \
+        {                                                                                                                                           \
+            getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
+        }
+
+    // Mutators for selected TE material
+    //
+    #define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc)                                                              \
+        static void MaterialMemberFunc(LLPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())     \
+        {                                                                                                                           \
+            edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id);                         \
+        }
+
+    // Accessors for selected TE state proper (legacy settings etc)
+    //
+    #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance)                                        \
+        static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance)      \
+        {                                                                                                                                       \
+            getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance);   \
+        }
+
+	class LLSelectedTEMaterial
+	{
+	public:
+		static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
+		static void getMaxSpecularRepeats(F32& repeats, bool& identical);
+		static void getMaxNormalRepeats(F32& repeats, bool& identical);
+		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
+
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
+
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
+
+		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
+		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
+
+		DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
+		DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
+
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
+		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
+	};
+
+	class LLSelectedTE
+	{
+	public:
+		static void getFace(class LLFace*& face_to_return, bool& identical_face);
+		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
+		static void getTexId(LLUUID& id, bool& identical);
+		static void getObjectScaleS(F32& scale_s, bool& identical);
+		static void getObjectScaleT(F32& scale_t, bool& identical);
+		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
+
+		DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
+		DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
+		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
+		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
+		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
+		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
+	};
+};
+
+#endif
+
-- 
cgit v1.2.3


From cdb3c018af9fc75064dc63537e61c5df567c331a Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Wed, 1 Mar 2023 10:26:34 -0500
Subject: SL-19336 Unload avatar and group icons from memory when not visible
 to reduce memory pressure on extremely large friends lists

---
 indra/llui/lliconctrl.cpp | 26 ++++++++++++++++++++++++++
 indra/llui/lliconctrl.h   |  3 +++
 indra/llui/lltextbase.cpp |  4 ++--
 indra/llui/llview.h       |  1 +
 4 files changed, 32 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index e01aba402e..2791377a5e 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -37,6 +37,8 @@
 #include "lluiimage.h"
 #include "llwindow.h"
 
+#include "llgltexture.h"
+
 static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
 
 LLIconCtrl::Params::Params()
@@ -94,6 +96,22 @@ BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask)
     return LLUICtrl::handleHover(x, y, mask);
 }
 
+void LLIconCtrl::onVisibilityChange(BOOL new_visibility)
+{
+	LLUICtrl::onVisibilityChange(new_visibility);
+	if (mPriority == LLGLTexture::BOOST_ICON)
+	{
+		if (new_visibility)
+		{
+			loadImage(getValue(), mPriority);
+		}
+		else
+		{
+			mImagep = nullptr;
+		}
+	}
+}
+
 // virtual
 // value might be a string or a UUID
 void LLIconCtrl::setValue(const LLSD& value)
@@ -110,6 +128,14 @@ void LLIconCtrl::setValue(const LLSD& value, S32 priority)
 		tvalue = LLSD(LLUUID(value.asString()));
 	}
 	LLUICtrl::setValue(tvalue);
+
+	loadImage(tvalue, priority);
+}
+
+void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority)
+{
+	if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return;
+
 	if (tvalue.isUUID())
 	{
         mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority);
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 9c3b517bca..5d6c544571 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -72,6 +72,7 @@ public:
     virtual BOOL handleHover(S32 x, S32 y, MASK mask);
 
 	// lluictrl overrides
+	void onVisibilityChange(BOOL new_visibility);
 	virtual void	setValue(const LLSD& value );
 
 	std::string	getImageName() const;
@@ -95,6 +96,8 @@ protected:
     bool mInteractable;
 
 private:
+	void loadImage(const LLSD& value, S32 priority);
+
 	LLUIColor mColor;
 	LLPointer<LLUIImage> mImagep;
 };
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 82a3c01c6d..3d8cf74855 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1356,9 +1356,9 @@ void LLTextBase::draw()
 		drawCursor();
 	}
  
-	mDocumentView->setVisible(FALSE);
+	mDocumentView->setVisibleDirect(FALSE);
 	LLUICtrl::draw();
-	mDocumentView->setVisible(TRUE);
+	mDocumentView->setVisibleDirect(TRUE);
 }
 
 
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index bec45df78a..8aa97aac39 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -287,6 +287,7 @@ public:
 	void 	setAllChildrenEnabled(BOOL b);
 
 	virtual void	setVisible(BOOL visible);
+	void			setVisibleDirect(BOOL visible) { mVisible = visible; }
 	const BOOL&		getVisible() const			{ return mVisible; }
 	virtual void	setEnabled(BOOL enabled);
 	BOOL			getEnabled() const			{ return mEnabled; }
-- 
cgit v1.2.3


From 4885ea4fba4c998960d0817e94e69cddd7cd189a Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Tue, 7 Mar 2023 01:44:39 +0200
Subject: INTL-483 Fixed PT translation

---
 indra/newview/skins/default/xui/pt/panel_edit_hair.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
index 13f1f892f9..e9750a1c2e 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_hair.xml
@@ -7,7 +7,7 @@
 		<accordion name="wearable_accordion">
 			<accordion_tab name="hair_color_tab" title="Cor"/>
 			<accordion_tab name="hair_style_tab" title="Estilo"/>
-			<accordion_tab name="hair_eyebrows_tab" title="Sombrancelhas"/>
+			<accordion_tab name="hair_eyebrows_tab" title="Sobrancelhas"/>
 			<accordion_tab name="hair_facial_tab" title="Faciais"/>
 		</accordion>
 	</panel>
-- 
cgit v1.2.3


From 5cbbfba46f11be76d1d5eb088f5448992d5e3bed Mon Sep 17 00:00:00 2001
From: Maxim Nikolenko <maximnproductengine@lindenlab.com>
Date: Thu, 9 Mar 2023 18:11:48 +0200
Subject: SL-19367 FIXED Failing to detach temporary mesh attachment

---
 indra/newview/llpanelwearing.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 3347c40687..bc9f0cef83 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -566,7 +566,7 @@ void LLPanelWearing::onRemoveAttachment()
 	{
 		LLSelectMgr::getInstance()->deselectAll();
 		LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]);
-		LLSelectMgr::getInstance()->sendDropAttachment();
+		LLSelectMgr::getInstance()->sendDetach();
 	}
 }
 
-- 
cgit v1.2.3


From 1a8c03cfda1863889b21b25a1f127bc541464f5b Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Wed, 15 Mar 2023 17:23:05 +0100
Subject: SL-19085 Save Wiki-style URL as link when creating the Pick with an
 existing link in About Land

---
 indra/newview/llpanelprofilepicks.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp
index 45d0252e4f..db3a3c6de5 100644
--- a/indra/newview/llpanelprofilepicks.cpp
+++ b/indra/newview/llpanelprofilepicks.cpp
@@ -529,6 +529,7 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id)
             pick_name = parcel->getName();
             pick_desc = parcel->getDesc();
             snapshot_id = parcel->getSnapshotID();
+            mPickDescription->setParseHTML(false);
         }
 
         LLViewerRegion* region = gAgent.getRegion();
-- 
cgit v1.2.3


From d2a8a3bd53f011b7137717ece39f01b5242bb45a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 16 Mar 2023 00:04:11 +0200
Subject: SL-18964 Smoke texture can fail to load

Debt from SL-18221.
Keep init together, after we got the cap; texture should finish loading before it's needed.
---
 indra/newview/lldrawpoolalpha.cpp     | 7 +------
 indra/newview/llviewertexture.cpp     | 7 -------
 indra/newview/llviewertexturelist.cpp | 2 ++
 3 files changed, 3 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index d4797321bb..f91069185a 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -281,12 +281,7 @@ void LLDrawPoolAlpha::renderDebugAlpha()
         gHighlightProgram.bind();
         gGL.diffuseColor4f(1, 0, 0, 1);
 
-        // SL-18964 : The creating of this texture was moved here from LLViewerTextureManager::init() to make the texture transparent before adding to cache
-        if (!LLViewerFetchedTexture::sSmokeImagep)
-        {
-            LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
-            LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
-        }
+
         LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f);
         gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep);
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 0d82aced23..df65fe8fb8 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -402,13 +402,6 @@ void LLViewerTextureManager::init()
 	LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
 	LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER);
 
-#if 0
-	// When called first time after clearing cache this call creates (and adds to cache) an opaque texture instead of transparent
-	// SL-18964 : The creating of this texture was moved to LLDrawPoolAlpha::renderDebugAlpha()
- 	LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
-	LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
-#endif
-
 	image_raw = new LLImageRaw(32,32,3);
 	data = image_raw->getData();
 
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 93ae1670c8..52e6a9a2df 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -228,6 +228,8 @@ void LLViewerTextureList::doPrefetchImages()
 
     LLViewerTextureManager::getFetchedTexture(IMG_SHOT);
     LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF);
+    LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
+    LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
 
     LLStandardBumpmap::addstandard();
 
-- 
cgit v1.2.3


From f5adfae1ade864d80f630855bc65bf65f5ae7ece Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Sun, 19 Mar 2023 05:07:44 +0100
Subject: SL-19099 The long name of the item is out of bounds on the Editing
 Tools/Content tab

---
 indra/llui/llfolderviewitem.cpp          | 2 +-
 indra/llui/llpanel.h                     | 1 +
 indra/newview/llpanelobjectinventory.cpp | 3 ++-
 3 files changed, 4 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index eba93beed9..e2b5279aab 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -395,7 +395,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
             // it is purely visual, so it is fine to do at our laisure
             refreshSuffix();
         }
-		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight; 
+		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
 		mLabelWidthDirty = false;
 	}
 
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index b8f47ef6ba..8018365d3e 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -127,6 +127,7 @@ public:
 	virtual 	void	clearCtrls(); // overridden in LLPanelObject and LLPanelVolume
 
 	// Border controls
+	const LLViewBorder* getBorder() const { return mBorder; }
 	void addBorder( LLViewBorder::Params p);
 	void addBorder();
 	void			removeBorder();
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index bd40c9dd2b..6a82a3b35d 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -1368,7 +1368,8 @@ void LLPanelObjectInventory::reset()
 		LLEditMenuHandler::gEditMenuHandler = mFolders;
 	}
 
-	LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+	int offset = hasBorder() ? getBorder()->getBorderWidth() << 1 : 0;
+	LLRect scroller_rect(0, getRect().getHeight() - offset, getRect().getWidth() - offset, 0);
 	LLScrollContainer::Params scroll_p;
 	scroll_p.name("task inventory scroller");
 	scroll_p.rect(scroller_rect);
-- 
cgit v1.2.3


From c23353cfc3f0a8c580c99332e47c288758a023c8 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Sun, 19 Mar 2023 17:50:13 +0100
Subject: SL-19417 Improve colors.xml behavior

---
 indra/llui/lluicolortable.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index 244f0c6f00..b84bb13edb 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -200,7 +200,6 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa
 void LLUIColorTable::setColor(const std::string& name, const LLColor4& color)
 {
 	setColor(name, color, mUserSetColors);
-	setColor(name, color, mLoadedColors);
 }
 
 bool LLUIColorTable::loadFromSettings()
@@ -229,6 +228,11 @@ void LLUIColorTable::saveUserSettings() const
 		it != mUserSetColors.end();
 		++it)
 	{
+		// Compare user color value with the default value, skip if equal
+		string_color_map_t::const_iterator itd = mLoadedColors.find(it->first);
+		if(itd != mUserSetColors.end() && itd->second == it->second)
+			continue;
+
 		ColorEntryParams color_entry;
 		color_entry.name = it->first;
 		color_entry.color.value = it->second;
-- 
cgit v1.2.3


From cf692c40b0b9f8d0d04cd10a02a84e3f697a2e99 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Mon, 20 Mar 2023 10:20:06 +0100
Subject: SL-18721: Faster viewer shutdown time since performance improvements
 can lead to perceived inventory loss due to cache corruption

---
 indra/llcommon/threadpool.cpp    | 5 +++++
 indra/llcommon/threadpool.h      | 4 ++++
 indra/llwindow/llwindowwin32.cpp | 3 +++
 3 files changed, 12 insertions(+)

(limited to 'indra')

diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index d5adf11264..4a7ead2110 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -39,6 +39,11 @@ void LL::ThreadPool::start()
                 run(tname);
             });
     }
+
+    // Special workflow for LLWindowWin32Thread - it's close() should be called explicitly
+    if (mExplicitShutdown)
+        return;
+
     // Listen on "LLApp", and when the app is shutting down, close the queue
     // and join the workers.
     LLEventPumps::instance().obtain("LLApp").listen(
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index f8eec3b457..0a5f14529b 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -59,6 +59,10 @@ namespace LL
          */
         virtual void run();
 
+    protected:
+        // LLWindowWin32Thread should set this flag to true
+        bool mExplicitShutdown { false };
+
     private:
         void run(const std::string& name);
 
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 41f3042ace..afe26ec5a4 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -4581,6 +4581,9 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
     : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
 {
+    // Set this flag to true to avoid of implicit call of close() from start()
+    mExplicitShutdown = true;
+
     ThreadPool::start();
 }
 
-- 
cgit v1.2.3


From e5b965c892154e5933b9cfe80ce750ff6f542620 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 20 Mar 2023 23:44:54 +0200
Subject: SL-19435 Bounce user back to login if caps are not present

---
 indra/newview/llstartup.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 6883ead5ee..dd3b33982a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1392,8 +1392,16 @@ bool idle_startup()
 		}
         else if (regionp->capabilitiesError())
         {
-            // Try to connect despite capabilities' error state
-            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+            LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL;
+            if (gRememberPassword)
+            {
+                LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
+            }
+            else
+            {
+                LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status);
+            }
+            reset_login();
         }
 		else
 		{
-- 
cgit v1.2.3


From b1fc17a50e9787163d8d984868050926ef7fa4dc Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Tue, 21 Mar 2023 01:17:43 +0100
Subject: SL-19348 Remove 'get mesh_rez_enabled' code in viewer

---
 indra/newview/llfloaterregioninfo.cpp | 14 --------------
 indra/newview/llfloaterregioninfo.h   |  1 -
 2 files changed, 15 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 07d4dcae38..9fb4040f5f 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -317,7 +317,6 @@ void LLFloaterRegionInfo::onOpen(const LLSD& key)
 	}
 	refreshFromRegion(gAgent.getRegion());
 	requestRegionInfo();
-	requestMeshRezInfo();
 
 	if (!mGodLevelChangeSlot.connected())
 	{
@@ -1008,19 +1007,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
 	return false;
 }
 
-void LLFloaterRegionInfo::requestMeshRezInfo()
-{
-	std::string sim_console_url = gAgent.getRegionCapability("SimConsoleAsync");
-
-	if (!sim_console_url.empty())
-	{
-		std::string request_str = "get mesh_rez_enabled";
-		
-        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str),
-            "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled");
-	}
-}
-
 // setregioninfo
 // strings[0] = 'Y' - block terraform, 'N' - not
 // strings[1] = 'Y' - block fly, 'N' - not
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index c34dbb62e8..3eb39b250f 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -102,7 +102,6 @@ public:
 	
 	void onRegionChanged();
 	void requestRegionInfo();
-	void requestMeshRezInfo();
 	void enableTopButtons();
 	void disableTopButtons();
 
-- 
cgit v1.2.3


From 275ad3fdabf8417376e01a4a994d4a78dba6f15f Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Tue, 21 Mar 2023 01:37:51 +0100
Subject: SL-19266 Potential Use-After-Free in LLImageGL::setImage

---
 indra/llrender/llimagegl.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9dc140b5b9..465f30a343 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -859,9 +859,16 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32
 							stop_glerror();
 
 							if (prev_mip_data)
-								delete[] prev_mip_data;
+							{
+								if (prev_mip_data != cur_mip_data)
+									delete[] prev_mip_data;
+								prev_mip_data = nullptr;
+							}
 							if (cur_mip_data)
+							{
 								delete[] cur_mip_data;
+								cur_mip_data = nullptr;
+							}
 							
 							mGLTextureCreated = false;
 							return FALSE;
-- 
cgit v1.2.3


From d1b414e48b4faa8f0b6b68fc6cb16701137478fd Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Fri, 24 Mar 2023 21:10:12 +0100
Subject: SL-17045 LSL editor cursor position desynchronization

---
 indra/llrender/llfontgl.cpp      | 24 +++++++++++++++---------
 indra/llrender/llfontgl.h        |  2 +-
 indra/llui/lltextbase.cpp        |  6 +++---
 indra/llui/lltextbase.h          |  2 +-
 indra/newview/llscripteditor.cpp |  2 +-
 5 files changed, 21 insertions(+), 15 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 1bf061bc8d..6f4f2ec62c 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -494,7 +494,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
 	return getWidthF32(wtext.c_str(), begin_offset, max_chars);
 }
 
-F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
+F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
 {
 	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
 
@@ -517,12 +517,15 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 
 		F32 advance = mFontFreetype->getXAdvance(fgi);
 
-		// for the last character we want to measure the greater of its width and xadvance values
-		// so keep track of the difference between these values for the each character we measure
-		// so we can fix things up at the end
-		width_padding = llmax(	0.f,											// always use positive padding amount
-								width_padding - advance,						// previous padding left over after advance of current character
-								(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character
+		if (!no_padding)
+		{
+			// for the last character we want to measure the greater of its width and xadvance values
+			// so keep track of the difference between these values for the each character we measure
+			// so we can fix things up at the end
+			width_padding = llmax(0.f,											// always use positive padding amount
+				width_padding - advance,						// previous padding left over after advance of current character
+				(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character
+		}
 
 		cur_x += advance;
 		llwchar next_char = wchars[i+1];
@@ -539,8 +542,11 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
 		cur_x = (F32)ll_round(cur_x);
 	}
 
-	// add in extra pixels for last character's width past its xadvance
-	cur_x += width_padding;
+	if (!no_padding)
+	{
+		// add in extra pixels for last character's width past its xadvance
+		cur_x += width_padding;
+	}
 
 	return cur_x / sScaleX;
 }
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 3b58a37d33..93c6b78ce8 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -138,7 +138,7 @@ public:
 	F32 getWidthF32(const std::string& utf8text) const;
 	F32 getWidthF32(const llwchar* wchars) const;
 	F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const;
-	F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const;
+	F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const;
 
 	// The following are called often, frequently with large buffers, so do not use a string interface
 	
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 3d8cf74855..8732a7ce45 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -361,7 +361,7 @@ void LLTextBase::onValueChange(S32 start, S32 end)
 {
 }
 
-std::vector<LLRect> LLTextBase::getSelctionRects()
+std::vector<LLRect> LLTextBase::getSelectionRects()
 {
     // Nor supposed to be called without selection
     llassert(hasSelection());
@@ -458,7 +458,7 @@ void LLTextBase::drawSelectionBackground()
     // Draw selection even if we don't have keyboard focus for search/replace
     if (hasSelection() && !mLineInfoList.empty())
     {
-        std::vector<LLRect> selection_rects = getSelctionRects();
+        std::vector<LLRect> selection_rects = getSelectionRects();
 		
 		// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -3464,7 +3464,7 @@ bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w
 		height = mFontHeight;
 		const LLWString &text = getWText();
 		// if last character is a newline, then return true, forcing line break
-		width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars);
+		width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars, true);
 	}
 	return false;
 }
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index e3cf56a5ee..3611ab0499 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -638,7 +638,7 @@ protected:
 		return mLabel.getString() + getToolTip();
 	}
 
-    std::vector<LLRect> getSelctionRects();
+    std::vector<LLRect> getSelectionRects();
 
 protected:
 	// text segmentation and flow
diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp
index 140cbbedbe..3278bd3aa9 100644
--- a/indra/newview/llscripteditor.cpp
+++ b/indra/newview/llscripteditor.cpp
@@ -187,7 +187,7 @@ void LLScriptEditor::drawSelectionBackground()
 	// Draw selection even if we don't have keyboard focus for search/replace
 	if( hasSelection() && !mLineInfoList.empty())
 	{
-        std::vector<LLRect> selection_rects = getSelctionRects();
+        std::vector<LLRect> selection_rects = getSelectionRects();
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		const LLColor4& color = mReadOnly ? mReadOnlyFgColor : mFgColor;
-- 
cgit v1.2.3


From 01fd1cdddedc11cb6d9803a6606f54d069994a45 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 5 Apr 2023 22:32:12 +0300
Subject: SL-19522 Some .anim files fail to upload

---
 indra/llcharacter/llkeyframemotion.cpp | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 403d5bcf49..6cc4295fc8 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1399,6 +1399,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 	// get number of joint motions
 	//-------------------------------------------------------------------------
 	U32 num_motions = 0;
+    S32 rotation_dupplicates = 0;
+    S32 position_dupplicates = 0;
 	if (!dp.unpackU32(num_motions, "num_joints"))
 	{
 		LL_WARNS() << "can't read number of joints"
@@ -1629,6 +1631,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 			rCurve->mKeys[time] = rot_key;
 		}
 
+        if (joint_motion->mRotationCurve.mNumKeys > joint_motion->mRotationCurve.mKeys.size())
+        {
+            rotation_dupplicates++;
+            LL_INFOS() << "Motion: " << asset_id << " had dupplicate rotation keys that were removed" << LL_ENDL;
+        }
+
 		//---------------------------------------------------------------------
 		// scan position curve header
 		//---------------------------------------------------------------------
@@ -1731,9 +1739,24 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id, boo
 			}
 		}
 
+        if (joint_motion->mPositionCurve.mNumKeys > joint_motion->mPositionCurve.mKeys.size())
+        {
+            position_dupplicates++;
+        }
+
 		joint_motion->mUsage = joint_state->getUsage();
 	}
 
+    if (rotation_dupplicates > 0)
+    {
+        LL_INFOS() << "Motion: " << asset_id << " had " << rotation_dupplicates << " dupplicate rotation keys that were removed" << LL_ENDL;
+    }
+
+    if (position_dupplicates > 0)
+    {
+        LL_INFOS() << "Motion: " << asset_id << " had " << position_dupplicates << " dupplicate position keys that were removed" << LL_ENDL;
+    }
+
 	//-------------------------------------------------------------------------
 	// get number of constraints
 	//-------------------------------------------------------------------------
@@ -2013,9 +2036,12 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
 		JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
 		success &= dp.packString(joint_motionp->mJointName, "joint_name");
 		success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
-		success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
+        success &= dp.packS32(joint_motionp->mRotationCurve.mKeys.size(), "num_rot_keys");
 
-		LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL;
+		LL_DEBUGS("BVH") << "Joint " << i
+            << " name: " << joint_motionp->mJointName
+            << " Rotation keys: " << joint_motionp->mRotationCurve.mKeys.size()
+            << " Position keys: " << joint_motionp->mPositionCurve.mKeys.size() << LL_ENDL;
 		for (RotationCurve::key_map_t::iterator iter = joint_motionp->mRotationCurve.mKeys.begin();
 			 iter != joint_motionp->mRotationCurve.mKeys.end(); ++iter)
 		{
@@ -2037,7 +2063,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
 			LL_DEBUGS("BVH") << "  rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
 		}
 
-		success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
+		success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys");
 		for (PositionCurve::key_map_t::iterator iter = joint_motionp->mPositionCurve.mKeys.begin();
 			 iter != joint_motionp->mPositionCurve.mKeys.end(); ++iter)
 		{
-- 
cgit v1.2.3


From 99a8c612d008531f64b2ff94713866adf2e91243 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 6 Apr 2023 01:20:51 +0300
Subject: SL-19536 Inventory isn't fetched automatically

Just a 'hotfix' that won't conflict with further changes, should be properly resolved in DRTVWR-567
---
 indra/newview/llstartup.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index dd3b33982a..c52fdf4bc1 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1905,6 +1905,7 @@ bool idle_startup()
 			LLNotificationsUtil::add("InventoryUnusable");
 		}
 		
+        LLInventoryModelBackgroundFetch::instance().start();
 		gInventory.createCommonSystemCategories();
 
 		// It's debatable whether this flag is a good idea - sets all
-- 
cgit v1.2.3


From d7690a3f211949e9e3958902531424fc22e56542 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 6 Apr 2023 19:57:33 +0300
Subject: SL-19545 Shift Azure's 'Verify' button

---
 .../xui/en/floater_translation_settings.xml        | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index a5154d99ec..dc3e072adf 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -224,15 +224,6 @@
   top_delta="-4"
   name="azure_api_key"
   width="210" />
- <button
-  follows="left|top"
-  height="23"
-  label="Verify"
-  layout="topleft"
-  left_pad="10"
-  name="verify_azure_api_key_btn"
-  top_delta="-2"
-  width="90" />
   <text
    type="string"
    length="1"
@@ -241,7 +232,7 @@
    layout="topleft"
    left="70"
    name="azure_api_region_label"
-   top_pad="10"
+   top_pad="11"
    width="85">
     Region:
   </text>
@@ -255,6 +246,15 @@
    top_delta="-4"
    name="azure_api_region"
    width="210" />
+  <button
+   follows="left|top"
+   height="23"
+   label="Verify"
+   layout="topleft"
+   left_pad="10"
+   name="verify_azure_api_key_btn"
+   top_delta="-2"
+   width="90" />
 
  <text
   follows="top|right"
@@ -263,7 +263,7 @@
   left="70"
   length="1"
   name="google_api_key_label"
-  top_pad="55"
+  top_pad="53"
   type="string"
   width="85">
   Google [http://code.google.com/apis/language/translate/v2/getting_started.html#auth API key]:
-- 
cgit v1.2.3


From 6bef1ed8c336468519c9f5459445aeec26890f35 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Sat, 8 Apr 2023 15:17:19 +0300
Subject: SL-19204 Fix voice's coroutine crash

Need to find a way to kill coroutines or to fobid using non static functions/members inside coroutines
---
 indra/newview/llvoicevivox.cpp | 48 +++++++++++++++++++++++-------------------
 indra/newview/llvoicevivox.h   |  7 +++---
 2 files changed, 30 insertions(+), 25 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index c73f96da2d..3725510b6a 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -276,13 +276,13 @@ static void killGateway()
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 bool LLVivoxVoiceClient::sShuttingDown = false;
+bool LLVivoxVoiceClient::sConnected = false;
+LLPumpIO *LLVivoxVoiceClient::sPump = nullptr;
 
 LLVivoxVoiceClient::LLVivoxVoiceClient() :
 	mSessionTerminateRequested(false),
 	mRelogRequested(false),
-	mConnected(false),
 	mTerminateDaemon(false),
-	mPump(NULL),
 	mSpatialJoiningNum(0),
 
 	mTuningMode(false),
@@ -350,7 +350,11 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
 	mIsProcessingChannels(false),
 	mIsCoroutineActive(false),
 	mVivoxPump("vivoxClientPump")
-{	
+{
+    sShuttingDown = false;
+    sConnected = false;
+    sPump = nullptr;
+
 	mSpeakerVolume = scale_speaker_volume(0);
 
 	mVoiceVersion.serverVersion = "";
@@ -392,7 +396,7 @@ LLVivoxVoiceClient::~LLVivoxVoiceClient()
 void LLVivoxVoiceClient::init(LLPumpIO *pump)
 {
 	// constructor will set up LLVoiceClient::getInstance()
-	mPump = pump;
+	sPump = pump;
 
 //     LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
 //         boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
@@ -413,10 +417,10 @@ void LLVivoxVoiceClient::terminate()
         logoutOfVivox(false);
     }
     
-	if(mConnected)
+	if(sConnected)
 	{
         breakVoiceConnection(false);
-		mConnected = false;
+        sConnected = false;
 	}
 	else
 	{
@@ -425,7 +429,7 @@ void LLVivoxVoiceClient::terminate()
 	}
 
     sShuttingDown = true;
-    mPump = NULL;
+    sPump = NULL;
 }
 
 //---------------------------------------------------
@@ -471,7 +475,7 @@ bool LLVivoxVoiceClient::writeString(const std::string &str)
 	bool result = false;
     LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL;
 
-	if(mConnected)
+	if(sConnected)
 	{
 		apr_status_t err;
 		apr_size_t size = (apr_size_t)str.size();
@@ -1051,7 +1055,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
 
     int retryCount(0);
     LLVoiceVivoxStats::getInstance()->reset();
-    while (!mConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
+    while (!sConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
     {
         LLVoiceVivoxStats::getInstance()->connectionAttemptStart();
         LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL;
@@ -1061,23 +1065,23 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
             mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
         }
 
-        mConnected = mSocket->blockingConnect(mDaemonHost);
-        LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(mConnected);
-        if (!mConnected)
+        sConnected = mSocket->blockingConnect(mDaemonHost);
+        LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(sConnected);
+        if (!sConnected)
         {
             llcoro::suspendUntilTimeout(DAEMON_CONNECT_THROTTLE_SECONDS);
         }
     }
     
     //---------------------------------------------------------------------
-    if (sShuttingDown && !mConnected)
+    if (sShuttingDown && !sConnected)
     {
         return false;
     }
 
     llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
 
-    while (!mPump && !sShuttingDown)
+    while (!sPump && !sShuttingDown)
     {   // Can't use the pump until we have it available.
         llcoro::suspend();
     }
@@ -1099,7 +1103,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
     readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
 
 
-    mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
+    sPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
 
 
     //---------------------------------------------------------------------
@@ -1321,9 +1325,9 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
             // the message, yet we need to receive "connector shutdown response".
             // Either wait a bit and emulate it or check gMessageSystem for specific message
             _sleep(1000);
-            if (mConnected)
+            if (sConnected)
             {
-                mConnected = false;
+                sConnected = false;
                 LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
                 mVivoxPump.post(vivoxevent);
             }
@@ -1335,7 +1339,7 @@ bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
     LL_DEBUGS("Voice") << "closing SLVoice socket" << LL_ENDL;
     closeSocket();		// Need to do this now -- bad things happen if the destructor does it later.
     cleanUp();
-    mConnected = false;
+    sConnected = false;
 
     return retval;
 }
@@ -2516,7 +2520,7 @@ bool LLVivoxVoiceClient::performMicTuning()
 void LLVivoxVoiceClient::closeSocket(void)
 {
 	mSocket.reset();
-	mConnected = false;
+    sConnected = false;
 	mConnectorEstablished = false;
 	mAccountLoggedIn = false;
 }
@@ -3017,7 +3021,7 @@ bool LLVivoxVoiceClient::deviceSettingsAvailable()
 {
 	bool result = true;
 	
-	if(!mConnected)
+	if(!sConnected)
 		result = false;
 	
 	if(mRenderDevices.empty())
@@ -3816,7 +3820,7 @@ void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &
 		// Should this ever fail?  do we care if it does?
 	}
 	
-	mConnected = false;
+	sConnected = false;
 	mShutdownComplete = true;
 	
     LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
@@ -7389,7 +7393,7 @@ LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
 	
 	LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
 	
-	if(!LLVivoxVoiceClient::getInstance()->mConnected)
+	if(!LLVivoxVoiceClient::sConnected)
 	{
 		// If voice has been disabled, we just want to close the socket.  This does so.
 		LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 0a785401c1..e3ab99c675 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -666,12 +666,10 @@ private:
 	
 	LLHost mDaemonHost;
 	LLSocket::ptr_t mSocket;
-	bool mConnected;
 	
 	// We should kill the voice daemon in case of connection alert 
 	bool mTerminateDaemon;
 	
-	LLPumpIO *mPump;
 	friend class LLVivoxProtocolParser;
 	
 	std::string mAccountName;
@@ -916,7 +914,10 @@ private:
     bool    mIsProcessingChannels;
     bool    mIsCoroutineActive;
 
-    static bool sShuttingDown; // corutines can last longer than vivox so we need a static variable as a shutdown flag
+    // This variables can last longer than vivox in coroutines so we need them as static
+    static bool sShuttingDown;
+    static bool sConnected;
+    static LLPumpIO* sPump;
 
     LLEventMailDrop mVivoxPump;
 };
-- 
cgit v1.2.3


From 107b1d00ed5d272cd87a6ca333cd719151208eaa Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Sat, 22 Apr 2023 00:31:42 +0300
Subject: SL-19636 Profile badges

---
 indra/newview/llavatarpropertiesprocessor.h        |   1 +
 indra/newview/llpanelprofile.cpp                   |  60 ++++++++++++++++++++-
 .../default/textures/icons/profile_badge_beta.png  | Bin 0 -> 3223 bytes
 .../textures/icons/profile_badge_beta_lifetime.png | Bin 0 -> 3221 bytes
 .../textures/icons/profile_badge_lifetime.png      | Bin 0 -> 3302 bytes
 .../textures/icons/profile_badge_linden.png        | Bin 0 -> 3521 bytes
 .../icons/profile_badge_pplus_lifetime.png         | Bin 0 -> 3311 bytes
 .../icons/profile_badge_premium_lifetime.png       | Bin 0 -> 3301 bytes
 indra/newview/skins/default/textures/textures.xml  |   8 ++-
 .../default/xui/en/panel_profile_secondlife.xml    |  56 +++++++++++++++++--
 10 files changed, 119 insertions(+), 6 deletions(-)
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_beta.png
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_lifetime.png
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_linden.png
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png
 create mode 100644 indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png

(limited to 'indra')

diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h
index f778634d25..10cde35f9c 100644
--- a/indra/newview/llavatarpropertiesprocessor.h
+++ b/indra/newview/llavatarpropertiesprocessor.h
@@ -85,6 +85,7 @@ struct LLAvatarData
 	std::string	profile_url;
 	U8			caption_index;
 	std::string	caption_text;
+    std::string	customer_type;
 	U32			flags;
 	BOOL		allow_publish;
 };
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 708ff26ced..34e1fd09d8 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -159,6 +159,7 @@ void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id)
     avatar_data->fl_about_text = result["fl_about_text"].asString();
     avatar_data->born_on = result["member_since"].asDate();
     avatar_data->profile_url = getProfileURL(agent_id.asString());
+    avatar_data->customer_type = result["customer_type"].asString();
 
     avatar_data->flags = 0;
 
@@ -1051,6 +1052,8 @@ void LLPanelProfileSecondLife::resetData()
     mCantEditObjectsIcon->setEnabled(false);
 
     childSetVisible("partner_layout", FALSE);
+    childSetVisible("badge_layout", FALSE);
+    childSetVisible("partner_spacer_layout", TRUE);
 }
 
 void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data)
@@ -1258,6 +1261,59 @@ void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data
 
     std::string caption_text = getString("CaptionTextAcctInfo", args);
     getChild<LLUICtrl>("account_info")->setValue(caption_text);
+
+    const S32 LINDEN_EMPLOYEE_INDEX = 3;
+    LLDate sl_release;
+    sl_release.fromYMDHMS(2003, 6, 23, 0, 0, 0);
+    std::string customer_lower = avatar_data->customer_type;
+    LLStringUtil::toLower(customer_lower);
+    if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Linden");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLinden"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (avatar_data->born_on < sl_release)
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBeta"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "beta_lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Beta_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeBetaLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgeLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "premium_lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Premium_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else if (customer_lower == "pplus_lifetime" || customer_lower == "premium_plus_lifetime")
+    {
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Pplus_Lifetime");
+        getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumPlusLifetime"));
+        childSetVisible("badge_layout", TRUE);
+        childSetVisible("partner_spacer_layout", FALSE);
+    }
+    else
+    {
+        childSetVisible("badge_layout", FALSE);
+        childSetVisible("partner_spacer_layout", TRUE);
+    }
 }
 
 void LLPanelProfileSecondLife::fillRightsData()
@@ -1412,7 +1468,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus()
     }
     else
     {
-        childSetVisible("frind_layout", false);
+        childSetVisible("friend_layout", false);
         childSetVisible("online_layout", false);
         childSetVisible("offline_layout", false);
     }
@@ -1420,7 +1476,7 @@ void LLPanelProfileSecondLife::updateOnlineStatus()
 
 void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_online, bool online)
 {
-    childSetVisible("frind_layout", is_friend);
+    childSetVisible("friend_layout", is_friend);
     childSetVisible("online_layout", online && show_online);
     childSetVisible("offline_layout", !online && show_online);
 }
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta.png b/indra/newview/skins/default/textures/icons/profile_badge_beta.png
new file mode 100644
index 0000000000..7c8a723c47
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_beta.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png
new file mode 100644
index 0000000000..7c38e9e2ae
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_beta_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png
new file mode 100644
index 0000000000..475edd080e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_linden.png b/indra/newview/skins/default/textures/icons/profile_badge_linden.png
new file mode 100644
index 0000000000..1b6ac03e86
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_linden.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png
new file mode 100644
index 0000000000..4286995202
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_pplus_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png
new file mode 100644
index 0000000000..47e93c4fac
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_badge_premium_lifetime.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 1f2c0867c4..03fc00b8f9 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -510,7 +510,13 @@ with the same filename but different name
   <texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" />
   <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />
   <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
-  
+
+  <texture name="Profile_Badge_Beta" file_name="icons/profile_badge_beta.png" preload="true"/>
+  <texture name="Profile_Badge_Beta_Lifetime" file_name="icons/profile_badge_beta_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Lifetime" file_name="icons/profile_badge_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Linden" file_name="icons/profile_badge_linden.png" preload="true"/>
+  <texture name="Profile_Badge_Pplus_Lifetime" file_name="icons/profile_badge_pplus_lifetime.png" preload="true"/>
+  <texture name="Profile_Badge_Premium_Lifetime" file_name="icons/profile_badge_premium_lifetime.png" preload="true"/>
   <texture name="Profile_Group_Visibility_Off" file_name="icons/profile_group_visibility_eye_off.png" preload="true"/>
   <texture name="Profile_Group_Visibility_Off_Pressed" file_name="icons/profile_group_visibility_eye_off_pressed.png" preload="true"/>
   <texture name="Profile_Group_Visibility_On" file_name="icons/profile_group_visibility_eye_on.png" preload="true"/>
diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
index 777b37d666..07cdd6d71e 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
@@ -27,6 +27,26 @@
 Account: [ACCTTYPE]
 [PAYMENTINFO]
     </string>
+    
+    <!--Badges-->
+    <string
+     name="BadgeBeta"
+     value="Original Beta Tester" />
+    <string
+     name="BadgeBetaLifetime"
+     value="Beta Lifetime member" />
+    <string
+     name="BadgeLifetime"
+     value="Lifetime member" />
+    <string
+     name="BadgeLinden"
+     value="Linden Lab employee" />
+    <string
+     name="BadgePremiumLifetime"
+     value="Premium lifetime" />
+    <string
+     name="BadgePremiumPlusLifetime"
+     value="Premium Plus lifetime" />
 
   <layout_stack
    name="image_stack"
@@ -156,9 +176,39 @@ Account: [ACCTTYPE]
      user_resize="false"
      visible="true">
     </layout_panel>
-    
+
+    <layout_panel
+     name="badge_layout"
+     follows="all"
+     layout="topleft"
+     height="40"
+     auto_resize="false"
+     user_resize="false"
+     visible="false">
+      <icon
+       name="badge_icon"
+       image_name="Beta_Tester"
+       layout="topleft"
+       follows="left|top"
+       top="10"
+       left="5"
+       height="18"
+       width="18"/>
+      <text
+       name="badge_text"
+       value="Badge Tester"
+       top="13"
+       left_pad="3"
+       right="-1"
+       height="16"
+       follows="left|top|right"
+       layout="topleft"
+       translate="false"
+       visible="true"/>
+    </layout_panel>
+
     <layout_panel
-     name="frind_layout"
+     name="friend_layout"
      follows="all"
      layout="topleft"
      height="16"
@@ -166,7 +216,7 @@ Account: [ACCTTYPE]
      user_resize="false"
      visible="false">
       <text
-       name="frind_text"
+       name="friend_text"
        value="You are friends"
        text_color="ConversationFriendColor"
        top="0"
-- 
cgit v1.2.3


From 1491eea28c9355ba3d69ce566ae5263e69db3daf Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 25 Apr 2023 22:47:31 +0300
Subject: SL-19652 Folder fetch dupplicate protection and over limit handling

---
 indra/newview/llinventorymodelbackgroundfetch.cpp | 44 ++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 4a9b471a47..0bb56c7d0c 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -408,6 +408,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	// *TODO:  Think I'd like to get a shared pointer to this and share it
 	// among all the folder requests.
 	uuid_vec_t recursive_cats;
+    uuid_vec_t all_cats; // dupplicate avoidance
 
 	LLSD folder_request_body;
 	LLSD folder_request_body_lib;
@@ -436,7 +437,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 			{
 				const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
 		
-				if (cat)
+				if (cat && std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
 				{
 					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
 					{
@@ -477,6 +478,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 			{
 				recursive_cats.push_back(cat_id);
 			}
+            all_cats.push_back(cat_id);
 		}
 		else
 		{
@@ -796,6 +798,46 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
 					  << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL;
 
 	// Could use a 404 test here to try to detect revoked caps...
+
+    if(status == LLCore::HttpStatus(HTTP_FORBIDDEN))
+    {
+        // too large, split into two, assume that this isn't the library
+        const std::string url(gAgent.getRegionCapability("FetchInventoryDescendents2"));
+        S32 size = mRequestSD["folders"].size();
+
+        if (!gDisconnected && !LLApp::isExiting() && !url.empty() && size > 1)
+        {
+            LLSD folders;
+            uuid_vec_t recursive_cats;
+            LLSD::array_iterator iter = mRequestSD["folders"].beginArray();
+            LLSD::array_iterator end = mRequestSD["folders"].endArray();
+            while (iter != end)
+            {
+                folders.append(*iter);
+                LLUUID fodler_id = iter->get("folder_id").asUUID();
+                if (std::find(mRecursiveCatUUIDs.begin(), mRecursiveCatUUIDs.end(), fodler_id) != mRecursiveCatUUIDs.end())
+                {
+                    recursive_cats.push_back(fodler_id);
+                }
+                if (folders.size() == (S32)(size / 2))
+                {
+                    LLSD request_body;
+                    request_body["folders"] = folders;
+                    LLCore::HttpHandler::ptr_t  handler(new BGFolderHttpHandler(request_body, recursive_cats));
+                    gInventory.requestPost(false, url, request_body, handler, "Inventory Folder");
+                    recursive_cats.clear();
+                    folders.clear();
+                }
+                iter++;
+            }
+
+            LLSD request_body;
+            request_body["folders"] = folders;
+            LLCore::HttpHandler::ptr_t  handler(new BGFolderHttpHandler(request_body, recursive_cats));
+            gInventory.requestPost(false, url, request_body, handler, "Inventory Folder");
+            return;
+        }
+    }
 	
 	// This was originally the request retry logic for the inventory
 	// request which tested on HTTP_INTERNAL_ERROR status.  This
-- 
cgit v1.2.3


From 895ce616ea71b2001ec4e826b80310da80db9a0e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 6 Apr 2023 21:19:44 +0300
Subject: SL-19652 Fixed 'working' cursor flicker

---
 indra/llwindow/llwindow.h          | 3 ++-
 indra/newview/llinventorypanel.cpp | 6 ++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 0edf39f6ef..802a3b5213 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -118,7 +118,8 @@ public:
 
 	// Sets cursor, may set to arrow+hourglass
 	virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; };
-	virtual ECursorType getCursor() const;
+    virtual ECursorType getCursor() const;
+    virtual ECursorType getNextCursor() const { return mNextCursor; };
 	virtual void updateCursor() = 0;
 
 	virtual void captureMouse() = 0;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 8029486d6f..2799cb4cdf 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1268,8 +1268,10 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = LLView::handleHover(x, y, mask);
 	if(handled)
-	{
-		ECursorType cursor = getWindow()->getCursor();
+    {
+        // getCursor gets current cursor, setCursor sets next cursor
+        // check that children didn't set own 'next' cursor
+		ECursorType cursor = getWindow()->getNextCursor();
 		if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW)
 		{
 			// replace arrow cursor with arrow and hourglass cursor
-- 
cgit v1.2.3


From d1e3959fef60d70c5f928422b9895b11e36ef343 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pantera=20P=C3=B3=C5=82nocy?= <panterapolnocy@gmail.com>
Date: Tue, 2 May 2023 19:19:03 +0200
Subject: Update floater_scene_load_stats.xml

Reducing the packet loss...
---
 .../skins/default/xui/en/floater_scene_load_stats.xml        | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
index 37efbe654e..b757f4eab8 100644
--- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml
@@ -414,7 +414,7 @@
         name="frame_stats"
         label="Frame breakdown"
         show_label="true">
-          <stat_bar name="packet_loss"
+          <stat_bar name="scenery_frame_pct"
             label="Scenery"
             orientation="horizontal"
             unit_label=" %"
@@ -422,7 +422,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="avatar_frame_pct"
             label="Avatar"
             orientation="horizontal"
             unit_label=" %"
@@ -430,7 +430,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="ui_frame_pct"
             label="UI"
             orientation="horizontal"
             unit_label=" %"
@@ -438,7 +438,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-          <stat_bar name="packet_loss"
+          <stat_bar name="huds_frame_pct"
             label="HUDs"
             orientation="horizontal"
             unit_label=" %"
@@ -446,7 +446,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-        <stat_bar name="packet_loss"
+        <stat_bar name="swap_frame_pct"
             label="Swap"
             orientation="horizontal"
             unit_label=" %"
@@ -454,7 +454,7 @@
             bar_max="100"
             tick_spacing="0.5"
             show_bar="false"/>
-        <stat_bar name="packet_loss"
+        <stat_bar name="idle_frame_pct"
             label="Tasks"
             orientation="horizontal"
             unit_label=" %"
-- 
cgit v1.2.3


From 534d3abd2a93ed2df429b8cdbba84a10f26b0add Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pantera=20P=C3=B3=C5=82nocy?= <panterapolnocy@gmail.com>
Date: Tue, 2 May 2023 19:35:14 +0200
Subject: Fixing a small typo in llviewerstats.cpp

---
 indra/newview/llviewerstats.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 519166af63..1607296194 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -124,7 +124,7 @@ SimMeasurement<>			SIM_TIME_DILATION("simtimedilation", "Simulator time scale",
 							SIM_MAIN_AGENTS("simmainagents", "Number of avatars in current region", LL_SIM_STAT_NUMAGENTMAIN),
 							SIM_CHILD_AGENTS("simchildagents", "Number of avatars in neighboring regions", LL_SIM_STAT_NUMAGENTCHILD),
 							SIM_OBJECTS("simobjects", "", LL_SIM_STAT_NUMTASKS),
-							SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or mocing objects", LL_SIM_STAT_NUMTASKSACTIVE),
+							SIM_ACTIVE_OBJECTS("simactiveobjects", "Number of scripted and/or moving objects", LL_SIM_STAT_NUMTASKSACTIVE),
 							SIM_ACTIVE_SCRIPTS("simactivescripts", "Number of scripted objects", LL_SIM_STAT_NUMSCRIPTSACTIVE),
 							SIM_IN_PACKETS_PER_SEC("siminpps", "", LL_SIM_STAT_INPPS),
 							SIM_OUT_PACKETS_PER_SEC("simoutpps", "", LL_SIM_STAT_OUTPPS),
-- 
cgit v1.2.3


From 42f16180a985fc0e4704a4e25489ada9d662631a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 10 May 2023 18:41:55 +0300
Subject: SL-19536 SL-19652 Fix inventory fetching

---
 indra/newview/llinventorymodelbackgroundfetch.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 0bb56c7d0c..6b88d0aaf7 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -437,9 +437,10 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 			{
 				const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
 		
-				if (cat && std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
+				if (cat)
 				{
-					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
+					if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()
+                        && std::find(all_cats.begin(), all_cats.end(), cat_id) == all_cats.end())
 					{
 						LLSD folder_sd;
 						folder_sd["folder_id"]		= cat->getUUID();
-- 
cgit v1.2.3


From d28e2c03a76151b7e6ba47fc892fb7c2c164c1e2 Mon Sep 17 00:00:00 2001
From: Maxim Nikolenko <maximnproductengine@lindenlab.com>
Date: Fri, 12 May 2023 16:35:27 +0300
Subject: SL-19649 reduce logging out time for larger inventories

---
 indra/llui/llview.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 9ba71913d0..3344300635 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -576,8 +576,10 @@ void LLView::deleteAllChildren()
 
 	while (!mChildList.empty())
 	{
-		LLView* viewp = mChildList.front();
-		delete viewp; // will remove the child from mChildList
+        LLView* viewp = mChildList.front();
+        viewp->mParentView = NULL;
+        delete viewp;
+        mChildList.pop_front();
 	}
 }
 
-- 
cgit v1.2.3


From cc8af5f37df1e200bc0b55740887a99157066e35 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 12 May 2023 18:26:02 +0300
Subject: SL-19649 Adjust other classes for new deleteAllChildren mechanics

---
 indra/llui/lllayoutstack.cpp       | 19 ++++++++++++++++---
 indra/llui/lllayoutstack.h         |  1 +
 indra/llui/llmenugl.cpp            |  7 +++++++
 indra/llui/llmenugl.h              |  1 +
 indra/newview/llinspecttoast.cpp   |  7 +++++++
 indra/newview/llinventorymodel.cpp |  6 +++++-
 6 files changed, 37 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 77938edf27..ae9dba5945 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -282,6 +282,17 @@ void LLLayoutStack::draw()
 	}
 }
 
+void LLLayoutStack::deleteAllChildren()
+{
+    mPanels.clear();
+    LLView::deleteAllChildren();
+
+    // Not really needed since nothing is left to
+    // display, but for the sake of consistency
+    updateFractionalSizes();
+    mNeedsLayout = true;
+}
+
 void LLLayoutStack::removeChild(LLView* view)
 {
 	LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
@@ -289,12 +300,14 @@ void LLLayoutStack::removeChild(LLView* view)
 	if (embedded_panelp)
 	{
 		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
-		delete embedded_panelp;
+        LLView::removeChild(view);
 		updateFractionalSizes();
 		mNeedsLayout = true;
 	}
-
-	LLView::removeChild(view);
+    else
+    {
+        LLView::removeChild(view);
+    }
 }
 
 BOOL LLLayoutStack::postBuild()
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index f772dbc6b4..22f11eb20f 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -67,6 +67,7 @@ public:
 	virtual ~LLLayoutStack();
 
 	/*virtual*/ void draw();
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild(LLView*);
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 5cb840fd61..33c4b6ec73 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1882,6 +1882,13 @@ bool LLMenuGL::addContextChild(LLView* view, S32 tab_group)
 	return false;
 }
 
+
+void LLMenuGL::deleteAllChildren()
+{
+    mItems.clear();
+    LLUICtrl::deleteAllChildren();
+}
+
 void LLMenuGL::removeChild( LLView* ctrl)
 {
 	// previously a dynamic_cast with if statement to check validity
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index f84c4d41eb..9d3be8d94f 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -442,6 +442,7 @@ public:
 	/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
 	/*virtual*/ void setVisible(BOOL visible);
 	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild( LLView* ctrl);
 	/*virtual*/ BOOL postBuild();
 	
diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index 68801b0895..6f93a78ca6 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -47,6 +47,7 @@ public:
 
 	/*virtual*/ void onOpen(const LLSD& notification_id);
 	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+    /*virtual*/ void deleteAllChildren();
 	/*virtual*/ void removeChild(LLView* child);
 private:
 	void onToastDestroy(LLToast * toast);
@@ -122,6 +123,12 @@ BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask)
 	return LLFloater::handleToolTip(x, y, mask);
 }
 
+void LLInspectToast::deleteAllChildren()
+{
+    mPanel = NULL;
+    LLInspect::deleteAllChildren();
+}
+
 // virtual
 void LLInspectToast::removeChild(LLView* child)
 {
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 0bbf201dc6..b4727de77f 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -594,7 +594,11 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
 		}
 	}
 	
-	if(rv.isNull() && create_folder && root_id.notNull())
+	if(rv.isNull() 
+       && root_id.notNull()
+       && create_folder
+       && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS
+       && preferred_type != LLFolderType::FT_OUTBOX)
 	{
 
 		if (isInventoryUsable())
-- 
cgit v1.2.3


From a10c876ae4db901ab60f58f0df82663b855b3d45 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Fri, 19 May 2023 02:20:48 +0300
Subject: DRTVWR-580 Post-merge fix

---
 indra/llcharacter/llkeyframemotion.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 9cb30882dd..3cef382bbf 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -2054,7 +2054,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
 			LL_DEBUGS("BVH") << "  rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
 		}
 
-		success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
+		success &= dp.packS32(joint_motionp->mPositionCurve.mKeys.size(), "num_pos_keys");
 		for (PositionCurve::key_map_t::value_type& pos_pair : joint_motionp->mPositionCurve.mKeys)
 		{
 			PositionKey& pos_key = pos_pair.second;
-- 
cgit v1.2.3


From 7140640b6963dacfa012dfec679798fc4dd13a17 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Fri, 19 May 2023 02:31:28 +0300
Subject: DRTVWR-580 Post-merge fix - unused code

---
 indra/newview/llfilepicker.cpp | 8 --------
 1 file changed, 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index ab5f88e210..f1f156c2e0 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -745,14 +745,6 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension,
             creator = "\?\?\?\?";
             extension = "xaf";
             break;
-
-#ifdef _CORY_TESTING
-        case LLFilePicker::FFSAVE_GEOMETRY:
-            type = "\?\?\?\?";
-            creator = "\?\?\?\?";
-            extension = "slg";
-            break;
-#endif
             
         case LLFilePicker::FFSAVE_XML:
             type = "\?\?\?\?";
-- 
cgit v1.2.3


From 1d1a63abe4a3d3a6191172c1693ffbdb0ffb2d71 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 19 May 2023 19:56:57 +0300
Subject: SL-19635 Implement DeepL tranlation support

---
 indra/newview/app_settings/settings.xml            |  11 +
 indra/newview/llfloatertranslationsettings.cpp     | 132 +++++++--
 indra/newview/llfloatertranslationsettings.h       |  10 +-
 indra/newview/lltranslate.cpp                      | 311 ++++++++++++++++++++-
 indra/newview/lltranslate.h                        |   1 +
 .../xui/en/floater_translation_settings.xml        |  97 ++++++-
 6 files changed, 527 insertions(+), 35 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index fa241dc30c..ca1b1e2f20 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13014,6 +13014,17 @@
       <key>Value</key>
       <string></string>
     </map>
+    <key>DeepLTranslateAPIKey</key>
+    <map>
+        <key>Comment</key>
+        <string>DeepL Translation service data to use with the DeepL Translator API</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>LLSD</string>
+        <key>Value</key>
+        <string></string>
+    </map>
     <key>TutorialURL</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index e14227f490..d29ecbbf95 100644
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -47,6 +47,7 @@ LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
 ,	mMachineTranslationCB(NULL)
 ,	mAzureKeyVerified(false)
 ,	mGoogleKeyVerified(false)
+,	mDeepLKeyVerified(false)
 {
 }
 
@@ -60,8 +61,11 @@ BOOL LLFloaterTranslationSettings::postBuild()
 	mAzureAPIKeyEditor = getChild<LLLineEditor>("azure_api_key");
     mAzureAPIRegionEditor = getChild<LLLineEditor>("azure_api_region");
 	mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key");
+    mDeepLAPIDomainCombo = getChild<LLComboBox>("deepl_api_domain_combo");
+    mDeepLAPIKeyEditor = getChild<LLLineEditor>("deepl_api_key");
 	mAzureVerifyBtn = getChild<LLButton>("verify_azure_api_key_btn");
 	mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn");
+    mDeepLVerifyBtn = getChild<LLButton>("verify_deepl_api_key_btn");
 	mOKBtn = getChild<LLButton>("ok_btn");
 
 	mMachineTranslationCB->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
@@ -70,18 +74,37 @@ BOOL LLFloaterTranslationSettings::postBuild()
 	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false));
 	mAzureVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnAzureVerify, this));
 	mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this));
+    mDeepLVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnDeepLVerify, this));
 
 	mAzureAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
 	mAzureAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
     mAzureAPIRegionEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
     mAzureAPIRegionEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this), NULL);
 
-    mAzureAPIEndpointEditor->setFocusLostCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this));
-    mAzureAPIEndpointEditor->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::onAzureKeyEdited, this));
+    mAzureAPIEndpointEditor->setFocusLostCallback([this](LLFocusableElement*)
+                                                  {
+                                                      setAzureVerified(false, false, 0);
+                                                  });
+    mAzureAPIEndpointEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param)
+                                               {
+                                                   setAzureVerified(false, false, 0);
+                                               });
 
 	mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
 	mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL);
 
+    mDeepLAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+    mDeepLAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onDeepLKeyEdited, this), NULL);
+
+    mDeepLAPIDomainCombo->setFocusLostCallback([this](LLFocusableElement*)
+                                                  {
+                                                      setDeepLVerified(false, false, 0);
+                                                  });
+    mDeepLAPIDomainCombo->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param)
+                                               {
+                                                setDeepLVerified(false, false, 0);
+                                               });
+
 	center();
 	return TRUE;
 }
@@ -130,6 +153,20 @@ void LLFloaterTranslationSettings::onOpen(const LLSD& key)
 		mGoogleKeyVerified = FALSE;
 	}
 
+    LLSD deepl_key = gSavedSettings.getLLSD("DeepLTranslateAPIKey");
+    if (deepl_key.isMap() && !deepl_key["id"].asString().empty())
+    {
+        mDeepLAPIKeyEditor->setText(deepl_key["id"].asString());
+        mDeepLAPIKeyEditor->setTentative(false);
+        mDeepLAPIDomainCombo->setValue(deepl_key["domain"]);
+        verifyKey(LLTranslate::SERVICE_DEEPL, deepl_key, false);
+    }
+    else
+    {
+        mDeepLAPIKeyEditor->setTentative(TRUE);
+        mDeepLKeyVerified = FALSE;
+    }
+
 	updateControlsEnabledState();
 }
 
@@ -155,6 +192,17 @@ void LLFloaterTranslationSettings::setGoogleVerified(bool ok, bool alert, S32 st
 	updateControlsEnabledState();
 }
 
+void LLFloaterTranslationSettings::setDeepLVerified(bool ok, bool alert, S32 status)
+{
+    if (alert)
+    {
+        showAlert(ok ? "deepl_api_key_verified" : "deepl_api_key_not_verified", status);
+    }
+
+    mDeepLKeyVerified = ok;
+    updateControlsEnabledState();
+}
+
 std::string LLFloaterTranslationSettings::getSelectedService() const
 {
 	return mTranslationServiceRadioGroup->getSelectedValue().asString();
@@ -180,6 +228,17 @@ std::string LLFloaterTranslationSettings::getEnteredGoogleKey() const
 	return mGoogleAPIKeyEditor->getTentative() ? LLStringUtil::null : mGoogleAPIKeyEditor->getText();
 }
 
+LLSD LLFloaterTranslationSettings::getEnteredDeepLKey() const
+{
+    LLSD key;
+    if (!mDeepLAPIKeyEditor->getTentative())
+    {
+        key["domain"] = mDeepLAPIDomainCombo->getValue();
+        key["id"] = mDeepLAPIKeyEditor->getText();
+    }
+    return key;
+}
+
 void LLFloaterTranslationSettings::showAlert(const std::string& msg_name, S32 status) const
 {
     LLStringUtil::format_map_t string_args;
@@ -199,29 +258,42 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
 	std::string service = getSelectedService();
 	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
+    bool deepl_selected = service == "deepl";
 
 	mTranslationServiceRadioGroup->setEnabled(on);
 	mLanguageCombo->setEnabled(on);
 
-	getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on);
-	mAzureAPIEndpointEditor->setEnabled(on);
+    // MS Azure
+    getChild<LLTextBox>("azure_api_endoint_label")->setEnabled(on);
+    mAzureAPIEndpointEditor->setEnabled(on && azure_selected);
     getChild<LLTextBox>("azure_api_key_label")->setEnabled(on);
-    mAzureAPIKeyEditor->setEnabled(on);
+    mAzureAPIKeyEditor->setEnabled(on && azure_selected);
     getChild<LLTextBox>("azure_api_region_label")->setEnabled(on);
-    mAzureAPIRegionEditor->setEnabled(on);
+    mAzureAPIRegionEditor->setEnabled(on && azure_selected);
 
-	getChild<LLTextBox>("google_api_key_label")->setEnabled(on);
-	mGoogleAPIKeyEditor->setEnabled(on);
+    mAzureVerifyBtn->setEnabled(on && azure_selected &&
+                                !mAzureKeyVerified && getEnteredAzureKey().isMap());
 
-	mAzureAPIKeyEditor->setEnabled(on && azure_selected);
-	mGoogleAPIKeyEditor->setEnabled(on && google_selected);
+    // Google
+    getChild<LLTextBox>("google_api_key_label")->setEnabled(on);
+    mGoogleAPIKeyEditor->setEnabled(on && google_selected);
 
-	mAzureVerifyBtn->setEnabled(on && azure_selected &&
-		!mAzureKeyVerified && getEnteredAzureKey().isMap());
 	mGoogleVerifyBtn->setEnabled(on && google_selected &&
 		!mGoogleKeyVerified && !getEnteredGoogleKey().empty());
 
-	bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified);
+    // DeepL
+    getChild<LLTextBox>("deepl_api_domain_label")->setEnabled(on);
+    mDeepLAPIDomainCombo->setEnabled(on && deepl_selected);
+    getChild<LLTextBox>("deepl_api_key_label")->setEnabled(on);
+    mDeepLAPIKeyEditor->setEnabled(on && deepl_selected);
+
+    mDeepLVerifyBtn->setEnabled(on && deepl_selected &&
+                                 !mDeepLKeyVerified && getEnteredDeepLKey().isMap());
+
+    bool service_verified =
+        (azure_selected && mAzureKeyVerified) 
+        || (google_selected && mGoogleKeyVerified)
+        || (deepl_selected && mDeepLKeyVerified);
 	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 
 	mOKBtn->setEnabled(!on || service_verified);
@@ -247,6 +319,9 @@ void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, b
     case LLTranslate::SERVICE_GOOGLE:
         floater->setGoogleVerified(ok, alert, status);
         break;
+    case LLTranslate::SERVICE_DEEPL:
+        floater->setDeepLVerified(ok, alert, status);
+        break;
     }
 }
 
@@ -273,8 +348,7 @@ void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
 void LLFloaterTranslationSettings::onAzureKeyEdited()
 {
 	if (mAzureAPIKeyEditor->isDirty()
-        || mAzureAPIRegionEditor->isDirty()
-        || mAzureAPIEndpointEditor->getValue().isString())
+        || mAzureAPIRegionEditor->isDirty())
 	{
         // todo: verify mAzureAPIEndpointEditor url
 		setAzureVerified(false, false, 0);
@@ -289,6 +363,14 @@ void LLFloaterTranslationSettings::onGoogleKeyEdited()
 	}
 }
 
+void LLFloaterTranslationSettings::onDeepLKeyEdited()
+{
+    if (mDeepLAPIKeyEditor->isDirty())
+    {
+        setDeepLVerified(false, false, 0);
+    }
+}
+
 void LLFloaterTranslationSettings::onBtnAzureVerify()
 {
 	LLSD key = getEnteredAzureKey();
@@ -306,15 +388,28 @@ void LLFloaterTranslationSettings::onBtnGoogleVerify()
 		verifyKey(LLTranslate::SERVICE_GOOGLE, LLSD(key));
 	}
 }
+
+void LLFloaterTranslationSettings::onBtnDeepLVerify()
+{
+    LLSD key = getEnteredDeepLKey();
+    if (key.isMap())
+    {
+        verifyKey(LLTranslate::SERVICE_DEEPL, key);
+    }
+}
+
 void LLFloaterTranslationSettings::onClose(bool app_quitting)
 {
 	std::string service = gSavedSettings.getString("TranslationService");
 	bool azure_selected = service == "azure";
 	bool google_selected = service == "google";
+    bool deepl_selected = service == "deepl";
 
-	bool service_verified = (azure_selected && mAzureKeyVerified) || (google_selected && mGoogleKeyVerified);
-	gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
-
+    bool service_verified =
+        (azure_selected && mAzureKeyVerified)
+        || (google_selected && mGoogleKeyVerified)
+        || (deepl_selected && mDeepLKeyVerified);
+    gSavedPerAccountSettings.setBOOL("TranslatingEnabled", service_verified);
 }
 void LLFloaterTranslationSettings::onBtnOK()
 {
@@ -323,6 +418,7 @@ void LLFloaterTranslationSettings::onBtnOK()
 	gSavedSettings.setString("TranslationService", getSelectedService());
 	gSavedSettings.setLLSD("AzureTranslateAPIKey", getEnteredAzureKey());
 	gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey());
+    gSavedSettings.setLLSD("DeepLTranslateAPIKey", getEnteredDeepLKey());
 
 	closeFloater(false);
 }
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index f039d90e27..eff0803fdd 100644
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -44,12 +44,14 @@ public:
 
 	void setAzureVerified(bool ok, bool alert, S32 status);
 	void setGoogleVerified(bool ok, bool alert, S32 status);
+    void setDeepLVerified(bool ok, bool alert, S32 status);
 	void onClose(bool app_quitting);
 
 private:
 	std::string getSelectedService() const;
 	LLSD getEnteredAzureKey() const;
 	std::string getEnteredGoogleKey() const;
+    LLSD getEnteredDeepLKey() const;
 	void showAlert(const std::string& msg_name, S32 status) const;
 	void updateControlsEnabledState();
     void verifyKey(int service, const LLSD& key, bool alert = true);
@@ -57,25 +59,31 @@ private:
 	void onEditorFocused(LLFocusableElement* control);
 	void onAzureKeyEdited();
 	void onGoogleKeyEdited();
+    void onDeepLKeyEdited();
 	void onBtnAzureVerify();
 	void onBtnGoogleVerify();
+    void onBtnDeepLVerify();
 	void onBtnOK();
 
     static void setVerificationStatus(int service, bool alert, bool ok, S32 status);
 
 	LLCheckBoxCtrl* mMachineTranslationCB;
 	LLComboBox* mLanguageCombo;
-    LLComboBox* mAzureAPIEndpointEditor;;
+    LLComboBox* mAzureAPIEndpointEditor;
 	LLLineEditor* mAzureAPIKeyEditor;
     LLLineEditor* mAzureAPIRegionEditor;
 	LLLineEditor* mGoogleAPIKeyEditor;
+    LLComboBox* mDeepLAPIDomainCombo;
+    LLLineEditor* mDeepLAPIKeyEditor;
 	LLRadioGroup* mTranslationServiceRadioGroup;
 	LLButton* mAzureVerifyBtn;
 	LLButton* mGoogleVerifyBtn;
+    LLButton* mDeepLVerifyBtn;
 	LLButton* mOKBtn;
 
 	bool mAzureKeyVerified;
 	bool mGoogleKeyVerified;
+    bool mDeepLKeyVerified;
 };
 
 #endif // LL_LLFLOATERTRANSLATIONSETTINGS_H
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 6589ce06c4..70a40921ef 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -133,7 +133,9 @@ public:
                                        LLCore::HttpOptions::ptr_t options,
                                        LLCore::HttpHeaders::ptr_t headers,
                                        const std::string & url,
-                                       const std::string & msg) const = 0;
+                                       const std::string & msg,
+                                       const std::string& from_lang,
+                                       const std::string& to_lang) const = 0;
     virtual LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
         LLCore::HttpRequest::ptr_t request,
         LLCore::HttpOptions::ptr_t options,
@@ -230,7 +232,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s
         return;
     }
 
-    LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg);
+    LLSD result = sendMessageAndSuspend(httpAdapter, httpRequest, httpOpts, httpHeaders, url, msg, fromTo.first, fromTo.second);
 
     if (LLApp::isQuitting())
     {
@@ -331,7 +333,9 @@ public:
         LLCore::HttpOptions::ptr_t options,
         LLCore::HttpHeaders::ptr_t headers,
         const std::string & url,
-        const std::string & msg) const override;
+        const std::string & msg,
+        const std::string& from_lang,
+        const std::string& to_lang) const override;
 
     LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
         LLCore::HttpRequest::ptr_t request,
@@ -508,7 +512,9 @@ LLSD LLGoogleTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorou
     LLCore::HttpOptions::ptr_t options,
     LLCore::HttpHeaders::ptr_t headers,
     const std::string & url,
-    const std::string & msg) const
+    const std::string & msg,
+    const std::string& from_lang,
+    const std::string& to_lang) const
 {
     return adapter->getRawAndSuspend(request, url, options, headers);
 }
@@ -558,7 +564,9 @@ public:
         LLCore::HttpOptions::ptr_t options,
         LLCore::HttpHeaders::ptr_t headers,
         const std::string & url,
-        const std::string & msg) const override;
+        const std::string & msg,
+        const std::string& from_lang,
+        const std::string& to_lang) const override;
 
     LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
         LLCore::HttpRequest::ptr_t request,
@@ -728,7 +736,7 @@ bool LLAzureTranslationHandler::parseResponse(
 // virtual
 bool LLAzureTranslationHandler::isConfigured() const
 {
-	return !getAPIKey().isMap();
+	return getAPIKey().isMap();
 }
 
 //static
@@ -814,7 +822,9 @@ LLSD LLAzureTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCorout
     LLCore::HttpOptions::ptr_t options,
     LLCore::HttpHeaders::ptr_t headers,
     const std::string & url,
-    const std::string & msg) const
+    const std::string & msg,
+    const std::string& from_lang,
+    const std::string& to_lang) const
 {
     LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
     LLCore::BufferArrayStream outs(rawbody.get());
@@ -838,6 +848,259 @@ LLSD LLAzureTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAd
     return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
 }
 
+//=========================================================================
+/// DeepL Translator API handler.
+class LLDeepLTranslationHandler: public LLTranslationAPIHandler
+{
+    LOG_CLASS(LLDeepLTranslationHandler);
+
+public:
+    std::string getTranslateURL(
+        const std::string& from_lang,
+        const std::string& to_lang,
+        const std::string& text) const override;
+    std::string getKeyVerificationURL(
+        const LLSD& key) const override;
+    bool checkVerificationResponse(
+        const LLSD& response,
+        int status) const override;
+    bool parseResponse(
+        const LLSD& http_response,
+        int& status,
+        const std::string& body,
+        std::string& translation,
+        std::string& detected_lang,
+        std::string& err_msg) const override;
+    bool isConfigured() const override;
+
+    LLTranslate::EService getCurrentService() override
+    {
+        return LLTranslate::EService::SERVICE_DEEPL;
+    }
+
+    void verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc) override;
+
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent) const override;
+    void initHttpHeader(LLCore::HttpHeaders::ptr_t headers, const std::string& user_agent, const LLSD& key) const override;
+    LLSD sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                               LLCore::HttpRequest::ptr_t request,
+                               LLCore::HttpOptions::ptr_t options,
+                               LLCore::HttpHeaders::ptr_t headers,
+                               const std::string& url,
+                               const std::string& msg,
+                               const std::string& from_lang,
+                               const std::string& to_lang) const override;
+
+    LLSD verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                          LLCore::HttpRequest::ptr_t request,
+                          LLCore::HttpOptions::ptr_t options,
+                          LLCore::HttpHeaders::ptr_t headers,
+                          const std::string& url) const override;
+private:
+    static std::string parseErrorResponse(
+        const std::string& body);
+    static LLSD getAPIKey();
+    static std::string getAPILanguageCode(const std::string& lang);
+};
+
+//-------------------------------------------------------------------------
+// virtual
+std::string LLDeepLTranslationHandler::getTranslateURL(
+    const std::string& from_lang,
+    const std::string& to_lang,
+    const std::string& text) const
+{
+    std::string url;
+    LLSD key = getAPIKey();
+    if (key.isMap())
+    {
+        url = key["domain"].asString();
+
+        if (*url.rbegin() != '/')
+        {
+            url += "/";
+        }
+        url += std::string("v2/translate");
+    }
+    return url;
+}
+
+
+// virtual
+std::string LLDeepLTranslationHandler::getKeyVerificationURL(
+    const LLSD& key) const
+{
+    std::string url;
+    if (key.isMap())
+    {
+        url = key["domain"].asString();
+
+        if (*url.rbegin() != '/')
+        {
+            url += "/";
+        }
+        url += std::string("v2/translate");
+    }
+    return url;
+}
+
+//virtual
+bool LLDeepLTranslationHandler::checkVerificationResponse(
+    const LLSD& response,
+    int status) const
+{
+    return status == HTTP_OK;
+}
+
+// virtual
+bool LLDeepLTranslationHandler::parseResponse(
+    const LLSD& http_response,
+    int& status,
+    const std::string& body,
+    std::string& translation,
+    std::string& detected_lang,
+    std::string& err_msg) const
+{
+    if (status != HTTP_OK)
+    {
+        if (http_response.has("error_body"))
+            err_msg = parseErrorResponse(http_response["error_body"].asString());
+        return false;
+    }
+
+    //Example:
+    // "{\"translations\":[{\"detected_source_language\":\"EN\",\"text\":\"test\"}]}"
+
+    Json::Value root;
+    Json::Reader reader;
+
+    if (!reader.parse(body, root))
+    {
+        err_msg = reader.getFormatedErrorMessages();
+        return false;
+    }
+
+    if (!root.isObject()
+        || !root.isMember("translations")) // empty response? should not happen
+    {
+        return false;
+    }
+
+    // Request succeeded, extract translation from the response.
+    const Json::Value& translations = root["translations"];
+    if (!translations.isArray() || translations.size() == 0)
+    {
+        return false;
+    }
+
+    const Json::Value& data= translations[0U];
+    if (!data.isObject()
+        || !data.isMember("detected_source_language")
+        || !data.isMember("text"))
+    {
+        return false;
+    }
+    
+
+    detected_lang = data["detected_source_language"].asString();
+    LLStringUtil::toLower(detected_lang);
+    translation = data["text"].asString();
+
+    return true;
+}
+
+// virtual
+bool LLDeepLTranslationHandler::isConfigured() const
+{
+    return getAPIKey().isMap();
+}
+
+//static
+std::string LLDeepLTranslationHandler::parseErrorResponse(
+    const std::string& body)
+{
+    // DeepL doesn't seem to have any error handling beyoun http codes
+    return std::string();
+}
+
+// static
+LLSD LLDeepLTranslationHandler::getAPIKey()
+{
+    static LLCachedControl<LLSD> deepl_key(gSavedSettings, "DeepLTranslateAPIKey");
+    return deepl_key;
+}
+
+// static
+std::string LLDeepLTranslationHandler::getAPILanguageCode(const std::string& lang)
+{
+    return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
+}
+
+/*virtual*/
+void LLDeepLTranslationHandler::verifyKey(const LLSD& key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+    LLCoros::instance().launch("DeepL /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+                                                                this, LLTranslate::SERVICE_DEEPL, key, fnc));
+}
+/*virtual*/
+void LLDeepLTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent) const
+{
+    initHttpHeader(headers, user_agent, getAPIKey());
+}
+
+/*virtual*/
+void LLDeepLTranslationHandler::initHttpHeader(
+    LLCore::HttpHeaders::ptr_t headers,
+    const std::string& user_agent,
+    const LLSD& key) const
+{
+    headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded");
+    headers->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+    if (key.has("id"))
+    {
+        std::string authkey = "DeepL-Auth-Key " + key["id"].asString();
+        headers->append(HTTP_OUT_HEADER_AUTHORIZATION, authkey);
+    }
+}
+
+LLSD LLDeepLTranslationHandler::sendMessageAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                                      LLCore::HttpRequest::ptr_t request,
+                                                      LLCore::HttpOptions::ptr_t options,
+                                                      LLCore::HttpHeaders::ptr_t headers,
+                                                      const std::string& url,
+                                                      const std::string& msg,
+                                                      const std::string& from_lang,
+                                                      const std::string& to_lang) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "text=";
+    std::string escaped_string = LLURI::escape(msg);
+    outs << escaped_string;
+    outs << "&target_lang=";
+    std::string lang = to_lang;
+    LLStringUtil::toUpper(lang);
+    outs << lang;
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
+LLSD LLDeepLTranslationHandler::verifyAndSuspend(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter,
+                                                 LLCore::HttpRequest::ptr_t request,
+                                                 LLCore::HttpOptions::ptr_t options,
+                                                 LLCore::HttpHeaders::ptr_t headers,
+                                                 const std::string& url) const
+{
+    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+    LLCore::BufferArrayStream outs(rawbody.get());
+    outs << "text=&target_lang=EN";
+
+    return adapter->postRawAndSuspend(request, url, rawbody, options, headers);
+}
+
 //=========================================================================
 LLTranslate::LLTranslate():
 	mCharsSeen(0),
@@ -867,6 +1130,11 @@ std::string LLTranslate::addNoTranslateTags(std::string mesg)
         return mesg;
     }
 
+    if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL)
+    {
+        return mesg;
+    }
+
     if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
     {
         // https://learn.microsoft.com/en-us/azure/cognitive-services/translator/prevent-translation
@@ -892,6 +1160,10 @@ std::string LLTranslate::removeNoTranslateTags(std::string mesg)
     {
         return mesg;
     }
+    if (getPreferredHandler().getCurrentService() == SERVICE_DEEPL)
+    {
+        return mesg;
+    }
 
     if (getPreferredHandler().getCurrentService() == SERVICE_AZURE)
     {
@@ -997,6 +1269,14 @@ LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
 	{
 		service = SERVICE_GOOGLE;
 	}
+    if (service_str == "azure")
+    {
+        service = SERVICE_AZURE;
+    }
+    if (service_str == "deepl")
+    {
+        service = SERVICE_DEEPL;
+    }
 
 	return getHandler(service);
 }
@@ -1006,11 +1286,18 @@ LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
 {
 	static LLGoogleTranslationHandler google;
 	static LLAzureTranslationHandler azure;
+    static LLDeepLTranslationHandler deepl;
 
-	if (service == SERVICE_GOOGLE)
-	{
-		return google;
-	}
+    switch (service)
+    {
+        case SERVICE_AZURE:
+            return azure;
+        case SERVICE_GOOGLE:
+            return google;
+        case SERVICE_DEEPL:
+            return deepl;
+    }
+
+    return azure;
 
-	return azure;
 }
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index ffbbb05e62..4a5d80737c 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -61,6 +61,7 @@ public :
 	typedef enum e_service {
 		SERVICE_AZURE,
 		SERVICE_GOOGLE,
+		SERVICE_DEEPL,
 	} EService;
 
     typedef boost::function<void(EService, bool, S32)> KeyVerificationResult_fn;
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index dc3e072adf..8a97d5e5d9 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  legacy_header_height="18"
- height="370"
+ height="470"
  layout="topleft"
  name="floater_translation_settings"
  help_topic="translation_settings"
@@ -11,9 +11,11 @@
 
  <string name="azure_api_key_not_verified">Azure service identifier not verified. Status: [STATUS]. Please check your settings and try again.</string>
  <string name="google_api_key_not_verified">Google API key not verified. Status: [STATUS]. Please check your key and try again.</string>
+ <string name="deepl_api_key_not_verified">DeepL Auth Key key not verified. Status: [STATUS]. Please check your key and try again.</string>
 
  <string name="azure_api_key_verified">Azure service identifier verified.</string>
  <string name="google_api_key_verified">Google API key verified.</string>
+ <string name="deepl_api_key_verified">DeepL API key verified.</string>
 
  <check_box
   height="16"     
@@ -128,7 +130,7 @@
 
  <radio_group
   follows="top|left"
-  height="140"
+  height="260"
   layout="topleft"
   left_delta="10"
   name="translation_service_rg"
@@ -145,6 +147,12 @@
    layout="topleft"
    name="google"
    top_pad="115" />
+  <radio_item
+   initial_value="deepl"
+   label="DeepL Translator"
+   layout="topleft"
+   name="deepl"
+   top_pad="61" />
  </radio_group>
 
   <text
@@ -154,7 +162,7 @@
    left="185"
    length="1"
    name="google_links_text"
-   top_pad="-142"
+   top_pad="-262"
    type="string"
    width="100">
     [https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup]
@@ -286,7 +294,7 @@
   left_pad="10"
   name="verify_google_api_key_btn"
   top_delta="-2"
-  width="90" />	
+  width="90" />
 
  <text
   follows="top|right"
@@ -301,6 +309,87 @@
   [http://code.google.com/apis/language/translate/v2/pricing.html Pricing] | [https://code.google.com/apis/console Stats] 
  </text>
 
+    <text
+     type="string"
+     length="1"
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="70"
+     name="deepl_api_domain_label"
+     top_pad="80"
+     width="85">
+        Domain:
+    </text>
+
+    <combo_box
+      allow_text_entry="false"
+      follows="left|top"
+      name="deepl_api_domain_combo"
+      height="23"
+      left_pad="10"
+      width="140"
+      top_delta="-4"
+      max_chars="512"
+      value="https://api-free.deepl.com"
+      combo_button.scale_image="true">
+        <combo_box.item
+          label="DeepL Free"
+          name="global"
+          value="https://api-free.deepl.com" />
+        <combo_box.item
+          label="DeepL Pro"
+          name="api-apc"
+          value="https://api.deepl.com" />
+    </combo_box>
+    
+    <text
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="70"
+     length="1"
+     name="deepl_api_key_label"
+     top_pad="11"
+     type="string"
+     width="85">
+      DeepL API key:
+    </text>
+
+    <line_editor
+     default_text="Enter DeepL API key and click &quot;Verify&quot;"
+     follows="top|left"
+     height="20"
+     layout="topleft"
+     left_pad="10"
+     max_length_chars="50"
+     top_delta="-4"
+     name="deepl_api_key"
+     width="210" />
+    
+    <button
+     follows="left|top"
+     height="23"
+     label="Verify"
+     layout="topleft"
+     left_pad="10"
+     name="verify_deepl_api_key_btn"
+     top_delta="-2"
+     width="90" />
+
+    <text
+     follows="top|right"
+     height="20"
+     layout="topleft"
+     left="185"
+     length="1"
+     name="deepl_links_text"
+     top_delta="-53"
+     type="string"
+     width="100">
+        [https://www.deepl.com/pro/select-country?cta=header-prices Pricing]
+    </text>
+
  <button
   follows="left|top"
   height="23"
-- 
cgit v1.2.3


From 27ee831e38b66bb3415c3df02fd2c518463ba404 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 19 May 2023 15:35:09 -0400
Subject: SL-19744: Remove LLErrorThread and LLAppViewer::handleViewerCrash()

---
 indra/llcommon/llapp.cpp            |  38 +--------
 indra/llcommon/llapp.h              |  16 +---
 indra/llcommon/llerror.h            |   1 -
 indra/llcommon/llerrorthread.cpp    | 133 ------------------------------
 indra/llcommon/llerrorthread.h      |  46 -----------
 indra/newview/llappviewer.cpp       | 159 ------------------------------------
 indra/newview/llappviewer.h         |   1 -
 indra/newview/llappviewerlinux.cpp  |   2 -
 indra/newview/llappviewermacosx.cpp |   2 -
 indra/newview/llappviewerwin32.cpp  |   2 -
 10 files changed, 5 insertions(+), 395 deletions(-)
 delete mode 100644 indra/llcommon/llerrorthread.cpp
 delete mode 100644 indra/llcommon/llerrorthread.h

(limited to 'indra')

diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index d839b19c99..89917b6324 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -39,7 +39,6 @@
 #include "llcommon.h"
 #include "llapr.h"
 #include "llerrorcontrol.h"
-#include "llerrorthread.h"
 #include "llframetimer.h"
 #include "lllivefile.h"
 #include "llmemory.h"
@@ -108,12 +107,7 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL;
 BOOL LLApp::sErrorThreadRunning = FALSE;
 
 
-LLApp::LLApp() : mThreadErrorp(NULL)
-{
-	commonCtor();
-}
-
-void LLApp::commonCtor()
+LLApp::LLApp()
 {
 	// Set our status to running
 	setStatus(APP_STATUS_RUNNING);
@@ -143,12 +137,6 @@ void LLApp::commonCtor()
 	mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
 }
 
-LLApp::LLApp(LLErrorThread *error_thread) :
-	mThreadErrorp(error_thread)
-{
-	commonCtor();
-}
-
 
 LLApp::~LLApp()
 {
@@ -158,13 +146,6 @@ LLApp::~LLApp()
 	mLiveFiles.clear();
 
 	setStopped();
-	// HACK: wait for the error thread to clean itself
-	ms_sleep(20);
-	if (mThreadErrorp)
-	{
-		delete mThreadErrorp;
-		mThreadErrorp = NULL;
-	}
 
 	SUBSYSTEM_CLEANUP_DBG(LLCommon);
 }
@@ -401,21 +382,6 @@ void LLApp::setupErrorHandling(bool second_instance)
 #endif
 }
 
-void LLApp::startErrorThread()
-{
-	//
-	// Start the error handling thread, which is responsible for taking action
-	// when the app goes into the APP_STATUS_ERROR state
-	//
-	if(!mThreadErrorp)
-	{
-		LL_INFOS() << "Starting error thread" << LL_ENDL;
-		mThreadErrorp = new LLErrorThread();
-		mThreadErrorp->setUserData((void *) this);
-		mThreadErrorp->start();
-	}
-}
-
 void LLApp::setErrorHandler(LLAppErrorHandler handler)
 {
 	LLApp::sErrorHandler = handler;
@@ -476,7 +442,7 @@ void LLApp::setStatus(EAppStatus status)
 // static
 void LLApp::setError()
 {
-	// set app status to ERROR so that the LLErrorThread notices
+	// set app status to ERROR
 	setStatus(APP_STATUS_ERROR);
 }
 
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index c65fe21c9c..436bc5437e 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -34,7 +34,6 @@
 #include <atomic>
 #include <chrono>
 // Forward declarations
-class LLErrorThread;
 class LLLiveFile;
 #if LL_LINUX
 #include <signal.h>
@@ -53,7 +52,6 @@ void clear_signals();
 
 class LL_COMMON_API LLApp
 {
-	friend class LLErrorThread;
 public:
 	typedef enum e_app_status
 	{
@@ -67,11 +65,6 @@ public:
 	LLApp();
 	virtual ~LLApp();
 
-protected:
-	LLApp(LLErrorThread* error_thread);
-	void commonCtor();
-public:
-	
 	/** 
 	 * @brief Return the static app instance if one was created.
 	 */
@@ -257,14 +250,14 @@ public:
 	void setupErrorHandling(bool mSecondInstance=false);
 
 	void setErrorHandler(LLAppErrorHandler handler);
-	static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
+	static void runErrorHandler(); // run shortly after we detect an error
 	//@}
-	
+
 	// the maximum length of the minidump filename returned by getMiniDumpFilename()
 	static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
 
 	// change the directory where Breakpad minidump files are written to
-    void setDebugFileNames(const std::string &path);
+	void setDebugFileNames(const std::string &path);
 
 	// Return the Google Breakpad minidump filename after a crash.
 	char *getMiniDumpFilename() { return mMinidumpPath; }
@@ -324,9 +317,6 @@ private:
 	typedef int(*signal_handler_func)(int signum);
 	static LLAppErrorHandler sErrorHandler;
 
-	// Default application threads
-	LLErrorThread* mThreadErrorp;		// Waits for app to go to status ERROR, then runs the error callback
-
 	// This is the application level runnable scheduler.
 	LLRunner mRunner;
 
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index d06c0e2132..020f05e8f5 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -274,7 +274,6 @@ namespace LLError
 		// used to indicate no class info known for logging
 
     //LLCallStacks keeps track of call stacks and output the call stacks to log file
-    //when LLAppViewer::handleViewerCrash() is triggered.
     //
     //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
     //LLCallStacks is designed not to be thread-safe.
diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp
deleted file mode 100644
index f6bc68b5c1..0000000000
--- a/indra/llcommon/llerrorthread.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/** 
- * @file llerrorthread.cpp
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llerrorthread.h"
-
-#include "llapp.h"
-#include "lltimer.h"	// ms_sleep()
-
-LLErrorThread::LLErrorThread()
-	: LLThread("Error"),
-	  mUserDatap(NULL)
-{
-}
-
-LLErrorThread::~LLErrorThread()
-{
-}
-
-void LLErrorThread::setUserData(void* user_data)
-{
-	mUserDatap = user_data;
-}
-
-
-void* LLErrorThread::getUserData() const
-{
-	return mUserDatap;
-}
-
-#if !LL_WINDOWS
-//
-// Various signal/error handling functions that can't be put into the class
-//
-void get_child_status(const int waitpid_status, int &process_status, bool &exited, bool do_logging)
-{
-	exited = false;
-	process_status = -1;
-	// The child process exited.  Call its callback, and then clean it up
-	if (WIFEXITED(waitpid_status))
-	{
-		process_status = WEXITSTATUS(waitpid_status);
-		exited = true;
-		if (do_logging)
-		{
-			LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL;
-		}
-		return;
-	}
-	else if (WIFSIGNALED(waitpid_status))
-	{
-		process_status = WTERMSIG(waitpid_status);
-		exited = true;
-		if (do_logging)
-		{
-			LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL;
-#ifdef WCOREDUMP
-			if (WCOREDUMP(waitpid_status))
-			{
-				LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL;
-			}
-			else
-			{
-				LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL;
-			}
-#endif
-		}
-		return;
-	}
-	else if (do_logging)
-	{
-		// This is weird.  I just dump the waitpid status into the status code,
-		// not that there's any way of telling what it is...
-		LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL;
-		process_status = waitpid_status;
-	}
-
-}
-#endif
-
-void LLErrorThread::run()
-{
-	LLApp::sErrorThreadRunning = TRUE;
-	// This thread sits and waits for the sole purpose
-	// of waiting for the signal/exception handlers to flag the
-	// application state as APP_STATUS_ERROR.
-	LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL;
-
-	S32 counter = 0;
-	while (! (LLApp::isError() || LLApp::isStopped()))
-	{
-		ms_sleep(10);
-		counter++;
-	}
-	if (LLApp::isError())
-	{
-		// The app is in an error state, run the application's error handler.
-		//LL_INFOS() << "thread_error - An error has occurred, running error callback!" << LL_ENDL;
-		// Run the error handling callback
-		LLApp::runErrorHandler();
-	}
-	else
-	{
-		// Everything is okay, a clean exit.
-		//LL_INFOS() << "thread_error - Application exited cleanly" << LL_ENDL;
-	}
-	
-	//LL_INFOS() << "thread_error - Exiting" << LL_ENDL;
-	LLApp::sErrorThreadRunning = FALSE;
-}
-
diff --git a/indra/llcommon/llerrorthread.h b/indra/llcommon/llerrorthread.h
deleted file mode 100644
index 474cef3a50..0000000000
--- a/indra/llcommon/llerrorthread.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/** 
- * @file llerrorthread.h
- * @brief Specialized thread to handle runtime errors.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLERRORTHREAD_H
-#define LL_LLERRORTHREAD_H
-
-#include "llthread.h"
-
-class LL_COMMON_API LLErrorThread : public LLThread
-{
-public:
-	LLErrorThread();
-	~LLErrorThread();
-
-	/*virtual*/ void run(void);
-	void setUserData(void *user_data);
-	void *getUserData() const;
-
-protected:
-	void* mUserDatap; // User data associated with this thread
-};
-
-#endif // LL_LLERRORTHREAD_H
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 8235e4466c..e70fcb6e86 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3582,8 +3582,6 @@ void LLAppViewer::writeSystemInfo()
 	// "CrashNotHandled" is set here, while things are running well,
 	// in case of a freeze. If there is a freeze, the crash logger will be launched
 	// and can read this value from the debug_info.log.
-	// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
-	// then the value of "CrashNotHandled" will be set to true.
 	gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true);
 #else // LL_BUGSPLAT
 	// "CrashNotHandled" is obsolete; it used (not very successsfully)
@@ -3675,163 +3673,6 @@ void getFileList()
 }
 #endif
 
-void LLAppViewer::handleViewerCrash()
-{
-	LL_INFOS("CRASHREPORT") << "Handle viewer crash entry." << LL_ENDL;
-
-	LL_INFOS("CRASHREPORT") << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ;
-
-	LLMemory::logMemoryInfo(true) ;
-
-	//print out recorded call stacks if there are any.
-	LLError::LLCallStacks::print();
-
-	LLAppViewer* pApp = LLAppViewer::instance();
-	if (pApp->beingDebugged())
-	{
-		// This will drop us into the debugger.
-		abort();
-	}
-
-	if (LLApp::isCrashloggerDisabled())
-	{
-		abort();
-	}
-
-	// Returns whether a dialog was shown.
-	// Only do the logic in here once
-	if (pApp->mReportedCrash)
-	{
-		return;
-	}
-	pApp->mReportedCrash = TRUE;
-
-	// Insert crash host url (url to post crash log to) if configured.
-	std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
-	if(crashHostUrl != "")
-	{
-		gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl;
-	}
-
-	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-	if ( parcel && parcel->getMusicURL()[0])
-	{
-		gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL();
-	}
-	if ( parcel && parcel->getMediaURL()[0])
-	{
-		gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL();
-	}
-
-	gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
-	gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = LLSD::Integer(LLMemory::getCurrentRSS() / 1024);
-
-	if(gLogoutInProgress)
-	{
-		gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
-	}
-	else
-	{
-		gDebugInfo["Dynamic"]["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
-	}
-
-	if(gAgent.getRegion())
-	{
-		gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegion()->getSimHostName();
-		gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName();
-
-		const LLVector3& loc = gAgent.getPositionAgent();
-		gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0];
-		gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1];
-		gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2];
-	}
-
-	if(LLAppViewer::instance()->mMainloopTimeout)
-	{
-		gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
-	}
-
-	// The crash is being handled here so set this value to false.
-	// Otherwise the crash logger will think this crash was a freeze.
-	gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false);
-
-	//Write out the crash status file
-	//Use marker file style setup, as that's the simplest, especially since
-	//we're already in a crash situation
-	if (gDirUtilp)
-	{
-		std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
-																			gLLErrorActivated
-																			? LLERROR_MARKER_FILE_NAME
-																			: ERROR_MARKER_FILE_NAME);
-		LLAPRFile crash_marker_file ;
-		crash_marker_file.open(crash_marker_file_name, LL_APR_WB);
-		if (crash_marker_file.getFileHandle())
-		{
-			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL;
-			recordMarkerVersion(crash_marker_file);
-		}
-		else
-		{
-			LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL;
-		}
-	}
-	else
-	{
-		LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL;
-	}
-
-#ifdef LL_WINDOWS
-	Sleep(200);
-#endif
-
-	char *minidump_file = pApp->getMiniDumpFilename();
-    LL_DEBUGS("CRASHREPORT") << "minidump file name " << minidump_file << LL_ENDL;
-	if(minidump_file && minidump_file[0] != 0)
-	{
-		gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file;
-	}
-	else
-	{
-#ifdef LL_WINDOWS
-		getFileList();
-#else
-        LL_WARNS("CRASHREPORT") << "no minidump file?" << LL_ENDL;
-#endif
-	}
-    gDebugInfo["Dynamic"]["CrashType"]="crash";
-
-	if (gMessageSystem && gDirUtilp)
-	{
-		std::string filename;
-		filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log");
-        LL_DEBUGS("CRASHREPORT") << "recording stats " << filename << LL_ENDL;
-		llofstream file(filename.c_str(), std::ios_base::binary);
-		if(file.good())
-		{
-			gMessageSystem->summarizeLogs(file);
-			file.close();
-		}
-        else
-        {
-            LL_WARNS("CRASHREPORT") << "problem recording stats" << LL_ENDL;
-        }
-	}
-
-	if (gMessageSystem)
-	{
-		gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
-		gMessageSystem->stopLogging();
-	}
-
-	if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]);
-
-	gDebugInfo["FatalMessage"] = LLError::getFatalMessage();
-
-	// Close the debug file
-	pApp->writeDebugInfo(false);  //false answers the isStatic question with the least overhead.
-}
-
 // static
 void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file)
 {
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index f28a90c703..bc4dec6bec 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -119,7 +119,6 @@ public:
 
 	virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
 	                                     // return false if the error trap needed restoration.
-	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
 	void checkForCrash();
     
 	// Thread accessors
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index dc487967fc..9f58f90326 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -80,8 +80,6 @@ int main( int argc, char **argv )
 
 	// install unexpected exception handler
 	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
-	// install crash handlers
-	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
 
 	bool ok = viewer_app_ptr->init();
 	if(!ok)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index cb5cac6f2d..8b313a321b 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -83,8 +83,6 @@ void constructViewer()
 	}
 
 	gViewerAppPtr = new LLAppViewerMacOSX();
-
-	gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);
 }
 
 bool initViewer()
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index d22fb7a4e6..298d841934 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -428,8 +428,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 
 	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
 
-	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
-
 	// Set a debug info flag to indicate if multiple instances are running.
 	bool found_other_instance = !create_app_mutex();
 	gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);
-- 
cgit v1.2.3


From 863e7f22a75e9d9c9d5c1f826eac6cd0000edac0 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 19 May 2023 16:19:42 -0400
Subject: SL-19744: Remove LLApp::startErrorThread() and references.

---
 indra/llcommon/CMakeLists.txt | 2 --
 indra/llcommon/llapp.cpp      | 6 ------
 indra/llcommon/llapp.h        | 6 ++----
 3 files changed, 2 insertions(+), 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 54020a4231..ef4899978e 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -39,7 +39,6 @@ set(llcommon_SOURCE_FILES
     lldependencies.cpp
     lldictionary.cpp
     llerror.cpp
-    llerrorthread.cpp
     llevent.cpp
     lleventapi.cpp
     lleventcoro.cpp
@@ -151,7 +150,6 @@ set(llcommon_HEADER_FILES
     llendianswizzle.h
     llerror.h
     llerrorcontrol.h
-    llerrorthread.h
     llevent.h
     lleventapi.h
     lleventcoro.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 89917b6324..b99166991f 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -374,12 +374,6 @@ void LLApp::setupErrorHandling(bool second_instance)
 #endif // ! LL_BUGSPLAT
 
 #endif // ! LL_WINDOWS
-
-#ifdef LL_BUGSPLAT
-    // do not start our own error thread
-#else // ! LL_BUGSPLAT
-	startErrorThread();
-#endif
 }
 
 void LLApp::setErrorHandler(LLAppErrorHandler handler)
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 436bc5437e..c832c8b142 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -303,13 +303,11 @@ protected:
 	void stepFrame();
 
 private:
-	void startErrorThread();
-	
 	// Contains the filename of the minidump file after a crash.
 	char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
     
-    std::string mStaticDebugFileName;
-    std::string mDynamicDebugFileName;
+	std::string mStaticDebugFileName;
+	std::string mDynamicDebugFileName;
 
 	// *NOTE: On Windows, we need a routine to reset the structured
 	// exception handler when some evil driver has taken it over for
-- 
cgit v1.2.3


From 6f7cba0f9111c85d32d9ec4e9f52be5e7fbaaf9e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 23 May 2023 23:06:41 +0300
Subject: SL-19635 Better error handling

---
 indra/newview/lltranslate.cpp                       | 21 ++++++++++++++++++---
 .../default/xui/en/floater_translation_settings.xml |  2 +-
 2 files changed, 19 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 70a40921ef..c37c955e8d 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -949,6 +949,8 @@ bool LLDeepLTranslationHandler::checkVerificationResponse(
     const LLSD& response,
     int status) const
 {
+    // Might need to parse body to make sure we got
+    // a valid response and not a message
     return status == HTTP_OK;
 }
 
@@ -1000,7 +1002,6 @@ bool LLDeepLTranslationHandler::parseResponse(
     {
         return false;
     }
-    
 
     detected_lang = data["detected_source_language"].asString();
     LLStringUtil::toLower(detected_lang);
@@ -1019,8 +1020,22 @@ bool LLDeepLTranslationHandler::isConfigured() const
 std::string LLDeepLTranslationHandler::parseErrorResponse(
     const std::string& body)
 {
-    // DeepL doesn't seem to have any error handling beyoun http codes
-    return std::string();
+    // Example: "{\"message\":\"One of the request inputs is not valid.\"}"
+
+    Json::Value root;
+    Json::Reader reader;
+
+    if (!reader.parse(body, root))
+    {
+        return std::string();
+    }
+
+    if (!root.isObject() || !root.isMember("message"))
+    {
+        return std::string();
+    }
+
+    return root["message"].asString();
 }
 
 // static
diff --git a/indra/newview/skins/default/xui/en/floater_translation_settings.xml b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
index 8a97d5e5d9..3f3331b468 100644
--- a/indra/newview/skins/default/xui/en/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_translation_settings.xml
@@ -319,7 +319,7 @@
      name="deepl_api_domain_label"
      top_pad="80"
      width="85">
-        Domain:
+        Endpoint:
     </text>
 
     <combo_box
-- 
cgit v1.2.3


From 6586055320922b4219d382f24383b00e20387e03 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 29 May 2023 21:04:52 +0300
Subject: SL-19787 Crash at LLUIColor::operator

---
 indra/llui/lluicolortable.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index b84bb13edb..096336045c 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -230,7 +230,7 @@ void LLUIColorTable::saveUserSettings() const
 	{
 		// Compare user color value with the default value, skip if equal
 		string_color_map_t::const_iterator itd = mLoadedColors.find(it->first);
-		if(itd != mUserSetColors.end() && itd->second == it->second)
+		if(itd != mLoadedColors.end() && itd->second == it->second)
 			continue;
 
 		ColorEntryParams color_entry;
-- 
cgit v1.2.3


From 5b9b4fcf6657ce2cfa5fde85012fe24213df37b5 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 29 May 2023 23:37:58 +0300
Subject: SL-17429 Message user when their inventory hits AIS2 limits

---
 indra/newview/llinventorymodelbackgroundfetch.cpp  | 25 +++++++++++++++++++---
 .../newview/skins/default/xui/en/notifications.xml |  8 +++++++
 2 files changed, 30 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 6b88d0aaf7..f544b318d6 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -30,8 +30,10 @@
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llcallbacklist.h"
-#include "llinventorypanel.h"
 #include "llinventorymodel.h"
+#include "llinventorypanel.h"
+#include "llnotificationsutil.h"
+#include "llstartup.h"
 #include "llviewercontrol.h"
 #include "llviewerinventory.h"
 #include "llviewermessage.h"
@@ -802,12 +804,24 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
 
     if(status == LLCore::HttpStatus(HTTP_FORBIDDEN))
     {
-        // too large, split into two, assume that this isn't the library
+        // Too large, split into two if possible
+        if (gDisconnected || LLApp::isExiting())
+        {
+            return;
+        }
+
         const std::string url(gAgent.getRegionCapability("FetchInventoryDescendents2"));
+        if (url.empty())
+        {
+            LL_WARNS(LOG_INV) << "Failed to get AIS2 cap" << LL_ENDL;
+            return;
+        }
+
         S32 size = mRequestSD["folders"].size();
 
-        if (!gDisconnected && !LLApp::isExiting() && !url.empty() && size > 1)
+        if (size > 1)
         {
+            // Can split, assume that this isn't the library
             LLSD folders;
             uuid_vec_t recursive_cats;
             LLSD::array_iterator iter = mRequestSD["folders"].beginArray();
@@ -838,6 +852,11 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
             gInventory.requestPost(false, url, request_body, handler, "Inventory Folder");
             return;
         }
+        else
+        {
+            // Can't split
+            LLNotificationsUtil::add("InventoryLimitReachedAIS");
+        }
     }
 	
 	// This was originally the request retry logic for the inventory
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f9211600ea..a216ef7c0d 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6369,6 +6369,14 @@ Your trash is overflowing. This may cause problems logging in.
          yestext="Check trash folder"/>
   </notification>
 
+  <notification
+   icon="notifytip.tga"
+   name="InventoryLimitReachedAIS"
+   type="notifytip">
+Your inventory is experiencing issues. Please, contact support.
+  <tag>fail</tag>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmClearBrowserCache"
-- 
cgit v1.2.3


From 6e30df2f370dd3b382a7404484e72a47adaf921e Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Thu, 1 Jun 2023 17:37:10 +0300
Subject: SL-19762 fix for cropped label text

---
 indra/llui/lltextbox.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index c567451973..521dabf9d4 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -171,7 +171,8 @@ void LLTextBox::reshapeToFitText(BOOL called_from_parent)
 
 	S32 width = getTextPixelWidth();
 	S32 height = getTextPixelHeight();
-	reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent );
+    //consider investigating reflow() to find missing width pixel (see SL-17045 changes)
+	reshape( width + 2 * mHPad + 1, height + 2 * mVPad, called_from_parent );
 }
 
 
-- 
cgit v1.2.3


From d134d155e2ddaf07ba1cdac50c1e31781e451ee5 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 1 Jun 2023 22:15:33 +0300
Subject: SL-19806 Crash at vobj

---
 indra/newview/lldrawpool.cpp      | 12 ++++++------
 indra/newview/lldrawpoolalpha.cpp |  4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 594cfe513d..3fd15d36df 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -402,7 +402,7 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t
             if(pparams->mFace)
             {
                 LLViewerObject* vobj = pparams->mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments(vobj, false, &ratPtr);
                 }
@@ -429,7 +429,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask,
             if(pparams->mFace)
             {
                 LLViewerObject* vobj = pparams->mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments( vobj, true ,&ratPtr);
                 }
@@ -459,7 +459,7 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
             if(pparams->mFace)
             {
                 LLViewerObject* vobj = pparams->mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments( vobj, false, &ratPtr);
                 }
@@ -484,7 +484,7 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc
             if(pparams->mFace)
             {
                 LLViewerObject* vobj = pparams->mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments( vobj, true, &ratPtr);
                 }
@@ -514,7 +514,7 @@ void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_
             if((*pparams).mFace)
             {
                 LLViewerObject* vobj = (*pparams).mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments( vobj, false, &ratPtr);
                 }
@@ -539,7 +539,7 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL
             if((*pparams).mFace)
             {
                 LLViewerObject* vobj = (*pparams).mFace->getViewerObject();
-                if(vobj->isAttachment())
+                if(vobj && vobj->isAttachment())
                 {
                     trackAttachments( vobj, true, &ratPtr);
                 }
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index edd0afe357..ab1ac7e30c 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -349,7 +349,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
                     if(params.mFace)
                     {
                         LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject();
-                        if(vobj->isAttachment())
+                        if(vobj && vobj->isAttachment())
                         {
                             trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr );
                         }
@@ -622,7 +622,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                 {
                     LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject();
 
-                    if(vobj->isAttachment())
+                    if(vobj && vobj->isAttachment())
                     {
                         trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr );
                     }
-- 
cgit v1.2.3


From 85967398ff8591170d89374652a6998ff6cd3d69 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Wed, 21 Jun 2023 20:50:50 -0500
Subject: SL-19792 Fix for visible gaps in water between region water and void
 water.

---
 indra/newview/app_settings/settings.xml            | 27 +++++++++-----
 .../shaders/class1/windlight/atmosphericsF.glsl    |  2 --
 indra/newview/llreflectionmapmanager.cpp           |  5 +--
 indra/newview/llsettingsvo.cpp                     |  8 +++--
 indra/newview/llvowater.cpp                        | 41 +++++++++++-----------
 5 files changed, 48 insertions(+), 35 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2b2a2d9d1b..f3065d12b8 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10590,27 +10590,38 @@
       <key>Value</key>
       <integer>3</integer>
     </map>
-  <key>RenderSkyHDRScale</key>
+  <key>RenderSkyAutoAdjustLegacy</key>
   <map>
     <key>Comment</key>
-    <string>Amount to over-brighten sun for HDR effect during the day</string>
+    <string>If true, automatically adjust legacy skies (those without a probe ambiance value) to take advantage of probes and HDR.  This is the "opt-out" button for HDR and tonemapping when coupled with a sky setting that predates PBR.</string>
     <key>Persist</key>
-    <integer>0</integer>
+    <integer>1</integer>
     <key>Type</key>
-    <string>F32</string>
+    <string>Boolean</string>
     <key>Value</key>
-    <real>1.0</real>
+    <integer>1</integer>
   </map>
-  <key>RenderSkyAutoAdjustLegacy</key>
+  <key>RenderSkyAutoAdjustAmbientScale</key>
   <map>
     <key>Comment</key>
-    <string>If true, automatically adjust legacy skies (those without a probe ambiance value) to take advantage of probes and HDR.  This is the "opt-out" button for HDR and tonemapping when coupled with a sky setting that predates PBR.</string>
+    <string>Amount to scale ambient when auto-adjusting legacy skies</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
-    <string>Boolean</string>
+    <string>F32</string>
     <key>Value</key>
+    <real>0.5</real>
+  </map>
+  <key>RenderSkyAutoAdjustHDRScale</key>
+  <map>
+    <key>Comment</key>
+    <string>HDR Scale value to use when auto-adjusting legacy skies</string>
+    <key>Persist</key>
     <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>2.0</real>
   </map>
   <key>RenderReflectionProbeMaxLocalLightAmbiance</key>
   <map>
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
index 48cf234aa0..41a848a14f 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
@@ -36,8 +36,6 @@ vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten)
 { 
     light *= atten.r;
     additive = srgb_to_linear(additive*2.0);
-    // magic 1.25 here is to match the default RenderSkyHDRScale -- this parameter needs to be plumbed into sky settings or something
-    // so it's available to all shaders that call atmosFragLighting instead of just softenLightF.glsl
     additive *= sky_hdr_scale;
     light += additive;
     return light;
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index e30aba3df7..779fe8bfd9 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -924,8 +924,9 @@ void LLReflectionMapManager::updateUniforms()
     static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
     F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(cloud_shadow_scale, should_auto_adjust);
 
-    F32 ambscale = gCubeSnapshot && !isRadiancePass() ? 0.f : 1.f;
-    F32 radscale = gCubeSnapshot && !isRadiancePass() ? 0.5f : 1.f;
+    bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass();
+    F32 ambscale = is_ambiance_pass ? 0.f : 1.f;
+    F32 radscale = is_ambiance_pass ? 0.5f : 1.f;
     
     for (auto* refmap : mReflectionMaps)
     {
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 258cc1c7b2..264359a3a9 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -719,6 +719,8 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
     F32 g = getGamma();
 
     static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+    static LLCachedControl<F32> auto_adjust_ambient_scale(gSavedSettings, "RenderSkyAutoAdjustAmbientScale", 0.75f);
+    static LLCachedControl<F32> auto_adjust_hdr_scale(gSavedSettings, "RenderSkyAutoAdjustHDRScale", 2.f);
 
     static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
     F32 probe_ambiance = getTotalReflectionProbeAmbiance(cloud_shadow_scale);
@@ -736,9 +738,9 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
         }
         else if (psky->canAutoAdjust() && should_auto_adjust)
         { // auto-adjust legacy sky to take advantage of probe ambiance 
-            shader->uniform3fv(LLShaderMgr::AMBIENT, (ambient * 0.5f).mV);
-            shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, 2.f);
-            probe_ambiance = 1.f;
+            shader->uniform3fv(LLShaderMgr::AMBIENT, (ambient * auto_adjust_ambient_scale).mV);
+            shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, auto_adjust_hdr_scale);
+            probe_ambiance = 1.f;  // NOTE -- must match LLSettingsSky::getReflectionProbeAmbiance value for "auto_adjust" true
         }
         else
         {
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 608d2cb799..77ad967cef 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -142,9 +142,14 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	static const unsigned int vertices_per_quad = 4;
 	static const unsigned int indices_per_quad = 6;
 
-	const S32 size = LLPipeline::sRenderTransparentWater ? 16 : 1;
+    S32 size_x = LLPipeline::sRenderTransparentWater ? 8 : 1;
+    S32 size_y = LLPipeline::sRenderTransparentWater ? 8 : 1;
 
-	const S32 num_quads = size * size;
+    const LLVector3& scale = getScale();
+    size_x *= llmin(llround(scale.mV[0] / 256.f), 8);
+    size_y *= llmin(llround(scale.mV[1] / 256.f), 8);
+
+	const S32 num_quads = size_x * size_y;
 	face->setSize(vertices_per_quad * num_quads,
 				  indices_per_quad * num_quads);
 	
@@ -175,41 +180,37 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 	face->mCenterLocal = position_agent;
 
 	S32 x, y;
-	F32 step_x = getScale().mV[0] / size;
-	F32 step_y = getScale().mV[1] / size;
+	F32 step_x = getScale().mV[0] / size_x;
+	F32 step_y = getScale().mV[1] / size_y;
 
 	const LLVector3 up(0.f, step_y * 0.5f, 0.f);
 	const LLVector3 right(step_x * 0.5f, 0.f, 0.f);
 	const LLVector3 normal(0.f, 0.f, 1.f);
 
-	F32 size_inv = 1.f / size;
-
-	F32 z_fudge = 0.f;
+	F32 size_inv_x = 1.f / size_x;
+    F32 size_inv_y = 1.f / size_y;
 
-	if (getIsEdgePatch())
-	{ //bump edge patches down 10 cm to prevent aliasing along edges
-		z_fudge = -0.1f;
-	}
-
-	for (y = 0; y < size; y++)
+	for (y = 0; y < size_y; y++)
 	{
-		for (x = 0; x < size; x++)
+		for (x = 0; x < size_x; x++)
 		{
-			S32 toffset = index_offset + 4*(y*size + x);
+			S32 toffset = index_offset + 4*(y*size_x + x);
 			position_agent = getPositionAgent() - getScale() * 0.5f;
 			position_agent.mV[VX] += (x + 0.5f) * step_x;
 			position_agent.mV[VY] += (y + 0.5f) * step_y;
-			position_agent.mV[VZ] += z_fudge;
+
+            position_agent.mV[VX] = llround(position_agent.mV[VX]);
+            position_agent.mV[VY] = llround(position_agent.mV[VY]);
 
 			*verticesp++  = position_agent - right + up;
 			*verticesp++  = position_agent - right - up;
 			*verticesp++  = position_agent + right + up;
 			*verticesp++  = position_agent + right - up;
 
-			*texCoordsp++ = LLVector2(x*size_inv, (y+1)*size_inv);
-			*texCoordsp++ = LLVector2(x*size_inv, y*size_inv);
-			*texCoordsp++ = LLVector2((x+1)*size_inv, (y+1)*size_inv);
-			*texCoordsp++ = LLVector2((x+1)*size_inv, y*size_inv);
+			*texCoordsp++ = LLVector2(x*size_inv_x, (y+1)*size_inv_y);
+			*texCoordsp++ = LLVector2(x*size_inv_x, y*size_inv_y);
+			*texCoordsp++ = LLVector2((x+1)*size_inv_x, (y+1)*size_inv_y);
+			*texCoordsp++ = LLVector2((x+1)*size_inv_x, y*size_inv_y);
 			
 			*normalsp++   = normal;
 			*normalsp++   = normal;
-- 
cgit v1.2.3


From 4e6303792a49e4db7a30ab5774668eb54b6a50b2 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 22 Jun 2023 00:53:18 +0300
Subject: SL-5161 Don't render meshes that are waiting for skin data

---
 indra/newview/llmeshrepository.cpp | 54 ++++++++++++++++++++++++++++++++
 indra/newview/llmeshrepository.h   |  4 +++
 indra/newview/llvovolume.cpp       | 63 ++++++++++++++++++++++++++++----------
 indra/newview/llvovolume.h         |  3 +-
 4 files changed, 107 insertions(+), 17 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 67bf6827ad..9f90e132f8 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4255,6 +4255,37 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
     return false;
 }
 
+bool LLMeshRepository::hasSkinInfo(const LLUUID& mesh_id)
+{
+    if (mesh_id.isNull())
+    {
+        return false;
+    }
+
+    if (mThread->hasSkinInfoInHeader(mesh_id))
+    {
+        return true;
+    }
+
+    const LLMeshSkinInfo* skininfo = getSkinInfo(mesh_id);
+    if (skininfo)
+    {
+        return true;
+    }
+
+    return false;
+}
+
+bool LLMeshRepository::hasHeader(const LLUUID& mesh_id)
+{
+    if (mesh_id.isNull())
+    {
+        return false;
+    }
+
+    return mThread->hasHeader(mesh_id);
+}
+
 bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id)
 {
     LLMutexLock lock(mHeaderMutex);
@@ -4271,6 +4302,29 @@ bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id)
     return false;
 }
 
+bool LLMeshRepoThread::hasSkinInfoInHeader(const LLUUID& mesh_id)
+{
+    LLMutexLock lock(mHeaderMutex);
+    mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
+    if (iter != mMeshHeader.end() && iter->second.first > 0)
+    {
+        LLMeshHeader& mesh = iter->second.second;
+        if (mesh.mSkinOffset >= 0
+            && mesh.mSkinSize > 0)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool LLMeshRepoThread::hasHeader(const LLUUID& mesh_id)
+{
+    LLMutexLock lock(mHeaderMutex);
+    mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
+    return iter != mMeshHeader.end();
+}
 
 void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
 								   bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 619e076fa6..89cd2d867f 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -401,6 +401,8 @@ public:
 	bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
 	EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
 	bool hasPhysicsShapeInHeader(const LLUUID& mesh_id);
+    bool hasSkinInfoInHeader(const LLUUID& mesh_id);
+    bool hasHeader(const LLUUID& mesh_id);
 
 	void notifyLoadedMeshes();
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@@ -650,6 +652,8 @@ public:
 	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
 	void fetchPhysicsShape(const LLUUID& mesh_id);
 	bool hasPhysicsShape(const LLUUID& mesh_id);
+    bool hasSkinInfo(const LLUUID& mesh_id);
+    bool hasHeader(const LLUUID& mesh_id);
 	
 	void buildHull(const LLVolumeParams& params, S32 detail);
 	void buildPhysicsMesh(LLModel::Decomposition& decomp);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 8160785d75..805eb47431 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -230,7 +230,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
     mColorChanged = FALSE;
 	mSpotLightPriority = 0.f;
 
-	mSkinInfoFailed = false;
+    mSkinInfoUnavaliable = false;
 	mSkinInfo = NULL;
 
 	mMediaImplList.resize(getNumTEs());
@@ -1132,7 +1132,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 				if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID())
 				{
 					mSkinInfo = NULL;
-					mSkinInfoFailed = false;
+					mSkinInfoUnavaliable = false;
 				}
 
 				if (!getVolume()->isMeshAssetLoaded())
@@ -1145,13 +1145,24 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 					}
 				}
 				
-				if (!mSkinInfo && !mSkinInfoFailed)
+				if (!mSkinInfo && !mSkinInfoUnavaliable)
 				{
-					const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this);
-					if (skin_info)
-					{
-						notifySkinInfoLoaded(skin_info);
-					}
+                    LLUUID mesh_id = volume_params.getSculptID();
+                    if (gMeshRepo.hasHeader(mesh_id) && !gMeshRepo.hasSkinInfo(mesh_id))
+                    {
+                        // If header is present but has no data about skin,
+                        // no point fetching
+                        mSkinInfoUnavaliable = true;
+                    }
+
+                    if (!mSkinInfoUnavaliable)
+                    {
+                        const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(mesh_id, this);
+                        if (skin_info)
+                        {
+                            notifySkinInfoLoaded(skin_info);
+                        }
+                    }
 				}
 			}
 			else // otherwise is sculptie
@@ -1186,7 +1197,7 @@ void LLVOVolume::updateSculptTexture()
 			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 		}
 
-		mSkinInfoFailed = false;
+        mSkinInfoUnavaliable = false;
 		mSkinInfo = NULL;
 	}
 	else
@@ -1227,6 +1238,16 @@ void LLVOVolume::notifyMeshLoaded()
 	mSculptChanged = TRUE;
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY);
 
+    if (!mSkinInfo && !mSkinInfoUnavaliable)
+    {
+        // Header was loaded, update skin info state from header
+        LLUUID mesh_id = getVolume()->getParams().getSculptID();
+        if (!gMeshRepo.hasSkinInfo(mesh_id))
+        {
+            mSkinInfoUnavaliable = true;
+        }
+    }
+
     LLVOAvatar *av = getAvatar();
     if (av && !isAnimatedObject())
     {
@@ -1244,7 +1265,7 @@ void LLVOVolume::notifyMeshLoaded()
 
 void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin)
 {
-	mSkinInfoFailed = false;
+    mSkinInfoUnavaliable = false;
 	mSkinInfo = skin;
 
 	notifyMeshLoaded();
@@ -1252,7 +1273,7 @@ void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin)
 
 void LLVOVolume::notifySkinInfoUnavailable()
 {
-	mSkinInfoFailed = true;
+	mSkinInfoUnavaliable = true;
 	mSkinInfo = nullptr;
 }
 
@@ -5589,11 +5610,21 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
             std::string vobj_name = llformat("Vol%p", vobj);
 
             bool is_mesh = vobj->isMesh();
-			if (is_mesh &&
-				((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
-			{
-				continue;
-			}
+            if (is_mesh)
+            {
+                if ((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded())
+                    || !gMeshRepo.meshRezEnabled())
+                {
+                    // Waiting for asset to fetch
+                    continue;
+                }
+
+                if (!vobj->getSkinInfo() && !vobj->isSkinInfoUnavaliable())
+                {
+                     // Waiting for skin info to fetch
+                     continue;
+                }
+            }
 
 			LLVolume* volume = vobj->getVolume();
 			if (volume)
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index acba18383f..aadc1fbcf3 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -330,6 +330,7 @@ public:
 	BOOL setIsFlexible(BOOL is_flexible);
 
     const LLMeshSkinInfo* getSkinInfo() const;
+    const bool isSkinInfoUnavaliable() const { return mSkinInfoUnavaliable; }
 
     //convenience accessor for mesh ID (which is stored in sculpt id for legacy reasons)
     const LLUUID& getMeshID() const { return getVolume()->getParams().getSculptID(); }
@@ -480,7 +481,7 @@ private:
 
 	LLPointer<LLRiggedVolume> mRiggedVolume;
 
-	bool mSkinInfoFailed;
+	bool mSkinInfoUnavaliable;
 	LLConstPointer<LLMeshSkinInfo> mSkinInfo;
 	// statics
 public:
-- 
cgit v1.2.3


From 3a1b60b2baa80218a79bf33cf983bd28df4f2343 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Thu, 22 Jun 2023 17:10:24 -0500
Subject: SL-19785 Fix for blown out skies from Glow Focus.  Add notification
 when editing legacy skies.

---
 indra/llinventory/llsettingssky.cpp                          |  1 +
 .../app_settings/shaders/class1/deferred/cloudsF.glsl        |  2 +-
 indra/newview/llfloaterenvironmentadjust.cpp                 |  7 +++++--
 indra/newview/llfloaterfixedenvironment.cpp                  |  6 ++++++
 indra/newview/llpaneleditsky.cpp                             |  5 ++++-
 indra/newview/skins/default/xui/en/notifications.xml         | 12 ++++++++++++
 6 files changed, 29 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 6521ec8b43..8338245897 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -1142,6 +1142,7 @@ void LLSettingsSky::setSkyIceLevel(F32 ice_level)
 
 void LLSettingsSky::setReflectionProbeAmbiance(F32 ambiance)
 {
+    mCanAutoAdjust = false; // we've now touched this sky in a "new" way, it can no longer auto adjust
     setValue(SETTING_REFLECTION_PROBE_AMBIANCE, ambiance);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl
index e0e97bb938..f6870c3ff0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl
@@ -110,7 +110,7 @@ void main()
     // Combine
     vec3 color;
     color = (cloudColorSun*(1.-alpha2) + cloudColorAmbient);
-    color.rgb= max(vec3(0), color.rgb);
+    color.rgb = clamp(color.rgb, vec3(0), vec3(1));
     color.rgb *= 2.0;
 
     /// Gamma correct for WL (soft clip effect).
diff --git a/indra/newview/llfloaterenvironmentadjust.cpp b/indra/newview/llfloaterenvironmentadjust.cpp
index f9e8963479..18be4fffda 100644
--- a/indra/newview/llfloaterenvironmentadjust.cpp
+++ b/indra/newview/llfloaterenvironmentadjust.cpp
@@ -174,7 +174,8 @@ void LLFloaterEnvironmentAdjust::refresh()
     getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setValue(mLiveSky->getCloudNoiseTextureId());
     getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setValue(mLiveWater->getNormalMapID());
 
-    getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setValue(mLiveSky->getReflectionProbeAmbiance());
+    static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+    getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setValue(mLiveSky->getReflectionProbeAmbiance(should_auto_adjust));
 
     LLColor3 glow(mLiveSky->getGlow());
 
@@ -488,7 +489,9 @@ void LLFloaterEnvironmentAdjust::onReflectionProbeAmbianceChanged()
 void LLFloaterEnvironmentAdjust::updateGammaLabel()
 {
     if (!mLiveSky) return;
-    F32 ambiance = mLiveSky->getReflectionProbeAmbiance();
+
+    static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+    F32 ambiance = mLiveSky->getReflectionProbeAmbiance(should_auto_adjust);
     if (ambiance != 0.f)
     {
         childSetValue("scene_gamma_label", getString("hdr_string"));
diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp
index b9dc14ac1a..bb6584302d 100644
--- a/indra/newview/llfloaterfixedenvironment.cpp
+++ b/indra/newview/llfloaterfixedenvironment.cpp
@@ -182,6 +182,12 @@ void LLFloaterFixedEnvironment::setEditSettingsAndUpdate(const LLSettingsBase::p
     syncronizeTabs();
     refresh();
     LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
+
+    // teach user about HDR settings
+    if (mSettings && ((LLSettingsSky*)mSettings.get())->canAutoAdjust())
+    {
+        LLNotificationsUtil::add("AutoAdjustHDRSky");
+    }
 }
 
 void LLFloaterFixedEnvironment::syncronizeTabs()
diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp
index a14af27e59..761d856aae 100644
--- a/indra/newview/llpaneleditsky.cpp
+++ b/indra/newview/llpaneleditsky.cpp
@@ -36,6 +36,7 @@
 #include "llsettingssky.h"
 #include "llenvironment.h"
 #include "llatmosphere.h"
+#include "llviewercontrol.h"
 
 namespace
 {   
@@ -207,7 +208,9 @@ void LLPanelSettingsSkyAtmosTab::refresh()
     F32 moisture_level  = mSkySettings->getSkyMoistureLevel();
     F32 droplet_radius  = mSkySettings->getSkyDropletRadius();
     F32 ice_level       = mSkySettings->getSkyIceLevel();
-    F32 rp_ambiance     = mSkySettings->getReflectionProbeAmbiance();
+
+    static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+    F32 rp_ambiance     = mSkySettings->getReflectionProbeAmbiance(should_auto_adjust);
 
     getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setValue(moisture_level);
     getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setValue(droplet_radius);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 4949075f2d..f77b235408 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -12097,5 +12097,17 @@ Material successfully created.  Asset ID: [ASSET_ID]
        notext="Cancel"
        yestext="OK"/>
   </notification>
+
+  <notification
+    icon="notifytip.tga"
+    name="AutoAdjustHDRSky"
+    persist="true"
+    type="alertmodal">
+      You are editing a non-HDR sky that has been automatically converted to HDR.  To remove HDR and tone mapping, set Reflection Probe Ambiance to zero.
+    <usetemplate
+        ignoretext="HDR Sky adjustment warning"
+        name="okignore"
+        yestext="OK"/>
+  </notification>
   
 </notifications>
-- 
cgit v1.2.3


From ca84e0e0c0b4b2844f478a549cb2cb1fbb52c898 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 22 Jun 2023 22:09:42 +0300
Subject: SL-5161 Avatars should stay hidden longer if they are waiting for
 meshes or skin data

---
 indra/llmath/llvolume.cpp          | 25 ++++++++++--
 indra/llmath/llvolume.h            |  9 +++--
 indra/newview/llmeshrepository.cpp |  8 +++-
 indra/newview/llvoavatar.cpp       | 80 ++++++++++++++++++++++++++++++++++++++
 indra/newview/llvoavatar.h         |  1 +
 5 files changed, 116 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 91e463cc32..0e3792fda3 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2056,7 +2056,8 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mDetail = detail;
 	mSculptLevel = -2;
 	mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
-	mIsMeshAssetLoaded = FALSE;
+	mIsMeshAssetLoaded = false;
+    mIsMeshAssetUnavaliable = false;
 	mLODScaleBias.setVec(1,1,1);
 	mHullPoints = NULL;
 	mHullIndices = NULL;
@@ -2804,14 +2805,32 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
 }
 
 
-BOOL LLVolume::isMeshAssetLoaded()
+bool LLVolume::isMeshAssetLoaded()
 {
 	return mIsMeshAssetLoaded;
 }
 
-void LLVolume::setMeshAssetLoaded(BOOL loaded)
+void LLVolume::setMeshAssetLoaded(bool loaded)
 {
 	mIsMeshAssetLoaded = loaded;
+    if (loaded)
+    {
+        mIsMeshAssetUnavaliable = false;
+    }
+}
+
+void LLVolume::setMeshAssetUnavaliable(bool unavaliable)
+{
+    // Don't set it if at least one lod loaded
+    if (!mIsMeshAssetLoaded)
+    {
+        mIsMeshAssetUnavaliable = unavaliable;
+    }
+}
+
+bool LLVolume::isMeshAssetUnavaliable()
+{
+    return mIsMeshAssetUnavaliable;
 }
 
 void LLVolume::copyFacesTo(std::vector<LLVolumeFace> &faces) const 
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index ad6a669531..afed98ff36 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -1111,15 +1111,18 @@ private:
 	bool unpackVolumeFacesInternal(const LLSD& mdl);
 
 public:
-	virtual void setMeshAssetLoaded(BOOL loaded);
-	virtual BOOL isMeshAssetLoaded();
+	virtual void setMeshAssetLoaded(bool loaded);
+	virtual bool isMeshAssetLoaded();
+    virtual void setMeshAssetUnavaliable(bool unavaliable);
+    virtual bool isMeshAssetUnavaliable();
 
  protected:
 	BOOL mUnique;
 	F32 mDetail;
 	S32 mSculptLevel;
 	F32 mSurfaceArea; //unscaled surface area
-	BOOL mIsMeshAssetLoaded;
+	bool mIsMeshAssetLoaded;
+    bool mIsMeshAssetUnavaliable;
 	
 	const LLVolumeParams mParams;
 	LLPath *mPathp;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 9f90e132f8..57ac111fdf 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -4067,7 +4067,7 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
 			if (sys_volume)
 			{
 				sys_volume->copyVolumeFaces(volume);
-				sys_volume->setMeshAssetLoaded(TRUE);
+				sys_volume->setMeshAssetLoaded(true);
 				LLPrimitive::getVolumeManager()->unrefVolume(sys_volume);
 			}
 			else
@@ -4099,6 +4099,12 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
 	{
 		F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
 
+        LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail);
+        if (sys_volume)
+        {
+            sys_volume->setMeshAssetUnavaliable(true);
+        }
+
 		for (LLVOVolume* vobj : obj_iter->second)
 		{
 			if (vobj)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c7a2cea627..22cd9f71b3 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7574,6 +7574,85 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
 	}
 }
 
+bool LLVOAvatar::hasPendingAttachedMeshes()
+{
+    for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+         iter != mAttachmentPoints.end();
+         ++iter)
+    {
+        LLViewerJointAttachment* attachment = iter->second;
+        if (attachment)
+        {
+            for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+                 attachment_iter != attachment->mAttachedObjects.end();
+                 ++attachment_iter)
+            {
+                LLViewerObject* objectp = attachment_iter->get();
+                if (objectp)
+                {
+                    LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
+                    for (LLViewerObject::child_list_t::const_iterator iter1 = child_list.begin();
+                         iter1 != child_list.end(); ++iter1)
+                    {
+                        LLViewerObject* objectchild = *iter1;
+                        if (objectchild && objectchild->getVolume())
+                        {
+                            const LLUUID& mesh_id = objectchild->getVolume()->getParams().getSculptID();
+                            if (mesh_id.isNull())
+                            {
+                                // No mesh nor skin info needed
+                                continue;
+                            }
+
+                            if (objectchild->getVolume()->isMeshAssetUnavaliable())
+                            {
+                                // Mesh failed to load, do not expect it
+                                continue;
+                            }
+
+                            if (objectchild->mDrawable)
+                            {
+                                LLVOVolume* pvobj = objectchild->mDrawable->getVOVolume();
+                                if (pvobj)
+                                {
+                                    if (!pvobj->isMesh())
+                                    {
+                                        // Not a mesh
+                                        continue;
+                                    }
+
+                                    if (!objectchild->getVolume()->isMeshAssetLoaded())
+                                    {
+                                        // Waiting for mesh
+                                        return true;
+                                    }
+
+                                    const LLMeshSkinInfo* skin_data = pvobj->getSkinInfo();
+                                    if (skin_data)
+                                    {
+                                        // Skin info present, done
+                                        continue;
+                                    }
+
+                                    if (pvobj->isSkinInfoUnavaliable())
+                                    {
+                                        // Load failed or info not present, don't expect it
+                                        continue;
+                                    }
+                                }
+
+                                // objectchild is not ready
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
 //-----------------------------------------------------------------------------
 // detachObject()
 //-----------------------------------------------------------------------------
@@ -8150,6 +8229,7 @@ BOOL LLVOAvatar::updateIsFullyLoaded()
                    || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC)
                    || !mPendingAttachment.empty()
                    || (rez_status < 3 && !isFullyBaked())
+                   || hasPendingAttachedMeshes()
                   );
 	}
 	updateRezzedStatusTimers(rez_status);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index f1dc503c9e..48bfd5293a 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -917,6 +917,7 @@ public:
 	virtual BOOL 		detachObject(LLViewerObject *viewer_object);
 	static bool		    getRiggedMeshID( LLViewerObject* pVO, LLUUID& mesh_id );
 	void				cleanupAttachedMesh( LLViewerObject* pVO );
+    bool                hasPendingAttachedMeshes();
 	static LLVOAvatar*  findAvatarFromAttachment(LLViewerObject* obj);
 	/*virtual*/ BOOL	isWearingWearableType(LLWearableType::EType type ) const;
 	LLViewerObject *	findAttachmentByID( const LLUUID & target_id ) const;
-- 
cgit v1.2.3


From f137e04c38ece6a26709378f4adbe15d54f023a1 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Fri, 23 Jun 2023 02:09:35 +0200
Subject: SL-19805 Second Life Viewer last update made invisible parts visible

---
 indra/newview/llvovolume.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 7a73ee1339..efcb049c3f 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5864,9 +5864,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
 							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
-								(gPipeline.sRenderHighlight &&
-								(LLPipeline::getRenderScriptedBeacons() || LLPipeline::getRenderScriptedTouchBeacons()) &&
-								drawablep->getVObj() && drawablep->getVObj()->flagScripted()))
+								(gPipeline.sRenderHighlight && !drawablep->getParent() &&
+								drawablep->getVObj() && drawablep->getVObj()->flagScripted() &&
+								(LLPipeline::getRenderScriptedBeacons() ||
+								LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch())))
 							{ //draw the transparent face for debugging purposes using a custom texture
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
-- 
cgit v1.2.3


From 22eecf1018d8adbf214b9f1072b3cd6d3ab3d5ae Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Fri, 23 Jun 2023 11:46:09 -0500
Subject: SL-19897 Fix for 100% transparent objects not showing up in highlight
 transparent until LoD switch.

---
 indra/newview/llspatialpartition.cpp | 37 ++----------------------------------
 indra/newview/llspatialpartition.h   |  5 +++--
 indra/newview/llviewermenu.cpp       |  7 +++----
 indra/newview/pipeline.cpp           | 34 ++++++++++++++++++++++++++++++---
 indra/newview/pipeline.h             |  5 ++++-
 5 files changed, 43 insertions(+), 45 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 978cb78083..f52f1a925d 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -777,7 +777,8 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 	assert_states_valid(this);
 }
 
-void LLSpatialGroup::destroyGL(bool keep_occlusion) 
+
+void LLSpatialGroup::destroyGLState(bool keep_occlusion) 
 {
 	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
 
@@ -1290,45 +1291,11 @@ void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
 	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
 }
 
-class LLOctreeDirty : public OctreeTraveler
-{
-public:
-	virtual void visit(const OctreeNode* state)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
-		group->destroyGL();
-
-		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-			if(!drawable)
-			{
-				continue;
-			}
-			if (drawable->getVObj().notNull() && !group->getSpatialPartition()->mRenderByGroup)
-			{
-				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL);
-			}
-		}
-
-		for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
-		{
-			LLSpatialBridge* bridge = *i;
-			traverse(bridge->mOctree);
-		}
-	}
-};
 
 void LLSpatialPartition::restoreGL()
 {
 }
 
-void LLSpatialPartition::resetVertexBuffers()
-{
-	LLOctreeDirty dirty;
-	dirty.traverse(mOctree);
-}
-
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 053ce9e60b..88584f535a 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -295,7 +295,9 @@ public:
 	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
 	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
 	void shift(const LLVector4a &offset);
-	void destroyGL(bool keep_occlusion = false);
+
+    // TODO: this no longer appears to be called, figure out if it's important and if not remove it
+	void destroyGLState(bool keep_occlusion = false);
 	
 	void updateDistance(LLCamera& camera);
 	F32 getUpdateUrgency() const;
@@ -419,7 +421,6 @@ public:
 	void renderDebug();
 	void renderIntersectingBBoxes(LLCamera* camera);
 	void restoreGL();
-	void resetVertexBuffers();
 
 	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index b9042b3496..6e5c268c00 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7826,10 +7826,6 @@ class LLToggleShaderControl : public view_listener_t
 		BOOL checked = gSavedSettings.getBOOL( control_name );
 		gSavedSettings.setBOOL( control_name, !checked );
         LLPipeline::refreshCachedSettings();
-        //gPipeline.updateRenderDeferred();
-		//gPipeline.releaseGLBuffers();
-		//gPipeline.createGLBuffers();
-		//gPipeline.resetVertexBuffers();
         LLViewerShaderMgr::instance()->setShaders();
 		return !checked;
 	}
@@ -8560,6 +8556,9 @@ class LLViewHighlightTransparent : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+
+        // invisible objects skip building their render batches unless sShowDebugAlpha is true, so rebuild batches whenever toggling this flag
+        gPipeline.rebuildDrawInfo(); 
 		return true;
 	}
 };
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 38f27d4dfa..e64ef6d555 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -10593,8 +10593,36 @@ void LLPipeline::handleShadowDetailChanged()
     }
 }
 
-void LLPipeline::overrideEnvironmentMap()
+class LLOctreeDirty : public OctreeTraveler
 {
-    //mReflectionMapManager.mProbes.clear();
-    //mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin());
+public:
+    virtual void visit(const OctreeNode* state)
+    {
+        LLSpatialGroup* group = (LLSpatialGroup*)state->getListener(0);
+
+        group->setState(LLSpatialGroup::GEOM_DIRTY);
+        gPipeline.markRebuild(group);
+
+        for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+        {
+            LLSpatialBridge* bridge = *i;
+            traverse(bridge->mOctree);
+        }
+    }
+};
+
+
+void LLPipeline::rebuildDrawInfo()
+{
+    for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+        iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+    {
+        LLViewerRegion* region = *iter;
+
+        LLOctreeDirty dirty;
+
+        LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
+        dirty.traverse(part->mOctree);
+    }
 }
+
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 19c8b06a46..961a55330a 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -131,6 +131,10 @@ public:
 	bool allocateScreenBuffer(U32 resX, U32 resY, U32 samples);
     bool allocateShadowBuffer(U32 resX, U32 resY);
 
+    // rebuild all LLVOVolume render batches
+    void rebuildDrawInfo();
+
+    // Clear LLFace mVertexBuffer pointers
 	void resetVertexBuffers(LLDrawable* drawable);
 
     // perform a profile of the given avatar
@@ -449,7 +453,6 @@ public:
     void handleShadowDetailChanged();
 
     LLReflectionMapManager mReflectionMapManager;
-    void overrideEnvironmentMap();
 
 private:
 	void unloadShaders();
-- 
cgit v1.2.3


From 5eef9143d0272c969337a3db191b07ffd396139e Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Fri, 23 Jun 2023 22:26:52 +0300
Subject: SL-19805 Follow-up fix

---
 indra/newview/llvovolume.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index efcb049c3f..d1bae2f68a 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5866,8 +5866,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
 								(gPipeline.sRenderHighlight && !drawablep->getParent() &&
 								drawablep->getVObj() && drawablep->getVObj()->flagScripted() &&
-								(LLPipeline::getRenderScriptedBeacons() ||
-								LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch())))
+								(LLPipeline::getRenderScriptedBeacons() || LLPipeline::getRenderScriptedTouchBeacons()) && 
+								drawablep->getVObj()->flagHandleTouch()))
 							{ //draw the transparent face for debugging purposes using a custom texture
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
-- 
cgit v1.2.3


From 7d3750c15bde9527e182513124cfd72818c1a282 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Sat, 24 Jun 2023 00:17:48 +0200
Subject: SL-19805 Fix touch handling logic

---
 indra/newview/llvovolume.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index d1bae2f68a..bf9a4dfa12 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5865,9 +5865,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 							}
 							else if (LLDrawPoolAlpha::sShowDebugAlpha ||
 								(gPipeline.sRenderHighlight && !drawablep->getParent() &&
+								//only root objects are highlighted with red color in this case
 								drawablep->getVObj() && drawablep->getVObj()->flagScripted() &&
-								(LLPipeline::getRenderScriptedBeacons() || LLPipeline::getRenderScriptedTouchBeacons()) && 
-								drawablep->getVObj()->flagHandleTouch()))
+								(LLPipeline::getRenderScriptedBeacons() ||
+								(LLPipeline::getRenderScriptedTouchBeacons() && drawablep->getVObj()->flagHandleTouch()))))
 							{ //draw the transparent face for debugging purposes using a custom texture
 								add_face(sAlphaFaces, alpha_count, facep);
 							}
-- 
cgit v1.2.3


From 21b67896e9d1d181f39b8e44b9efe2b4c153d22b Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Mon, 26 Jun 2023 15:37:18 -0500
Subject: SL-19909 Fix for reflection probes on vehicles blocking mouse clicks.
  Incidental instrumentation and decruft.

---
 indra/newview/llappviewer.cpp        | 2 --
 indra/newview/llreflectionmap.cpp    | 2 +-
 indra/newview/llviewerobject.cpp     | 2 ++
 indra/newview/llviewerobjectlist.cpp | 4 ++++
 indra/newview/llviewerregion.cpp     | 7 +++++++
 indra/newview/llvovolume.cpp         | 9 ++++++++-
 indra/newview/llworld.cpp            | 3 ++-
 7 files changed, 24 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index abef25e34f..cf84094aa4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4675,7 +4675,6 @@ public:
 static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio");
 static LLTrace::BlockTimerStatHandle FTM_CLEANUP("Cleanup");
 static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLES("Drawables");
-static LLTrace::BlockTimerStatHandle FTM_CLEANUP_OBJECTS("Objects");
 static LLTrace::BlockTimerStatHandle FTM_IDLE_CB("Idle Callbacks");
 static LLTrace::BlockTimerStatHandle FTM_LOD_UPDATE("Update LOD");
 static LLTrace::BlockTimerStatHandle FTM_OBJECTLIST_UPDATE("Update Objectlist");
@@ -4972,7 +4971,6 @@ void LLAppViewer::idle()
 	{
 		LL_RECORD_BLOCK_TIME(FTM_CLEANUP);
 		{
-			LL_RECORD_BLOCK_TIME(FTM_CLEANUP_OBJECTS);
 			gObjectList.cleanDeadObjects();
 		}
 		{
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index 72dab0cba8..efaf068bd2 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -117,7 +117,7 @@ void LLReflectionMap::autoAdjustOrigin()
             {
                 int face = -1;
                 LLVector4a intersection;
-                LLDrawable* drawable = mGroup->lineSegmentIntersect(bounds[0], corners[i], true, false, true, &face, &intersection);
+                LLDrawable* drawable = mGroup->lineSegmentIntersect(bounds[0], corners[i], false, false, true, &face, &intersection);
                 if (drawable != nullptr)
                 {
                     hit = true;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index e67750af7c..628a787b9d 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -418,6 +418,7 @@ void LLViewerObject::markDead()
 {
 	if (!mDead)
 	{
+        LL_PROFILE_ZONE_SCOPED;
 		//LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL;
 		
 		// Root object of this hierarchy unlinks itself.
@@ -1153,6 +1154,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					 const EObjectUpdateType update_type,
 					 LLDataPacker *dp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LL_DEBUGS_ONCE("SceneLoadTiming") << "Received viewer object data" << LL_ENDL;
 
     LL_DEBUGS("ObjectUpdate") << " mesgsys " << mesgsys << " dp " << dp << " id " << getID() << " update_type " << (S32) update_type << LL_ENDL;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index e576784db8..ce4f9b7e64 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1353,6 +1353,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 
 BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	// Don't ever kill gAgentAvatarp, just force it to the agent's region
 	// unless region is NULL which is assumed to mean you are logging out.
 	if ((objectp == gAgentAvatarp) && gAgent.getRegion())
@@ -1379,6 +1380,7 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
 
 void LLViewerObjectList::killObjects(LLViewerRegion *regionp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLViewerObject *objectp;
 
 	
@@ -1438,6 +1440,8 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer)
 		return;
 	}
 
+    LL_PROFILE_ZONE_SCOPED;
+
 	S32 num_removed = 0;
 	LLViewerObject *objectp;
 	
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index d60fae4bd6..6b92b16ef4 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -716,6 +716,7 @@ static LLTrace::BlockTimerStatHandle FTM_SAVE_REGION_CACHE("Save Region Cache");
 
 LLViewerRegion::~LLViewerRegion() 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	mDead = TRUE;
 	mImpl->mActiveSet.clear();
 	mImpl->mVisibleEntries.clear();
@@ -1590,6 +1591,7 @@ void LLViewerRegion::lightIdleUpdate()
 
 void LLViewerRegion::idleUpdate(F32 max_update_time)
 {	
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer update_timer;
 	F32 max_time;
 
@@ -1693,6 +1695,10 @@ BOOL LLViewerRegion::isViewerCameraStatic()
 
 void LLViewerRegion::killInvisibleObjects(F32 max_time)
 {
+#if 1 // TODO: kill this.  This is ill-conceived, objects that aren't in the camera frustum should not be deleted from memory.
+        // because of this, every time you turn around the simulator sends a swarm of full object update messages from cache
+    // probe misses and objects have to be reloaded from scratch.  From some reason, disabling this causes holes to 
+    // appear in the scene when flying back and forth between regions
 	if(!sVOCacheCullingEnabled)
 	{
 		return;
@@ -1769,6 +1775,7 @@ void LLViewerRegion::killInvisibleObjects(F32 max_time)
 	}
 
 	return;
+#endif
 }
 
 void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list)
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 8160785d75..de1d3fc012 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -244,6 +244,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 
 LLVOVolume::~LLVOVolume()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	delete mTextureAnimp;
 	mTextureAnimp = NULL;
 	delete mVolumeImpl;
@@ -267,6 +268,7 @@ void LLVOVolume::markDead()
 {
 	if (!mDead)
 	{
+        LL_PROFILE_ZONE_SCOPED;
         if (getVolume())
         {
             LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID());
@@ -4676,7 +4678,12 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
 			end_face = face+1;
 		}
 		pick_transparent |= isHiglightedOrBeacon();
-		bool special_cursor = specialHoverCursor();
+
+        // we *probably* shouldn't care about special cursor at all, but we *definitely*
+        // don't care about special cursor for reflection probes -- makes alt-zoom
+        // go through reflection probes on vehicles
+		bool special_cursor = mReflectionProbe.isNull() && specialHoverCursor();
+
 		for (S32 i = start_face; i < end_face; ++i)
 		{
 			if (!special_cursor && !pick_transparent && getTE(i) && getTE(i)->getColor().mV[3] == 0.f)
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 0e0dbdc071..709a457862 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -111,7 +111,7 @@ LLWorld::LLWorld() :
 	gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
 	mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
-	LLViewerRegion::sVOCacheCullingEnabled = gSavedSettings.getBOOL("RequestFullRegionCache") && gSavedSettings.getBOOL("ObjectCacheEnabled");
+    LLViewerRegion::sVOCacheCullingEnabled = gSavedSettings.getBOOL("RequestFullRegionCache") && gSavedSettings.getBOOL("ObjectCacheEnabled");
 }
 
 
@@ -681,6 +681,7 @@ static LLTrace::SampleStatHandle<> sNumActiveCachedObjects("numactivecachedobjec
 
 void LLWorld::updateRegions(F32 max_update_time)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	LLTimer update_timer;
 	mNumOfActiveCachedObjects = 0;
 	
-- 
cgit v1.2.3


From 77ea8eedb8dab989043fed4d7db6938a8c6cf54d Mon Sep 17 00:00:00 2001
From: Brad Linden <brad@lindenlab.com>
Date: Mon, 26 Jun 2023 14:07:16 -0700
Subject: Fix for SL-19620 & SL-19768 material overrides incorrectly affecting
 other faces

---
 indra/newview/llvocache.cpp | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 7081ecaa4b..a4070a513c 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -105,7 +105,7 @@ bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
                 std::string error, warn;
                 if (override_mat->fromJSON(gltf_json_str, warn, error))
                 {
-                    mGLTFMaterial[i] = override_mat;
+                    mGLTFMaterial[side_idx] = override_mat;
                 }
                 else
                 {
@@ -126,6 +126,16 @@ bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
             LL_WARNS_IF(sides.size() != 0, "GLTF") << "broken override cache entry" << LL_ENDL;
         }
     }
+
+    llassert(mSides.size() == mGLTFMaterial.size());
+#ifdef SHOW_ASSERT
+    for (auto const & side : mSides)
+    {
+        // check that mSides and mGLTFMaterial have exactly the same keys present
+        llassert(mGLTFMaterial.count(side.first) == 1);
+    }
+#endif
+
     return true;
 }
 
@@ -141,8 +151,11 @@ LLSD LLGLTFOverrideCacheEntry::toLLSD() const
     data["object_id"] = mObjectId;
     data["local_id"] = (LLSD::Integer) mLocalId;
 
+    llassert(mSides.size() == mGLTFMaterial.size());
     for (auto const & side : mSides)
     {
+        // check that mSides and mGLTFMaterial have exactly the same keys present
+        llassert(mGLTFMaterial.count(side.first) == 1);
         data["sides"].append(LLSD::Integer(side.first));
         data["gltf_json"].append(side.second);
     }
-- 
cgit v1.2.3


From d35ef7e5d8f3968479543819501bd201e6321355 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 27 Jun 2023 20:20:56 +0300
Subject: SL-19924 Update profile type names

---
 indra/newview/llpanelprofile.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 34e1fd09d8..8ac1efe8e7 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -1295,14 +1295,14 @@ void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data
         childSetVisible("badge_layout", TRUE);
         childSetVisible("partner_spacer_layout", FALSE);
     }
-    else if (customer_lower == "premium_lifetime")
+    else if (customer_lower == "secondlifetime_premium")
     {
-        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Premium_Lifetime");
+        getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Premium_Lifetime");
         getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumLifetime"));
         childSetVisible("badge_layout", TRUE);
         childSetVisible("partner_spacer_layout", FALSE);
     }
-    else if (customer_lower == "pplus_lifetime" || customer_lower == "premium_plus_lifetime")
+    else if (customer_lower == "secondlifetime_premium_plus")
     {
         getChild<LLUICtrl>("badge_icon")->setValue("Profile_Badge_Pplus_Lifetime");
         getChild<LLUICtrl>("badge_text")->setValue(getString("BadgePremiumPlusLifetime"));
-- 
cgit v1.2.3


From 8032aa20c8c421da6996a92ffb2f567256e23b66 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Tue, 27 Jun 2023 13:35:57 -0500
Subject: SL-19925 Make high graphics default to shadows on.

---
 indra/newview/featuretable.txt     | 10 +++++-----
 indra/newview/featuretable_mac.txt | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index ec2467200a..39f7996c7c 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 57
+version 58
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -163,7 +163,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   1
 
 //
-// Medium High Graphics Settings (deferred enabled)
+// Medium High Graphics Settings
 //
 list MidHigh
 RenderAnisotropic			1	1
@@ -192,7 +192,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   2
 
 //
-// High Graphics Settings (deferred + SSAO)
+// High Graphics Settings (SSAO + sun shadows)
 //
 list High
 RenderAnisotropic			1	1
@@ -212,7 +212,7 @@ RenderTreeLODFactor			1	0.5
 RenderVolumeLODFactor		1	1.5
 RenderDeferredSSAO			1	1
 RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
+RenderShadowDetail			1	1
 WLSkyDetail					1	96
 RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
@@ -221,7 +221,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   3
 
 //
-// High Ultra Graphics Settings (deferred + SSAO + shadows)
+// High Ultra Graphics Settings (deferred + SSAO + all shadows)
 //
 list HighUltra
 RenderAnisotropic			1	1
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 0687a3cea1..cce403c7aa 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 52
+version 53
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -161,7 +161,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   0
 
 //
-// Medium High Graphics Settings (deferred enabled)
+// Medium High Graphics Settings
 //
 list MidHigh
 RenderAnisotropic			1	1
@@ -190,7 +190,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   0
 
 //
-// High Graphics Settings (deferred + SSAO)
+// High Graphics Settings (SSAO + sun shadows)
 //
 list High
 RenderAnisotropic			1	1
@@ -210,7 +210,7 @@ RenderTreeLODFactor			1	0.5
 RenderVolumeLODFactor		1	1.5
 RenderDeferredSSAO			1	1
 RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail			1	0
+RenderShadowDetail			1	1
 WLSkyDetail					1	96
 RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
@@ -219,7 +219,7 @@ RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   1
 
 //
-// High Ultra Graphics Settings (deferred + SSAO + shadows)
+// High Ultra Graphics Settings (SSAO + all shadows)
 //
 list HighUltra
 RenderAnisotropic			1	1
-- 
cgit v1.2.3


From 298109864503d9c1e00d41dd1556f9dfea988e14 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Tue, 27 Jun 2023 14:01:42 -0500
Subject: SL-19897 Followup -- handle 100% transparent objects that are
 "active"

---
 indra/newview/pipeline.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e64ef6d555..0c767e7767 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -10600,8 +10600,11 @@ public:
     {
         LLSpatialGroup* group = (LLSpatialGroup*)state->getListener(0);
 
-        group->setState(LLSpatialGroup::GEOM_DIRTY);
-        gPipeline.markRebuild(group);
+        if (group->getSpatialPartition()->mRenderByGroup)
+        {
+            group->setState(LLSpatialGroup::GEOM_DIRTY);
+            gPipeline.markRebuild(group);
+        }
 
         for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
         {
@@ -10623,6 +10626,9 @@ void LLPipeline::rebuildDrawInfo()
 
         LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
         dirty.traverse(part->mOctree);
+
+        part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
+        dirty.traverse(part->mOctree);
     }
 }
 
-- 
cgit v1.2.3


From ed63ef3c0b6ceddf9ed667c1d69441d132b34983 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 28 Jun 2023 00:34:15 +0300
Subject: SL-19572 Fix some obscure cases of residents bypasing mute list

---
 indra/llmessage/llcachename.cpp | 4 +++-
 indra/newview/llmutelist.h      | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 66bd85f4e6..a2e85cf6c2 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -552,7 +552,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
 
 	// if the input wasn't a correctly formatted legacy name, just return it  
 	// cleaned up from a potential terminal "Resident"
-	return cleanFullName(full_name);
+    std::string clean_name = cleanFullName(full_name);
+    LLStringUtil::toLower(clean_name);
+	return clean_name;
 }
 
 //static 
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 2c45014321..14840f1b2e 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -99,6 +99,7 @@ public:
 	BOOL isMuted(const LLUUID& id, const std::string& name = LLStringUtil::null, U32 flags = 0) const;
 
 	// Workaround for username-based mute search, a lot of string conversions so use cautiously
+    // Expects lower case username
 	BOOL isMuted(const std::string& username, U32 flags = 0) const;
 
 	// Alternate (convenience) form for places we don't need to pass the name, but do need flags
-- 
cgit v1.2.3


From 8d17467f7f70aa28d7ad012426ca59dc760bc43f Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Tue, 27 Jun 2023 18:49:36 -0500
Subject: SL-19884 Fix for garbled rigged meshes in model import preview
 window.

---
 .../shaders/class1/objects/previewV.glsl           |  24 +++--
 indra/newview/llmodelpreview.cpp                   | 115 ++++++++++++---------
 indra/newview/llviewershadermgr.cpp                |  12 +--
 3 files changed, 86 insertions(+), 65 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
index b474a5803f..f51b0f4d9e 100644
--- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
@@ -25,7 +25,6 @@
 
 uniform mat3 normal_matrix;
 uniform mat4 texture_matrix0;
-uniform mat4 modelview_matrix;
 uniform mat4 modelview_projection_matrix;
 
 in vec3 position;
@@ -54,14 +53,27 @@ float calcDirectionalLight(vec3 n, vec3 l)
 //====================================================================================================
 
 
+#ifdef HAS_SKIN
+mat4 getObjectSkinnedTransform();
+uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+#endif
+
 void main()
 {
-	//transform vertex
-	vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0));
-	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+    vec3 norm;
+#ifdef HAS_SKIN
+    mat4 mat = getObjectSkinnedTransform();
+    mat = modelview_matrix * mat;
+    vec4 pos = mat * vec4(position.xyz, 1.0);
+    gl_Position = projection_matrix * pos;
+    norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#else
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
+    norm = normalize(normal_matrix * normal);
+#endif
+
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-	
-	vec3 norm = normalize(normal_matrix * normal);
 
 	vec4 col = vec4(0,0,0,1);
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index c98e0e1bbe..6ceffd452e 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2751,6 +2751,16 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 
         base_iter++;
 
+        bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
+
+        LLMatrix4a mat_normal;
+        if (skinned)
+        {
+            glh::matrix4f m((F32*)mdl->mSkinInfo.mBindShapeMatrix.getF32ptr());
+            m = m.inverse().transpose();
+            mat_normal.loadu(m.m);
+        }
+
         S32 num_faces = mdl->getNumVolumeFaces();
         for (S32 i = 0; i < num_faces; ++i)
         {
@@ -2765,7 +2775,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 
             LLVertexBuffer* vb = NULL;
 
-            bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
+            
 
             U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 
@@ -2803,6 +2813,15 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
 
             LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)vf.mPositions, num_vertices * 4 * sizeof(F32));
 
+            if (skinned)
+            {
+                for (U32 i = 0; i < num_vertices; ++i)
+                {
+                    LLVector4a* v = (LLVector4a*)vertex_strider.get();
+                    mdl->mSkinInfo.mBindShapeMatrix.affineTransform(*v, *v);
+                    vertex_strider++;
+                }
+            }
             if (vf.mTexCoords)
             {
                 vb->getTexCoord0Strider(tc_strider);
@@ -2813,7 +2832,25 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
             if (vf.mNormals)
             {
                 vb->getNormalStrider(normal_strider);
-                LLVector4a::memcpyNonAliased16((F32*)normal_strider.get(), (F32*)vf.mNormals, num_vertices * 4 * sizeof(F32));
+
+                if (skinned)
+                {
+                    F32* normals = (F32*)normal_strider.get();
+                    LLVector4a* src = vf.mNormals;
+                    LLVector4a* end = src + num_vertices;
+
+                    while (src < end)
+                    {
+                        LLVector4a normal;
+                        mat_normal.rotate(*src++, normal);
+                        normal.store4a(normals);
+                        normals += 4;
+                    }
+                }
+                else
+                {
+                    LLVector4a::memcpyNonAliased16((F32*)normal_strider.get(), (F32*)vf.mNormals, num_vertices * 4 * sizeof(F32));
+                }
             }
 
             if (skinned)
@@ -3276,7 +3313,7 @@ BOOL LLModelPreview::render()
         refresh();
     }
 
-    gObjectPreviewProgram.bind();
+    gObjectPreviewProgram.bind(skin_weight);
 
     gGL.loadIdentity();
     gPipeline.enableLightsPreview();
@@ -3351,11 +3388,11 @@ BOOL LLModelPreview::render()
                 }
 
                 gGL.pushMatrix();
+
                 LLMatrix4 mat = instance.mTransform;
 
                 gGL.multMatrix((GLfloat*)mat.mMatrix);
-
-
+        
                 U32 num_models = mVertexBuffer[mPreviewLOD][model].size();
                 for (U32 i = 0; i < num_models; ++i)
                 {
@@ -3685,65 +3722,41 @@ BOOL LLModelPreview::render()
                         {
                             LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
 
-                            const LLVolumeFace& face = model->getVolumeFace(i);
-
-                            LLStrider<LLVector3> position;
-                            buffer->getVertexStrider(position);
-
-                            LLStrider<LLVector4> weight;
-                            buffer->getWeight4Strider(weight);
+                            model->mSkinInfo.updateHash();
+                            LLRenderPass::uploadMatrixPalette(mPreviewAvatar, &model->mSkinInfo);
 
-                            //quick 'n dirty software vertex skinning
-
-                            //build matrix palette
-
-                            LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-                            LLSkinningUtil::initSkinningMatrixPalette(mat, joint_count,
-                                skin, getPreviewAvatar());
+                            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-                            const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix;
-                            U32 max_joints = LLSkinningUtil::getMaxJointCount();
-                            for (U32 j = 0; j < buffer->getNumVerts(); ++j)
+                            if (textures)
                             {
-                                LLMatrix4a final_mat;
-                                F32 *wptr = weight[j].mV;
-                                LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints);
-
-                                //VECTORIZE THIS
-                                LLVector4a& v = face.mPositions[j];
+                                int materialCnt = instance.mModel->mMaterialList.size();
+                                if (i < materialCnt)
+                                {
+                                    const std::string& binding = instance.mModel->mMaterialList[i];
+                                    const LLImportMaterial& material = instance.mMaterial[binding];
 
-                                LLVector4a t;
-                                LLVector4a dst;
-                                bind_shape_matrix.affineTransform(v, t);
-                                final_mat.affineTransform(t, dst);
+                                    gGL.diffuseColor4fv(material.mDiffuseColor.mV);
 
-                                position[j][0] = dst[0];
-                                position[j][1] = dst[1];
-                                position[j][2] = dst[2];
+                                    // Find the tex for this material, bind it, and add it to our set
+                                    //
+                                    LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
+                                    if (tex)
+                                    {
+                                        mTextureSet.insert(tex);
+                                    }
+                                }
                             }
-
-                            llassert(model->mMaterialList.size() > i);
-                            const std::string& binding = instance.mModel->mMaterialList[i];
-                            const LLImportMaterial& material = instance.mMaterial[binding];
-
-                            buffer->unmapBuffer();
-
-                            buffer->setBuffer();
-                            gGL.diffuseColor4fv(material.mDiffuseColor.mV);
-                            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-                            // Find the tex for this material, bind it, and add it to our set
-                            //
-                            LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
-                            if (tex)
+                            else
                             {
-                                mTextureSet.insert(tex);
+                                gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV);
                             }
 
+                            buffer->setBuffer();
                             buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
 
                             if (edges)
                             {
+                                gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
                                 gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV);
                                 glLineWidth(PREVIEW_EDGE_WIDTH);
                                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 5eae1dfb18..4559d71d6d 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -92,6 +92,7 @@ LLGLSLShader    gCopyDepthProgram;
 
 //object shaders
 LLGLSLShader		gObjectPreviewProgram;
+LLGLSLShader        gSkinnedObjectPreviewProgram;
 LLGLSLShader        gPhysicsPreviewProgram;
 LLGLSLShader		gObjectFullbrightAlphaMaskProgram;
 LLGLSLShader        gSkinnedObjectFullbrightAlphaMaskProgram;
@@ -251,7 +252,6 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gWaterProgram);
 	mShaderList.push_back(&gWaterEdgeProgram);
 	mShaderList.push_back(&gAvatarEyeballProgram); 
-	mShaderList.push_back(&gObjectPreviewProgram);
 	mShaderList.push_back(&gImpostorProgram);
 	mShaderList.push_back(&gObjectBumpProgram);
     mShaderList.push_back(&gSkinnedObjectBumpProgram);
@@ -2876,20 +2876,16 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 
 	if (success)
 	{
-		gObjectPreviewProgram.mName = "Simple Shader";
-		gObjectPreviewProgram.mFeatures.calculatesLighting = false;
-		gObjectPreviewProgram.mFeatures.calculatesAtmospherics = false;
-		gObjectPreviewProgram.mFeatures.hasGamma = false;
-		gObjectPreviewProgram.mFeatures.hasAtmospherics = false;
-		gObjectPreviewProgram.mFeatures.hasLighting = false;
-		gObjectPreviewProgram.mFeatures.mIndexedTextureChannels = 0;
+		gObjectPreviewProgram.mName = "Object Preview Shader";
 		gObjectPreviewProgram.mFeatures.disableTextureIndex = true;
 		gObjectPreviewProgram.mShaderFiles.clear();
 		gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewV.glsl", GL_VERTEX_SHADER));
 		gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewF.glsl", GL_FRAGMENT_SHADER));
 		gObjectPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT];
+        success = make_rigged_variant(gObjectPreviewProgram, gSkinnedObjectPreviewProgram);
 		success = gObjectPreviewProgram.createShader(NULL, NULL);
 		gObjectPreviewProgram.mFeatures.hasLighting = true;
+        gSkinnedObjectPreviewProgram.mFeatures.hasLighting = true;
 	}
 
 	if (success)
-- 
cgit v1.2.3


From ca47c7ff44ed0f5f1582f3a3dc5a31fcb3454885 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Tue, 27 Jun 2023 20:11:01 -0500
Subject: DRTVWR-559 Fix for manual probes not updating as often as they should
 when nearby (bad distance calculation)

---
 indra/newview/llreflectionmapmanager.cpp | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 779fe8bfd9..bb0bb04797 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -253,6 +253,10 @@ void LLReflectionMapManager::update()
 
         if (probe != mDefaultProbe)
         {
+            if (probe->mViewerObject) //make sure probes track the viewer objects they are attached to
+            {
+                probe->mOrigin.load3(probe->mViewerObject->getPositionAgent().mV);
+            }
             d.setSub(camera_pos, probe->mOrigin);
             probe->mDistance = d.getLength3().getF32() - probe->mRadius;
         }
-- 
cgit v1.2.3


From 36949692b63031f70451317445a1a368efbfcaff Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Wed, 28 Jun 2023 11:00:10 -0500
Subject: SL-19842 Nudge dynamic exposure coefficient and soften indirect
 lighting.

---
 indra/newview/app_settings/settings.xml                      |  2 +-
 .../shaders/class3/deferred/reflectionProbeF.glsl            | 12 +++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f3065d12b8..09eda2534c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10643,7 +10643,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>0.4</real>
+    <real>0.5</real>
   </map>
     <key>RenderShaderLODThreshold</key>
     <map>
diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index 1b2a34ef01..41821def8e 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -364,7 +364,8 @@ return texCUBE(envMap, ReflDirectionWS);
 // dir - ray direction in clip space
 // i - probe index in refBox/refSphere
 // d - distance to nearest wall in clip space
-vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
+// scale - scale of box, default 1.0
+vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d, float scale)
 {
     // Intersection with OBB convert to unit box space
     // Transform in local unit parallax cube space (scaled and rotated)
@@ -375,7 +376,7 @@ vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
 
     d = 1.0-max(max(abs(PositionLS.x), abs(PositionLS.y)), abs(PositionLS.z));
 
-    vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
+    vec3 Unitary = vec3(scale);
     vec3 FirstPlaneIntersect  = (Unitary - PositionLS) / RayLS;
     vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
     vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
@@ -387,6 +388,11 @@ vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
     return IntersectPositionCS;
 }
 
+vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
+{
+    return boxIntersect(origin, dir, i, d, 1.0);
+}
+
 void debugBoxCol(vec3 ro, vec3 rd, float t, vec3 p, inout vec4 col)
 {
     vec3 v = ro + rd * t;
@@ -531,7 +537,7 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int
     if (refIndex[i].w < 0)
     {
         float d = 0.0;
-        v = boxIntersect(pos, dir, i, d);
+        v = boxIntersect(pos, dir, i, d, 3.0);
         w = max(d, 0.001);
     }
     else
-- 
cgit v1.2.3


From 79223b63a2d1d5947b7955ebfa79054b897265d9 Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Wed, 28 Jun 2023 13:47:14 -0500
Subject: SL-19842 Sanity clamp sky brightness.

---
 indra/newview/app_settings/shaders/class1/deferred/skyF.glsl | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
index cc4c3b5dce..9d9ba49d82 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
@@ -84,6 +84,7 @@ void main()
     color.rgb += rainbow(optic_d);
     color.rgb += halo_22;
     color.rgb *= 2.;
+    color.rgb = clamp(color.rgb, vec3(0), vec3(5));
 
     frag_data[0] = vec4(0);
     frag_data[1] = vec4(0);
-- 
cgit v1.2.3


From f7134beb405cd080765fd5cf905ee6cc503e9074 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Wed, 28 Jun 2023 09:40:26 -0700
Subject: SL-17405 (Part 2): Fix viewer not requesting land impact when a
 non-root prim in a link set gets a GLTF material ID update

---
 indra/newview/llviewerobject.cpp | 22 +++++++++++++++++++---
 indra/newview/llviewerobject.h   |  1 +
 2 files changed, 20 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index e67750af7c..004674997b 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -1269,7 +1269,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				LL_INFOS() << "Full:" << getID() << LL_ENDL;
 #endif
 				//clear cost and linkset cost
-				mCostStale = true;
+				setObjectCostStale();
 				if (isSelected())
 				{
 					gFloaterTools->dirty();
@@ -1825,7 +1825,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 #ifdef DEBUG_UPDATE_TYPE
 				LL_INFOS() << "CompFull:" << getID() << LL_ENDL;
 #endif
-				mCostStale = true;
+				setObjectCostStale();
 
 				if (isSelected())
 				{
@@ -3779,6 +3779,16 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
 	}
 }
 
+void LLViewerObject::setObjectCostStale()
+{
+	mCostStale = true;
+    // *NOTE: This is harmlessly redundant for Blinn-Phong material updates, as
+    // the root prim currently gets set stale anyway due to other property
+    // updates. But it is needed for GLTF material ID updates.
+    // -Cosmic,2023-06-27
+    getRootEdit()->mCostStale = true;
+}
+
 void LLViewerObject::setObjectCost(F32 cost)
 {
 	mObjectCost = cost;
@@ -6796,7 +6806,7 @@ void LLViewerObject::setPhysicsShapeType(U8 type)
 	if (type != mPhysicsShapeType)
 	{
 	mPhysicsShapeType = type;
-	mCostStale = true;
+	setObjectCostStale();
 }
 }
 
@@ -7303,6 +7313,12 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat
             LLGLTFMaterialList::queueApply(this, te, id);
         }
     }
+
+    if (!update_server)
+    {
+        // Land impact may have changed
+        setObjectCostStale();
+    }
 }
 
 void LLViewerObject::setRenderMaterialIDs(const LLUUID& id)
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index bf82c43cd3..3665c64965 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -637,6 +637,7 @@ public:
 	std::vector<LLVector3> mUnselectedChildrenPositions ;
 
 private:
+    void setObjectCostStale();
     bool isAssetInInventory(LLViewerInventoryItem* item);
 
 	ExtraParameter* createNewParameterEntry(U16 param_type);
-- 
cgit v1.2.3


From 79198eddf76dfa69e8161f7646d8da19853a8a5a Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Fri, 7 Jul 2023 20:24:49 +0300
Subject: SL-19966 Reverted "SL-18721: Faster viewer shutdown time since
 performance improvements can lead to perceived inventory loss due to cache
 corruption"

This reverts commit cf692c40b0b9f8d0d04cd10a02a84e3f697a2e99.
---
 indra/llcommon/threadpool.cpp    | 5 -----
 indra/llcommon/threadpool.h      | 4 ----
 indra/llwindow/llwindowwin32.cpp | 3 ---
 3 files changed, 12 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp
index 4a7ead2110..d5adf11264 100644
--- a/indra/llcommon/threadpool.cpp
+++ b/indra/llcommon/threadpool.cpp
@@ -39,11 +39,6 @@ void LL::ThreadPool::start()
                 run(tname);
             });
     }
-
-    // Special workflow for LLWindowWin32Thread - it's close() should be called explicitly
-    if (mExplicitShutdown)
-        return;
-
     // Listen on "LLApp", and when the app is shutting down, close the queue
     // and join the workers.
     LLEventPumps::instance().obtain("LLApp").listen(
diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h
index 0a5f14529b..f8eec3b457 100644
--- a/indra/llcommon/threadpool.h
+++ b/indra/llcommon/threadpool.h
@@ -59,10 +59,6 @@ namespace LL
          */
         virtual void run();
 
-    protected:
-        // LLWindowWin32Thread should set this flag to true
-        bool mExplicitShutdown { false };
-
     private:
         void run(const std::string& name);
 
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 2f1a631585..2e560ddb0a 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -4592,9 +4592,6 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
     : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
 {
-    // Set this flag to true to avoid of implicit call of close() from start()
-    mExplicitShutdown = true;
-
     ThreadPool::start();
 }
 
-- 
cgit v1.2.3


From 4aa44bdfc9bae011bdfbb01bd888f7ab92e18215 Mon Sep 17 00:00:00 2001
From: Maxim Nikolenko <maximnproductengine@lindenlab.com>
Date: Thu, 6 Jul 2023 21:46:19 +0300
Subject: SL-19702 restore previous double clicking behavior for objects

---
 indra/newview/llviewerinput.cpp  | 5 +++--
 indra/newview/llviewerwindow.cpp | 3 ++-
 indra/newview/llviewerwindow.h   | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 6bab2c2100..226e0a9a56 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1597,7 +1597,8 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 
 BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
 {
-    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+    bool is_toolmgr_action = false;
+    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down, is_toolmgr_action);
 
     if (clicktype != CLICK_NONE)
     {
@@ -1616,7 +1617,7 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,
 
         // If the first LMB click is handled by the menu, skip the following double click
         static bool skip_double_click = false;
-        if (clicktype == CLICK_LEFT && down )
+        if (clicktype == CLICK_LEFT && down && !is_toolmgr_action)
         {
             skip_double_click = handled;
         }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index b9fcc25310..e8fd74b37b 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1050,7 +1050,7 @@ void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
     }
 }
 
-BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool& is_toolmgr_action)
 {
 	const char* buttonname = "";
 	const char* buttonstatestr = "";
@@ -1199,6 +1199,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 	if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
 	{
 		LLViewerEventRecorder::instance().clear_xui(); 
+        is_toolmgr_action = true;
 		return TRUE;
 	}
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 1927e01ddb..92905ef21a 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -179,7 +179,7 @@ public:
 
     void            reshapeStatusBarContainer();
 
-	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down, bool &is_toolmgr_action);
 
 	//
 	// LLWindowCallback interface implementation
-- 
cgit v1.2.3


From bce11a1fa03b95782378ecb431850f77f762a348 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 7 Jul 2023 23:13:04 +0300
Subject: SL-19958 An inventory material without asset should default to a
 blank material

A New Material created in Inventory should be immediately usable.
---
 indra/newview/lltooldraganddrop.cpp | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 6633951db3..4705970c7b 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -40,6 +40,7 @@
 #include "llfloatertools.h"
 #include "llgesturemgr.h"
 #include "llgiveinventory.h"
+#include "llgltfmateriallist.h"
 #include "llhudmanager.h"
 #include "llhudeffecttrail.h"
 #include "llimview.h"
@@ -1095,12 +1096,17 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no material item." << LL_ENDL;
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
+    LLUUID asset_id = item->getAssetUUID();
+    if (asset_id.isNull())
+    {
+        // use blank material
+        asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
+    }
 
     hit_obj->setRenderMaterialID(hit_face, asset_id);
 
@@ -1121,13 +1127,19 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no material item." << LL_ENDL;
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
 
+    LLUUID asset_id = item->getAssetUUID();
+    if (asset_id.isNull())
+    {
+        // use blank material
+        asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
+    }
+
     hit_obj->setRenderMaterialIDs(asset_id);
     dialog_refresh_all();
     // send the update to the simulator
-- 
cgit v1.2.3


From ba4b596894e8eb9b9eb51169b9b3f88c21173c29 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 11 Jul 2023 01:24:22 +0300
Subject: SL-19141 Fixed applying a no-copy texture to two objects failing
 silently

---
 indra/newview/llpanelface.cpp                      | 22 ++++++++++++++++----
 indra/newview/llselectmgr.cpp                      | 24 ++++++++++++++--------
 indra/newview/llselectmgr.h                        |  4 ++--
 .../newview/skins/default/xui/en/notifications.xml | 20 ++++++++++++++++++
 4 files changed, 56 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 7d6015f557..702a8a82e2 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -520,7 +520,11 @@ void LLPanelFace::sendTexture()
 		{
 			id = mTextureCtrl->getImageAssetID();
 		}
-		LLSelectMgr::getInstance()->selectionSetImage(id);
+        if (!LLSelectMgr::getInstance()->selectionSetImage(id))
+        {
+            // need to refresh value in texture ctrl
+            refresh();
+        }
 	}
 }
 
@@ -3032,7 +3036,11 @@ void LLPanelFace::onCommitPbr(const LLSD& data)
         {
             id = pbr_ctrl->getImageAssetID();
         }
-        LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id);
+        if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
+        {
+            // If failed to set material, refresh pbr_ctrl's value
+            refresh();
+        }
     }
 }
 
@@ -3056,8 +3064,14 @@ void LLPanelFace::onSelectPbr(const LLSD& data)
         {
             id = pbr_ctrl->getImageAssetID();
         }
-        LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id);
-        LLSelectedTEMaterial::setMaterialID(this, id);
+        if (LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
+        {
+            LLSelectedTEMaterial::setMaterialID(this, id);
+        }
+        else
+        {
+            refresh();
+        }
     }
 }
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index dca341e5a2..3b20ed1e00 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -1821,7 +1821,7 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item)
 // selectionSetImage()
 //-----------------------------------------------------------------------------
 // *TODO: re-arch texture applying out of lltooldraganddrop
-void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
+bool LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 {
 	// First for (no copy) textures and multiple object selection
 	LLViewerInventoryItem* item = gInventory.getItem(imageid);
@@ -1829,9 +1829,11 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 		&& !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
 		&& (mSelectedObjects->getNumNodes() > 1) )
 	{
-		LL_WARNS() << "Attempted to apply no-copy texture to multiple objects"
-				<< LL_ENDL;
-		return;
+         LL_DEBUGS() << "Attempted to apply no-copy texture " << imageid
+             << " to multiple objects" << LL_ENDL;
+
+        LLNotificationsUtil::add("FailedToApplyTextureNoCopyToMultiple");
+        return false;
 	}
 
 	struct f : public LLSelectedTEFunctor
@@ -1896,12 +1898,14 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 		}
 	} sendfunc(item);
 	getSelection()->applyToObjects(&sendfunc);
+
+    return true;
 }
 
 //-----------------------------------------------------------------------------
 // selectionSetGLTFMaterial()
 //-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
+bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
 {
     // First for (no copy) textures and multiple object selection
     LLViewerInventoryItem* item = gInventory.getItem(mat_id);
@@ -1909,9 +1913,11 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
         && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
         && (mSelectedObjects->getNumNodes() > 1))
     {
-        LL_WARNS() << "Attempted to apply no-copy material to multiple objects"
-            << LL_ENDL;
-        return;
+        LL_DEBUGS() << "Attempted to apply no-copy material " << mat_id
+            << "to multiple objects" << LL_ENDL;
+
+        LLNotificationsUtil::add("FailedToApplyGLTFNoCopyToMultiple");
+        return false;
     }
 
     struct f : public LLSelectedTEFunctor
@@ -1983,6 +1989,8 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
     getSelection()->applyToObjects(&sendfunc);
 
     LLGLTFMaterialList::flushUpdates();
+
+    return true;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index ca9a32f0db..327134a487 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -634,8 +634,8 @@ public:
 	void selectionSetDensity(F32 density);
 	void selectionSetRestitution(F32 restitution);
 	void selectionSetMaterial(U8 material);
-	void selectionSetImage(const LLUUID& imageid); // could be item or asset id
-    void selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id
+	bool selectionSetImage(const LLUUID& imageid); // could be item or asset id
+    bool selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id
 	void selectionSetColor(const LLColor4 &color);
 	void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
 	void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f77b235408..c4abd27a01 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9211,6 +9211,26 @@ Paste failed. [REASON]
     yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="FailedToApplyTextureNoCopyToMultiple"
+   type="alertmodal">
+Failed to apply texture. You can not apply a no-copy texture to multiple objects.
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="FailedToApplyGLTFNoCopyToMultiple"
+   type="alertmodal">
+Failed to apply GLTF material. You can not apply a no-copy material to multiple objects.
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="FacePasteTexturePermissions"
-- 
cgit v1.2.3


From 59a626c2a22aa7cbccf87ce435012583d7610cd4 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Tue, 11 Jul 2023 16:08:03 -0700
Subject: SL-19992: Fix assert in LLVolumeLODGroup::refLOD when
 LLMeshRepository::notifyMeshUnavailable is called on the highest LOD

---
 indra/llmath/llvolumemgr.cpp       | 18 +++++++++---------
 indra/newview/llmeshrepository.cpp | 20 ++++++++++----------
 2 files changed, 19 insertions(+), 19 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 89cdb1c6b9..9399504529 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -89,7 +89,7 @@ BOOL LLVolumeMgr::cleanup()
 // Note however that LLVolumeLODGroup that contains the volume
 //  also holds a LLPointer so the volume will only go away after
 //  anything holding the volume and the LODGroup are destroyed
-LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
+LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod)
 {
 	LLVolumeLODGroup* volgroupp;
 	if (mDataMutex)
@@ -109,7 +109,7 @@ LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32
 	{
 		mDataMutex->unlock();
 	}
-	return volgroupp->refLOD(detail);
+	return volgroupp->refLOD(lod);
 }
 
 // virtual
@@ -287,18 +287,18 @@ bool LLVolumeLODGroup::cleanupRefs()
 	return res;
 }
 
-LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
+LLVolume* LLVolumeLODGroup::refLOD(const S32 lod)
 {
-	llassert(detail >=0 && detail < NUM_LODS);
-	mAccessCount[detail]++;
+	llassert(lod >=0 && lod < NUM_LODS);
+	mAccessCount[lod]++;
 	
 	mRefs++;
-	if (mVolumeLODs[detail].isNull())
+	if (mVolumeLODs[lod].isNull())
 	{
-		mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
+		mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]);
 	}
-	mLODRefs[detail]++;
-	return mVolumeLODs[detail];
+	mLODRefs[lod]++;
+	return mVolumeLODs[lod];
 }
 
 BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 57ac111fdf..2118ee74d3 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -3021,7 +3021,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLMeshHeader& header, S32 lod)
 	}
 
 	//search up to find then ext available higher lod
-	for (S32 i = lod+1; i < 4; ++i)
+	for (S32 i = lod+1; i < LLVolumeLODGroup::NUM_LODS; ++i)
 	{
 		if (header.mLodSize[i] > 0)
 		{
@@ -3183,7 +3183,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)
 
 	// Can't get the header so none of the LODs will be available
 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
-	for (int i(0); i < 4; ++i)
+	for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 	{
 		gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
 	}
@@ -3212,7 +3212,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
 
 		// Can't get the header so none of the LODs will be available
 		LLMutexLock lock(gMeshRepo.mThread->mMutex);
-		for (int i(0); i < 4; ++i)
+		for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 		{
 			gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
 		}
@@ -3293,7 +3293,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
 
 			// headerReceived() parsed header, but header's data is invalid so none of the LODs will be available
 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
-			for (int i(0); i < 4; ++i)
+			for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 			{
 				gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));
 			}
@@ -3654,7 +3654,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 	// Manage time-to-load metrics for mesh download operations.
 	metricsProgress(1);
 
-	if (detail < 0 || detail >= 4)
+	if (detail < 0 || detail >= LLVolumeLODGroup::NUM_LODS)
 	{
 		return detail;
 	}
@@ -3717,7 +3717,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 			}
 
 			//no lower LOD is a available, is a higher lod available?
-			for (S32 i = detail+1; i < 4; ++i)
+			for (S32 i = detail+1; i < LLVolumeLODGroup::NUM_LODS; ++i)
 			{
 				LLVolume* lod = group->refLOD(i);
 				if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0)
@@ -3918,7 +3918,7 @@ void LLMeshRepository::notifyLoadedMeshes()
 				//create score map
 				std::map<LLUUID, F32> score_map;
 
-				for (U32 i = 0; i < 4; ++i)
+				for (U32 i = 0; i < LLVolumeLODGroup::NUM_LODS; ++i)
 				{
 					for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin();  iter != mLoadingMeshes[i].end(); ++iter)
 					{
@@ -4099,7 +4099,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
 	{
 		F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
 
-        LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail);
+        LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, lod);
         if (sys_volume)
         {
             sys_volume->setMeshAssetUnavaliable(true);
@@ -4480,7 +4480,7 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by
             {
                 LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL;
             }
-            if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod)))
+            if (bytes_visible && (lod >=0) && (lod < LLVolumeLODGroup::NUM_LODS) && (*bytes_visible != data.getSizeByLOD(lod)))
             {
                 LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL;
             }
@@ -4640,7 +4640,7 @@ bool LLMeshCostData::init(const LLMeshHeader& header)
     static LLCachedControl<U32> minimum_size(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free"
     static LLCachedControl<U32> bytes_per_triangle(gSavedSettings, "MeshBytesPerTriangle", 16);
 
-    for (S32 i=0; i<4; i++)
+    for (S32 i=0; i<LLVolumeLODGroup::NUM_LODS; i++)
     {
         mEstTrisByLOD[i] = llmax((F32)mSizeByLOD[i] - (F32)metadata_discount, (F32)minimum_size) / (F32)bytes_per_triangle;
     }
-- 
cgit v1.2.3


From 0a93c3e22d8df03a9989ebd89e85c4f5a578a2ce Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 12 Jul 2023 15:21:28 +0300
Subject: SL-19990 Brightness slider should be named HDR Scale unless
 Reflection Probe Ambiance (HDR) is 0

---
 indra/newview/llpaneleditsky.cpp | 6 +++---
 indra/newview/llpaneleditsky.h   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp
index 761d856aae..0a7a4763be 100644
--- a/indra/newview/llpaneleditsky.cpp
+++ b/indra/newview/llpaneleditsky.cpp
@@ -217,7 +217,7 @@ void LLPanelSettingsSkyAtmosTab::refresh()
     getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setValue(ice_level);
     getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setValue(rp_ambiance);
 
-    updateGammaLabel();
+    updateGammaLabel(should_auto_adjust);
 }
 
 //-------------------------------------------------------------------------
@@ -335,10 +335,10 @@ void LLPanelSettingsSkyAtmosTab::onReflectionProbeAmbianceChanged()
 }
 
 
-void LLPanelSettingsSkyAtmosTab::updateGammaLabel()
+void LLPanelSettingsSkyAtmosTab::updateGammaLabel(bool auto_adjust)
 {
     if (!mSkySettings) return;
-    F32 ambiance = mSkySettings->getReflectionProbeAmbiance();
+    F32 ambiance = mSkySettings->getReflectionProbeAmbiance(auto_adjust);
     if (ambiance != 0.f)
     {
         childSetValue("scene_gamma_label", getString("hdr_string"));
diff --git a/indra/newview/llpaneleditsky.h b/indra/newview/llpaneleditsky.h
index 33af667ab7..523cc134a8 100644
--- a/indra/newview/llpaneleditsky.h
+++ b/indra/newview/llpaneleditsky.h
@@ -80,7 +80,7 @@ private:
     void                    onDropletRadiusChanged();
     void                    onIceLevelChanged();
     void                    onReflectionProbeAmbianceChanged();
-    void                    updateGammaLabel();
+    void                    updateGammaLabel(bool auto_adjust = false);
 
 };
 
-- 
cgit v1.2.3


From 162f10e021d778e499836bd1f9d1f88b004b8017 Mon Sep 17 00:00:00 2001
From: Brad Linden <brad@lindenlab.com>
Date: Wed, 12 Jul 2023 14:18:20 -0700
Subject: added info log lines for assistance diagnosing SL-19968

---
 indra/newview/llvocache.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 55fc663496..8d1f5b5f5b 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -1086,6 +1086,8 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 
 	readCacheHeader();	
 
+	LL_INFOS() << "Viewer Object Cache Versions - expected: " << cache_version << " found: " << mMetaInfo.mVersion <<  LL_ENDL;
+
 	if( mMetaInfo.mVersion != cache_version
 		|| mMetaInfo.mAddressSize != expected_address) 
 	{
@@ -1096,7 +1098,8 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 			clearCacheInMemory();
 		}
 		else //delete the current cache if the format does not match.
-		{			
+		{
+			LL_INFOS() << "Viewer Object Cache Versions unmatched.  clearing cache." <<  LL_ENDL;
 			removeCache();
 		}
 	}	
-- 
cgit v1.2.3


From afcb421bdc666d9b45fb5adb7098b7e433042823 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Thu, 6 Jul 2023 12:53:42 -0700
Subject: SL-19567: (WIP) Add options to use higher precision for glow and
 post-process buffers. Disabled by default.

---
 indra/newview/app_settings/settings.xml | 22 ++++++++++++++++++++++
 indra/newview/llviewercontrol.cpp       |  2 ++
 indra/newview/pipeline.cpp              |  8 ++++++--
 3 files changed, 30 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 09eda2534c..9f3a5bd5b9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9340,6 +9340,17 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+  <key>RenderPostProcessingHDR</key>
+  <map>
+    <key>Comment</key>
+    <string>Enable HDR for post processing buffer</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>RenderMaxOpenGLVersion</key>
   <map>
     <key>Comment</key>
@@ -10155,6 +10166,17 @@
       <key>Value</key>
       <integer>9</integer>
     </map>
+    <key>RenderGlowHDR</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable HDR for glow map</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderGlowStrength</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index aae4409167..9707a2a7e6 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -700,6 +700,7 @@ void settings_setup_listeners()
     setting_setup_signal_listener(gSavedSettings, "RenderUIBuffer", handleWindowResized);
     setting_setup_signal_listener(gSavedSettings, "RenderDepthOfField", handleReleaseGLBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderFSAASamples", handleReleaseGLBufferChanged);
+    setting_setup_signal_listener(gSavedSettings, "RenderPostProcessingHDR", handleReleaseGLBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderSpecularResX", handleLUTBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderSpecularResY", handleLUTBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderSpecularExponent", handleLUTBufferChanged);
@@ -708,6 +709,7 @@ void settings_setup_listeners()
     setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleReleaseGLBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleSetShaderChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGlowResolutionPow", handleReleaseGLBufferChanged);
+    setting_setup_signal_listener(gSavedSettings, "RenderGlowHDR", handleReleaseGLBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 0c767e7767..4183990261 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -840,7 +840,9 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
         mSceneMap.allocate(resX, resY, GL_RGB, true);
     }
 
-    mPostMap.allocate(resX, resY, GL_RGBA);
+	const bool post_hdr = gSavedSettings.getBOOL("RenderPostProcessingHDR");
+    const U32 post_color_fmt = post_hdr ? GL_RGBA16F : GL_RGBA;
+    mPostMap.allocate(resX, resY, post_color_fmt);
 
     //HACK make screenbuffer allocations start failing after 30 seconds
     if (gSavedSettings.getBOOL("SimulateFBOFailure"))
@@ -1163,9 +1165,11 @@ void LLPipeline::createGLBuffers()
 
     // allocate screen space glow buffers
     const U32 glow_res = llmax(1, llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
+	const bool glow_hdr = gSavedSettings.getBOOL("RenderGlowHDR");
+    const U32 glow_color_fmt = glow_hdr ? GL_RGBA16F : GL_RGBA;
     for (U32 i = 0; i < 3; i++)
     {
-        mGlow[i].allocate(512, glow_res, GL_RGBA);
+        mGlow[i].allocate(512, glow_res, glow_color_fmt);
     }
 
     allocateScreenBuffer(resX, resY);
-- 
cgit v1.2.3


From 66283201301b0e55336f4b20407fed811acdc739 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Tue, 11 Jul 2023 09:51:14 -0700
Subject: SL-19567: Add option RenderGlowNoise for low precision glow
 dithering, enabled by default

---
 indra/llrender/llshadermgr.cpp                           |  3 ++-
 indra/llrender/llshadermgr.h                             |  1 +
 indra/newview/app_settings/settings.xml                  | 11 +++++++++++
 .../shaders/class1/effects/glowExtractF.glsl             | 15 ++++++++++++++-
 indra/newview/llviewercontrol.cpp                        |  1 +
 indra/newview/llviewershadermgr.cpp                      | 11 ++++++++++-
 indra/newview/pipeline.cpp                               | 16 ++++++++++++++++
 indra/newview/pipeline.h                                 |  1 +
 8 files changed, 56 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 75d6ef6c46..22940dc703 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1300,8 +1300,9 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("warmthAmount");
 	mReservedUniforms.push_back("glowStrength");
 	mReservedUniforms.push_back("glowDelta");
+	mReservedUniforms.push_back("glowNoiseMap");
 
-	llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1);
+	llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_NOISE_MAP+1);
 
 
 	mReservedUniforms.push_back("minimum_alpha");
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 46f352aa58..ac4b393fb7 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -131,6 +131,7 @@ public:
         GLOW_WARMTH_AMOUNT,                 //  "warmthAmount"
         GLOW_STRENGTH,                      //  "glowStrength"
         GLOW_DELTA,                         //  "glowDelta"
+        GLOW_NOISE_MAP,                     //  "glowNoiseMap"
 
         MINIMUM_ALPHA,                      //  "minimum_alpha"
         EMISSIVE_BRIGHTNESS,                //  "emissive_brightness"
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 9f3a5bd5b9..8e5e092250 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10225,6 +10225,17 @@
       <key>Value</key>
       <real>1.3</real>
     </map>
+    <key>RenderGlowNoise</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables glow noise (dithering). Reduces banding from glow in certain cases.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <real>1</real>
+    </map>
     <key>DisableAllRenderTypes</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
index 7a5e14566b..b5437d43d2 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
@@ -28,6 +28,10 @@
 out vec4 frag_color;
 
 uniform sampler2D diffuseMap;
+#if HAS_NOISE
+uniform sampler2D glowNoiseMap;
+uniform vec2 screen_res;
+#endif
 uniform float minLuminance;
 uniform float maxExtractAlpha;
 uniform vec3 lumWeights;
@@ -44,7 +48,16 @@ void main()
 	float lum = smoothstep(minLuminance, minLuminance+1.0, dot(col.rgb, lumWeights ) );
 	float warmth = smoothstep(minLuminance, minLuminance+1.0, max(col.r * warmthWeights.r, max(col.g * warmthWeights.g, col.b * warmthWeights.b)) ); 
 	
-	frag_color.rgb = col.rgb; 
+#if HAS_NOISE
+    float TRUE_NOISE_RES = 128; // See mTrueNoiseMap
+    // *NOTE: Usually this is vary_fragcoord not vary_texcoord0, but glow extraction is in screen space
+    vec3 glow_noise = texture(glowNoiseMap, vary_texcoord0.xy * (screen_res / TRUE_NOISE_RES)).xyz;
+    // Dithering. Reduces banding effects in the reduced precision glow buffer.
+    float NOISE_DEPTH = 64.0;
+    col.rgb += glow_noise / NOISE_DEPTH;
+    col.rgb = max(col.rgb, vec3(0));
+#endif
+	frag_color.rgb = col.rgb;
 	frag_color.a = max(col.a, mix(lum, warmth, warmthAmount) * maxExtractAlpha);
 	
 }
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 9707a2a7e6..9f4287c23d 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -710,6 +710,7 @@ void settings_setup_listeners()
     setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleSetShaderChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGlowResolutionPow", handleReleaseGLBufferChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGlowHDR", handleReleaseGLBufferChanged);
+    setting_setup_signal_listener(gSavedSettings, "RenderGlowNoise", handleSetShaderChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged);
     setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 4559d71d6d..82b16d67bd 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -898,11 +898,20 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 	
 	if (success)
 	{
-		gGlowExtractProgram.mName = "Glow Extract Shader (Post)";
+        const bool use_glow_noise = gSavedSettings.getBOOL("RenderGlowNoise");
+        const std::string glow_noise_label = use_glow_noise ? " (+Noise)" : "";
+
+		gGlowExtractProgram.mName = llformat("Glow Extract Shader (Post)%s", glow_noise_label.c_str());
 		gGlowExtractProgram.mShaderFiles.clear();
 		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractV.glsl", GL_VERTEX_SHADER));
 		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractF.glsl", GL_FRAGMENT_SHADER));
 		gGlowExtractProgram.mShaderLevel = mShaderLevel[SHADER_EFFECT];
+
+        if (use_glow_noise)
+        {
+            gGlowExtractProgram.addPermutation("HAS_NOISE", "1");
+        }
+
 		success = gGlowExtractProgram.createShader(NULL, NULL);
 		if (!success)
 		{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 4183990261..d50e671e05 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -157,6 +157,7 @@ S32 LLPipeline::RenderGlowResolutionPow;
 S32 LLPipeline::RenderGlowIterations;
 F32 LLPipeline::RenderGlowWidth;
 F32 LLPipeline::RenderGlowStrength;
+bool LLPipeline::RenderGlowNoise;
 bool LLPipeline::RenderDepthOfField;
 bool LLPipeline::RenderDepthOfFieldInEditMode;
 F32 LLPipeline::CameraFocusTransitionTime;
@@ -517,6 +518,7 @@ void LLPipeline::init()
 	connectRefreshCachedSettingsSafe("RenderGlowIterations");
 	connectRefreshCachedSettingsSafe("RenderGlowWidth");
 	connectRefreshCachedSettingsSafe("RenderGlowStrength");
+	connectRefreshCachedSettingsSafe("RenderGlowNoise");
 	connectRefreshCachedSettingsSafe("RenderDepthOfField");
 	connectRefreshCachedSettingsSafe("RenderDepthOfFieldInEditMode");
 	connectRefreshCachedSettingsSafe("CameraFocusTransitionTime");
@@ -1007,6 +1009,7 @@ void LLPipeline::refreshCachedSettings()
 	RenderGlowIterations = gSavedSettings.getS32("RenderGlowIterations");
 	RenderGlowWidth = gSavedSettings.getF32("RenderGlowWidth");
 	RenderGlowStrength = gSavedSettings.getF32("RenderGlowStrength");
+	RenderGlowNoise = gSavedSettings.getBOOL("RenderGlowNoise");
 	RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField");
 	RenderDepthOfFieldInEditMode = gSavedSettings.getBOOL("RenderDepthOfFieldInEditMode");
 	CameraFocusTransitionTime = gSavedSettings.getF32("CameraFocusTransitionTime");
@@ -6886,6 +6889,19 @@ void LLPipeline::generateGlow(LLRenderTarget* src)
 			warmthWeights.mV[2]);
 		gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount);
 
+        if (RenderGlowNoise)
+        {
+            S32 channel = gGlowExtractProgram.enableTexture(LLShaderMgr::GLOW_NOISE_MAP);
+            if (channel > -1)
+            {
+                gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
+                gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+            }
+            gGlowExtractProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES,
+                                          mGlow[2].getWidth(),
+                                          mGlow[2].getHeight());
+        }
+
 		{
 			LLGLEnable blend_on(GL_BLEND);
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 961a55330a..c0559ce83b 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -1001,6 +1001,7 @@ public:
 	static S32 RenderGlowIterations;
 	static F32 RenderGlowWidth;
 	static F32 RenderGlowStrength;
+	static bool RenderGlowNoise;
 	static bool RenderDepthOfField;
 	static bool RenderDepthOfFieldInEditMode;
 	static F32 CameraFocusTransitionTime;
-- 
cgit v1.2.3


From 5ce4d42f55187e710fac64efbd34947900ef2d58 Mon Sep 17 00:00:00 2001
From: Maxim Nikolenko <maximnproductengine@lindenlab.com>
Date: Thu, 13 Jul 2023 18:52:45 +0300
Subject: SL-19993 Warn of automatic changes to Day Cycle when it's opened

---
 indra/newview/llfloatereditextdaycycle.cpp | 24 ++++++++++++++++++++++++
 indra/newview/llfloatereditextdaycycle.h   |  2 ++
 2 files changed, 26 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp
index 6e8143384a..bb47feaa95 100644
--- a/indra/newview/llfloatereditextdaycycle.cpp
+++ b/indra/newview/llfloatereditextdaycycle.cpp
@@ -475,6 +475,8 @@ void LLFloaterEditExtDayCycle::refresh()
 void LLFloaterEditExtDayCycle::setEditSettingsAndUpdate(const LLSettingsBase::ptr_t &settings)
 {
     setEditDayCycle(std::dynamic_pointer_cast<LLSettingsDay>(settings));
+
+    showHDRNotification(std::dynamic_pointer_cast<LLSettingsDay>(settings));
 }
 
 void LLFloaterEditExtDayCycle::setEditDayCycle(const LLSettingsDay::ptr_t &pday)
@@ -1710,6 +1712,28 @@ void LLFloaterEditExtDayCycle::onPickerCommitSetting(LLUUID item_id, S32 track)
     }
 }
 
+void LLFloaterEditExtDayCycle::showHDRNotification(const LLSettingsDay::ptr_t &pday)
+{
+    for (U32 i = LLSettingsDay::TRACK_GROUND_LEVEL; i <= LLSettingsDay::TRACK_MAX; i++)
+    {
+        LLSettingsDay::CycleTrack_t &day_track = pday->getCycleTrack(i);
+
+        LLSettingsDay::CycleTrack_t::iterator iter = day_track.begin();
+        LLSettingsDay::CycleTrack_t::iterator end = day_track.end();
+
+        while (iter != end)
+        {
+            LLSettingsSky::ptr_t sky = std::static_pointer_cast<LLSettingsSky>(iter->second);
+            if (sky && sky->canAutoAdjust()) 
+            {
+                LLNotificationsUtil::add("AutoAdjustHDRSky");
+                return;
+            }
+            iter++;
+        }
+    }
+}
+
 void LLFloaterEditExtDayCycle::onAssetLoadedForInsertion(LLUUID item_id, LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 source_track, S32 dest_track, LLSettingsBase::TrackPosition frame)
 {
     std::function<void()> cb = [this, settings, frame, source_track, dest_track]()
diff --git a/indra/newview/llfloatereditextdaycycle.h b/indra/newview/llfloatereditextdaycycle.h
index ab5d12fa36..025a2ee5d1 100644
--- a/indra/newview/llfloatereditextdaycycle.h
+++ b/indra/newview/llfloatereditextdaycycle.h
@@ -188,6 +188,8 @@ private:
     bool                        isRemovingFrameAllowed();
     bool                        isAddingFrameAllowed();
 
+    void                        showHDRNotification(const LLSettingsDay::ptr_t &pday);
+
     LLSettingsDay::ptr_t        mEditDay; // edited copy
     LLSettingsDay::Seconds      mDayLength;
     U32                         mCurrentTrack;
-- 
cgit v1.2.3


From df1eb38b2109bf9cb57b42e2c361c4143276ae5a Mon Sep 17 00:00:00 2001
From: Brad Linden <brad@lindenlab.com>
Date: Thu, 13 Jul 2023 10:08:19 -0700
Subject: SL-19999 stop outputing debug info about created material asset id
 unnecessarily

---
 indra/newview/llmaterialeditor.cpp                   | 4 +---
 indra/newview/skins/default/xui/en/notifications.xml | 7 -------
 2 files changed, 1 insertion(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 609d8ea5d7..3a0e64985c 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1327,9 +1327,7 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std:
                 [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response)
                 {
                     // done callback
-                    LL_INFOS("Material") << "inventory item uploaded.  item: " << item_id << " asset: " << new_asset_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL;
-                    LLSD params = llsd::map("ASSET_ID", new_asset_id);
-                    LLNotificationsUtil::add("MaterialCreated", params);
+                    LL_INFOS("Material") << "inventory item uploaded.  item: " << item_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL;
                 },
                 nullptr // failure callback, floater already closed
             );
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index c4abd27a01..3d151a9868 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -12098,13 +12098,6 @@ Would you like to save them first?
        yestext="Yes"/>
   </notification>
     
-<notification
- icon="notifytip.tga"
- name="MaterialCreated"
- type="notifytip">
-Material successfully created.  Asset ID: [ASSET_ID]
-</notification>
-
   <notification
     icon="notifytip.tga"
     name="ReflectionProbeApplied"
-- 
cgit v1.2.3


From d192d91db95ec9ed3ad47039e126134bc05ad5f4 Mon Sep 17 00:00:00 2001
From: Brad Linden <brad@lindenlab.com>
Date: Thu, 13 Jul 2023 11:28:36 -0700
Subject: Fixed failure to open Material Editor when creating or uploading a
 new material

found this warning found while working on SL-19999
---
 indra/newview/llviewermessage.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index f14e3ed737..b756d3d87f 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1532,7 +1532,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
 						LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus);
 						break;
                     case LLAssetType::AT_MATERIAL:
-                        LLFloaterReg::showInstance("material editor", LLSD(obj_id), take_focus);
+                        LLFloaterReg::showInstance("material_editor", LLSD(obj_id), take_focus);
                         break;
 					default:
 						LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type)  << LL_ENDL;
-- 
cgit v1.2.3


From 2f8f1c7a44f45490db5b5f040914e42aef2f5280 Mon Sep 17 00:00:00 2001
From: Brad Linden <brad@lindenlab.com>
Date: Fri, 14 Jul 2023 12:46:20 -0700
Subject: Fix crash SL-20013 crash when applying nocopy material via
 drag-and-drop

---
 indra/newview/lltooldraganddrop.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 4705970c7b..1918d11964 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1096,12 +1096,16 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no material item." << LL_ENDL;
         return;
     }
+
+    // SL-20013 must save asset_id before handleDropMaterialProtections since our item instance
+    // may be deleted if it is moved into task inventory
+    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
+
     if (asset_id.isNull())
     {
         // use blank material
@@ -1127,13 +1131,17 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no material item." << LL_ENDL;
         return;
     }
+
+    // SL-20013 must save asset_id before handleDropMaterialProtections since our item instance
+    // may be deleted if it is moved into task inventory
+    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
+
     if (!success)
     {
         return;
     }
 
-    LLUUID asset_id = item->getAssetUUID();
     if (asset_id.isNull())
     {
         // use blank material
-- 
cgit v1.2.3


From ec4135da63a3f3877222fba4ecb59b15650371fe Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 17 Jul 2023 16:12:39 -0400
Subject: Increment viewer version to 6.6.14 following promotion of DRTVWR-580

---
 indra/newview/VIEWER_VERSION.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 97154f804c..e9d5f8c17f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.6.13
+6.6.14
-- 
cgit v1.2.3