diff options
| author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2025-04-25 18:57:58 +0300 | 
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2025-04-28 23:36:55 +0300 | 
| commit | 7bd18e256d70804f72d747ccc1e62c92679dd645 (patch) | |
| tree | 014ef7b4884a293cdd3729243c2eafbe058ca0b6 /indra/newview | |
| parent | 1f3ba13a632a751cc3217cbe02d8aa2190df6b41 (diff) | |
viewerp#300 Fix inconsistency with copying textures vs pbr
Diffstat (limited to 'indra/newview')
| -rw-r--r-- | indra/newview/llinventorymodel.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llpanelface.cpp | 462 | ||||
| -rw-r--r-- | indra/newview/llpanelface.h | 3 | ||||
| -rw-r--r-- | indra/newview/lltexturectrl.cpp | 3 | 
4 files changed, 312 insertions, 157 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<LLUUID, LLUUID> &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<LLUUID, LLUUID>::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<LLUUID, LLUUID>::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; -                        } +                        set_item_availability(img_id, te_data["te"], "img", is_creator, asset_item_map, objectp);                      } - -                    if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) +                    if (pbr_id.notNull())                      { -                        full_perm = true; -                        from_library = true; -                    } +                        set_item_availability(pbr_id, te_data["te"], "pbr", is_creator, asset_item_map, objectp); -                    { -                        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()) +                        // permissions for overrides +                        // Overrides do not permit no-copy textures +                        LLGLTFMaterial* override = tep->getGLTFMaterialOverride(); +                        if (override != nullptr)                          { -                            LLViewerInventoryItem* itemp = gInventory.getItem(item_id); -                            if (itemp) +                            for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)                              { -                                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); - -                    // 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 -                            } -                        } -                    } -                } +                get_item_and_permissions(imageid, img_itemp_res, img_full_perm, img_from_library, te_data["te"], "img"); -                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; +                        } +                    } +                } + +                if (allow && pbr_itemp_res) +                { +                    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; +                    }                  } -                else + +                if (allow)                  { -                    LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID()); +                    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;      } | 
