diff options
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
-rw-r--r-- | indra/newview/llfloaterbulkpermission.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llinventorybridge.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.cpp | 630 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.h | 50 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llviewerregion.cpp | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 25 |
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'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'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. |