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); | 
