summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2022-09-29 22:38:40 +0300
committerAndrey Kleshchev <andreykproductengine@lindenlab.com>2022-09-29 22:39:32 +0300
commit9346b45188462056698083f4f83fe8fecbe19bdf (patch)
tree9d0ac5c1633c27d85ffb9e44d62c6d4f6c1a2a27
parent02df55b9b366f3df98fc4b861dffa779c9d0a536 (diff)
SL-17653 Multi-material file support for local materials
-rw-r--r--indra/newview/llgltfmateriallist.cpp2
-rw-r--r--indra/newview/lllocalgltfmaterials.cpp190
-rw-r--r--indra/newview/lllocalgltfmaterials.h12
-rw-r--r--indra/newview/llmaterialeditor.cpp15
-rw-r--r--indra/newview/llmaterialeditor.h4
-rw-r--r--indra/newview/lltexturectrl.cpp7
-rw-r--r--indra/newview/lltinygltfhelper.cpp33
-rw-r--r--indra/newview/lltinygltfhelper.h2
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);