summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/lldrawpoolwlsky.cpp5
-rw-r--r--indra/newview/llfilepicker.cpp1
-rw-r--r--indra/newview/lllocalgltfmaterials.cpp44
-rw-r--r--indra/newview/llmaterialeditor.cpp74
-rw-r--r--indra/newview/llmaterialeditor.h3
-rw-r--r--indra/newview/llpanelface.cpp12
-rw-r--r--indra/newview/lltexturectrl.cpp10
-rw-r--r--indra/newview/lltexturectrl.h2
-rw-r--r--indra/newview/lltinygltfhelper.cpp53
-rw-r--r--indra/newview/lltinygltfhelper.h4
-rw-r--r--indra/newview/llviewermenufile.cpp81
-rw-r--r--indra/newview/skins/default/xui/en/panel_tools_texture.xml70
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml5
13 files changed, 251 insertions, 113 deletions
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 4bd7536964..f09d1abe2d 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -166,6 +166,11 @@ void LLDrawPoolWLSky::renderDome(const LLVector3& camPosLocal, F32 camHeightLoca
void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 camHeightLocal) const
{
+ if (!gSky.mVOSkyp)
+ {
+ return;
+ }
+
LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 1dd9a43b72..1ec25ccaa1 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -179,6 +179,7 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
SOUND_FILTER \
IMAGE_FILTER \
ANIM_FILTER \
+ MATERIAL_FILTER \
L"\0";
break;
case FFLOAD_WAV:
diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp
index 89f14c6cfa..a9099b1ce9 100644
--- a/indra/newview/lllocalgltfmaterials.cpp
+++ b/indra/newview/lllocalgltfmaterials.cpp
@@ -308,48 +308,10 @@ S32 LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames)
S32 LLLocalGLTFMaterialMgr::addUnit(const std::string& filename)
{
- std::string exten = gDirUtilp->getExtension(filename);
- S32 materials_in_file = 0;
-
- if (exten == "gltf" || exten == "glb")
+ S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
+ if (materials_in_file <= 0)
{
- tinygltf::TinyGLTF loader;
- std::string error_msg;
- std::string warn_msg;
-
- tinygltf::Model model_in;
-
- std::string filename_lc = filename;
- LLStringUtil::toLower(filename_lc);
-
- // Load a tinygltf model fom a file. Assumes that the input filename has already been
- // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
- bool decode_successful = false;
- if (std::string::npos == filename_lc.rfind(".gltf"))
- { // file is binary
- decode_successful = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
- }
- else
- { // file is ascii
- decode_successful = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
- }
-
- if (!decode_successful)
- {
- LL_WARNS("GLTF") << "Cannot load, error: Failed to decode" << error_msg
- << ", warning:" << warn_msg
- << " file: " << filename
- << LL_ENDL;
- return 0;
- }
-
- if (model_in.materials.empty())
- {
- // materials are missing
- LL_WARNS("GLTF") << "Cannot load. File has no materials " << filename << LL_ENDL;
- return 0;
- }
- materials_in_file = model_in.materials.size();
+ return 0;
}
S32 loaded_materials = 0;
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 4b9d870d18..660ad879ca 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -390,10 +390,10 @@ BOOL LLMaterialEditor::postBuild()
if (!gAgent.isGodlike())
{
// Only allow fully permissive textures
- mBaseColorTextureCtrl->setImmediateFilterPermMask(PERM_ITEM_UNRESTRICTED);
- mMetallicTextureCtrl->setImmediateFilterPermMask(PERM_ITEM_UNRESTRICTED);
- mEmissiveTextureCtrl->setImmediateFilterPermMask(PERM_ITEM_UNRESTRICTED);
- mNormalTextureCtrl->setImmediateFilterPermMask(PERM_ITEM_UNRESTRICTED);
+ mBaseColorTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mMetallicTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mEmissiveTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mNormalTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
}
// Texture callback
@@ -1400,8 +1400,6 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std:
LLNotificationsUtil::add("MaterialCreated", params);
});
- // todo: apply permissions from textures here if server doesn't
- // if any texture is 'no transfer', material should be 'no transfer' as well
const LLViewerRegion* region = gAgent.getRegion();
if (region)
{
@@ -1684,6 +1682,59 @@ static void pack_textures(
}
}
+void LLMaterialEditor::uploadMaterialFromFile(const std::string& filename, S32 index)
+{
+ if (index < 0)
+ {
+ return;
+ }
+
+ tinygltf::TinyGLTF loader;
+ std::string error_msg;
+ std::string warn_msg;
+
+ bool loaded = false;
+ tinygltf::Model model_in;
+
+ std::string filename_lc = filename;
+ LLStringUtil::toLower(filename_lc);
+
+ // Load a tinygltf model fom a file. Assumes that the input filename has already been
+ // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
+ if (std::string::npos == filename_lc.rfind(".gltf"))
+ { // file is binary
+ loaded = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename);
+ }
+ else
+ { // file is ascii
+ loaded = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename);
+ }
+
+ if (!loaded)
+ {
+ LLNotificationsUtil::add("CannotUploadMaterial");
+ return;
+ }
+
+ if (model_in.materials.empty())
+ {
+ // materials are missing
+ return;
+ }
+
+ if (index >= 0 && model_in.materials.size() <= index)
+ {
+ // material is missing
+ return;
+ }
+
+ // Todo: no point in loading whole editor
+ LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor", LLSD().with("filename", filename).with("index", LLSD::Integer(index)));
+ me->loadMaterial(model_in, filename_lc, index, false);
+ me->saveIfNeeded();
+}
+
+
void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index)
{
tinygltf::TinyGLTF loader;
@@ -1976,7 +2027,7 @@ void LLMaterialEditor::loadFromGLTFMaterial(LLUUID &asset_id)
me->setFocus(TRUE);
}
-void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename_lc, S32 index)
+void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename_lc, S32 index, bool open_floater)
{
if (model_in.materials.size() <= index)
{
@@ -2074,10 +2125,13 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::
markChangesUnsaved(U32_MAX);
- openFloater();
- setFocus(TRUE);
+ if (open_floater)
+ {
+ openFloater(getKey());
+ setFocus(TRUE);
- applyToSelection();
+ applyToSelection();
+ }
}
bool LLMaterialEditor::setFromGltfModel(const tinygltf::Model& model, S32 index, bool set_textures)
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 6deda5df50..d23a741e49 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -103,6 +103,7 @@ public:
void loadAsset() override;
// @index if -1 and file contains more than one material,
// will promt to select specific one
+ static void uploadMaterialFromFile(const std::string& filename, S32 index);
static void loadMaterialFromFile(const std::string& filename, S32 index = -1);
void onSelectionChanged(); // live overrides selection changes
@@ -242,7 +243,7 @@ private:
void setFromGLTFMaterial(LLGLTFMaterial* mat);
bool setFromSelection();
- void loadMaterial(const tinygltf::Model &model, const std::string &filename_lc, S32 index);
+ void loadMaterial(const tinygltf::Model &model, const std::string &filename_lc, S32 index, bool open_floater = true);
friend class LLMaterialFilePicker;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 3d72865f69..92e92ac6a6 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1064,7 +1064,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);
- getChildView("ColorTrans")->setEnabled(editable);
+ getChildView("ColorTrans")->setEnabled(editable && has_material);
// Specular map
LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec);
@@ -1818,11 +1818,11 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,
LLUICtrl* gltfCtrlTextureOffsetU = getChild<LLUICtrl>("gltfTextureOffsetU");
LLUICtrl* gltfCtrlTextureOffsetV = getChild<LLUICtrl>("gltfTextureOffsetV");
- gltfCtrlTextureScaleU->setEnabled(show_texture_info && has_pbr_capabilities);
- gltfCtrlTextureScaleV->setEnabled(show_texture_info && has_pbr_capabilities);
- gltfCtrlTextureRotation->setEnabled(show_texture_info && has_pbr_capabilities);
- gltfCtrlTextureOffsetU->setEnabled(show_texture_info && has_pbr_capabilities);
- gltfCtrlTextureOffsetV->setEnabled(show_texture_info && has_pbr_capabilities);
+ gltfCtrlTextureScaleU->setEnabled(show_texture_info && has_pbr_capabilities && has_pbr_material);
+ gltfCtrlTextureScaleV->setEnabled(show_texture_info && has_pbr_capabilities && has_pbr_material);
+ gltfCtrlTextureRotation->setEnabled(show_texture_info && has_pbr_capabilities && has_pbr_material);
+ gltfCtrlTextureOffsetU->setEnabled(show_texture_info && has_pbr_capabilities && has_pbr_material);
+ gltfCtrlTextureOffsetV->setEnabled(show_texture_info && has_pbr_capabilities && has_pbr_material);
// Control values are set in setMaterialOverridesFromSelection
}
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 9891d7b078..6cf7e8850d 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -1800,7 +1800,7 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
allow_dnd = is_texture || is_mesh || is_material;
}
- if (getEnabled() && allow_dnd && allowDrop(item))
+ if (getEnabled() && allow_dnd && allowDrop(item, cargo_type, tooltip_msg))
{
if (drop)
{
@@ -1952,7 +1952,7 @@ void LLTextureCtrl::draw()
LLUICtrl::draw();
}
-BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item)
+BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item, EDragAndDropType cargo_type, std::string& tooltip_msg)
{
BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
@@ -1978,6 +1978,12 @@ BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item)
}
else
{
+ PermissionMask mask = PERM_COPY | PERM_TRANSFER;
+ if ((filter_perm_mask & mask) == mask
+ && cargo_type == DAD_TEXTURE)
+ {
+ tooltip_msg.assign(LLTrans::getString("TooltipTextureRestrictedDrop"));
+ }
return FALSE;
}
}
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 8d6a520dfd..d898722006 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -223,7 +223,7 @@ public:
EPickInventoryType getInventoryPickType() { return mInventoryPickType; };
private:
- BOOL allowDrop(LLInventoryItem* item);
+ BOOL allowDrop(LLInventoryItem* item, EDragAndDropType cargo_type, std::string& tooltip_msg);
BOOL doDrop(LLInventoryItem* item);
private:
diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp
index 05587af9bc..838524e910 100644
--- a/indra/newview/lltinygltfhelper.cpp
+++ b/indra/newview/lltinygltfhelper.cpp
@@ -182,12 +182,62 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny
return rawImage;
}
+S32 LLTinyGLTFHelper::getMaterialCountFromFile(const std::string& filename)
+{
+ std::string exten = gDirUtilp->getExtension(filename);
+ S32 materials_in_file = 0;
+
+ if (exten == "gltf" || exten == "glb")
+ {
+ tinygltf::TinyGLTF loader;
+ std::string error_msg;
+ std::string warn_msg;
+
+ tinygltf::Model model_in;
+
+ std::string filename_lc = filename;
+ LLStringUtil::toLower(filename_lc);
+
+ // Load a tinygltf model fom a file. Assumes that the input filename has already been
+ // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
+ bool decode_successful = false;
+ if (std::string::npos == filename_lc.rfind(".gltf"))
+ { // file is binary
+ decode_successful = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
+ }
+ else
+ { // file is ascii
+ decode_successful = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
+ }
+
+ if (!decode_successful)
+ {
+ LL_WARNS("GLTF") << "Cannot load, error: Failed to decode" << error_msg
+ << ", warning:" << warn_msg
+ << " file: " << filename
+ << LL_ENDL;
+ return 0;
+ }
+
+ if (model_in.materials.empty())
+ {
+ // materials are missing
+ LL_WARNS("GLTF") << "Cannot load. File has no materials " << filename << LL_ENDL;
+ return 0;
+ }
+ materials_in_file = model_in.materials.size();
+ }
+ return materials_in_file;
+}
+
bool LLTinyGLTFHelper::getMaterialFromFile(
const std::string& filename,
S32 mat_index,
- LLPointer < LLFetchedGLTFMaterial> material,
+ LLFetchedGLTFMaterial* material,
std::string& material_name)
{
+ llassert(material);
+
tinygltf::TinyGLTF loader;
std::string error_msg;
std::string warn_msg;
@@ -304,5 +354,4 @@ bool LLTinyGLTFHelper::getMaterialFromFile(
}
return true;
-
}
diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h
index 250a4b0b9a..92c9876aff 100644
--- a/indra/newview/lltinygltfhelper.h
+++ b/indra/newview/lltinygltfhelper.h
@@ -43,10 +43,12 @@ namespace LLTinyGLTFHelper
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index);
+ S32 getMaterialCountFromFile(const std::string& filename);
+
bool getMaterialFromFile(
const std::string& filename,
S32 mat_index,
- LLPointer < LLFetchedGLTFMaterial> material,
+ LLFetchedGLTFMaterial* material,
std::string& material_name);
void initFetchedTextures(tinygltf::Material& material,
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index c028a663ea..33c7240fe0 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -38,6 +38,7 @@
#include "llfloatermap.h"
#include "llfloatermodelpreview.h"
#include "llmaterialeditor.h"
+#include "llfloaterperms.h"
#include "llfloatersnapshot.h"
#include "llfloateroutfitsnapshot.h"
#include "llimage.h"
@@ -49,9 +50,9 @@
#include "llinventorymodel.h" // gInventory
#include "llpluginclassmedia.h"
#include "llresourcedata.h"
-#include "lltoast.h"
-#include "llfloaterperms.h"
#include "llstatusbar.h"
+#include "lltinygltfhelper.h"
+#include "lltoast.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewertexturelist.h"
#include "lluictrlfactory.h"
@@ -471,19 +472,33 @@ void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification
if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
{
- LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
- filename,
- asset_name,
- asset_name, 0,
- LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost));
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+ filename,
+ asset_name,
+ asset_name, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(uploadInfo);
+ }
- upload_new_resource(uploadInfo);
- }
-}
+ // gltf does not use normal upload procedure
+ if (ext == "gltf" || ext == "glb")
+ {
+ S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
+
+ for (S32 i = 0; i < materials_in_file; i++)
+ {
+ // Todo:
+ // 1. Decouple bulk upload from material editor
+ // 2. Take into account possiblity of identical textures
+ LLMaterialEditor::uploadMaterialFromFile(filename, i);
+ }
+ }
+ }
}
bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost, S32& file_count, S32& bvh_count)
@@ -511,6 +526,44 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3
total_cost += cost;
file_count++;
}
+
+ if (ext == "gltf" || ext == "glb")
+ {
+ S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
+ S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
+
+ for (S32 i = 0; i < materials_in_file; i++)
+ {
+ LLPointer<LLFetchedGLTFMaterial> material = new LLFetchedGLTFMaterial();
+ std::string material_name;
+ bool decode_successful = LLTinyGLTFHelper::getMaterialFromFile(filename, i, material.get(), material_name);
+
+ if (decode_successful)
+ {
+ // Todo: make it account for possibility of same texture in different
+ // materials and even in scope of same material
+ S32 texture_count = 0;
+ if (material->mBaseColorId.notNull())
+ {
+ texture_count++;
+ }
+ if (material->mMetallicRoughnessId.notNull())
+ {
+ texture_count++;
+ }
+ if (material->mNormalId.notNull())
+ {
+ texture_count++;
+ }
+ if (material->mEmissiveId.notNull())
+ {
+ texture_count++;
+ }
+ total_cost += texture_count * texture_upload_cost;
+ file_count++;
+ }
+ }
+ }
}
return file_count > 0;
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 ba5a20dd22..3bcbe0ca3a 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -891,6 +891,40 @@
max_val="1"
name="shinyOffsetV"
width="265" />
+ <check_box
+ follows="top|left"
+ height="16"
+ initial_value="false"
+ label="Align planar faces"
+ layout="topleft"
+ left="7"
+ name="checkbox planar align"
+ tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping."
+ top_delta="20"
+ width="260" />
+ <button
+ follows="left|top"
+ layout="topleft"
+ left="9"
+ top="231"
+ height="20"
+ label="Align"
+ label_selected="Align current texture layers"
+ name="button align textures"
+ tool_tip="Align current texture layers"
+ width="66" />
+ <web_browser
+ visible="false"
+ enabled="false"
+ border_visible="true"
+ bottom_delta="0"
+ follows="top|left"
+ left="0"
+ name="title_media"
+ width="4"
+ height="4"
+ start_url="about:blank"
+ decouple_texture_size="true" />
<!-- BEGIN PBR Material texture transform parameters -->
<spinner
follows="left|top"
@@ -903,7 +937,7 @@
min_val="-100"
max_val="100"
name="gltfTextureScaleU"
- top_delta="-115"
+ top_delta="34"
width="265" />
<spinner
follows="left|top"
@@ -954,38 +988,4 @@
name="gltfTextureOffsetV"
width="265" />
<!-- END PBR Material texture transform parameters -->
- <check_box
- follows="top|left"
- height="16"
- initial_value="false"
- label="Align planar faces"
- layout="topleft"
- left="7"
- name="checkbox planar align"
- tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping."
- top_delta="43"
- width="260" />
- <button
- follows="left|top"
- layout="topleft"
- left="9"
- top="231"
- height="20"
- label="Align"
- label_selected="Align current texture layers"
- name="button align textures"
- tool_tip="Align current texture layers"
- width="66" />
- <web_browser
- visible="false"
- enabled="false"
- border_visible="true"
- bottom_delta="0"
- follows="top|left"
- left="0"
- name="title_media"
- width="4"
- height="4"
- start_url="about:blank"
- decouple_texture_size="true" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index e7e1a24f5e..255aff06be 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -319,6 +319,11 @@ Only items with unrestricted
'next owner' permissions
can be attached to notecards.
</string>
+ <string name="TooltipTextureRestrictedDrop">
+Only textures with unrestricted
+copy and transfer permissions
+are allowed.
+ </string>
<!-- searching - generic -->
<string name="Searching">Searching...</string>