From 04c0bc100401c8f4541b6eeda3a110291ee54166 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 28 Apr 2025 17:17:29 +0300 Subject: [PATCH 1/7] #3978 Fix offset in Land Owner highlights texture_stride with '-1' was added in DRTVWR-592 along with getMetersPerGrid multiplication. --- indra/newview/llsurfacepatch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 6f99da5957..875af76c10 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -210,7 +210,6 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 llassert_always(vertex && normal && tex1); U32 surface_stride = mSurfacep->getGridsPerEdge(); - U32 texture_stride = mSurfacep->getGridsPerEdge() - 1; U32 point_offset = x + y*surface_stride; *normal = getNormal(x, y); @@ -223,7 +222,7 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 // tex0 is used for ownership overlay LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent(); - LLVector3 tex_pos = rel_pos * (1.f / (texture_stride * mSurfacep->getMetersPerGrid())); + LLVector3 tex_pos = rel_pos * (1.f / (surface_stride * mSurfacep->getMetersPerGrid())); tex0->mV[0] = tex_pos.mV[0]; tex0->mV[1] = tex_pos.mV[1]; From 1f3ba13a632a751cc3217cbe02d8aa2190df6b41 Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Mon, 28 Apr 2025 10:51:47 -0700 Subject: [PATCH 2/7] Attempt to fix qatest.yaml CodeQL issues (#3987) --- .github/workflows/.gitattributes | 1 + .github/workflows/qatest.yaml | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/.gitattributes diff --git a/.github/workflows/.gitattributes b/.github/workflows/.gitattributes new file mode 100644 index 0000000000..6dc1cca42a --- /dev/null +++ b/.github/workflows/.gitattributes @@ -0,0 +1 @@ +qatest.yaml -text eol=crlf diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml index 7f3a5242e9..4892cfaae3 100644 --- a/.github/workflows/qatest.yaml +++ b/.github/workflows/qatest.yaml @@ -1,4 +1,7 @@ name: Run QA Test # Runs automated tests on a self-hosted QA machine +permissions: + contents: read + #pull-requests: write # maybe need to re-add this later on: workflow_run: @@ -15,11 +18,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Debug Workflow Variables + env: + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + HEAD_COMMIT_MSG: ${{ github.event.workflow_run.head_commit.message }} run: | echo "Workflow Conclusion: ${{ github.event.workflow_run.conclusion }}" - echo "Workflow Head Branch: ${{ github.event.workflow_run.head_branch }}" + echo "Workflow Head Branch: $HEAD_BRANCH" echo "Workflow Run ID: ${{ github.event.workflow_run.id }}" - echo "Head Commit Message: ${{ github.event.workflow_run.head_commit.message }}" + echo "Head Commit Message: $HEAD_COMMIT_MSG" echo "GitHub Ref: ${{ github.ref }}" echo "GitHub Ref Name: ${{ github.ref_name }}" echo "GitHub Event Name: ${{ github.event_name }}" From 7bd18e256d70804f72d747ccc1e62c92679dd645 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 25 Apr 2025 18:57:58 +0300 Subject: [PATCH 3/7] viewerp#300 Fix inconsistency with copying textures vs pbr --- indra/newview/llinventorymodel.cpp | 1 + indra/newview/llpanelface.cpp | 468 +++++++++++++++++++---------- indra/newview/llpanelface.h | 3 + indra/newview/lltexturectrl.cpp | 3 +- 4 files changed, 315 insertions(+), 160 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 0a2d938bd0..cf1efd283a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2768,6 +2768,7 @@ bool LLInventoryModel::loadSkeleton( bool is_cache_obsolete = false; if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) { + LL_PROFILE_ZONE_NAMED("loadFromFile"); // We were able to find a cache of files. So, use what we // found to generate a set of categories we should add. We // will go through each category loaded and if the version diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 6e0b0d252e..2e57e2a5bd 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -4009,6 +4009,85 @@ void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) } } +void set_item_availability( + const LLUUID& id, + LLSD& dest, + const std::string& modifier, + bool is_creator, + std::map &asset_item_map, + LLViewerObject* objectp) +{ + if (id.isNull()) + { + return; + } + + LLUUID item_id; + bool from_library = get_is_predefined_texture(id); + bool full_perm = from_library; + full_perm |= is_creator; + + if (!full_perm) + { + std::map::iterator iter = asset_item_map.find(id); + if (iter != asset_item_map.end()) + { + item_id = iter->second; + } + else + { + // What this does is simply searches inventory for item with same asset id, + // as result it is Hightly unreliable, leaves little control to user, borderline hack + // but there are little options to preserve permissions - multiple inventory + // items might reference same asset and inventory search is expensive. + bool no_transfer = false; + if (objectp->getInventoryItemByAsset(id)) + { + no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm(); + } + item_id = get_copy_free_item_by_asset_id(id, no_transfer); + // record value to avoid repeating inventory search when possible + asset_item_map[id] = item_id; + } + } + + if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) + { + full_perm = true; + from_library = true; + } + + dest[modifier + "itemfullperm"] = full_perm; + dest[modifier + "fromlibrary"] = from_library; + + // If full permission object, texture is free to copy, + // but otherwise we need to check inventory and extract permissions + // + // Normally we care only about restrictions for current user and objects + // don't inherit any 'next owner' permissions from texture, so there is + // no need to record item id if full_perm==true + if (!full_perm && item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + dest[modifier + "itemid"] = item_id; + dest[modifier + "itemfullperm"] = itemp->getIsFullPerm(); + if (!itemp->isFinished()) + { + // needed for dropTextureAllFaces + LLInventoryModelBackgroundFetch::instance().start(item_id, false); + } + } + } + } +} + void LLPanelFace::onCopyTexture() { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); @@ -4046,6 +4125,7 @@ void LLPanelFace::onCopyTexture() if (tep) { LLSD te_data; + LLUUID pbr_id = objectp->getRenderMaterialID(te); // asLLSD() includes media te_data["te"] = tep->asLLSD(); @@ -4054,21 +4134,20 @@ void LLPanelFace::onCopyTexture() te_data["te"]["bumpshiny"] = tep->getBumpShiny(); te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); te_data["te"]["texgen"] = tep->getTexGen(); - te_data["te"]["pbr"] = objectp->getRenderMaterialID(te); + te_data["te"]["pbr"] = pbr_id; if (tep->getGLTFMaterialOverride() != nullptr) { te_data["te"]["pbr_override"] = tep->getGLTFMaterialOverride()->asJSON(); } - if (te_data["te"].has("imageid")) + if (te_data["te"].has("imageid") || pbr_id.notNull()) { - LLUUID item_id; - LLUUID id = te_data["te"]["imageid"].asUUID(); - bool from_library = get_is_predefined_texture(id); - bool full_perm = from_library; + LLUUID img_id = te_data["te"]["imageid"].asUUID(); + bool pbr_from_library = false; + bool pbr_full_perm = false; + bool is_creator = false; - if (!full_perm - && objectp->permCopy() + if (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()) { @@ -4078,66 +4157,31 @@ void LLPanelFace::onCopyTexture() std::string creator_app_link; LLUUID creator_id; LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); - full_perm = objectp->mOwnerID == creator_id; + is_creator = objectp->mOwnerID == creator_id; } - if (id.notNull() && !full_perm) + // check permissions for blin-phong/diffuse image and for pbr asset + if (img_id.notNull()) { - std::map::iterator iter = asset_item_map.find(id); - if (iter != asset_item_map.end()) + set_item_availability(img_id, te_data["te"], "img", is_creator, asset_item_map, objectp); + } + if (pbr_id.notNull()) + { + set_item_availability(pbr_id, te_data["te"], "pbr", is_creator, asset_item_map, objectp); + + // permissions for overrides + // Overrides do not permit no-copy textures + LLGLTFMaterial* override = tep->getGLTFMaterialOverride(); + if (override != nullptr) { - item_id = iter->second; - } - else - { - // What this does is simply searches inventory for item with same asset id, - // as result it is Hightly unreliable, leaves little control to user, borderline hack - // but there are little options to preserve permissions - multiple inventory - // items might reference same asset and inventory search is expensive. - bool no_transfer = false; - if (objectp->getInventoryItemByAsset(id)) + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) { - no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm(); - } - item_id = get_copy_free_item_by_asset_id(id, no_transfer); - // record value to avoid repeating inventory search when possible - asset_item_map[id] = item_id; - } - } - - if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) - { - full_perm = true; - from_library = true; - } - - { - te_data["te"]["itemfullperm"] = full_perm; - te_data["te"]["fromlibrary"] = from_library; - - // If full permission object, texture is free to copy, - // but otherwise we need to check inventory and extract permissions - // - // Normally we care only about restrictions for current user and objects - // don't inherit any 'next owner' permissions from texture, so there is - // no need to record item id if full_perm==true - if (!full_perm && !from_library && item_id.notNull()) - { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (itemp) - { - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowOperationBy(PERM_COPY, - gAgent.getID(), - gAgent.getGroupID())) + LLUUID& texture_id = override->mTextureId[i]; + if (texture_id.notNull()) { - te_data["te"]["imageitemid"] = item_id; - te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); - if (!itemp->isFinished()) - { - // needed for dropTextureAllFaces - LLInventoryModelBackgroundFetch::instance().start(item_id, false); - } + const std::string prefix = "pbr" + std::to_string(i); + te_data["te"][prefix + "imageid"] = texture_id; + set_item_availability(texture_id, te_data["te"], prefix, is_creator, asset_item_map, objectp); } } } @@ -4201,6 +4245,44 @@ void LLPanelFace::onCopyTexture() } } +bool get_full_permission(const LLSD& te, const std::string &prefix) +{ + return te.has(prefix + "itemfullperm") && te[prefix+"itemfullperm"].asBoolean(); +} + +bool LLPanelFace::validateInventoryItem(const LLSD& te, const std::string& prefix) +{ + if (te.has(prefix + "itemid")) + { + LLUUID item_id = te[prefix + "itemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return false; + } + } + } + else + { + // Item was not found on 'copy' stage + // Since this happened at copy, might be better to either show this + // at copy stage or to drop clipboard here + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return false; + } + return true; +} + void LLPanelFace::onPasteTexture() { if (!mClipboardParams.has("texture")) @@ -4265,39 +4347,49 @@ void LLPanelFace::onPasteTexture() for (; iter != end; ++iter) { const LLSD& te_data = *iter; - if (te_data.has("te") && te_data["te"].has("imageid")) + if (te_data.has("te")) { - bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); - full_perm_object &= full_perm; - if (!full_perm) + if (te_data["te"].has("imageid")) { - if (te_data["te"].has("imageitemid")) + bool full_perm = get_full_permission(te_data["te"], "img"); + full_perm_object &= full_perm; + if (!full_perm) { - LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); - if (item_id.notNull()) + if (!validateInventoryItem(te_data["te"], "img")) { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (!itemp) - { - // image might be in object's inventory, but it can be not up to date - LLSD notif_args; - static std::string reason = getString("paste_error_inventory_not_found"); - notif_args["REASON"] = reason; - LLNotificationsUtil::add("FacePasteFailed", notif_args); - return; - } + return; } } - else + } + if (te_data["te"].has("pbr")) + { + bool full_perm = get_full_permission(te_data["te"], "pbr"); + full_perm_object &= full_perm; + if (!full_perm) { - // Item was not found on 'copy' stage - // Since this happened at copy, might be better to either show this - // at copy stage or to drop clipboard here - LLSD notif_args; - static std::string reason = getString("paste_error_inventory_not_found"); - notif_args["REASON"] = reason; - LLNotificationsUtil::add("FacePasteFailed", notif_args); - return; + if (!validateInventoryItem(te_data["te"], "pbr")) + { + return; + } + } + if (te_data["te"].has("pbr_override")) + { + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + const std::string prefix = "pbr" + std::to_string(i); + if (te_data["te"].has(prefix + "imageid")) + { + bool full_perm = get_full_permission(te_data["te"], prefix); + full_perm_object &= full_perm; + if (!full_perm) + { + if (!validateInventoryItem(te_data["te"], prefix)) + { + return; + } + } + } + } } } } @@ -4322,6 +4414,71 @@ void LLPanelFace::onPasteTexture() selected_objects->applyToTEs(&navigate_home_func); } +void get_item_and_permissions(const LLUUID &id, LLViewerInventoryItem*& itemp, bool& full_perm, bool& from_library, const LLSD &data, const std::string &prefix) +{ + full_perm = get_full_permission(data, prefix); + from_library = data.has(prefix + "fromlibrary") && data.get(prefix + "fromlibrary").asBoolean(); + LLViewerInventoryItem* itemp_res = NULL; + + if (data.has(prefix + "itemid")) + { + LLUUID item_id = data.get(prefix + "itemid").asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + itemp_res = itemp; + } + else + { + // Theoretically shouldn't happend, but if it does happen, we + // might need to add a notification to user that paste will fail + // since inventory isn't fully loaded + LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; + } + } + } + + // for case when item got removed from inventory after we pressed 'copy' + // or texture got pasted into previous object + if (!itemp_res && !full_perm) + { + // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable. + LL_INFOS() << "Item " << data.get(prefix + "itemid").asUUID() << " no longer in inventory." << LL_ENDL; + // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) + // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // Extremely unreliable and perfomance unfriendly. + // But we need this to check permissions and it is how texture control finds items + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + itemp_res = itemp; + break; // first match + } + } + } + } +} + void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) { LLSD te_data; @@ -4345,77 +4502,22 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) if (te_data.has("te")) { // Texture - bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); - bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); if (te_data["te"].has("imageid")) { + bool img_full_perm = false; + bool img_from_library = false; const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id - LLViewerInventoryItem* itemp_res = NULL; + LLViewerInventoryItem* img_itemp_res = NULL; - if (te_data["te"].has("imageitemid")) - { - LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); - if (item_id.notNull()) - { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (itemp && itemp->isFinished()) - { - // dropTextureAllFaces will fail if incomplete - itemp_res = itemp; - } - else - { - // Theoretically shouldn't happend, but if it does happen, we - // might need to add a notification to user that paste will fail - // since inventory isn't fully loaded - LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; - } - } - } - // for case when item got removed from inventory after we pressed 'copy' - // or texture got pasted into previous object - if (!itemp_res && !full_perm) - { - // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable. - LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; - // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) - // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(imageid); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); + get_item_and_permissions(imageid, img_itemp_res, img_full_perm, img_from_library, te_data["te"], "img"); - // Extremely unreliable and perfomance unfriendly. - // But we need this to check permissions and it is how texture control finds items - for (S32 i = 0; i < items.size(); i++) - { - LLViewerInventoryItem* itemp = items[i]; - if (itemp && itemp->isFinished()) - { - // dropTextureAllFaces will fail if incomplete - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowOperationBy(PERM_COPY, - gAgent.getID(), - gAgent.getGroupID())) - { - itemp_res = itemp; - break; // first match - } - } - } - } - - if (itemp_res) + if (img_itemp_res) { if (te == -1) // all faces { LLToolDragAndDrop::dropTextureAllFaces(objectp, - itemp_res, - from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + img_itemp_res, + img_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false); } @@ -4423,15 +4525,15 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) { LLToolDragAndDrop::dropTextureOneFace(objectp, te, - itemp_res, - from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + img_itemp_res, + img_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false, 0); } } // not an inventory item or no complete items - else if (full_perm) + else if (img_full_perm) { // Either library, local or existed as fullperm when user made a copy LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); @@ -4459,17 +4561,65 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) // PBR/GLTF if (te_data["te"].has("pbr")) { - objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/); - tep->setGLTFRenderMaterial(nullptr); - tep->setGLTFMaterialOverride(nullptr); + const LLUUID pbr_id = te_data["te"]["pbr"].asUUID(); + bool pbr_full_perm = false; + bool pbr_from_library = false; + LLViewerInventoryItem* pbr_itemp_res = NULL; + get_item_and_permissions(pbr_id, pbr_itemp_res, pbr_full_perm, pbr_from_library, te_data["te"], "pbr"); + + bool allow = true; + + // check overrides first since they don't need t be moved to inventory if (te_data["te"].has("pbr_override")) { - LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID(), te_data["te"]["pbr_override"]); + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + const std::string prefix = "pbr" + std::to_string(i); + if (te_data["te"].has(prefix + "imageid")) + { + LLUUID tex_id = te_data["te"][prefix + "imageid"]; + + bool full_perm = false; + bool from_library = false; + LLViewerInventoryItem* itemp_res = NULL; + get_item_and_permissions(tex_id, itemp_res, full_perm, from_library, te_data["te"], prefix); + allow = full_perm; + if (!allow) break; + } + } } - else + + if (allow && pbr_itemp_res) { - LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID()); + if (pbr_itemp_res) + { + allow = LLToolDragAndDrop::handleDropMaterialProtections( + objectp, + pbr_itemp_res, + pbr_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + pbr_id); + } + else + { + allow = pbr_full_perm; + } + } + + if (allow) + { + objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/); + tep->setGLTFRenderMaterial(nullptr); + tep->setGLTFMaterialOverride(nullptr); + + if (te_data["te"].has("pbr_override")) + { + LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID(), te_data["te"]["pbr_override"]); + } + else + { + LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID()); + } } } else diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 6e0d34cbd6..b59f7434af 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -264,6 +264,9 @@ public: // needs to be accessible to selection manager void onCopyTexture(); void onPasteTexture(); void onPasteTexture(LLViewerObject* objectp, S32 te); +private: + // for copy/paste operations + bool validateInventoryItem(const LLSD& te, const std::string& prefix); protected: void menuDoToSelected(const LLSD& userdata); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 35057a910a..20127f5f27 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -88,7 +88,8 @@ bool get_is_predefined_texture(LLUUID asset_id) || asset_id == DEFAULT_OBJECT_NORMAL || asset_id == BLANK_OBJECT_NORMAL || asset_id == IMG_WHITE - || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) + || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE) + || asset_id == BLANK_MATERIAL_ASSET_ID) { return true; } From fdda524ee1395c7dd5d5f65ce1f61c64e256c531 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 29 Apr 2025 00:50:38 +0300 Subject: [PATCH 4/7] #3791 check against alpha blending as a part of determining exclude water --- indra/newview/llpanelface.cpp | 111 +++++++++++++++++----------------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 2e57e2a5bd..99471a2555 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1106,6 +1106,63 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) updateVisibility(objectp); + bool missing_asset = false; + { + LLGLenum image_format = GL_RGB; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset); + + if (!missing_asset) + { + 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; + } + } + else + { + // Don't know image's properties, use material's mode value + mIsAlpha = true; + } + + // Diffuse Alpha Mode + // Init to the default that is appropriate for the alpha content of the asset + // + U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + bool identical_alpha_mode = false; + + // See if that's been overridden by a material setting for same... + // + LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha); + + // it is invalid to have any alpha mode other than blend if transparency is greater than zero ... + // Want masking? Want emissive? Tough! You get BLEND! + alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode; + + // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none + alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode); + updateAlphaControls(); + + mExcludeWater &= (LLMaterial::DIFFUSE_ALPHA_MODE_BLEND == alpha_mode); + } + // Water exclusion { mCheckHideWater->setEnabled(editable && !has_pbr_material && !isMediaTexSelected()); @@ -1188,65 +1245,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) // Texture { - LLGLenum image_format = GL_RGB; - bool identical_image_format = false; - bool missing_asset = false; - LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset); - - if (!missing_asset) - { - 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; - } - } - else - { - // Don't know image's properties, use material's mode value - mIsAlpha = true; - } - if (LLViewerMedia::getInstance()->textureHasMedia(id)) { mBtnAlign->setEnabled(editable); } - // Diffuse Alpha Mode - - // Init to the default that is appropriate for the alpha content of the asset - // - U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; - - bool identical_alpha_mode = false; - - // See if that's been overridden by a material setting for same... - // - LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha); - - // it is invalid to have any alpha mode other than blend if transparency is greater than zero ... - // Want masking? Want emissive? Tough! You get BLEND! - alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode; - - // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none - alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; - - mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode); - - updateAlphaControls(); - if (mTextureCtrl) { if (identical_diffuse) From d9e55c44152064133796bfb08f1da524387c1300 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 29 Apr 2025 17:09:19 +0300 Subject: [PATCH 5/7] #3997 Crash in a gltf asset enabled region --- indra/llrender/llglslshader.cpp | 6 +++--- indra/newview/gltfscenemanager.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 50e40a3eb6..3735a99109 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1076,8 +1076,8 @@ void LLGLSLShader::bind() void LLGLSLShader::bind(U8 variant) { - llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); - llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS); + llassert_always(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); + llassert_always(variant < LLGLSLShader::NUM_GLTF_VARIANTS); mGLTFVariants[variant].bind(); } @@ -1085,7 +1085,7 @@ void LLGLSLShader::bind(bool rigged) { if (rigged) { - llassert(mRiggedVariant); + llassert_always(mRiggedVariant); mRiggedVariant->bind(); } else diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index e0cd762776..9faead9533 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -643,6 +643,12 @@ void GLTFSceneManager::render(Asset& asset, U8 variant) return; } + if (gGLTFPBRMetallicRoughnessProgram.mGLTFVariants.size() <= variant) + { + llassert(false); // mGLTFVariants should have been initialized + return; + } + for (U32 ds = 0; ds < 2; ++ds) { RenderData& rd = asset.mRenderData[ds]; From 98078b9aade28c8e24f74103f57f96bcdacd4fa4 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 30 Apr 2025 15:06:56 +0300 Subject: [PATCH 6/7] #3748 Don't allow dropping material onto water exclusion surface --- indra/newview/lltooldraganddrop.cpp | 49 ++++++++++++++++++- .../skins/default/xui/en/notifications.xml | 9 ++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 9d6f44c096..ff4fcc2b0b 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -2351,6 +2351,47 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( return rv; } + +bool is_water_exclusion_face(LLViewerObject* obj, S32 face) +{ + LLViewerTexture* image = obj->getTEImage(face); + if (!image) + return false; + + // magic texture and alpha blending + bool exclude_water = (image->getID() == IMG_ALPHA_GRAD) && obj->isImageAlphaBlended(face); + + // transparency + exclude_water &= (obj->getTE(face)->getColor().mV[VALPHA] == 1); + + //absence of normal and specular textures + image = obj->getTENormalMap(face); + if (image && image != LLViewerFetchedTexture::sDefaultImagep) + exclude_water &= image->getID().isNull(); + image = obj->getTESpecularMap(face); + if (image && image != LLViewerFetchedTexture::sDefaultImagep) + exclude_water &= image->getID().isNull(); + + return exclude_water; +} + +bool is_water_exclusion_surface(LLViewerObject* obj, S32 face, bool all_faces) +{ + if (all_faces) + { + bool exclude_water = false; + for (S32 it_face = 0; it_face < obj->getNumTEs(); it_face++) + { + exclude_water |= is_water_exclusion_face(obj, it_face); + } + return exclude_water; + } + else + { + return is_water_exclusion_face(obj, face); + } +} + EAcceptance LLToolDragAndDrop::dad3dApplyToObject( LLViewerObject* obj, S32 face, MASK mask, bool drop, EDragAndDropType cargo_type) { @@ -2441,7 +2482,13 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( else if (cargo_type == DAD_MATERIAL) { bool all_faces = mask & MASK_SHIFT; - if (item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + + if (is_water_exclusion_surface(obj, face, all_faces)) + { + LLNotificationsUtil::add("WaterExclusionNoMaterial"); + return ACCEPT_NO; + } + else if (item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) { dropMaterial(obj, face, item, mSource, mSourceID, all_faces); } diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 1a56d7e3a3..a51feeb7ab 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12610,4 +12610,13 @@ are wearing now. notext="Cancel" yestext="Continue"/> + + + Unable to apply material to the water exclusion surface. + fail + From a0cbf22d64862aa9a2036541c39f868d1c384cf1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 1 May 2025 10:50:56 +0300 Subject: [PATCH 7/7] #4001 Bump cache version --- indra/newview/llappviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7e7aa521d3..677f34456e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4248,7 +4248,7 @@ U32 LLAppViewer::getTextureCacheVersion() U32 LLAppViewer::getDiskCacheVersion() { // Viewer disk cache version intorduced in Simple Cache Viewer, change if the cache format changes. - const U32 DISK_CACHE_VERSION = 2; + const U32 DISK_CACHE_VERSION = 3; return DISK_CACHE_VERSION ; }