summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llfloaterbulkpermission.cpp1
-rw-r--r--indra/newview/llinventorybridge.cpp3
-rw-r--r--indra/newview/llmaterialeditor.cpp630
-rw-r--r--indra/newview/llmaterialeditor.h50
-rw-r--r--indra/newview/llviewerinventory.cpp4
-rw-r--r--indra/newview/llviewermessage.cpp6
-rw-r--r--indra/newview/llviewerregion.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml25
9 files changed, 652 insertions, 80 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 35a79f12de..1be6124a2a 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1252,6 +1252,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>BulkChangeIncludeMaterials</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect materials</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>BulkChangeEveryoneCopy</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp
index a1a06706bc..a3cc939f85 100644
--- a/indra/newview/llfloaterbulkpermission.cpp
+++ b/indra/newview/llfloaterbulkpermission.cpp
@@ -306,6 +306,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve
( asstype == LLAssetType::AT_LSL_TEXT && gSavedSettings.getBOOL("BulkChangeIncludeScripts" )) ||
( asstype == LLAssetType::AT_SOUND && gSavedSettings.getBOOL("BulkChangeIncludeSounds" )) ||
( asstype == LLAssetType::AT_SETTINGS && gSavedSettings.getBOOL("BulkChangeIncludeSettings" )) ||
+ ( asstype == LLAssetType::AT_MATERIAL && gSavedSettings.getBOOL("BulkChangeIncludeMaterials")) ||
( asstype == LLAssetType::AT_TEXTURE && gSavedSettings.getBOOL("BulkChangeIncludeTextures" )))
{
LLViewerObject* object = gObjectList.findObject(viewer_obj->getID());
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index cd6f631ee1..2bb2c9676b 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -7651,8 +7651,7 @@ public:
LLViewerInventoryItem* item = getItem();
if (item)
{
- // TODO - show UI for material preview?
- LL_INFOS() << "inventory action performed on material: " << item->getName() << " " << item->getUUID() << LL_ENDL;
+ LLFloaterReg::showInstance("material_editor", LLSD(item->getUUID()), TAKE_FOCUS_YES);
}
LLInvFVBridgeAction::doIt();
}
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index f1166fbc0d..ada5bb3882 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -42,8 +42,14 @@
#include "llviewerinventory.h"
#include "llviewerregion.h"
#include "llvovolume.h"
-
+#include "roles_constants.h"
#include "tinygltf/tiny_gltf.h"
+#include "llviewerobjectlist.h"
+#include "llfloaterreg.h"
+#include "llfilesystem.h"
+#include "llsdserialize.h"
+
+#include <strstream>
///----------------------------------------------------------------------------
/// Class LLPreviewNotecard
@@ -51,9 +57,14 @@
// Default constructor
LLMaterialEditor::LLMaterialEditor(const LLSD& key)
- : LLFloater(key)
+ : LLPreview(key)
, mHasUnsavedChanges(false)
{
+ const LLInventoryItem* item = getItem();
+ if (item)
+ {
+ mAssetID = item->getAssetUUID();
+ }
}
BOOL LLMaterialEditor::postBuild()
@@ -104,7 +115,7 @@ BOOL LLMaterialEditor::postBuild()
// Disable/enable setCanApplyImmediately() based on
// working from inventory, upload or editing inworld
- return LLFloater::postBuild();
+ return LLPreview::postBuild();
}
void LLMaterialEditor::onClickCloseBtn(bool app_quitting)
@@ -149,7 +160,7 @@ LLColor4 LLMaterialEditor::getAlbedoColor()
void LLMaterialEditor::setAlbedoColor(const LLColor4& color)
{
childSetValue("albedo color", color.getValue());
- childSetValue("transparency", color.mV[3]);
+ setTransparency(color.mV[3]);
}
F32 LLMaterialEditor::getTransparency()
@@ -157,6 +168,11 @@ F32 LLMaterialEditor::getTransparency()
return childGetValue("transparency").asReal();
}
+void LLMaterialEditor::setTransparency(F32 transparency)
+{
+ childSetValue("transparency", transparency);
+}
+
std::string LLMaterialEditor::getAlphaMode()
{
return childGetValue("alpha mode").asString();
@@ -375,11 +391,51 @@ static U32 write_texture(const LLUUID& id, tinygltf::Model& model)
return texture_idx;
}
+
void LLMaterialEditor::onClickSave()
{
applyToSelection();
+
+ saveIfNeeded();
+}
+
+std::string LLMaterialEditor::getGLTFJson(bool prettyprint)
+{
tinygltf::Model model;
+ getGLTFModel(model);
+
+ std::ostringstream str;
+
+ tinygltf::TinyGLTF gltf;
+
+ gltf.WriteGltfSceneToStream(&model, str, prettyprint, false);
+
+ std::string dump = str.str();
+
+ return dump;
+}
+
+void LLMaterialEditor::getGLBData(std::vector<U8>& data)
+{
+ tinygltf::Model model;
+ getGLTFModel(model);
+
+ std::ostringstream str;
+
+ tinygltf::TinyGLTF gltf;
+
+ gltf.WriteGltfSceneToStream(&model, str, false, true);
+
+ std::string dump = str.str();
+
+ data.resize(dump.length());
+
+ memcpy(&data[0], dump.c_str(), dump.length());
+}
+
+void LLMaterialEditor::getGLTFModel(tinygltf::Model& model)
+{
model.materials.resize(1);
tinygltf::PbrMetallicRoughness& pbrMaterial = model.materials[0].pbrMetallicRoughness;
@@ -392,11 +448,11 @@ void LLMaterialEditor::onClickSave()
model.materials[0].alphaMode = getAlphaMode();
LLUUID albedo_id = getAlbedoId();
-
+
if (albedo_id.notNull())
{
U32 texture_idx = write_texture(albedo_id, model);
-
+
pbrMaterial.baseColorTexture.index = texture_idx;
}
@@ -406,14 +462,14 @@ void LLMaterialEditor::onClickSave()
pbrMaterial.metallicFactor = metalness;
pbrMaterial.roughnessFactor = roughness;
-
+
LLUUID mr_id = getMetallicRoughnessId();
if (mr_id.notNull())
{
U32 texture_idx = write_texture(mr_id, model);
pbrMaterial.metallicRoughnessTexture.index = texture_idx;
}
-
+
//write emissive
LLColor4 emissive_color = getEmissiveColor();
model.materials[0].emissiveFactor.resize(3);
@@ -437,54 +493,213 @@ void LLMaterialEditor::onClickSave()
//write doublesided
model.materials[0].doubleSided = getDoubleSided();
+ model.asset.version = "2.0";
+}
+
+std::string LLMaterialEditor::getEncodedAsset()
+{
+ LLSD asset;
+ asset["version"] = "1.0";
+ asset["type"] = "GLTF 2.0";
+ asset["data"] = getGLTFJson(false);
+
std::ostringstream str;
+ LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY);
- tinygltf::TinyGLTF gltf;
- model.asset.version = "2.0";
- gltf.WriteGltfSceneToStream(&model, str, true, false);
+ return str.str();
+}
+
+bool LLMaterialEditor::decodeAsset(const std::vector<char>& buffer)
+{
+ LLSD asset;
- std::string dump = str.str();
+ std::istrstream str(&buffer[0], buffer.size());
+ if (LLSDSerialize::deserialize(asset, str, buffer.size()))
+ {
+ if (asset.has("version") && asset["version"] == "1.0")
+ {
+ if (asset.has("type") && asset["type"] == "GLTF 2.0")
+ {
+ if (asset.has("data") && asset["data"].isString())
+ {
+ std::string data = asset["data"];
+
+ tinygltf::TinyGLTF gltf;
+ tinygltf::TinyGLTF loader;
+ std::string error_msg;
+ std::string warn_msg;
+
+ tinygltf::Model model_in;
+
+ if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), ""))
+ {
+ return setFromGltfModel(model_in, true);
+ }
+ else
+ {
+ LL_WARNS() << "Failed to decode material asset: " << LL_ENDL;
+ LL_WARNS() << warn_msg << LL_ENDL;
+ LL_WARNS() << error_msg << LL_ENDL;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Failed to deserialize material LLSD" << LL_ENDL;
+ }
+
+ return false;
+}
- LL_INFOS() << mMaterialName << ": " << dump << LL_ENDL;
-
- // gen a new uuid for this asset
- LLTransactionID tid;
- tid.generate(); // timestamp-based randomization + uniquification
- LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
- std::string res_desc = "Saved Material";
- U32 next_owner_perm = LLPermissions::DEFAULT.getMaskNextOwner();
- LLUUID parent = gInventory.findCategoryUUIDForType(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, mMaterialName, res_desc,
- LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm,
- new LLBoostFuncInventoryCallback([output=dump](LLUUID const & inv_item_id){
- // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem()
- LLResourceUploadInfo::ptr_t uploadInfo =
- std::make_shared<LLBufferedAssetUploadInfo>(
- inv_item_id,
- LLAssetType::AT_SETTINGS, // TODO switch to AT_MATERIAL
- output,
- [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) {
- LL_INFOS("Material") << "inventory item uploaded. item: " << item_id << " asset: " << new_asset_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL;
- LLSD params = llsd::map("ASSET_ID", new_asset_id);
- LLNotificationsUtil::add("MaterialCreated", params);
+bool LLMaterialEditor::saveIfNeeded(LLInventoryItem* copyitem, bool sync)
+{
+ std::string buffer = getEncodedAsset();
+
+ const LLInventoryItem* item = getItem();
+ // save it out to database
+ if (item)
+ {
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "Not connected to a region, cannot save material." << LL_ENDL;
+ return false;
+ }
+ std::string agent_url = region->getCapability("UpdateMaterialAgentInventory");
+ std::string task_url = region->getCapability("UpdateMaterialTaskInventory");
+
+ if (!agent_url.empty() && !task_url.empty())
+ {
+ std::string url;
+ LLResourceUploadInfo::ptr_t uploadInfo;
+
+ if (mObjectUUID.isNull() && !agent_url.empty())
+ {
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mItemUUID, LLAssetType::AT_MATERIAL, buffer,
+ [](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD) {
+ LLMaterialEditor::finishInventoryUpload(itemId, newAssetId, newItemId);
});
+ url = agent_url;
+ }
+ else if (!mObjectUUID.isNull() && !task_url.empty())
+ {
+ LLUUID object_uuid(mObjectUUID);
+ uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(mObjectUUID, mItemUUID, LLAssetType::AT_MATERIAL, buffer,
+ [object_uuid](LLUUID itemId, LLUUID, LLUUID newAssetId, LLSD) {
+ LLMaterialEditor::finishTaskUpload(itemId, newAssetId, object_uuid);
+ });
+ url = task_url;
+ }
- const LLViewerRegion* region = gAgent.getRegion();
- if (region)
+ if (!url.empty() && uploadInfo)
{
- std::string agent_url(region->getCapability("UpdateSettingsAgentInventory"));
- if (agent_url.empty())
- {
- LL_ERRS() << "missing required agent inventory cap url" << LL_ENDL;
- }
- LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo);
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ setEnabled(false);
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
}
- })
- );
+
+ }
+ else // !gAssetStorage
+ {
+ LL_WARNS() << "Not connected to an materials capable region." << LL_ENDL;
+ return false;
+ }
+
+ if (mCloseAfterSave)
+ {
+ closeFloater();
+ }
+ }
+ else
+ { //make a new inventory item
+ // gen a new uuid for this asset
+ LLTransactionID tid;
+ tid.generate(); // timestamp-based randomization + uniquification
+ LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+ std::string res_desc = "Saved Material";
+ U32 next_owner_perm = LLPermissions::DEFAULT.getMaskNextOwner();
+ LLUUID parent = gInventory.findCategoryUUIDForType(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, mMaterialName, res_desc,
+ LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm,
+ new LLBoostFuncInventoryCallback([output = buffer](LLUUID const& inv_item_id) {
+ // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem()
+ LLResourceUploadInfo::ptr_t uploadInfo =
+ std::make_shared<LLBufferedAssetUploadInfo>(
+ inv_item_id,
+ LLAssetType::AT_MATERIAL,
+ output,
+ [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) {
+ LL_INFOS("Material") << "inventory item uploaded. item: " << item_id << " asset: " << new_asset_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL;
+ LLSD params = llsd::map("ASSET_ID", new_asset_id);
+ LLNotificationsUtil::add("MaterialCreated", params);
+ });
+
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ std::string agent_url(region->getCapability("UpdateMaterialAgentInventory"));
+ if (agent_url.empty())
+ {
+ LL_ERRS() << "missing required agent inventory cap url" << LL_ENDL;
+ }
+ LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo);
+ }
+ })
+ );
+ }
+
+ return true;
+}
+
+void LLMaterialEditor::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId)
+{
+ // Update the UI with the new asset.
+ LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(itemId));
+ if (me)
+ {
+ if (newItemId.isNull())
+ {
+ me->setAssetId(newAssetId);
+ me->refreshFromInventory();
+ }
+ else
+ {
+ me->refreshFromInventory(newItemId);
+ }
+ }
}
+void LLMaterialEditor::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId)
+{
+
+ LLSD floater_key;
+ floater_key["taskid"] = taskId;
+ floater_key["itemid"] = itemId;
+ LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(itemId));
+ if (me)
+ {
+ me->setAssetId(newAssetId);
+ me->refreshFromInventory();
+ }
+}
+
+void LLMaterialEditor::refreshFromInventory(const LLUUID& new_item_id)
+{
+ if (new_item_id.notNull())
+ {
+ mItemUUID = new_item_id;
+ setKey(LLSD(new_item_id));
+ }
+ LL_DEBUGS() << "LLPreviewNotecard::refreshFromInventory()" << LL_ENDL;
+ loadAsset();
+}
+
+
void LLMaterialEditor::onClickSaveAs()
{
LLSD args;
@@ -806,16 +1021,7 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename)
mME->setEmissiveId(emissive_id);
mME->setNormalId(normal_id);
- mME->setAlphaMode(material_in.alphaMode);
- mME->setAlphaCutoff(material_in.alphaCutoff);
-
- mME->setAlbedoColor(get_color(material_in.pbrMetallicRoughness.baseColorFactor));
- mME->setEmissiveColor(get_color(material_in.emissiveFactor));
-
- mME->setMetalnessFactor(material_in.pbrMetallicRoughness.metallicFactor);
- mME->setRoughnessFactor(material_in.pbrMetallicRoughness.roughnessFactor);
-
- mME->setDoubleSided(material_in.doubleSided);
+ mME->setFromGltfModel(model_in);
std::string new_material = LLTrans::getString("New Material");
mME->setMaterialName(new_material);
@@ -826,6 +1032,81 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename)
mME->applyToSelection();
}
+bool LLMaterialEditor::setFromGltfModel(tinygltf::Model& model, bool set_textures)
+{
+ if (model.materials.size() > 0)
+ {
+ tinygltf::Material& material_in = model.materials[0];
+
+ if (set_textures)
+ {
+ S32 index;
+ LLUUID id;
+
+ // get albedo texture
+ index = material_in.pbrMetallicRoughness.baseColorTexture.index;
+ if (index >= 0)
+ {
+ id.set(model.images[index].uri);
+ setAlbedoId(id);
+ }
+ else
+ {
+ setAlbedoId(LLUUID::null);
+ }
+
+ // get normal map
+ index = material_in.normalTexture.index;
+ if (index >= 0)
+ {
+ id.set(model.images[index].uri);
+ setNormalId(id);
+ }
+ else
+ {
+ setNormalId(LLUUID::null);
+ }
+
+ // get metallic-roughness texture
+ index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index;
+ if (index >= 0)
+ {
+ id.set(model.images[index].uri);
+ setMetallicRoughnessId(id);
+ }
+ else
+ {
+ setMetallicRoughnessId(LLUUID::null);
+ }
+
+ // get emissive texture
+ index = material_in.emissiveTexture.index;
+ if (index >= 0)
+ {
+ id.set(model.images[index].uri);
+ setEmissiveId(id);
+ }
+ else
+ {
+ setEmissiveId(LLUUID::null);
+ }
+ }
+
+ setAlphaMode(material_in.alphaMode);
+ setAlphaCutoff(material_in.alphaCutoff);
+
+ setAlbedoColor(get_color(material_in.pbrMetallicRoughness.baseColorFactor));
+ setEmissiveColor(get_color(material_in.emissiveFactor));
+
+ setMetalnessFactor(material_in.pbrMetallicRoughness.metallicFactor);
+ setRoughnessFactor(material_in.pbrMetallicRoughness.roughnessFactor);
+
+ setDoubleSided(material_in.doubleSided);
+ }
+
+ return true;
+}
+
void LLMaterialEditor::importMaterial()
{
(new LLMaterialFilePicker(this))->getFile();
@@ -841,22 +1122,7 @@ void LLMaterialEditor::applyToSelection()
if (objectp && objectp->getVolume())
{
LLGLTFMaterial* mat = new LLGLTFMaterial();
- mat->mAlbedoColor = getAlbedoColor();
- mat->mAlbedoColor.mV[3] = getTransparency();
- mat->mAlbedoId = getAlbedoId();
-
- mat->mNormalId = getNormalId();
-
- mat->mMetallicRoughnessId = getMetallicRoughnessId();
- mat->mMetallicFactor = getMetalnessFactor();
- mat->mRoughnessFactor = getRoughnessFactor();
-
- mat->mEmissiveColor = getEmissiveColor();
- mat->mEmissiveId = getEmissiveId();
-
- mat->mDoubleSided = getDoubleSided();
- mat->setAlphaMode(getAlphaMode());
-
+ getGLTFMaterial(mat);
LLVOVolume* vobjp = (LLVOVolume*)objectp;
for (int i = 0; i < vobjp->getNumTEs(); ++i)
{
@@ -867,3 +1133,223 @@ void LLMaterialEditor::applyToSelection()
vobjp->markForUpdate(TRUE);
}
}
+
+void LLMaterialEditor::getGLTFMaterial(LLGLTFMaterial* mat)
+{
+ mat->mAlbedoColor = getAlbedoColor();
+ mat->mAlbedoColor.mV[3] = getTransparency();
+ mat->mAlbedoId = getAlbedoId();
+
+ mat->mNormalId = getNormalId();
+
+ mat->mMetallicRoughnessId = getMetallicRoughnessId();
+ mat->mMetallicFactor = getMetalnessFactor();
+ mat->mRoughnessFactor = getRoughnessFactor();
+
+ mat->mEmissiveColor = getEmissiveColor();
+ mat->mEmissiveId = getEmissiveId();
+
+ mat->mDoubleSided = getDoubleSided();
+ mat->setAlphaMode(getAlphaMode());
+}
+
+void LLMaterialEditor::setFromGLTFMaterial(LLGLTFMaterial* mat)
+{
+ setAlbedoColor(mat->mAlbedoColor);
+ setAlbedoId(mat->mAlbedoId);
+ setNormalId(mat->mNormalId);
+
+ setMetallicRoughnessId(mat->mMetallicRoughnessId);
+ setMetalnessFactor(mat->mMetallicFactor);
+ setRoughnessFactor(mat->mRoughnessFactor);
+
+ setEmissiveColor(mat->mEmissiveColor);
+ setEmissiveId(mat->mEmissiveId);
+
+ setDoubleSided(mat->mDoubleSided);
+ setAlphaMode(mat->getAlphaMode());
+}
+
+void LLMaterialEditor::loadAsset()
+{
+ // derived from LLPreviewNotecard::loadAsset
+
+ // TODO: see commented out "editor" references and make them do something appropriate to the UI
+
+ // request the asset.
+ const LLInventoryItem* item = getItem();
+
+ bool fail = false;
+
+ if (item)
+ {
+ LLPermissions perm(item->getPermissions());
+ BOOL is_owner = gAgent.allowOperation(PERM_OWNER, perm, GP_OBJECT_MANIPULATE);
+ BOOL allow_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE);
+ BOOL allow_modify = canModify(mObjectUUID, item);
+ BOOL source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(mItemUUID, gInventory.getLibraryRootFolderID());
+
+ if (allow_copy || gAgent.isGodlike())
+ {
+ mAssetID = item->getAssetUUID();
+ if (mAssetID.isNull())
+ {
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ LLHost source_sim = LLHost();
+ LLSD* user_data = new LLSD();
+
+ if (mObjectUUID.notNull())
+ {
+ LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
+ if (objectp && objectp->getRegion())
+ {
+ source_sim = objectp->getRegion()->getHost();
+ }
+ else
+ {
+ // The object that we're trying to look at disappeared, bail.
+ LL_WARNS() << "Can't find object " << mObjectUUID << " associated with notecard." << LL_ENDL;
+ mAssetID.setNull();
+ /*editor->setText(getString("no_object"));
+ editor->makePristine();
+ editor->setEnabled(FALSE);*/
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ return;
+ }
+ user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);
+ }
+ else
+ {
+ user_data = new LLSD(mItemUUID);
+ }
+
+ gAssetStorage->getInvItemAsset(source_sim,
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getPermissions().getOwner(),
+ mObjectUUID,
+ item->getUUID(),
+ item->getAssetUUID(),
+ item->getType(),
+ &onLoadComplete,
+ (void*)user_data,
+ TRUE);
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ }
+ }
+ else
+ {
+ mAssetID.setNull();
+ /*editor->setText(getString("not_allowed"));
+ editor->makePristine();
+ editor->setEnabled(FALSE);*/
+ mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+
+ if (!allow_modify)
+ {
+ //editor->setEnabled(FALSE);
+ //getChildView("lock")->setVisible(TRUE);
+ //getChildView("Edit")->setEnabled(FALSE);
+ }
+
+ if ((allow_modify || is_owner) && !source_library)
+ {
+ //getChildView("Delete")->setEnabled(TRUE);
+ }
+ }
+ else if (mObjectUUID.notNull() && mItemUUID.notNull())
+ {
+ LLViewerObject* objectp = gObjectList.findObject(mObjectUUID);
+ if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty()))
+ {
+ // It's a material in object's inventory and we failed to get it because inventory is not up to date.
+ // Subscribe for callback and retry at inventoryChanged()
+ registerVOInventoryListener(objectp, NULL); //removes previous listener
+
+ if (objectp->isInventoryDirty())
+ {
+ objectp->requestInventory();
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+ }
+ else
+ {
+ fail = true;
+ }
+
+ if (fail)
+ {
+ /*editor->setText(LLStringUtil::null);
+ editor->makePristine();
+ editor->setEnabled(TRUE);*/
+ // Don't set asset status here; we may not have set the item id yet
+ // (e.g. when this gets called initially)
+ //mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+}
+
+// static
+void LLMaterialEditor::onLoadComplete(const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status)
+{
+ LL_INFOS() << "LLMaterialEditor::onLoadComplete()" << LL_ENDL;
+ LLSD* floater_key = (LLSD*)user_data;
+ LLMaterialEditor* editor = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", *floater_key);
+ if (editor)
+ {
+ if (0 == status)
+ {
+ LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
+
+ S32 file_length = file.getSize();
+
+ std::vector<char> buffer(file_length + 1);
+ file.read((U8*)&buffer[0], file_length);
+
+ editor->decodeAsset(buffer);
+
+ BOOL modifiable = editor->canModify(editor->mObjectID, editor->getItem());
+ editor->setEnabled(modifiable);
+ editor->mAssetStatus = PREVIEW_ASSET_LOADED;
+ }
+ else
+ {
+ if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ LLNotificationsUtil::add("MaterialMissing");
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ LLNotificationsUtil::add("MaterialNoPermissions");
+ }
+ else
+ {
+ LLNotificationsUtil::add("UnableToLoadMaterial");
+ }
+
+ LL_WARNS() << "Problem loading material: " << status << LL_ENDL;
+ editor->mAssetStatus = PREVIEW_ASSET_ERROR;
+ }
+ }
+ delete floater_key;
+}
+
+void LLMaterialEditor::inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data)
+{
+ removeVOInventoryListener();
+ loadAsset();
+}
+
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 7f9c6c0b63..4090ed120b 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -26,22 +26,62 @@
#pragma once
-#include "llfloater.h"
+#include "llpreview.h"
+#include "llvoinventorylistener.h"
class LLTextureCtrl;
-class LLMaterialEditor : public LLFloater
+namespace tinygltf
+{
+ class Model;
+}
+
+class LLGLTFMaterial;
+
+class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
{
public:
LLMaterialEditor(const LLSD& key);
+ bool setFromGltfModel(tinygltf::Model& model, bool set_textures = false);
+
// open a file dialog and select a gltf/glb file for import
void importMaterial();
// for live preview, apply current material to currently selected object
void applyToSelection();
+ void getGLTFMaterial(LLGLTFMaterial* mat);
+
+ void setFromGLTFMaterial(LLGLTFMaterial* mat);
+
+ void loadAsset();
+
+ static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status);
+
+ void inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) override;
+
void onClickSave();
+
+ // get a dump of the json representation of the current state of the editor UI in GLTF format
+ std::string getGLTFJson(bool prettyprint = true);
+
+ void getGLBData(std::vector<U8>& data);
+
+ void getGLTFModel(tinygltf::Model& model);
+
+ std::string getEncodedAsset();
+
+ bool decodeAsset(const std::vector<char>& buffer);
+
+ bool saveIfNeeded(LLInventoryItem* copyitem = nullptr, bool sync = true);
+
+ static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId);
+
+ static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId);
+
+ void refreshFromInventory(const LLUUID& new_item_id = LLUUID::null);
+
void onClickSaveAs();
void onSaveAsMsgCallback(const LLSD& notification, const LLSD& response);
void onClickCancel();
@@ -60,7 +100,8 @@ public:
void setAlbedoColor(const LLColor4& color);
F32 getTransparency();
-
+ void setTransparency(F32 transparency);
+
std::string getAlphaMode();
void setAlphaMode(const std::string& alpha_mode);
@@ -98,6 +139,9 @@ public:
void onCommitNormalTexture(LLUICtrl* ctrl, const LLSD& data);
private:
+ LLUUID mAssetID;
+ LLUUID mObjectID;
+
LLTextureCtrl* mAlbedoTextureCtrl;
LLTextureCtrl* mMetallicTextureCtrl;
LLTextureCtrl* mEmissiveTextureCtrl;
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index d777cde554..2265379ce4 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1731,8 +1731,8 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge,
}
else if ("material" == type_name)
{
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
- create_new_item(NEW_GESTURE_NAME,
+ const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL);
+ create_new_item(NEW_MATERIAL_NAME,
parent_id,
LLAssetType::AT_MATERIAL,
LLInventoryType::IT_MATERIAL,
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index a886303563..375f176b60 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1414,7 +1414,8 @@ bool check_asset_previewable(const LLAssetType::EType asset_type)
(asset_type == LLAssetType::AT_TEXTURE) ||
(asset_type == LLAssetType::AT_ANIMATION) ||
(asset_type == LLAssetType::AT_SCRIPT) ||
- (asset_type == LLAssetType::AT_SOUND);
+ (asset_type == LLAssetType::AT_SOUND) ||
+ (asset_type == LLAssetType::AT_MATERIAL);
}
void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name)
@@ -1519,6 +1520,9 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
case LLAssetType::AT_SOUND:
LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus);
break;
+ case LLAssetType::AT_MATERIAL:
+ LLFloaterReg::showInstance("material editor", LLSD(obj_id), take_focus);
+ break;
default:
LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL;
break;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 67ad72e997..6345323ff9 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -3095,6 +3095,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("UpdateScriptTask");
capabilityNames.append("UpdateSettingsAgentInventory");
capabilityNames.append("UpdateSettingsTaskInventory");
+ capabilityNames.append("UpdateMaterialAgentInventory");
+ capabilityNames.append("UpdateMaterialTaskInventory");
capabilityNames.append("UploadBakedTexture");
capabilityNames.append("UserInfo");
capabilityNames.append("ViewerAsset");
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 0ca3e043e7..ae4b0538d8 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6764,6 +6764,22 @@ You don&apos;t have permission to view this notecard.
<notification
icon="notifytip.tga"
+ name="MaterialMissing"
+ type="notifytip">
+ Material is missing from database.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="MaterialNoPermissions"
+ type="notifytip">
+ You don&apos;t have permission to view this material.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
name="RezItemNoPermissions"
type="notifytip">
Insufficient permissions to rez object.
@@ -6795,6 +6811,15 @@ Please try again.
<notification
icon="notifytip.tga"
+ name="UnableToLoadMaterial"
+ type="notifytip">
+ Unable to load material.
+ Please try again.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
name="ScriptMissing"
type="notifytip">
Script is missing from database.