From 94b92868587c652d7140aa704db42e497482827d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 22 Sep 2022 02:14:51 +0300
Subject: [PATCH] SL-17999 'copy' functionality for 'features' and 'texture'
 tabs

And a fix to prevent message spam
---
 indra/newview/llpanelface.cpp       | 37 +++++++++++++--
 indra/newview/llpanelvolume.cpp     | 21 ++++++++
 indra/newview/llselectmgr.cpp       | 25 +---------
 indra/newview/lltooldraganddrop.cpp | 16 ++-----
 indra/newview/llviewerobject.cpp    | 74 ++++++++++++++++++++++++++++-
 indra/newview/llviewerobject.h      |  5 +-
 6 files changed, 134 insertions(+), 44 deletions(-)

diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 6498215e948..f7eff39da70 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -3632,10 +3632,31 @@ struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor
 
 struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
 {
-    LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {}
+    LLPanelFaceUpdateFunctor(bool update_media, bool update_pbr)
+        : mUpdateMedia(update_media)
+        , mUpdatePbr(update_pbr)
+    {}
+
     virtual bool apply(LLViewerObject* object)
     {
+        if (mUpdatePbr)
+        {
+            LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)object->getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL);
+            if (param_block)
+            {
+                if (param_block->isEmpty())
+                {
+                    object->setHasRenderMaterialParams(false);
+                }
+                else
+                {
+                    object->parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true);
+                }
+            }
+        }
+
         object->sendTEUpdate();
+
         if (mUpdateMedia)
         {
             LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
@@ -3648,6 +3669,7 @@ struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
     }
 private:
     bool mUpdateMedia;
+    bool mUpdatePbr;
 };
 
 struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor
@@ -3783,7 +3805,7 @@ void LLPanelFace::onPasteColor()
     LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR);
     selected_objects->applyToTEs(&paste_func);
 
-    LLPanelFaceUpdateFunctor sendfunc(false);
+    LLPanelFaceUpdateFunctor sendfunc(false, false);
     selected_objects->applyToObjects(&sendfunc);
 }
 
@@ -3886,6 +3908,7 @@ void LLPanelFace::onCopyTexture()
                 te_data["te"]["bumpmap"] = tep->getBumpmap();
                 te_data["te"]["bumpshiny"] = tep->getBumpShiny();
                 te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright();
+                te_data["te"]["pbr"] = objectp->getRenderMaterialID(te);
 
                 if (te_data["te"].has("imageid"))
                 {
@@ -4139,7 +4162,7 @@ void LLPanelFace::onPasteTexture()
     LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE);
     selected_objects->applyToTEs(&paste_func);
 
-    LLPanelFaceUpdateFunctor sendfunc(true);
+    LLPanelFaceUpdateFunctor sendfunc(true, true);
     selected_objects->applyToObjects(&sendfunc);
 
     LLPanelFaceNavigateHomeFunctor navigate_home_func;
@@ -4273,6 +4296,14 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
             {
                 objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger());
             }
+            if (te_data["te"].has("pbr"))
+            {
+                objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false);
+            }
+            else
+            {
+                objectp->setRenderMaterialID(te, LLUUID::null, false);
+            }
 
             // Texture map
             if (te_data["te"].has("scales") && te_data["te"].has("scalet"))
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index b50b652966e..7ddce19bd0c 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -1091,6 +1091,14 @@ void LLPanelVolume::onCopyLight()
         }
     }
 
+    if (volobjp && volobjp->isReflectionProbe())
+    {
+        clipboard["reflection_probe"]["is_box"] = volobjp->getReflectionProbeIsBox();
+        clipboard["reflection_probe"]["ambiance"] = volobjp->getReflectionProbeAmbiance();
+        clipboard["reflection_probe"]["near_clip"] = volobjp->getReflectionProbeNearClip();
+        clipboard["reflection_probe"]["dynamic"] = volobjp->getReflectionProbeIsDynamic();
+    }
+
     mClipboardParams["light"] = clipboard;
 }
 
@@ -1138,6 +1146,19 @@ void LLPanelVolume::onPasteLight()
             spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal();
             volobjp->setSpotLightParams(spot_params);
         }
+
+        if (clipboard.has("reflection_probe"))
+        {
+            volobjp->setIsReflectionProbe(TRUE);
+            volobjp->setReflectionProbeIsBox(clipboard["reflection_probe"]["is_box"].asBoolean());
+            volobjp->setReflectionProbeAmbiance((F32)clipboard["reflection_probe"]["ambiance"].asReal());
+            volobjp->setReflectionProbeNearClip((F32)clipboard["reflection_probe"]["near_clip"].asReal());
+            volobjp->setReflectionProbeIsDynamic(clipboard["reflection_probe"]["dynamic"].asBoolean());
+        }
+        else
+        {
+            volobjp->setIsReflectionProbe(false);
+        }
     }
 }
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 99835d4e5a9..8f674afc24e 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2198,30 +2198,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials()
             if (nodep && te < (S32)nodep->mSavedGLTFMaterials.size())
             {
                 LLUUID asset_id = nodep->mSavedGLTFMaterials[te];
-                LLTextureEntry* tep = objectp->getTE(te);
-                if (asset_id.notNull())
-                {
-                    tep->setGLTFMaterial(gGLTFMaterialList.getMaterial(asset_id));
-
-                    if (!objectp->hasRenderMaterialParams())
-                    {
-                        // make sure param section exists
-                        objectp->setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, TRUE, false /*prevent an immediate update*/);
-                    }
-                }
-                else
-                {
-                    tep->setGLTFMaterial(nullptr);
-                }
-
-                objectp->faceMappingChanged();
-                gPipeline.markTextured(objectp->mDrawable);
-
-                LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)objectp->getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL);
-                if (param_block)
-                {
-                    param_block->setMaterial(te, asset_id);
-                }
+                objectp->setRenderMaterialID(te, asset_id, false /*wait for bulk update*/);
             }
             return true;
         }
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 282c84d7fc2..be42e6f2b2f 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1109,19 +1109,9 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
     {
         return;
     }
