diff options
| author | Cosmic Linden <cosmic@lindenlab.com> | 2023-10-13 14:02:51 -0700 | 
|---|---|---|
| committer | Cosmic Linden <cosmic@lindenlab.com> | 2023-10-13 14:02:51 -0700 | 
| commit | a91f08ba84844647bbcdecac11e85c449579527c (patch) | |
| tree | 9bfdc77c9e7de33413b95f2648cb139b19cb06f0 /indra/newview/llpanelface.cpp | |
| parent | cc0f831aaa960552b218da436da57b44cb2dfe0f (diff) | |
| parent | cba71633559ccdfd394983a6086da816e739a730 (diff) | |
Merge branch 'DRTVWR-559' into DRTVWR-592
Diffstat (limited to 'indra/newview/llpanelface.cpp')
| -rw-r--r-- | indra/newview/llpanelface.cpp | 485 | 
1 files changed, 351 insertions, 134 deletions
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ba379f77d8..cb28fb4770 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -51,6 +51,7 @@  #include "llinventorymodelbackgroundfetch.h"  #include "llfloatermediasettings.h"  #include "llfloaterreg.h" +#include "llfloatertools.h"  #include "lllineeditor.h"  #include "llmaterialmgr.h"  #include "llmaterialeditor.h" @@ -77,6 +78,7 @@  #include "llviewerregion.h"  #include "llviewerstats.h"  #include "llvovolume.h" +#include "llvoinventorylistener.h"  #include "lluictrlfactory.h"  #include "llpluginclassmedia.h"  #include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI @@ -328,7 +330,7 @@ BOOL	LLPanelFace::postBuild()          pbr_ctrl->setImmediateFilterPermMask(PERM_NONE);          pbr_ctrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);          pbr_ctrl->setBakeTextureEnabled(false); -        pbr_ctrl->setInventoryPickType(EPickInventoryType::MATERIAL); +        pbr_ctrl->setInventoryPickType(LLTextureCtrl::PICK_MATERIAL);      }  	mTextureCtrl = getChild<LLTextureCtrl>("texture control"); @@ -490,6 +492,15 @@ LLPanelFace::~LLPanelFace()      unloadMedia();  } +void LLPanelFace::onVisibilityChange(BOOL new_visibility) +{ +    if (new_visibility) +    { +        gAgent.showLatestFeatureNotification("gltf"); +    } +    LLPanel::onVisibilityChange(new_visibility); +} +  void LLPanelFace::draw()  {      updateCopyTexButton(); @@ -504,6 +515,7 @@ void LLPanelFace::draw()      if (sMaterialOverrideSelection.update())      {          setMaterialOverridesFromSelection(); +        LLMaterialEditor::updateLive();      }  } @@ -520,7 +532,11 @@ void LLPanelFace::sendTexture()  		{  			id = mTextureCtrl->getImageAssetID();  		} -		LLSelectMgr::getInstance()->selectionSetImage(id); +        if (!LLSelectMgr::getInstance()->selectionSetImage(id)) +        { +            // need to refresh value in texture ctrl +            refresh(); +        }  	}  } @@ -987,16 +1003,19 @@ void LLPanelFace::getState()  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(); +    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +	LLViewerObject* objectp = node ? node->getObject() : NULL; -	if( objectp +	if (objectp  		&& objectp->getPCode() == LL_PCODE_VOLUME  		&& objectp->permModify())  	{  		BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced(); +        BOOL attachment = objectp->isAttachment();          bool has_pbr_material; -        updateUIGLTF(objectp, has_pbr_material, force_set_values); +        bool has_faces_without_pbr; +        updateUIGLTF(objectp, has_pbr_material, has_faces_without_pbr, force_set_values);          const bool has_material = !has_pbr_material; @@ -1017,9 +1036,68 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)              }          } +        // *NOTE: The "identical" variable is currently only used to decide if +        // the texgen control should be tentative - this is not used by GLTF +        // materials. -Cosmic;2022-11-09 +        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"); +        LLTextureCtrl *bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control"); + +        LLUUID id; +        LLUUID normmap_id; +        LLUUID specmap_id; + +        LLSelectedTE::getTexId(id, identical_diffuse); +        LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm); +        LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec); + +        static S32 selected_te = -1; +        static LLUUID prev_obj_id; +        if ((LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()) &&  +            !LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())  +        { +            S32 new_selection = -1; // Don't use getLastSelectedTE, it could have been deselected +            S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); +            for (S32 te = 0; te < num_tes; ++te) +            { +                if (node->isTESelected(te)) +                { +                    new_selection = te; +                    break; +                } +            } + +            if ((new_selection != selected_te) +                || (prev_obj_id != objectp->getID())) +            { +                bool te_has_media = objectp->getTE(new_selection) && objectp->getTE(new_selection)->hasMedia(); +                bool te_has_pbr = objectp->getRenderMaterialID(new_selection).notNull(); + +                if (te_has_pbr && !((mComboMatMedia->getCurrentIndex() == MATMEDIA_MEDIA) && te_has_media)) +                { +                    mComboMatMedia->selectNthItem(MATMEDIA_PBR); +                } +                else if (te_has_media)  +                { +                    mComboMatMedia->selectNthItem(MATMEDIA_MEDIA); +                } +                else if (id.notNull() || normmap_id.notNull() || specmap_id.notNull())  +                { +                    mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL); +                } +                selected_te = new_selection; +                prev_obj_id = objectp->getID(); +            } +        } +          mComboMatMedia->setEnabled(editable); -		LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type"); +        LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");          if (radio_mat_type->getSelectedIndex() < MATTYPE_DIFFUSE)          {              radio_mat_type->selectNthItem(MATTYPE_DIFFUSE); @@ -1038,34 +1116,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  		getChildView("checkbox_sync_settings")->setEnabled(editable);  		childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings")); -		updateVisibility(); +		updateVisibility(objectp); -        // *NOTE: The "identical" variable is currently only used to decide if -        // the texgen control should be tentative - this is not used by GLTF -        // materials. -Cosmic;2022-11-09 -		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"); -		LLTextureCtrl*	bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control"); -		 -		LLUUID id; -		LLUUID normmap_id; -		LLUUID specmap_id; -		  		// Color swatch  		{  			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(); @@ -1085,9 +1147,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  		getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);  		getChildView("ColorTrans")->setEnabled(editable && has_material); -		// Specular map -		LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec); -		  		U8 shiny = 0;  		bool identical_shiny = false; @@ -1099,7 +1158,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  		LLCtrlSelectionInterface* combobox_shininess = childGetSelectionInterface("combobox shininess");  		if (combobox_shininess) -				{ +		{  			combobox_shininess->selectNthItem((S32)shiny);  		} @@ -1119,8 +1178,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 ); @@ -1138,50 +1197,45 @@ 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  		{ -			LLSelectedTE::getTexId(id,identical_diffuse); - -			// Normal map -			LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm); -  			mIsAlpha = FALSE;  			LLGLenum image_format = GL_RGB;  			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; -			if(LLViewerMedia::getInstance()->textureHasMedia(id)) +				case GL_RGB: break; +				default: +				{ +					LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL; +				} +				break; +			} + +			if (LLViewerMedia::getInstance()->textureHasMedia(id))  			{  				getChildView("button align")->setEnabled(editable);  			} @@ -1233,7 +1287,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  				}  				else if (id.isNull())  				{ -						// None selected +					// None selected  					texture_ctrl->setTentative(FALSE);  					texture_ctrl->setEnabled(FALSE);  					texture_ctrl->setImageAssetID(LLUUID::null); @@ -1246,7 +1300,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  				}  				else  				{ -						// Tentative: multiple selected with different textures +					// Tentative: multiple selected with different textures  					texture_ctrl->setTentative(TRUE);  					texture_ctrl->setEnabled(editable && !has_pbr_material);  					texture_ctrl->setImageAssetID(id); @@ -1257,7 +1311,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  					texture_ctrl->setBakeTextureEnabled(TRUE);  				} -				 + +                if (attachment) +                { +                    // attachments are in world and in inventory, +                    // server doesn't support changing permissions +                    // in such case +                    texture_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); +                } +                else +                { +                    texture_ctrl->setImmediateFilterPermMask(PERM_NONE); +                }  			}  			if (shinytexture_ctrl) @@ -1265,6 +1330,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  				shinytexture_ctrl->setTentative( !identical_spec );  				shinytexture_ctrl->setEnabled( editable && !has_pbr_material);  				shinytexture_ctrl->setImageAssetID( specmap_id ); + +                if (attachment) +                { +                    shinytexture_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); +                } +                else +                { +                    shinytexture_ctrl->setImmediateFilterPermMask(PERM_NONE); +                }  			}  			if (bumpytexture_ctrl) @@ -1272,6 +1346,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  				bumpytexture_ctrl->setTentative( !identical_norm );  				bumpytexture_ctrl->setEnabled( editable && !has_pbr_material);  				bumpytexture_ctrl->setImageAssetID( normmap_id ); + +                if (attachment) +                { +                    bumpytexture_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); +                } +                else +                { +                    bumpytexture_ctrl->setImmediateFilterPermMask(PERM_NONE); +                }  			}  		} @@ -1515,15 +1598,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; @@ -1534,7 +1616,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  			getChild<LLUICtrl>("checkbox fullbright")->setValue((S32)(fullbright_flag != 0));  			getChildView("checkbox fullbright")->setEnabled(editable && !has_pbr_material);  			getChild<LLUICtrl>("checkbox fullbright")->setTentative(!identical_fullbright); -            getChild<LLComboBox>("combobox matmedia")->setEnabledByValue("Materials", !has_pbr_material); +            mComboMatMedia->setEnabledByValue("Materials", !has_pbr_material);  		}  		// Repeats per meter @@ -1553,7 +1635,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; @@ -1649,14 +1731,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(); @@ -1668,15 +1750,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); @@ -1688,7 +1770,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. @@ -1756,14 +1838,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)              pbr_ctrl->setEnabled(FALSE);          }  		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") ); @@ -1798,36 +1880,96 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)  	}  } -void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values) +// One-off listener that updates the build floater UI when the prim inventory updates +class PBRPickerItemListener : public LLVOInventoryListener +{ +protected: +    LLViewerObject* mObjectp; +    bool mChangePending = true; +public: + +    PBRPickerItemListener(LLViewerObject* object) +    : mObjectp(object) +    { +        registerVOInventoryListener(mObjectp, nullptr); +    } + +    const bool isListeningFor(const LLViewerObject* objectp) const +    { +        return mChangePending && (objectp == mObjectp); +    } + +    void inventoryChanged(LLViewerObject* object, +        LLInventoryObject::object_list_t* inventory, +        S32 serial_num, +        void* user_data) override +    { +        if (gFloaterTools) +        { +            gFloaterTools->dirty(); +        } +        removeVOInventoryListener(); +        mChangePending = false; +    } + +    ~PBRPickerItemListener() +    { +        removeVOInventoryListener(); +        mChangePending = false; +    } +}; + +void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values)  {      has_pbr_material = false; -    const bool editable = objectp->permModify() && !objectp->isPermanentEnforced();      bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); +    bool identical_pbr = true; +    const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced(); +    const bool editable = LLMaterialEditor::canModifyObjectsMaterial(); +    const bool saveable = LLMaterialEditor::canSaveObjectsMaterial();      // pbr material      LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");      if (pbr_ctrl)      {          LLUUID pbr_id; -        bool identical_pbr; -        LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr); - -        has_pbr_material = pbr_id.notNull(); +        LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr, has_pbr_material, has_faces_without_pbr);          pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE); -        pbr_ctrl->setEnabled(editable && has_pbr_capabilities); +        pbr_ctrl->setEnabled(settable);          pbr_ctrl->setImageAssetID(pbr_id); + +        if (objectp->isAttachment()) +        { +            pbr_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); +        } +        else +        { +            pbr_ctrl->setImmediateFilterPermMask(PERM_NONE); +        }      } -    getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities); -    getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && has_pbr_capabilities); -    getChildView("save_selected_pbr")->setEnabled(objectp->permCopy() && has_pbr_material && has_pbr_capabilities); +    getChildView("pbr_from_inventory")->setEnabled(settable); +    getChildView("edit_selected_pbr")->setEnabled(editable && !has_faces_without_pbr); +    getChildView("save_selected_pbr")->setEnabled(saveable && identical_pbr); +    if (objectp->isInventoryPending()) +    { +        // Reuse the same listener when possible +        if (!mInventoryListener || !mInventoryListener->isListeningFor(objectp)) +        { +            mInventoryListener = std::make_unique<PBRPickerItemListener>(objectp); +        } +    } +    else +    { +        mInventoryListener = nullptr; +    }      const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();      if (show_pbr)      { -        const bool new_state = has_pbr_capabilities && has_pbr_material; +        const bool new_state = has_pbr_capabilities && has_pbr_material && !has_faces_without_pbr;          LLUICtrl* gltfCtrlTextureScaleU = getChild<LLUICtrl>("gltfTextureScaleU");          LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV"); @@ -1847,9 +1989,10 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,      }  } -void LLPanelFace::updateVisibilityGLTF() +void LLPanelFace::updateVisibilityGLTF(LLViewerObject* objectp /*= nullptr */)  {      const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); +    const bool inventory_pending = objectp && objectp->isInventoryPending();      LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type");      radio_pbr_type->setVisible(show_pbr); @@ -1860,8 +2003,9 @@ void LLPanelFace::updateVisibilityGLTF()      getChildView("pbr_control")->setVisible(show_pbr_render_material_id);      getChildView("pbr_from_inventory")->setVisible(show_pbr_render_material_id); -    getChildView("edit_selected_pbr")->setVisible(show_pbr_render_material_id); -    getChildView("save_selected_pbr")->setVisible(show_pbr_render_material_id); +    getChildView("edit_selected_pbr")->setVisible(show_pbr_render_material_id && !inventory_pending); +    getChildView("save_selected_pbr")->setVisible(show_pbr_render_material_id && !inventory_pending); +    getChildView("material_permissions_loading_label")->setVisible(show_pbr_render_material_id && inventory_pending);      getChildView("gltfTextureScaleU")->setVisible(show_pbr);      getChildView("gltfTextureScaleV")->setVisible(show_pbr); @@ -1875,10 +2019,10 @@ void LLPanelFace::updateCopyTexButton()      LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();      mMenuClipboardTexture->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()                                                       && !objectp->isPermanentEnforced() && !objectp->isInventoryPending()  -                                                    && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1)); +                                                    && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1) +                                                    && LLMaterialEditor::canClipboardObjectsMaterial());      std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");      mMenuClipboardTexture->setToolTip(tooltip); -  }  void LLPanelFace::refresh() @@ -2703,7 +2847,7 @@ void LLPanelFace::onCommitMaterialsMedia(LLUICtrl* ctrl, void* userdata)  	self->refreshMedia();  } -void LLPanelFace::updateVisibility() +void LLPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */)  {      LLRadioGroup* radio_mat_type = findChild<LLRadioGroup>("radio_material_type");      LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type"); @@ -2794,7 +2938,7 @@ void LLPanelFace::updateVisibility()      getChild<LLSpinCtrl>("rptctrl")->setVisible(show_material || show_media);      // PBR controls -    updateVisibilityGLTF(); +    updateVisibilityGLTF(objectp);  }  // static @@ -3032,7 +3176,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 +3204,10 @@ void LLPanelFace::onSelectPbr(const LLSD& data)          {              id = pbr_ctrl->getImageAssetID();          } -        LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id); -        LLSelectedTEMaterial::setMaterialID(this, id); +        if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) +        { +            refresh(); +        }      }  } @@ -4042,7 +4192,8 @@ void LLPanelFace::onCopyTexture()          || objectp->getPCode() != LL_PCODE_VOLUME          || !objectp->permModify()          || objectp->isPermanentEnforced() -        || selected_count > 1) +        || selected_count > 1 +        || !LLMaterialEditor::canClipboardObjectsMaterial())      {          return;      } @@ -4237,7 +4388,8 @@ void LLPanelFace::onPasteTexture()          || objectp->getPCode() != LL_PCODE_VOLUME          || !objectp->permModify()          || objectp->isPermanentEnforced() -        || selected_count > 1) +        || selected_count > 1 +        || !LLMaterialEditor::canClipboardObjectsMaterial())      {          // not supposed to happen          LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; @@ -4666,13 +4818,6 @@ void LLPanelFace::updateGLTFTextureTransform(float value, U32 pbr_type, std::fun              edit(&new_transform);          }      }); - -    LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); -    if (node) -    { -        LLViewerObject* object = node->getObject(); -        sMaterialOverrideSelection.setObjectUpdatePending(object->getID(), node->getLastSelectedTE()); -    }  }  void LLPanelFace::setMaterialOverridesFromSelection() @@ -4785,17 +4930,22 @@ bool LLPanelFace::Selection::update()      return changed;  } -void LLPanelFace::Selection::setObjectUpdatePending(const LLUUID &object_id, S32 side) -{ -    mPendingObjectID = object_id; -    mPendingSide = side; -} -  void LLPanelFace::Selection::onSelectedObjectUpdated(const LLUUID& object_id, S32 side)  { -    if (object_id == mSelectedObjectID && side == mSelectedSide) +    if (object_id == mSelectedObjectID)      { -        mChanged = true; +        if (side == mLastSelectedSide) +        { +            mChanged = true; +        } +        else if (mLastSelectedSide == -1) // if last selected face was deselected +        { +            LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); +            if (node && node->isTESelected(side)) +            { +                mChanged = true; +            } +        }      }  } @@ -4808,8 +4958,9 @@ bool LLPanelFace::Selection::compareSelection()      mNeedsSelectionCheck = false;      const S32 old_object_count = mSelectedObjectCount; +    const S32 old_te_count = mSelectedTECount;      const LLUUID old_object_id = mSelectedObjectID; -    const S32 old_side = mSelectedSide; +    const S32 old_side = mLastSelectedSide;      LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();      LLSelectNode* node = selection->getFirstNode(); @@ -4817,17 +4968,23 @@ bool LLPanelFace::Selection::compareSelection()      {          LLViewerObject* object = node->getObject();          mSelectedObjectCount = selection->getObjectCount(); +        mSelectedTECount = selection->getTECount();          mSelectedObjectID = object->getID(); -        mSelectedSide = node->getLastSelectedTE(); +        mLastSelectedSide = node->getLastSelectedTE();      }      else      {          mSelectedObjectCount = 0; +        mSelectedTECount = 0;          mSelectedObjectID = LLUUID::null; -        mSelectedSide = -1; +        mLastSelectedSide = -1;      } -    const bool selection_changed = old_object_count != mSelectedObjectCount || old_object_id != mSelectedObjectID || old_side != mSelectedSide; +    const bool selection_changed = +        old_object_count != mSelectedObjectCount +        || old_te_count != mSelectedTECount +        || old_object_id != mSelectedObjectID +        || old_side != mLastSelectedSide;      mChanged = mChanged || selection_changed;      return selection_changed;  } @@ -4946,23 +5103,24 @@ void LLPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp)          LLSaleInfo sale_info;          LLSelectMgr::instance().selectGetSaleInfo(sale_info); -        bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture? -        bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture? -        bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent? -        bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale? +        bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this material? +        bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this material? +        bool can_modify = itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgentID); // do we have perm to transfer this material? +        bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply material belong to the agent? +        bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply material not for sale? -        if (can_copy && can_transfer) +        if (can_copy && can_transfer && can_modify)          {              pbr_ctrl->setCanApply(true, true);              return;          } -        // if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale +        // if material has (no-transfer) attribute it can be applied only for object which we own and is not for sale          pbr_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale);          if (gSavedSettings.getBOOL("TextureLivePreview"))          { -            LLNotificationsUtil::add("LivePreviewUnavailable"); +            LLNotificationsUtil::add("LivePreviewUnavailablePBR");          }      }  } @@ -5046,16 +5204,75 @@ void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)  	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id );  } -void LLPanelFace::LLSelectedTE::getPbrMaterialId(LLUUID& id, bool& identical) +void LLPanelFace::LLSelectedTE::getPbrMaterialId(LLUUID& id, bool& identical, bool& has_faces_with_pbr, bool& has_faces_without_pbr)  { -    struct LLSelectedTEGetmatId : public LLSelectedTEGetFunctor<LLUUID> +    struct LLSelectedTEGetmatId : public LLSelectedTEFunctor      { -        LLUUID get(LLViewerObject* object, S32 te_index) +        LLSelectedTEGetmatId() +            : mHasFacesWithoutPBR(false) +            , mHasFacesWithPBR(false) +            , mIdenticalId(true) +            , mIdenticalOverride(true) +            , mInitialized(false) +            , mMaterialOverride(LLGLTFMaterial::sDefault)          { -            return object->getRenderMaterialID(te_index);          } +        bool apply(LLViewerObject* object, S32 te_index) override +        { +            LLUUID pbr_id = object->getRenderMaterialID(te_index); +            if (pbr_id.isNull()) +            { +                mHasFacesWithoutPBR = true; +            } +            else +            { +                mHasFacesWithPBR = true; +            } +            if (mInitialized) +            { +                if (mPBRId != pbr_id) +                { +                    mIdenticalId = false; +                } +                 +                LLGLTFMaterial* te_override = object->getTE(te_index)->getGLTFMaterialOverride(); +                if (te_override) +                { +                    LLGLTFMaterial override = *te_override; +                    override.sanitizeAssetMaterial(); +                    mIdenticalOverride &= (override == mMaterialOverride); +                } +                else +                { +                    mIdenticalOverride &= (mMaterialOverride == LLGLTFMaterial::sDefault); +                } +            } +            else +            { +                mInitialized = true; +                mPBRId = pbr_id; +                LLGLTFMaterial* override = object->getTE(te_index)->getGLTFMaterialOverride(); +                if (override) +                { +                    mMaterialOverride = *override; +                    mMaterialOverride.sanitizeAssetMaterial(); +                } +            } +            return true; +        } +        bool mHasFacesWithoutPBR; +        bool mHasFacesWithPBR; +        bool mIdenticalId; +        bool mIdenticalOverride; +        bool mInitialized; +        LLGLTFMaterial mMaterialOverride; +        LLUUID mPBRId;      } func; -    identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, id); +    LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); +    id = func.mPBRId; +    identical = func.mIdenticalId && func.mIdenticalOverride; +    has_faces_with_pbr = func.mHasFacesWithPBR; +    has_faces_without_pbr = func.mHasFacesWithoutPBR;  }  void LLPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material)  | 
