From a4012ea073283b1e360333dfd9a13ede009f24d9 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 19 Jul 2023 16:49:26 -0700 Subject: SL-20024: Generalize some comments/error --- indra/newview/lltooldraganddrop.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 1918d11964..c123501059 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -948,7 +948,14 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, { hit_obj->requestInventory(); LLSD args; - args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again."; + if (LLAssetType::AT_MATERIAL == item->getType()) + { + args["ERROR_MESSAGE"] = "Unable to add material.\nPlease wait a few seconds and try again."; + } + else + { + args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again."; + } LLNotificationsUtil::add("ErrorMessage", args); return FALSE; } @@ -957,7 +964,7 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, // if the asset is already in the object's inventory // then it can always be added to a side. // This saves some work if the task's inventory is already loaded - // and ensures that the texture item is only added once. + // and ensures that the asset item is only added once. return TRUE; } @@ -995,7 +1002,7 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, return FALSE; } } - // Add the texture item to the target object's inventory. + // Add the asset item to the target object's inventory. if (LLAssetType::AT_TEXTURE == new_item->getType() || LLAssetType::AT_MATERIAL == new_item->getType()) { @@ -1011,14 +1018,14 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, else if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) { - // Check that we can add the texture as inventory to the object + // Check that we can add the asset as inventory to the object if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE ) { return FALSE; } // *FIX: may want to make sure agent can paint hit_obj. - // Add the texture item to the target object's inventory. + // Add the asset item to the target object's inventory. if (LLAssetType::AT_TEXTURE == new_item->getType() || LLAssetType::AT_MATERIAL == new_item->getType()) { @@ -1028,7 +1035,7 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, { hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true); } - // Force the object to update and refetch its inventory so it has this texture. + // Force the object to update and refetch its inventory so it has this asset. hit_obj->dirtyInventory(); hit_obj->requestInventory(); // TODO: Check to see if adding the item was successful; if not, then -- cgit v1.2.3 From 9be8103142dc16b58dcf930d5d1f70f49272837f Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 19 Jul 2023 16:56:36 -0700 Subject: SL-20024: Early return --- indra/newview/lltooldraganddrop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index c123501059..dd5f607b04 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -930,6 +930,8 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, LLToolDragAndDrop::ESource source, const LLUUID& src_id) { + if (!item) return FALSE; + // Always succeed if.... // material is from the library // or already in the contents of the object @@ -967,8 +969,6 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, // and ensures that the asset item is only added once. return TRUE; } - - if (!item) return FALSE; LLPointer new_item = new LLViewerInventoryItem(item); if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) -- cgit v1.2.3 From e7e565dc6e7e0c666132ffffa4798b2cfc00d6a4 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 21 Jul 2023 13:01:11 -0700 Subject: SL-20024: Put material in object inventory when material is no-modify or no-transfer --- indra/llprimitive/llmaterial.cpp | 11 ----------- indra/llprimitive/llmaterial.h | 2 -- indra/newview/llpanelface.cpp | 7 +------ indra/newview/llpanelface.h | 1 - indra/newview/llselectmgr.cpp | 36 ++++++++++++++++++++++++++---------- indra/newview/llselectmgr.h | 14 ++++++++++++-- indra/newview/lltooldraganddrop.cpp | 20 ++++++++++++++++++++ 7 files changed, 59 insertions(+), 32 deletions(-) diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp index f6cb3c8b70..0d146de949 100644 --- a/indra/llprimitive/llmaterial.cpp +++ b/indra/llprimitive/llmaterial.cpp @@ -332,17 +332,6 @@ void LLMaterial::setAlphaMaskCutoff(U8 cutoff) mAlphaMaskCutoff = cutoff; } -LLUUID LLMaterial::getMaterialID() const -{ - // TODO - not null - return LLUUID::null; -} - -void LLMaterial::setMaterialID(const LLUUID &material_id) -{ - // TODO - set -} - LLSD LLMaterial::asLLSD() const { LLSD material_data; diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h index b46d85c2d1..81f41ddc51 100644 --- a/indra/llprimitive/llmaterial.h +++ b/indra/llprimitive/llmaterial.h @@ -115,8 +115,6 @@ public: void setDiffuseAlphaMode(U8 alpha_mode); U8 getAlphaMaskCutoff() const; void setAlphaMaskCutoff(U8 cutoff); - LLUUID getMaterialID() const; - void setMaterialID(LLUUID const & material_id); bool isNull() const; static const LLMaterial null; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 837217387f..b633ccc5d5 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -3093,12 +3093,7 @@ void LLPanelFace::onSelectPbr(const LLSD& data) { id = pbr_ctrl->getImageAssetID(); } - if (LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) - { - LLSelectedTEMaterial::setMaterialID(this, id); - } - else - { + if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) refresh(); } } diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index f6a813f9e5..e2d9f65e58 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -583,7 +583,6 @@ public: DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); - DEF_EDIT_MAT_STATE(LLUUID, const LLUUID&, setMaterialID); }; class LLSelectedTE diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 5c1a339570..6692d124d8 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1773,15 +1773,17 @@ void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item) } } -void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item) +bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item) { if (!item) { - return; + return false; } LLUUID asset_id = item->getAssetUUID(); + bool material_copied_all_faces = true; + for (iterator iter = begin(); iter != end(); ++iter) { LLSelectNode* node = *iter; @@ -1797,12 +1799,17 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item) { if (node->isTESelected(te)) { - //(no-copy) materials must be moved to the object's inventory only once + //(no-copy), (no-modify), and (no-transfer) materials must be moved to the object's inventory only once // without making any copies if (!material_copied && asset_id.notNull()) { - LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); - material_copied = true; + material_copied = (bool)LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + if (!material_copied) + { + // Applying the material is not possible for this object given the current inventory + material_copied_all_faces = false; + break; } // apply texture for the selected faces @@ -1814,6 +1821,8 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item) } LLGLTFMaterialList::flushUpdates(); + + return material_copied_all_faces; } @@ -1924,6 +1933,8 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) { LLViewerInventoryItem* mItem; LLUUID mMatId; + bool material_copied_any_face = false; + bool material_copied_all_faces = true; f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mMatId(id) {} bool apply(LLViewerObject* objectp, S32 te) { @@ -1950,14 +1961,19 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) } }; - if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + bool success = true; + if (item && + (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) || + !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) || + !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()) + )) { - getSelection()->applyNoCopyPbrMaterialToTEs(item); + success = success && getSelection()->applyRestrictedPbrMaterialToTEs(item); } else { f setfunc(item, mat_id); - getSelection()->applyToTEs(&setfunc); + success = success && getSelection()->applyToTEs(&setfunc); } struct g : public LLSelectedObjectFunctor @@ -1986,11 +2002,11 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) return true; } } sendfunc(item); - getSelection()->applyToObjects(&sendfunc); + success = success && getSelection()->applyToObjects(&sendfunc); LLGLTFMaterialList::flushUpdates(); - return true; + return success; } //----------------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 327134a487..f89209b437 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -378,7 +378,17 @@ public: * Then this only texture is used for all selected faces. */ void applyNoCopyTextureToTEs(LLViewerInventoryItem* item); - void applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item); + /* + * Multi-purpose function for applying PBR materials to the + * selected object or faces, any combination of copy/mod/transfer + * permission restrictions. This method moves the restricted + * material to the object's inventory and doesn't make a copy of the + * material for each face. Then this only material is used for + * all selected faces. + * Returns false if applying the material failed on one or more selected + * faces. + */ + bool applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item); ESelectType getSelectType() const { return mSelectType; } @@ -635,7 +645,7 @@ public: void selectionSetRestitution(F32 restitution); void selectionSetMaterial(U8 material); bool selectionSetImage(const LLUUID& imageid); // could be item or asset id - bool selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id + bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only 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/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index dd5f607b04..23a6634154 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1042,6 +1042,26 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj, // we should return false here. This will requre a separate listener // since without listener, we have no way to receive update } + else if (LLAssetType::AT_MATERIAL == new_item->getType() && + !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) + { + // Check that we can add the material as inventory to the object + if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE ) + { + return FALSE; + } + // *FIX: may want to make sure agent can paint hit_obj. + + // Add the material item to the target object's inventory. + hit_obj->updateMaterialInventory(new_item, TASK_INVENTORY_ITEM_KEY, true); + + // Force the object to update and refetch its inventory so it has this material. + hit_obj->dirtyInventory(); + hit_obj->requestInventory(); + // TODO: Check to see if adding the item was successful; if not, then + // we should return false here. This will requre a separate listener + // since without listener, we have no way to receive update + } return TRUE; } -- cgit v1.2.3 From a4030031f895f8497e106f0547eb29780d6ec4e9 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 21 Jul 2023 17:28:09 -0700 Subject: SL-20024: Do not show material preview for no-modify materials --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llpanelface.cpp | 16 +++++++++------- indra/newview/skins/default/xui/en/notifications.xml | 12 ++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0cd63d9d5f..b92a829f36 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -250,7 +250,7 @@ TextureLivePreview Comment - Preview selections in texture picker immediately + Preview selections in texture picker or material picker immediately Persist 1 Type diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index b633ccc5d5..e91b14a453 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -3094,6 +3094,7 @@ void LLPanelFace::onSelectPbr(const LLSD& data) id = pbr_ctrl->getImageAssetID(); } if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) + { refresh(); } } @@ -4989,23 +4990,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"); } } } diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index ca07aacb21..bbc3798034 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -9209,6 +9209,18 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran yestext="OK"/> + + +We cannot display a preview of this material because it is no-copy, no-transfer, and/or no-modify. + + + Date: Mon, 24 Jul 2023 16:16:52 -0700 Subject: SL-20024: Disable material editor on prim when contained material is no mod --- indra/newview/llmaterialeditor.cpp | 7 ++++++- indra/newview/llpreview.cpp | 20 ++++++++++++++------ indra/newview/llpreview.h | 2 ++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 3a0e64985c..b30f94e145 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -238,6 +238,7 @@ struct LLSelectedTEGetMatData : public LLSelectedTEFunctor LLUUID mTexNormalId; LLUUID mObjectId; S32 mObjectTE; + LLUUID mMaterialId; LLPointer mMaterial; LLPointer mLocalMaterial; }; @@ -259,6 +260,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) return false; } LLUUID mat_id = objectp->getRenderMaterialID(te_index); + mMaterialId = mat_id; bool can_use = mIsOverride ? objectp->permModify() : objectp->permCopy(); LLTextureEntry *tep = objectp->getTE(te_index); // We might want to disable this entirely if at least @@ -2708,7 +2710,10 @@ bool LLMaterialEditor::setFromSelection() if (func.mMaterial.notNull()) { setFromGLTFMaterial(func.mMaterial); - setEnableEditing(true); + LLViewerObject* selected_object = selected_objects->getFirstSelectedObject(NULL); + const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); + const bool allow_modify = !item || canModify(selected_object, item); + setEnableEditing(allow_modify); } else { diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index b9b2279e77..0117db86e8 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -241,14 +241,22 @@ void LLPreview::refreshFromItem() // static BOOL LLPreview::canModify(const LLUUID taskUUID, const LLInventoryItem* item) { + const LLViewerObject* object = nullptr; if (taskUUID.notNull()) { - LLViewerObject* object = gObjectList.findObject(taskUUID); - if(object && !object->permModify()) - { - // No permission to edit in-world inventory - return FALSE; - } + object = gObjectList.findObject(taskUUID); + } + + return canModify(object, item); +} + +// static +BOOL LLPreview::canModify(const LLViewerObject* object, const LLInventoryItem* item) +{ + if (object && !object->permModify()) + { + // No permission to edit in-world inventory + return FALSE; } return item && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index ab60f4c008..3688ee0192 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -36,6 +36,7 @@ #include class LLInventoryItem; +class LLViewerObject; class LLLineEditor; class LLRadioGroup; class LLPreview; @@ -109,6 +110,7 @@ public: // We can't modify Item or description in preview if either in-world Object // or Item itself is unmodifiable static BOOL canModify(const LLUUID taskUUID, const LLInventoryItem* item); + static BOOL canModify(const LLViewerObject* object, const LLInventoryItem* item); protected: virtual void onCommit(); -- cgit v1.2.3 From 7bf6103ad95c281c2ed680c9eb9b07cc584ddc91 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Tue, 25 Jul 2023 14:52:56 -0700 Subject: SL-20024: (WIP) (not tested) Improved behavior for saving material to inventory. Check perms, keep perms. --- indra/llinventory/llpermissions.h | 4 +- indra/newview/llmaterialeditor.cpp | 164 +++++++++++++++++++++++++++---------- indra/newview/llmaterialeditor.h | 8 +- indra/newview/llpanelface.cpp | 2 +- 4 files changed, 129 insertions(+), 49 deletions(-) diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index 27252f7b97..32fae844fb 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -251,7 +251,9 @@ public: BOOL setNextOwnerBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits); // This is currently only used in the Viewer to handle calling cards - // where the creator is actually used to store the target. Use with care. + // where the creator is actually used to store the target. + // It is also used for saving a GLTF material on a prim. + // Use with care. void setCreator(const LLUUID& creator) { mCreator = creator; } // diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index b30f94e145..6e043ecee5 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -237,6 +237,7 @@ struct LLSelectedTEGetMatData : public LLSelectedTEFunctor LLUUID mTexEmissiveId; LLUUID mTexNormalId; LLUUID mObjectId; + LLViewerObject* mObject = nullptr; S32 mObjectTE; LLUUID mMaterialId; LLPointer mMaterial; @@ -293,6 +294,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) mTexNormalId = tex_normal_id; mObjectTE = te_index; mObjectId = objectp->getID(); + mObject = objectp; mFirst = false; } else @@ -1194,7 +1196,9 @@ bool LLMaterialEditor::saveIfNeeded() { //make a new inventory item std::string res_desc = buildMaterialDescription(); - createInventoryItem(buffer, mMaterialName, res_desc); + LLPermissions local_permissions; + local_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + createInventoryItem(buffer, mMaterialName, res_desc, local_permissions); // We do not update floater with uploaded asset yet, so just close it. closeFloater(); @@ -1288,7 +1292,7 @@ bool LLMaterialEditor::updateInventoryItem(const std::string &buffer, const LLUU return true; } -void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc) +void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& owner_permissions) { // gen a new uuid for this asset LLTransactionID tid; @@ -1299,7 +1303,7 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, name, desc, LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm, - new LLBoostFuncInventoryCallback([output = buffer](LLUUID const& inv_item_id) + new LLBoostFuncInventoryCallback([output = buffer, owner_permissions](LLUUID const& inv_item_id) { LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); if (item) @@ -1309,8 +1313,15 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Materials") || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Materials")) { - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); + LLPermissions floater_perm; + floater_perm.set(perm); + floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); + floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); + perm.accumulate(floater_perm); + perm.accumulate(owner_permissions); + // TODO: Decide if these are needed + perm.setCreator(owner_permissions.getCreator()); + perm.setLastOwner(owner_permissions.getLastOwner()); item->setPermissions(perm); @@ -1794,55 +1805,112 @@ void LLMaterialEditor::loadLive() } } -void LLMaterialEditor::saveObjectsMaterialAs() +// *NOTE: permissions_out ignores user preferences for new item creation +// (LLFloaterPerms). Those are applied later on in +// LLMaterialEditor::createInventoryItem. +bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& permissions_out) { - LLSelectedTEGetMatData func(false); LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/); - saveMaterialAs(func.mMaterial, func.mLocalMaterial); -} -void LLMaterialEditor::savePickedMaterialAs() -{ - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - if (pick.mPickType != LLPickInfo::PICK_OBJECT || !pick.getObject()) + LLViewerObject* selected_object = func.mObject; + llassert(selected_object); // Note the function name + const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); + + LLPermissions item_permissions; + const bool previous_item_owned = item && item->getPermissions().getLastOwner().notNull(); + if (item) { - return; + item_permissions.set(item->getPermissions()); + if (!gAgent.allowOperation(PERM_MODIFY, item_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } + if (!gAgent.allowOperation(PERM_COPY, item_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } + if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) + { + llassert(false); + return false; + } } - - LLPointer render_material; - LLPointer local_material; - - LLViewerObject *objectp = pick.getObject(); - LLUUID mat_id = objectp->getRenderMaterialID(pick.mObjectFace); - if (mat_id.notNull() && objectp->permCopy()) + else { - // Try a face user picked first - // (likely the only method we need, but in such case - // enable_object_save_gltf_material will need to check this) - LLTextureEntry *tep = objectp->getTE(pick.mObjectFace); - LLGLTFMaterial *mat = tep->getGLTFMaterial(); - LLLocalGLTFMaterial *local_mat = dynamic_cast(mat); + item_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + } - if (local_mat) + LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(selected_object); + LLPermissions object_permissions; + const bool previous_object_owned = object_permissions_p && object_permissions_p->getLastOwner().notNull(); + if (object_permissions_p) + { + object_permissions.set(*object_permissions_p); + if (!gAgent.allowOperation(PERM_MODIFY, object_permissions, GP_OBJECT_MANIPULATE)) { - local_material = local_mat; + return false; + } + if (!gAgent.allowOperation(PERM_COPY, object_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } + if (!object_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) + { + llassert(false); + return false; } - render_material = tep->getGLTFRenderMaterial(); } else { - // Find an applicable material. - // Do this before showing message, because - // message is going to drop selection. - LLSelectedTEGetMatData func(false); - LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/); - local_material = func.mLocalMaterial; - render_material = func.mMaterial; + object_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); } - saveMaterialAs(render_material, local_material); + permissions_out.set(item_permissions); + permissions_out.accumulate(object_permissions); + + if (previous_item_owned != previous_object_owned) + { + // Likely ownership history conflict. Prefer the item history. Fall + // back to object history if no associated item. + if (previous_item_owned) + { + permissions_out.setCreator(item_permissions.getCreator()); + permissions_out.setLastOwner(item_permissions.getLastOwner()); + } + else if (previous_object_owned) + { + permissions_out.setCreator(object_permissions.getCreator()); + permissions_out.setLastOwner(object_permissions.getLastOwner()); + } + } + + llassert(permissions_out.getOwner() == gAgent.getID()); + llassert(permissions_out.getCreator().notNull()); + llassert(permissions_out.getGroup().isNull()); + + return true; +} + +bool LLMaterialEditor::canSaveObjectsMaterial() +{ + LLSelectedTEGetMatData func(false); + LLPermissions permissions; + return can_save_objects_material(func, permissions); } -void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, const LLLocalGLTFMaterial *local_material) +void LLMaterialEditor::saveObjectsMaterialAs() +{ + LLSelectedTEGetMatData func(false); + LLPermissions permissions; + bool allowed = can_save_objects_material(func, permissions); + if (!allowed) + { + LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; + return; + } + saveMaterialAs(func.mMaterial, func.mLocalMaterial, permissions); +} + +void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions) { if (local_material) { @@ -1918,10 +1986,20 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con LLSD args; args["DESC"] = LLTrans::getString("New Material"); - LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2)); + // At this point, last owner, etc should be set. LLFloaterPerms will be honored later on + if (local_material) + { + LLPermissions local_permissions; + local_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, local_permissions)); + } + else + { + LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions)); + } } -void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response) +void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) @@ -1936,7 +2014,7 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY); std::string new_name = response["message"].asString(); - createInventoryItem(str.str(), new_name, std::string()); + createInventoryItem(str.str(), new_name, std::string(), permissions); } } @@ -2710,7 +2788,7 @@ bool LLMaterialEditor::setFromSelection() if (func.mMaterial.notNull()) { setFromGLTFMaterial(func.mMaterial); - LLViewerObject* selected_object = selected_objects->getFirstSelectedObject(NULL); + LLViewerObject* selected_object = func.mObject; const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); const bool allow_modify = !item || canModify(selected_object, item); setEnableEditing(allow_modify); diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 6f674a4170..5ee42f65f4 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -112,9 +112,9 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static void updateLive(const LLUUID &object_id, S32 te); static void loadLive(); + static bool canSaveObjectsMaterial(); static void saveObjectsMaterialAs(); - static void savePickedMaterialAs(); - static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response); + static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions); static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); @@ -229,10 +229,10 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static bool capabilitiesAvailable(); private: - static void saveMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material); + static void saveMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions); static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id); - static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc); + static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& owner_permissions); void setFromGLTFMaterial(LLGLTFMaterial* mat); bool setFromSelection(); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index e91b14a453..b9daf19284 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1856,7 +1856,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities); getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && !has_faces_without_pbr && has_pbr_capabilities); - getChildView("save_selected_pbr")->setEnabled(objectp->permCopy() && has_pbr_material && identical_pbr && has_pbr_capabilities); + getChildView("save_selected_pbr")->setEnabled(LLMaterialEditor::canSaveObjectsMaterial() && identical_pbr); const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); if (show_pbr) -- cgit v1.2.3 From a5d318567cc5c3e8f2f86fce1132f5883014e14e Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 28 Jul 2023 17:29:09 -0700 Subject: SL-20024: (WIP) (untested) Fix GLTF material permissions in some more edge cases --- indra/newview/llmaterialeditor.cpp | 139 ++++++++++++++++++++----------------- indra/newview/llmaterialeditor.h | 1 + indra/newview/llpanelface.cpp | 57 +++++++++++++-- indra/newview/llpanelface.h | 6 ++ 4 files changed, 134 insertions(+), 69 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 6e043ecee5..af40c9e931 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -293,8 +293,8 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) mTexEmissiveId = tex_emissive_id; mTexNormalId = tex_normal_id; mObjectTE = te_index; - mObjectId = objectp->getID(); mObject = objectp; + mObjectId = objectp->getID(); mFirst = false; } else @@ -322,6 +322,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) LLGLTFMaterial *mat = tep->getGLTFMaterial(); LLLocalGLTFMaterial *local_mat = dynamic_cast(mat); + mObject = objectp; if (local_mat) { mLocalMaterial = local_mat; @@ -1297,38 +1298,39 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: // gen a new uuid for this asset LLTransactionID tid; tid.generate(); // timestamp-based randomization + uniquification - U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials"); + LLPermissions final_perm; + { + final_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + + LLPermissions floater_perm; + floater_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); + floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); + floater_perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Materials")); + + final_perm.accumulate(floater_perm); + final_perm.accumulate(owner_permissions); + } + // NOTE: create_inventory_item doesn't allow presetting some permissions. + // The rest will be fixed after the callback. LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL); const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, name, desc, - LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm, - new LLBoostFuncInventoryCallback([output = buffer, owner_permissions](LLUUID const& inv_item_id) + LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, final_perm.getMaskNextOwner(), + new LLBoostFuncInventoryCallback([output = buffer, final_perm](LLUUID const& inv_item_id) { LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); if (item) { // create_inventory_item doesn't allow presetting some permissions, fix it now LLPermissions perm = item->getPermissions(); - if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Materials") - || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Materials")) - { - LLPermissions floater_perm; - floater_perm.set(perm); - floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); - floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); - perm.accumulate(floater_perm); - perm.accumulate(owner_permissions); - // TODO: Decide if these are needed - perm.setCreator(owner_permissions.getCreator()); - perm.setLastOwner(owner_permissions.getLastOwner()); + perm.accumulate(final_perm); + item->setPermissions(perm); - item->setPermissions(perm); - - item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - } + item->updateServer(FALSE); + gInventory.updateItem(item); + gInventory.notifyObservers(); } // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem() @@ -1805,29 +1807,47 @@ void LLMaterialEditor::loadLive() } } -// *NOTE: permissions_out ignores user preferences for new item creation -// (LLFloaterPerms). Those are applied later on in +// *NOTE: permissions_out ignores user preferences for new item creation. See +// LLFloaterPerms. Preferences are applied later on in // LLMaterialEditor::createInventoryItem. -bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& permissions_out) +bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector& ops, LLPermissions& permissions_out) { + if (!LLMaterialEditor::capabilitiesAvailable()) + { + return false; + } + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/); LLViewerObject* selected_object = func.mObject; - llassert(selected_object); // Note the function name + if (!selected_object) + { + // LLSelectedTEGetMatData can fail if there are no selected faces + // with materials, but we expect at least some object is selected. + llassert(LLSelectMgr::getInstance()->getSelection()->getFirstObject()); + return false; + } + for (PermissionBit op : ops) + { + if (op == PERM_MODIFY && selected_object->isPermanentEnforced()) + { + return false; + } + } + const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); LLPermissions item_permissions; - const bool previous_item_owned = item && item->getPermissions().getLastOwner().notNull(); if (item) { item_permissions.set(item->getPermissions()); - if (!gAgent.allowOperation(PERM_MODIFY, item_permissions, GP_OBJECT_MANIPULATE)) - { - return false; - } - if (!gAgent.allowOperation(PERM_COPY, item_permissions, GP_OBJECT_MANIPULATE)) + for (PermissionBit op : ops) { - return false; + if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } } + // Update flags for new owner if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) { llassert(false); @@ -1839,20 +1859,21 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm item_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); } - LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(selected_object); + // Use root object for permissions checking + LLViewerObject* root_object = selected_object->getRootEdit(); + LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(root_object); LLPermissions object_permissions; - const bool previous_object_owned = object_permissions_p && object_permissions_p->getLastOwner().notNull(); if (object_permissions_p) { object_permissions.set(*object_permissions_p); - if (!gAgent.allowOperation(PERM_MODIFY, object_permissions, GP_OBJECT_MANIPULATE)) + for (PermissionBit op : ops) { - return false; - } - if (!gAgent.allowOperation(PERM_COPY, object_permissions, GP_OBJECT_MANIPULATE)) - { - return false; + if (!gAgent.allowOperation(op, object_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } } + // Update flags for new owner if (!object_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) { llassert(false); @@ -1865,43 +1886,34 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm } permissions_out.set(item_permissions); + // *NOTE: A close inspection of LLPermissions::accumulate shows that + // conflicting UUIDs will be unset. This is acceptable behavior for now. + // The server doesn't allow us to create an item while claiming someone + // else was the creator/previous owner. permissions_out.accumulate(object_permissions); - if (previous_item_owned != previous_object_owned) - { - // Likely ownership history conflict. Prefer the item history. Fall - // back to object history if no associated item. - if (previous_item_owned) - { - permissions_out.setCreator(item_permissions.getCreator()); - permissions_out.setLastOwner(item_permissions.getLastOwner()); - } - else if (previous_object_owned) - { - permissions_out.setCreator(object_permissions.getCreator()); - permissions_out.setLastOwner(object_permissions.getLastOwner()); - } - } - - llassert(permissions_out.getOwner() == gAgent.getID()); - llassert(permissions_out.getCreator().notNull()); - llassert(permissions_out.getGroup().isNull()); - return true; } +bool LLMaterialEditor::canModifyObjectsMaterial() +{ + LLSelectedTEGetMatData func(false); + LLPermissions permissions; + return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions); +} + bool LLMaterialEditor::canSaveObjectsMaterial() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - return can_save_objects_material(func, permissions); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); } void LLMaterialEditor::saveObjectsMaterialAs() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - bool allowed = can_save_objects_material(func, permissions); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; @@ -1986,7 +1998,6 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con LLSD args; args["DESC"] = LLTrans::getString("New Material"); - // At this point, last owner, etc should be set. LLFloaterPerms will be honored later on if (local_material) { LLPermissions local_permissions; diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 5ee42f65f4..54e59fcdf8 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -112,6 +112,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static void updateLive(const LLUUID &object_id, S32 te); static void loadLive(); + static bool canModifyObjectsMaterial(); static bool canSaveObjectsMaterial(); static void saveObjectsMaterialAs(); static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index b9daf19284..90271b75b2 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 @@ -1834,13 +1836,48 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } +// One-off listener that updates the build floater UI when the prim inventory updates +class PBRPickerItemListener : public LLVOInventoryListener +{ +protected: + LLViewerObject* mObjectp; +public: + + PBRPickerItemListener(LLViewerObject* object) + : mObjectp(object) + { + registerVOInventoryListener(mObjectp, nullptr); + } + + const LLViewerObject* const getObject() { return mObjectp; } + + void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) override + { + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + removeVOInventoryListener(); + } + + ~PBRPickerItemListener() + { + removeVOInventoryListener(); + } +}; + 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("pbr_control"); @@ -1850,13 +1887,23 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, 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); } - getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities); - getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && !has_faces_without_pbr && has_pbr_capabilities); - getChildView("save_selected_pbr")->setEnabled(LLMaterialEditor::canSaveObjectsMaterial() && identical_pbr); + const bool inventory_pending = objectp->isInventoryPending(); + getChildView("pbr_from_inventory")->setEnabled(settable); + getChildView("edit_selected_pbr")->setEnabled(editable && !inventory_pending && !has_faces_without_pbr); + getChildView("save_selected_pbr")->setEnabled(saveable && !inventory_pending && identical_pbr); + // TODO: Vet inventory updates and memory management + if (inventory_pending && (!mInventoryListener || mInventoryListener->getObject() != objectp)) + { + mInventoryListener = std::make_unique(objectp); + } + else + { + mInventoryListener = nullptr; + } const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); if (show_pbr) diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index e2d9f65e58..d737665ad0 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -35,6 +35,8 @@ #include "lltextureentry.h" #include "llselectmgr.h" +#include + class LLButton; class LLCheckBoxCtrl; class LLColorSwatchCtrl; @@ -51,6 +53,8 @@ class LLMaterialID; class LLMediaCtrl; class LLMenuButton; +class PBRPickerItemListener; + // 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 @@ -503,6 +507,8 @@ private: static Selection sMaterialOverrideSelection; + std::unique_ptr mInventoryListener; + public: #if defined(DEF_GET_MAT_STATE) #undef DEF_GET_MAT_STATE -- cgit v1.2.3 From 27842d0c5f34b03f6ce16ebbff0e7cb39d3a4fd8 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 31 Jul 2023 16:30:50 -0700 Subject: SL-20024: Fix material edit/save buttons on build floater sometimes not re-enabling after object inventory load --- indra/newview/llpanelface.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 90271b75b2..790c693a3d 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1841,6 +1841,7 @@ class PBRPickerItemListener : public LLVOInventoryListener { protected: LLViewerObject* mObjectp; + bool mChangePending = true; public: PBRPickerItemListener(LLViewerObject* object) @@ -1849,7 +1850,10 @@ public: registerVOInventoryListener(mObjectp, nullptr); } - const LLViewerObject* const getObject() { return mObjectp; } + const bool isListeningFor(const LLViewerObject* objectp) const + { + return mChangePending && (objectp == mObjectp); + } void inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, @@ -1861,11 +1865,13 @@ public: gFloaterTools->dirty(); } removeVOInventoryListener(); + mChangePending = false; } ~PBRPickerItemListener() { removeVOInventoryListener(); + mChangePending = false; } }; @@ -1893,12 +1899,16 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, const bool inventory_pending = objectp->isInventoryPending(); getChildView("pbr_from_inventory")->setEnabled(settable); + // TODO: Put message on these two buttons when material permissions are still loading getChildView("edit_selected_pbr")->setEnabled(editable && !inventory_pending && !has_faces_without_pbr); getChildView("save_selected_pbr")->setEnabled(saveable && !inventory_pending && identical_pbr); - // TODO: Vet inventory updates and memory management - if (inventory_pending && (!mInventoryListener || mInventoryListener->getObject() != objectp)) + if (inventory_pending) { - mInventoryListener = std::make_unique(objectp); + // Reuse the same listener when possible + if (!mInventoryListener || !mInventoryListener->isListeningFor(objectp)) + { + mInventoryListener = std::make_unique(objectp); + } } else { -- cgit v1.2.3 From 6c8ced0edd9e2b86914e3e316ba65ae9492d3e6f Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Tue, 1 Aug 2023 12:36:49 -0700 Subject: SL-20024: Show loading message when inventory permissions are loading --- indra/newview/llpanelface.cpp | 15 ++++++++------- indra/newview/llpanelface.h | 4 ++-- .../newview/skins/default/xui/en/panel_tools_texture.xml | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 790c693a3d..21651899db 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1102,7 +1102,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) getChildView("checkbox_sync_settings")->setEnabled(editable); childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings")); - updateVisibility(); + updateVisibility(objectp); // Color swatch { @@ -1899,7 +1899,6 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, const bool inventory_pending = objectp->isInventoryPending(); getChildView("pbr_from_inventory")->setEnabled(settable); - // TODO: Put message on these two buttons when material permissions are still loading getChildView("edit_selected_pbr")->setEnabled(editable && !inventory_pending && !has_faces_without_pbr); getChildView("save_selected_pbr")->setEnabled(saveable && !inventory_pending && identical_pbr); if (inventory_pending) @@ -1938,9 +1937,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("radio_pbr_type"); radio_pbr_type->setVisible(show_pbr); @@ -1951,8 +1951,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); @@ -2793,7 +2794,7 @@ void LLPanelFace::onCommitMaterialsMedia(LLUICtrl* ctrl, void* userdata) self->refreshMedia(); } -void LLPanelFace::updateVisibility() +void LLPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */) { LLRadioGroup* radio_mat_type = findChild("radio_material_type"); LLRadioGroup* radio_pbr_type = findChild("radio_pbr_type"); @@ -2884,7 +2885,7 @@ void LLPanelFace::updateVisibility() getChild("rptctrl")->setVisible(show_material || show_media); // PBR controls - updateVisibilityGLTF(); + updateVisibilityGLTF(objectp); } // static diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index d737665ad0..d07be2e4b4 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -296,7 +296,7 @@ private: // // Do NOT call updateUI from within this function. // - void updateVisibility(); + void updateVisibility(LLViewerObject* objectp = nullptr); // Hey look everyone, a type-safe alternative to copy and paste! :) // @@ -457,7 +457,7 @@ private: void onPbrSelectionChanged(LLInventoryItem* itemp); void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values); - void updateVisibilityGLTF(); + void updateVisibilityGLTF(LLViewerObject* objectp = nullptr); void updateSelectedGLTFMaterials(std::function func); void updateGLTFTextureTransform(float value, U32 pbr_type, std::function edit); diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 51e6099ceb..5b15752eb7 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -284,12 +284,26 @@ name="pbr_from_inventory" label="Choose from inventory" width="140"/> + + Loading contents... +