-    
-    S32 num_faces = hit_obj->getNumTEs();
-    for (S32 face = 0; face < num_faces; face++)
-    {
-        // update viewer side material in anticipation of update from simulator
-
-        // TODO: fix this!
-        // Calling setRenderMaterialID multiple times sends material param
-        // updates multiple times and can create race condition.
-        // Send update only once!
-        hit_obj->setRenderMaterialID(face, asset_id);
-        dialog_refresh_all();
-    }
+
+    hit_obj->setRenderMaterialIDs(asset_id);
+    dialog_refresh_all();
     // send the update to the simulator
     hit_obj->sendTEUpdate();
 }
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 022c191a655..f9c8f396a23 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -7075,7 +7075,7 @@ const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const
     return LLUUID::null;
 }
 
-void LLViewerObject::setRenderMaterialID(U8 te, const LLUUID& id)
+void LLViewerObject::setRenderMaterialID(U8 te, const LLUUID& id, bool update_server)
 {
     if (id.notNull())
     {
@@ -7084,7 +7084,12 @@ void LLViewerObject::setRenderMaterialID(U8 te, const LLUUID& id)
         if (!hasRenderMaterialParams())
         {
             // make sure param section exists
-            setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, TRUE, false /*prevent an immediate update*/);
+            // but do not update server to avoid race conditions
+            ExtraParameter* param = getExtraParameterEntryCreate(LLNetworkData::PARAMS_RENDER_MATERIAL);
+            if (param)
+            {
+                param->in_use = true;
+            }
         }
     }
     else
@@ -7102,6 +7107,71 @@ void LLViewerObject::setRenderMaterialID(U8 te, const LLUUID& id)
 
         if (param_block->isEmpty())
         { // might be empty if id is null
+            if (hasRenderMaterialParams())
+            {
+                if (update_server)
+                {
+                    setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, FALSE, true);
+                }
+                else
+                {
+                    ExtraParameter* param = getExtraParameterEntryCreate(LLNetworkData::PARAMS_RENDER_MATERIAL);
+                    if (param)
+                    {
+                        param->in_use = false;
+                    }
+                }
+            }
+        }
+        else if (update_server)
+        {
+            parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true);
+        }
+    }
+}
+
+void LLViewerObject::setRenderMaterialIDs(const LLUUID& id)
+{
+    if (id.notNull())
+    {
+        if (!hasRenderMaterialParams())
+        {
+            // make sure param section exists
+            // but do not update server to avoid race conditions
+            ExtraParameter* param = getExtraParameterEntryCreate(LLNetworkData::PARAMS_RENDER_MATERIAL);
+            if (param)
+            {
+                param->in_use = true;
+            }
+        }
+    }
+
+    LLRenderMaterialParams* param_block = nullptr;
+    if (hasRenderMaterialParams())
+    {
+        param_block = (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL);
+    }
+
+    LLGLTFMaterial* material = id.isNull() ? nullptr : gGLTFMaterialList.getMaterial(id);
+    const S32 num_tes = llmin((S32)getNumTEs(), (S32)getNumFaces());
+
+    for (S32 te = 0; te < num_tes; te++)
+    {
+        getTE(te)->setGLTFMaterial(material);
+
+        if (param_block)
+        {
+            param_block->setMaterial(te, id);
+        }
+    }
+
+    faceMappingChanged();
+    gPipeline.markTextured(mDrawable);
+
+    if (param_block)
+    {
+        if (param_block->isEmpty())
+        {
             setHasRenderMaterialParams(false);
         }
         else
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 680cfb9639e..32f03c7869e 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -184,8 +184,8 @@ class LLViewerObject
     void setHasRenderMaterialParams(bool has_params);
 
     const LLUUID& getRenderMaterialID(U8 te) const;
-    void setRenderMaterialID(U8 te, const LLUUID& id);
-    void setRenderMaterialIDs(const LLRenderMaterialParams* material_params, bool local_origin);
+    void setRenderMaterialID(U8 te, const LLUUID& id, bool update_server = true);
+    void setRenderMaterialIDs(const LLUUID& id);
 
 	virtual BOOL	isHUDAttachment() const { return FALSE; }
 	virtual BOOL	isTempAttachment() const;
@@ -220,6 +220,7 @@ class LLViewerObject
 	F32					getRotTime() { return mRotTime; }
 private:
 	void				resetRotTime();
+    void				setRenderMaterialIDs(const LLRenderMaterialParams* material_params, bool local_origin);
 public:
 	void				resetRot();
 	void				applyAngularVelocity(F32 dt);
-- 
GitLab