diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-09-29 22:38:40 +0300 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-09-29 22:39:32 +0300 |
commit | 9346b45188462056698083f4f83fe8fecbe19bdf (patch) | |
tree | 9d0ac5c1633c27d85ffb9e44d62c6d4f6c1a2a27 | |
parent | 02df55b9b366f3df98fc4b861dffa779c9d0a536 (diff) |
SL-17653 Multi-material file support for local materials
-rw-r--r-- | indra/newview/llgltfmateriallist.cpp | 2 | ||||
-rw-r--r-- | indra/newview/lllocalgltfmaterials.cpp | 190 | ||||
-rw-r--r-- | indra/newview/lllocalgltfmaterials.h | 12 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.cpp | 15 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.h | 4 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.cpp | 7 | ||||
-rw-r--r-- | indra/newview/lltinygltfhelper.cpp | 33 | ||||
-rw-r--r-- | indra/newview/lltinygltfhelper.h | 2 |
8 files changed, 173 insertions, 92 deletions
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index b2d223a3e8..5cbf853179 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -92,7 +92,7 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id) if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), "")) { - LLTinyGLTFHelper::setFromModel(mat, model_in); + LLTinyGLTFHelper::setFromModel(mat, model_in, 0); } else { diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 524693e7ea..6e6671d360 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -59,70 +59,76 @@ static const S32 LL_LOCAL_UPDATE_RETRIES = 5; /*=======================================*/ /* LLLocalGLTFMaterial: unit class */ /*=======================================*/ -LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename) - : mFilename(filename) - , mShortName(gDirUtilp->getBaseFileName(filename, true)) - , mValid(false) - , mLastModified() - , mLinkStatus(LS_ON) - , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) +LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename, S32 index) + : mFilename(filename) + , mShortName(gDirUtilp->getBaseFileName(filename, true)) + , mValid(false) + , mLastModified() + , mLinkStatus(LS_ON) + , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) + , mMaterialIndex(index) { - mTrackingID.generate(); + mTrackingID.generate(); - /* extension */ - std::string temp_exten = gDirUtilp->getExtension(mFilename); + /* extension */ + std::string temp_exten = gDirUtilp->getExtension(mFilename); - if (temp_exten == "gltf") - { - mExtension = ET_MATERIAL_GLTF; - } - else if (temp_exten == "glb") - { - mExtension = ET_MATERIAL_GLB; - } - else - { - LL_WARNS() << "File of no valid extension given, local material creation aborted." << "\n" - << "Filename: " << mFilename << LL_ENDL; - return; // no valid extension. - } + if (temp_exten == "gltf") + { + mExtension = ET_MATERIAL_GLTF; + } + else if (temp_exten == "glb") + { + mExtension = ET_MATERIAL_GLB; + } + else + { + LL_WARNS() << "File of no valid extension given, local material creation aborted." << "\n" + << "Filename: " << mFilename << LL_ENDL; + return; // no valid extension. + } - /* next phase of unit creation is nearly the same as an update cycle. - we're running updateSelf as a special case with the optional UT_FIRSTUSE - which omits the parts associated with removing the outdated texture */ - mValid = updateSelf(); + /* next phase of unit creation is nearly the same as an update cycle. + we're running updateSelf as a special case with the optional UT_FIRSTUSE + which omits the parts associated with removing the outdated texture */ + mValid = updateSelf(); } LLLocalGLTFMaterial::~LLLocalGLTFMaterial() { - // delete self from material list + // delete self from material list gGLTFMaterialList.removeMaterial(mWorldID); } /* accessors */ std::string LLLocalGLTFMaterial::getFilename() { - return mFilename; + return mFilename; } std::string LLLocalGLTFMaterial::getShortName() { - return mShortName; + return mShortName; } LLUUID LLLocalGLTFMaterial::getTrackingID() { - return mTrackingID; + return mTrackingID; } LLUUID LLLocalGLTFMaterial::getWorldID() { - return mWorldID; + return mWorldID; +} + +S32 LLLocalGLTFMaterial::getIndexInFile() +{ + return mMaterialIndex; } bool LLLocalGLTFMaterial::getValid() { - return mValid; + return mValid; } /* update functions */ @@ -147,7 +153,7 @@ bool LLLocalGLTFMaterial::updateSelf() if (mLastModified.asString() != new_last_modified.asString()) { LLPointer<LLGLTFMaterial> raw_material = new LLGLTFMaterial(); - if (loadMaterial(raw_material)) + if (loadMaterial(raw_material, mMaterialIndex)) { // decode is successful, we can safely proceed. if (mWorldID.isNull()) @@ -207,7 +213,7 @@ bool LLLocalGLTFMaterial::updateSelf() return updated; } -bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat) +bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat, S32 index) { bool decode_successful = false; @@ -238,26 +244,31 @@ bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat) if (!decode_successful) { - LL_WARNS() << "Cannot Upload Material, error: " << error_msg + LL_WARNS() << "Cannot load Material, error: " << error_msg << ", warning:" << warn_msg << " file: " << mFilename << LL_ENDL; break; } - if (model_in.materials.empty()) + if (model_in.materials.size() <= index) { // materials are missing - LL_WARNS() << "Cannot Upload Material, Material missing, " << mFilename << LL_ENDL; + LL_WARNS() << "Cannot load Material, Material " << index << " is missing, " << mFilename << LL_ENDL; decode_successful = false; break; } // sets everything, but textures will have inaccurate ids - LLTinyGLTFHelper::setFromModel(mat, model_in); + LLTinyGLTFHelper::setFromModel(mat, model_in, index); std::string folder = gDirUtilp->getDirName(filename_lc); - tinygltf::Material material_in = model_in.materials[0]; + tinygltf::Material material_in = model_in.materials[index]; + + if (!material_in.name.empty()) + { + mShortName = material_in.name; + } // get base color texture LLPointer<LLImageRaw> base_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); @@ -362,44 +373,95 @@ LLLocalGLTFMaterialMgr::~LLLocalGLTFMaterialMgr() mMaterialList.clear(); } -bool LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames) +S32 LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames) { - bool add_successful = false; + S32 add_count = 0; std::vector<std::string>::const_iterator iter = filenames.begin(); while (iter != filenames.end()) { - if (!iter->empty() && addUnit(*iter).notNull()) + if (!iter->empty()) { - add_successful = true; + add_count += addUnit(*iter); } iter++; } - return add_successful; + return add_count; } -LLUUID LLLocalGLTFMaterialMgr::addUnit(const std::string& filename) +S32 LLLocalGLTFMaterialMgr::addUnit(const std::string& filename) { - LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename); + std::string exten = gDirUtilp->getExtension(filename); + S32 materials_in_file = 0; - if (unit->getValid()) + if (exten == "gltf" || exten == "glb") { - mMaterialList.push_back(unit); - return unit->getTrackingID(); + 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() << "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() << "Cannot load. File has no materials " << filename << LL_ENDL; + return 0; + } + materials_in_file = model_in.materials.size(); } - else + + S32 loaded_materials = 0; + for (S32 i = 0; i < materials_in_file; i++) { - LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" - << "Filename: " << filename << LL_ENDL; + // Todo: this is rather inefficient, files will be spammed with + // separate loads and date checks, find a way to improve this. + // May be doUpdates() should be checking individual files. + LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename, i); + + if (unit->getValid()) + { + mMaterialList.push_back(unit); + loaded_materials++; + } + else + { + LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" + << "Filename: " << filename << LL_ENDL; - LLSD notif_args; - notif_args["FNAME"] = filename; - LLNotificationsUtil::add("LocalGLTFVerifyFail", notif_args); + LLSD notif_args; + notif_args["FNAME"] = filename; + LLNotificationsUtil::add("LocalGLTFVerifyFail", notif_args); - delete unit; - unit = NULL; + delete unit; + unit = NULL; + } } - return LLUUID::null; + return loaded_materials; } void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id) @@ -456,9 +518,10 @@ bool LLLocalGLTFMaterialMgr::isLocal(const LLUUID world_id) return false; } -std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id) +void LLLocalGLTFMaterialMgr::getFilenameAndIndex(LLUUID tracking_id, std::string &filename, S32 &index) { - std::string filename = ""; + filename = ""; + index = 0; for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) { @@ -466,10 +529,9 @@ std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id) if (unit->getTrackingID() == tracking_id) { filename = unit->getFilename(); + index = unit->getIndexInFile(); } } - - return filename; } // probably shouldn't be here, but at the moment this mirrors lllocalbitmaps diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index de775615a8..f762dcc2ce 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -38,7 +38,7 @@ class LLViewerFetchedTexture; class LLLocalGLTFMaterial { public: /* main */ - LLLocalGLTFMaterial(std::string filename); + LLLocalGLTFMaterial(std::string filename, S32 index); ~LLLocalGLTFMaterial(); public: /* accessors */ @@ -46,13 +46,14 @@ public: /* accessors */ std::string getShortName(); LLUUID getTrackingID(); LLUUID getWorldID(); + S32 getIndexInFile(); bool getValid(); public: bool updateSelf(); private: - bool loadMaterial(LLPointer<LLGLTFMaterial> raw); + bool loadMaterial(LLPointer<LLGLTFMaterial> raw, S32 index); private: /* private enums */ enum ELinkStatus @@ -77,6 +78,7 @@ private: /* members */ EExtension mExtension; ELinkStatus mLinkStatus; S32 mUpdateRetries; + S32 mMaterialIndex; // Single file can have more than one // material needs to maintain textures LLPointer<LLViewerFetchedTexture> mBaseColorFetched; @@ -103,13 +105,13 @@ class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr> LLSINGLETON(LLLocalGLTFMaterialMgr); ~LLLocalGLTFMaterialMgr(); public: - bool addUnit(const std::vector<std::string>& filenames); - LLUUID addUnit(const std::string& filename); + S32 addUnit(const std::vector<std::string>& filenames); + S32 addUnit(const std::string& filename); // file can hold multiple materials void delUnit(LLUUID tracking_id); LLUUID getWorldID(LLUUID tracking_id); bool isLocal(LLUUID world_id); - std::string getFilename(LLUUID tracking_id); + void getFilenameAndIndex(LLUUID tracking_id, std::string &filename, S32 &index); void feedScrollList(LLScrollListCtrl* ctrl); void doUpdates(); diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 27694e9ce4..7270317b8c 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1176,6 +1176,8 @@ void LLMaterialFilePicker::notify(const std::vector<std::string>& filenames) if (filenames.size() > 0) { + // Todo: there is no point creating LLMaterialEditor before + // loading material, just creates unnessesary work if decode fails LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); if (me) { @@ -1235,7 +1237,7 @@ void LLMaterialFilePicker::textureLoadedCallback(BOOL success, LLViewerFetchedTe { } -void LLMaterialEditor::loadMaterialFromFile(const std::string& filename) +void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index) { tinygltf::TinyGLTF loader; std::string error_msg; @@ -1264,19 +1266,26 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename) return; } - if (model_in.materials.empty()) + if (model_in.materials.empty() || (index >= model_in.materials.size())) { // materials are missing LLNotificationsUtil::add("CannotUploadMaterial"); return; } - if (model_in.materials.size() == 1) + if (index >= 0) { + // Prespecified material + loadMaterial(model_in, filename_lc, index); + } + else if (model_in.materials.size() == 1) + { + // Only one, just load it loadMaterial(model_in, filename_lc, 0); } else { + // Promt user to select material std::list<std::string> material_list; std::vector<tinygltf::Material>::const_iterator mat_iter = model_in.materials.begin(); std::vector<tinygltf::Material>::const_iterator mat_end = model_in.materials.end(); diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index c6b976ea5a..23cfc93763 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -101,7 +101,9 @@ public: void setFromGLTFMaterial(LLGLTFMaterial* mat); void loadAsset() override; - void loadMaterialFromFile(const std::string& filename); + // @index if -1 and file contains more than one material, + // will promt to select specific one + void loadMaterialFromFile(const std::string& filename, S32 index = -1); static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index f4649a672b..ff0d74a7c9 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -965,13 +965,16 @@ void LLFloaterTexturePicker::onBtnUpload(void* userdata) if (LLAssetType::AT_MATERIAL == asset_type) { - std::string filename = LLLocalGLTFMaterialMgr::getInstance()->getFilename(tracking_id); + std::string filename; + S32 index; + LLLocalGLTFMaterialMgr::getInstance()->getFilenameAndIndex(tracking_id, filename, index); if (!filename.empty()) { LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); if (me) { - me->loadMaterialFromFile(filename); + me->loadMaterialFromFile(filename, index); + me->setFocus(TRUE); } } } diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 3125cacbd5..c3dc10c2a0 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -122,17 +122,20 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, } } -void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) +void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model, S32 mat_index) { - S32 index; + if (model.materials.size() <= mat_index) + { + return; + } - auto& material_in = model.materials[0]; + tinygltf::Material& material_in = model.materials[mat_index]; // get base color texture - index = material_in.pbrMetallicRoughness.baseColorTexture.index; - if (index >= 0) + S32 tex_index = material_in.pbrMetallicRoughness.baseColorTexture.index; + if (tex_index >= 0) { - mat->mBaseColorId.set(model.images[index].uri); + mat->mBaseColorId.set(model.images[tex_index].uri); } else { @@ -140,10 +143,10 @@ void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) } // get normal map - index = material_in.normalTexture.index; - if (index >= 0) + tex_index = material_in.normalTexture.index; + if (tex_index >= 0) { - mat->mNormalId.set(model.images[index].uri); + mat->mNormalId.set(model.images[tex_index].uri); } else { @@ -151,10 +154,10 @@ void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) } // get metallic-roughness texture - index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; - if (index >= 0) + tex_index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (tex_index >= 0) { - mat->mMetallicRoughnessId.set(model.images[index].uri); + mat->mMetallicRoughnessId.set(model.images[tex_index].uri); } else { @@ -162,10 +165,10 @@ void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) } // get emissive texture - index = material_in.emissiveTexture.index; - if (index >= 0) + tex_index = material_in.emissiveTexture.index; + if (tex_index >= 0) { - mat->mEmissiveId.set(model.images[index].uri); + mat->mEmissiveId.set(model.images[tex_index].uri); } else { diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h index 89e09b189e..afe4517417 100644 --- a/indra/newview/lltinygltfhelper.h +++ b/indra/newview/lltinygltfhelper.h @@ -35,7 +35,7 @@ class LLViewerFetchedTexture; namespace LLTinyGLTFHelper { - void setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model); + void setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model, S32 index); LLColor4 getColor(const std::vector<double>& in); const tinygltf::Image* getImageFromTextureIndex(const tinygltf::Model& model, S32 texture_index); LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name); |