summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llrender/llshadermgr.cpp2
-rw-r--r--indra/newview/CMakeLists.txt4
-rw-r--r--indra/newview/llfloaterautoreplacesettings.cpp4
-rw-r--r--indra/newview/llfloatereditextdaycycle.cpp2
-rw-r--r--indra/newview/llfloaterfixedenvironment.cpp4
-rw-r--r--indra/newview/llfloaterspellchecksettings.cpp2
-rw-r--r--indra/newview/llfloateruipreview.cpp4
-rw-r--r--indra/newview/llgltfmateriallist.cpp87
-rw-r--r--indra/newview/llgltfmateriallist.h3
-rw-r--r--indra/newview/llinventorypanel.cpp62
-rw-r--r--indra/newview/llinventorypanel.h7
-rw-r--r--indra/newview/lllocalbitmaps.cpp93
-rw-r--r--indra/newview/lllocalbitmaps.h2
-rw-r--r--indra/newview/lllocalgltfmaterials.cpp546
-rw-r--r--indra/newview/lllocalgltfmaterials.h125
-rw-r--r--indra/newview/llmaterialeditor.cpp216
-rw-r--r--indra/newview/llmaterialeditor.h3
-rw-r--r--indra/newview/lloutfitgallery.cpp2
-rw-r--r--indra/newview/llplacesinventorypanel.h2
-rw-r--r--indra/newview/llpreviewscript.cpp4
-rw-r--r--indra/newview/llpreviewtexture.cpp2
-rw-r--r--indra/newview/lltexturectrl.cpp254
-rw-r--r--indra/newview/lltexturectrl.h5
-rw-r--r--indra/newview/lltinygltfhelper.cpp245
-rw-r--r--indra/newview/lltinygltfhelper.h55
-rw-r--r--indra/newview/llviewermenufile.cpp24
-rw-r--r--indra/newview/llviewermenufile.h12
-rw-r--r--indra/newview/llviewershadermgr.cpp21
-rw-r--r--indra/newview/llviewershadermgr.h6
-rw-r--r--indra/newview/llviewertexturelist.h6
-rw-r--r--indra/newview/llviewerwindow.cpp4
-rw-r--r--indra/newview/skins/default/xui/en/floater_my_environments.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_settings_picker.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_texture_ctrl.xml36
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml9
35 files changed, 1478 insertions, 379 deletions
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 686eaddc24..96fb764f75 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -673,7 +673,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (file == NULL)
{
- LL_SHADER_LOADING_WARNS() << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
+ LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << open_file_name << LL_ENDL;
return 0;
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b67bc91277..950697a72a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -394,6 +394,7 @@ set(viewer_SOURCE_FILES
lllistcontextmenu.cpp
lllistview.cpp
lllocalbitmaps.cpp
+ lllocalgltfmaterials.cpp
lllocationhistory.cpp
lllocationinputctrl.cpp
lllogchat.cpp
@@ -607,6 +608,7 @@ set(viewer_SOURCE_FILES
lltextureinfodetails.cpp
lltexturestats.cpp
lltextureview.cpp
+ lltinygltfhelper.cpp
lltoast.cpp
lltoastalertpanel.cpp
lltoastgroupnotifypanel.cpp
@@ -1036,6 +1038,7 @@ set(viewer_HEADER_FILES
lllistcontextmenu.h
lllistview.h
lllocalbitmaps.h
+ lllocalgltfmaterials.h
lllocationhistory.h
lllocationinputctrl.h
lllogchat.h
@@ -1240,6 +1243,7 @@ set(viewer_HEADER_FILES
lltextureinfodetails.h
lltexturestats.h
lltextureview.h
+ lltinygltfhelper.h
lltoast.h
lltoastalertpanel.h
lltoastgroupnotifypanel.h
diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp
index ec05ba924c..0964daa4d5 100644
--- a/indra/newview/llfloaterautoreplacesettings.cpp
+++ b/indra/newview/llfloaterautoreplacesettings.cpp
@@ -350,7 +350,7 @@ void LLFloaterAutoReplaceSettings::onDeleteEntry()
// called when the Import List button is pressed
void LLFloaterAutoReplaceSettings::onImportList()
{
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterAutoReplaceSettings::loadListFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::loadListFromFile, this, _1), LLFilePicker::FFLOAD_XML, false);
}
void LLFloaterAutoReplaceSettings::loadListFromFile(const std::vector<std::string>& filenames)
@@ -537,7 +537,7 @@ void LLFloaterAutoReplaceSettings::onExportList()
{
std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString();
std::string listFileName = listName + ".xml";
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterAutoReplaceSettings::saveListToFile, this, _1, listName), LLFilePicker::FFSAVE_XML, listFileName))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::saveListToFile, this, _1, listName), LLFilePicker::FFSAVE_XML, listFileName);
}
void LLFloaterAutoReplaceSettings::saveListToFile(const std::vector<std::string>& filenames, std::string listName)
diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp
index 24673d5a7c..a6a825500d 100644
--- a/indra/newview/llfloatereditextdaycycle.cpp
+++ b/indra/newview/llfloatereditextdaycycle.cpp
@@ -1523,7 +1523,7 @@ bool LLFloaterEditExtDayCycle::isAddingFrameAllowed()
void LLFloaterEditExtDayCycle::doImportFromDisk()
{ // Load a a legacy Windlight XML from disk.
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterEditExtDayCycle::loadSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterEditExtDayCycle::loadSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false);
}
void LLFloaterEditExtDayCycle::loadSettingFromFile(const std::vector<std::string>& filenames)
diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp
index fec218ca3b..68bb458e61 100644
--- a/indra/newview/llfloaterfixedenvironment.cpp
+++ b/indra/newview/llfloaterfixedenvironment.cpp
@@ -439,7 +439,7 @@ void LLFloaterFixedEnvironmentWater::onOpen(const LLSD& key)
void LLFloaterFixedEnvironmentWater::doImportFromDisk()
{ // Load a a legacy Windlight XML from disk.
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false);
}
void LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile(const std::vector<std::string>& filenames)
@@ -525,7 +525,7 @@ void LLFloaterFixedEnvironmentSky::onClose(bool app_quitting)
void LLFloaterFixedEnvironmentSky::doImportFromDisk()
{ // Load a a legacy Windlight XML from disk.
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentSky::loadSkySettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterFixedEnvironmentSky::loadSkySettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false);
}
void LLFloaterFixedEnvironmentSky::loadSkySettingFromFile(const std::vector<std::string>& filenames)
diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp
index de5d59f484..32eb70cd39 100644
--- a/indra/newview/llfloaterspellchecksettings.cpp
+++ b/indra/newview/llfloaterspellchecksettings.cpp
@@ -259,7 +259,7 @@ BOOL LLFloaterSpellCheckerImport::postBuild(void)
void LLFloaterSpellCheckerImport::onBtnBrowse()
{
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterSpellCheckerImport::importSelectedDictionary, this, _1), LLFilePicker::FFLOAD_DICTIONARY, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterSpellCheckerImport::importSelectedDictionary, this, _1), LLFilePicker::FFLOAD_DICTIONARY, false);
}
void LLFloaterSpellCheckerImport::importSelectedDictionary(const std::vector<std::string>& filenames)
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index e67c79a3a0..67a205417e 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -1023,7 +1023,7 @@ void LLFloaterUIPreview::onClickEditFloater()
void LLFloaterUIPreview::onClickBrowseForEditor()
{
// Let the user choose an executable through the file picker dialog box
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false);
}
void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filenames)
@@ -1077,7 +1077,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filen
void LLFloaterUIPreview::onClickBrowseForDiffs()
{
// create load dialog box
- (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false);
}
void LLFloaterUIPreview::getDiffsFilePath(const std::vector<std::string>& filenames)
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 96c29d7ed2..af00cdd05f 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -30,86 +30,13 @@
#include "llassetstorage.h"
#include "llfilesystem.h"
#include "llsdserialize.h"
+#include "lltinygltfhelper.h"
#include "tinygltf/tiny_gltf.h"
#include <strstream>
LLGLTFMaterialList gGLTFMaterialList;
-static LLColor4 get_color(const std::vector<double>& in)
-{
- LLColor4 out;
- for (S32 i = 0; i < llmin((S32)in.size(), 4); ++i)
- {
- out.mV[i] = in[i];
- }
-
- return out;
-}
-
-static void set_from_model(LLGLTFMaterial* mat, tinygltf::Model& model)
-{
-
- S32 index;
-
- auto& material_in = model.materials[0];
-
- // get albedo texture
- index = material_in.pbrMetallicRoughness.baseColorTexture.index;
- if (index >= 0)
- {
- mat->mAlbedoId.set(model.images[index].uri);
- }
- else
- {
- mat->mAlbedoId.setNull();
- }
-
- // get normal map
- index = material_in.normalTexture.index;
- if (index >= 0)
- {
- mat->mNormalId.set(model.images[index].uri);
- }
- else
- {
- mat->mNormalId.setNull();
- }
-
- // get metallic-roughness texture
- index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index;
- if (index >= 0)
- {
- mat->mMetallicRoughnessId.set(model.images[index].uri);
- }
- else
- {
- mat->mMetallicRoughnessId.setNull();
- }
-
- // get emissive texture
- index = material_in.emissiveTexture.index;
- if (index >= 0)
- {
- mat->mEmissiveId.set(model.images[index].uri);
- }
- else
- {
- mat->mEmissiveId.setNull();
- }
-
- mat->setAlphaMode(material_in.alphaMode);
- mat->mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f);
-
- mat->mAlbedoColor = get_color(material_in.pbrMetallicRoughness.baseColorFactor);
- mat->mEmissiveColor = get_color(material_in.emissiveFactor);
-
- mat->mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f);
- mat->mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f);
-
- mat->mDoubleSided = material_in.doubleSided;
-}
-
LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
{
List::iterator iter = mList.find(id);
@@ -158,7 +85,7 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), ""))
{
- set_from_model(mat, model_in);
+ LLTinyGLTFHelper::setFromModel(mat, model_in);
}
else
{
@@ -184,3 +111,13 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
return iter->second;
}
+void LLGLTFMaterialList::addMaterial(const LLUUID& id, LLGLTFMaterial* material)
+{
+ mList[id] = material;
+}
+
+void LLGLTFMaterialList::removeMaterial(const LLUUID& id)
+{
+ mList.erase(id);
+}
+
diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h
index c22134c468..49760504e6 100644
--- a/indra/newview/llgltfmateriallist.h
+++ b/indra/newview/llgltfmateriallist.h
@@ -41,6 +41,9 @@ public:
LLGLTFMaterial* getMaterial(const LLUUID& id);
+ void addMaterial(const LLUUID& id, LLGLTFMaterial* material);
+ void removeMaterial(const LLUUID& id);
+
};
extern LLGLTFMaterialList gGLTFMaterialList;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 6b102c7500..cd24b3ea43 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -2010,7 +2010,43 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
void LLAssetFilteredInventoryPanel::initFromParams(const Params& p)
{
- mAssetType = LLAssetType::lookup(p.filter_asset_type.getValue());
+ // Init asset types
+ std::string types = p.filter_asset_types.getValue();
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|");
+ tokenizer tokens(types, sep);
+ tokenizer::iterator token_iter = tokens.begin();
+
+ memset(mAssetTypes, 0, LLAssetType::AT_COUNT * sizeof(bool));
+ while (token_iter != tokens.end())
+ {
+ const std::string& token_str = *token_iter;
+ LLAssetType::EType asset_type = LLAssetType::lookup(token_str);
+ if (asset_type > LLAssetType::AT_NONE && asset_type < LLAssetType::AT_COUNT)
+ {
+ mAssetTypes[asset_type] = true;
+ }
+ ++token_iter;
+ }
+
+ // Init drag types
+ memset(mDragTypes, 0, EDragAndDropType::DAD_COUNT * sizeof(bool));
+ for (S32 i = 0; i < LLAssetType::AT_COUNT; i++)
+ {
+ if (mAssetTypes[i])
+ {
+ EDragAndDropType drag_type = LLViewerAssetType::lookupDragAndDropType((LLAssetType::EType)i);
+ if (drag_type != DAD_NONE)
+ {
+ mDragTypes[drag_type] = true;
+ }
+ }
+ }
+ // Always show AT_CATEGORY, but it shouldn't get into mDragTypes
+ mAssetTypes[LLAssetType::AT_CATEGORY] = true;
+
+ // Init the panel
LLInventoryPanel::initFromParams(p);
U64 filter_cats = getFilter().getFilterCategoryTypes();
filter_cats &= ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS);
@@ -2028,10 +2064,9 @@ BOOL LLAssetFilteredInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, B
if (mAcceptsDragAndDrop)
{
- EDragAndDropType allow_type = LLViewerAssetType::lookupDragAndDropType(mAssetType);
// Don't allow DAD_CATEGORY here since it can contain other items besides required assets
// We should see everything we drop!
- if (allow_type == cargo_type)
+ if (mDragTypes[cargo_type])
{
result = LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
}
@@ -2047,8 +2082,14 @@ bool LLAssetFilteredInventoryPanel::typedViewsFilter(const LLUUID& id, LLInvento
{
return false;
}
+ LLAssetType::EType asset_type = objectp->getType();
- if (objectp->getType() != mAssetType && objectp->getType() != LLAssetType::AT_CATEGORY)
+ if (asset_type < 0 || asset_type >= LLAssetType::AT_COUNT)
+ {
+ return false;
+ }
+
+ if (!mAssetTypes[asset_type])
{
return false;
}
@@ -2064,11 +2105,16 @@ void LLAssetFilteredInventoryPanel::itemChanged(const LLUUID& id, U32 mask, cons
return;
}
- if (model_item
- && model_item->getType() != mAssetType
- && model_item->getType() != LLAssetType::AT_CATEGORY)
+ if (model_item)
{
- return;
+ LLAssetType::EType asset_type = model_item->getType();
+
+ if (asset_type < 0
+ || asset_type >= LLAssetType::AT_COUNT
+ || !mAssetTypes[asset_type])
+ {
+ return;
+ }
}
LLInventoryPanel::itemChanged(id, mask, model_item);
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 552c61b915..d5219a22e7 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -393,9 +393,9 @@ public:
struct Params
: public LLInitParam::Block<Params, LLInventoryPanel::Params>
{
- Mandatory<std::string> filter_asset_type;
+ Mandatory<std::string> filter_asset_types;
- Params() : filter_asset_type("filter_asset_type") {}
+ Params() : filter_asset_types("filter_asset_types") {}
};
void initFromParams(const Params& p);
@@ -416,7 +416,8 @@ protected:
/*virtual*/ void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override;
private:
- LLAssetType::EType mAssetType;
+ bool mAssetTypes[LLAssetType::AT_COUNT];
+ bool mDragTypes[EDragAndDropType::DAD_COUNT];
};
#endif // LL_LLINVENTORYPANEL_H
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 5a17332fde..c3e3fd5c1b 100644
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -62,6 +62,7 @@
#include "pipeline.h"
#include "llmaterialmgr.h"
#include "llimagedimensionsinfo.h"
+#include "llinventoryicon.h"
#include "llviewercontrol.h"
#include "lltrans.h"
#include "llviewerdisplay.h"
@@ -931,32 +932,7 @@ bool LLLocalBitmapMgr::addUnit()
std::string filename = picker.getFirstFile();
while(!filename.empty())
{
- if(!checkTextureDimensions(filename))
- {
- filename = picker.getNextFile();
- continue;
- }
-
- LLLocalBitmap* unit = new LLLocalBitmap(filename);
-
- if (unit->getValid())
- {
- mBitmapList.push_back(unit);
- add_successful = true;
- }
- 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("LocalBitmapsVerifyFail", notif_args);
-
- delete unit;
- unit = NULL;
- }
-
+ add_successful |= addUnit(filename);
filename = picker.getNextFile();
}
@@ -965,6 +941,49 @@ bool LLLocalBitmapMgr::addUnit()
return add_successful;
}
+bool LLLocalBitmapMgr::addUnit(const std::vector<std::string>& filenames)
+{
+ bool add_successful = false;
+ std::vector<std::string>::const_iterator iter = filenames.begin();
+ while (iter != filenames.end())
+ {
+ if (!iter->empty())
+ {
+ add_successful |= addUnit(*iter);
+ }
+ iter++;
+ }
+ return add_successful;
+}
+
+bool LLLocalBitmapMgr::addUnit(const std::string& filename)
+{
+ if (!checkTextureDimensions(filename))
+ {
+ return false;
+ }
+
+ LLLocalBitmap* unit = new LLLocalBitmap(filename);
+
+ if (unit->getValid())
+ {
+ mBitmapList.push_back(unit);
+ return true;
+ }
+ 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("LocalBitmapsVerifyFail", notif_args);
+
+ delete unit;
+ unit = NULL;
+ return false;
+ }
+}
bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename)
{
@@ -1071,7 +1090,9 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl)
{
if (ctrl)
{
- ctrl->clearRows();
+ std::string icon_name = LLInventoryIcon::getIconName(
+ LLAssetType::AT_TEXTURE,
+ LLInventoryType::IT_NONE);
if (!mBitmapList.empty())
{
@@ -1079,13 +1100,19 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl)
iter != mBitmapList.end(); iter++)
{
LLSD element;
- element["columns"][0]["column"] = "unit_name";
- element["columns"][0]["type"] = "text";
- element["columns"][0]["value"] = (*iter)->getShortName();
- element["columns"][1]["column"] = "unit_id_HIDDEN";
- element["columns"][1]["type"] = "text";
- element["columns"][1]["value"] = (*iter)->getTrackingID();
+ element["columns"][0]["column"] = "icon";
+ element["columns"][0]["type"] = "icon";
+ element["columns"][0]["value"] = icon_name;
+
+ element["columns"][1]["column"] = "unit_name";
+ element["columns"][1]["type"] = "text";
+ element["columns"][1]["value"] = (*iter)->getShortName();
+
+ LLSD data;
+ data["id"] = (*iter)->getTrackingID();
+ data["type"] = (S32)LLAssetType::AT_TEXTURE;
+ element["value"] = data;
ctrl->addElement(element);
}
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index def5a6bd6e..362d47142d 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -116,6 +116,8 @@ class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr>
~LLLocalBitmapMgr();
public:
bool addUnit();
+ bool addUnit(const std::vector<std::string>& filenames);
+ bool addUnit(const std::string& filename);
void delUnit(LLUUID tracking_id);
bool checkTextureDimensions(std::string filename);
diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp
new file mode 100644
index 0000000000..ef488e9ef4
--- /dev/null
+++ b/indra/newview/lllocalgltfmaterials.cpp
@@ -0,0 +1,546 @@
+/**
+ * @file lllocalrendermaterials.cpp
+ * @brief Local GLTF materials source
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+/* precompiled headers */
+#include "llviewerprecompiledheaders.h"
+
+/* own header */
+#include "lllocalgltfmaterials.h"
+
+/* boost: will not compile unless equivalent is undef'd, beware. */
+#include "fix_macros.h"
+#include <boost/filesystem.hpp>
+
+/* time headers */
+#include <time.h>
+#include <ctime>
+
+/* misc headers */
+#include "llfilepicker.h"
+#include "llgltfmateriallist.h"
+#include "llimage.h"
+#include "llinventoryicon.h"
+#include "llmaterialmgr.h"
+#include "llnotificationsutil.h"
+#include "llscrolllistctrl.h"
+#include "lltinygltfhelper.h"
+#include "llviewertexture.h"
+#include "tinygltf/tiny_gltf.h"
+
+/*=======================================*/
+/* Formal declarations, constants, etc. */
+/*=======================================*/
+
+static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0;
+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)
+{
+ mTrackingID.generate();
+
+ /* 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.
+ }
+
+ /* 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
+ gGLTFMaterialList.removeMaterial(mWorldID);
+}
+
+/* accessors */
+std::string LLLocalGLTFMaterial::getFilename()
+{
+ return mFilename;
+}
+
+std::string LLLocalGLTFMaterial::getShortName()
+{
+ return mShortName;
+}
+
+LLUUID LLLocalGLTFMaterial::getTrackingID()
+{
+ return mTrackingID;
+}
+
+LLUUID LLLocalGLTFMaterial::getWorldID()
+{
+ return mWorldID;
+}
+
+bool LLLocalGLTFMaterial::getValid()
+{
+ return mValid;
+}
+
+/* update functions */
+bool LLLocalGLTFMaterial::updateSelf()
+{
+ bool updated = false;
+
+ if (mLinkStatus == LS_ON)
+ {
+ // verifying that the file exists
+ if (gDirUtilp->fileExists(mFilename))
+ {
+ // verifying that the file has indeed been modified
+
+#ifndef LL_WINDOWS
+ const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename));
+#else
+ const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename)));
+#endif
+ LLSD new_last_modified = asctime(localtime(&temp_time));
+
+ if (mLastModified.asString() != new_last_modified.asString())
+ {
+ LLPointer<LLGLTFMaterial> raw_material = new LLGLTFMaterial();
+ if (loadMaterial(raw_material))
+ {
+ // decode is successful, we can safely proceed.
+ if (mWorldID.isNull())
+ {
+ mWorldID.generate();
+ }
+ mLastModified = new_last_modified;
+
+ // will replace material if it already exists
+ gGLTFMaterialList.addMaterial(mWorldID, raw_material);
+
+ mUpdateRetries = LL_LOCAL_UPDATE_RETRIES;
+ updated = true;
+ }
+
+ // if decoding failed, we get here and it will attempt to decode it in the next cycles
+ // until mUpdateRetries runs out. this is done because some software lock the material while writing to it
+ else
+ {
+ if (mUpdateRetries)
+ {
+ mUpdateRetries--;
+ }
+ else
+ {
+ LL_WARNS() << "During the update process the following file was found" << "\n"
+ << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n"
+ << "Filename: " << mFilename << "\n"
+ << "Disabling further update attempts for this file." << LL_ENDL;
+
+ LLSD notif_args;
+ notif_args["FNAME"] = mFilename;
+ notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES;
+ LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args);
+
+ mLinkStatus = LS_BROKEN;
+ }
+ }
+ }
+
+ } // end if file exists
+
+ else
+ {
+ LL_WARNS() << "During the update process, the following file was not found." << "\n"
+ << "Filename: " << mFilename << "\n"
+ << "Disabling further update attempts for this file." << LL_ENDL;
+
+ LLSD notif_args;
+ notif_args["FNAME"] = mFilename;
+ LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args);
+
+ mLinkStatus = LS_BROKEN;
+ }
+ }
+
+ return updated;
+}
+
+bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat)
+{
+ bool decode_successful = false;
+
+ switch (mExtension)
+ {
+ case ET_MATERIAL_GLTF:
+ case ET_MATERIAL_GLB:
+ {
+ tinygltf::TinyGLTF loader;
+ std::string error_msg;
+ std::string warn_msg;
+
+ tinygltf::Model model_in;
+
+ std::string filename_lc = mFilename;
+ 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.
+ 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 Upload Material, error: " << error_msg
+ << ", warning:" << warn_msg
+ << " file: " << mFilename
+ << LL_ENDL;
+ break;
+ }
+
+ if (model_in.materials.empty())
+ {
+ // materials are missing
+ LL_WARNS() << "Cannot Upload Material, Material missing, " << mFilename << LL_ENDL;
+ decode_successful = false;
+ break;
+ }
+
+ // sets everything, but textures will have inaccurate ids
+ LLTinyGLTFHelper::setFromModel(mat, model_in);
+
+ std::string folder = gDirUtilp->getDirName(filename_lc);
+ tinygltf::Material material_in = model_in.materials[0];
+
+ // get albedo texture
+ LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index);
+ // get normal map
+ LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index);
+ // get metallic-roughness texture
+ LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index);
+ // get emissive texture
+ LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index);
+ // get occlusion map if needed
+ LLPointer<LLImageRaw> occlusion_img;
+ if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index)
+ {
+ occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index);
+ }
+
+ // todo: pass it into local bitmaps?
+ LLTinyGLTFHelper::initFetchedTextures(material_in,
+ albedo_img, normal_img, mr_img, emissive_img, occlusion_img,
+ mAlbedoFetched, mNormalFetched, mMRFetched, mEmissiveFetched);
+
+ if (mAlbedoFetched)
+ {
+ mat->mAlbedoId = mAlbedoFetched->getID();
+ }
+ if (mNormalFetched)
+ {
+ mat->mNormalId = mNormalFetched->getID();
+ }
+ if (mMRFetched)
+ {
+ mat->mMetallicRoughnessId = mMRFetched->getID();
+ }
+ if (mEmissiveFetched)
+ {
+ mat->mEmissiveId = mEmissiveFetched->getID();
+ }
+
+ break;
+ }
+
+ default:
+ {
+ // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens
+ // accessing mFilename and any other object properties might very well crash the viewer.
+ // getting here should be impossible, or there's been a pretty serious bug.
+
+ LL_WARNS() << "During a decode attempt, the following local material had no properly assigned extension." << LL_ENDL;
+ LL_WARNS() << "Filename: " << mFilename << LL_ENDL;
+ LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL;
+ mLinkStatus = LS_BROKEN;
+ }
+ }
+
+ return decode_successful;
+}
+
+
+/*=======================================*/
+/* LLLocalGLTFMaterialTimer: timer class */
+/*=======================================*/
+LLLocalGLTFMaterialTimer::LLLocalGLTFMaterialTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT)
+{
+}
+
+LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer()
+{
+}
+
+void LLLocalGLTFMaterialTimer::startTimer()
+{
+ mEventTimer.start();
+}
+
+void LLLocalGLTFMaterialTimer::stopTimer()
+{
+ mEventTimer.stop();
+}
+
+bool LLLocalGLTFMaterialTimer::isRunning()
+{
+ return mEventTimer.getStarted();
+}
+
+BOOL LLLocalGLTFMaterialTimer::tick()
+{
+ // todo: do on idle? No point in timer
+ LLLocalGLTFMaterialMgr::getInstance()->doUpdates();
+ return FALSE;
+}
+
+/*=======================================*/
+/* LLLocalGLTFMaterialMgr: manager class */
+/*=======================================*/
+LLLocalGLTFMaterialMgr::LLLocalGLTFMaterialMgr()
+{
+}
+
+LLLocalGLTFMaterialMgr::~LLLocalGLTFMaterialMgr()
+{
+ std::for_each(mMaterialList.begin(), mMaterialList.end(), DeletePointer());
+ mMaterialList.clear();
+}
+
+bool LLLocalGLTFMaterialMgr::addUnit()
+{
+ bool add_successful = false;
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_MATERIAL))
+ {
+ mTimer.stopTimer();
+
+ std::string filename = picker.getFirstFile();
+ while (!filename.empty())
+ {
+ add_successful |= addUnit(filename);
+ filename = picker.getNextFile();
+ }
+
+ mTimer.startTimer();
+ }
+
+ return add_successful;
+}
+
+bool LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames)
+{
+ bool add_successful = false;
+ std::vector<std::string>::const_iterator iter = filenames.begin();
+ while (iter != filenames.end())
+ {
+ if (!iter->empty())
+ {
+ add_successful |= addUnit(*iter);
+ }
+ iter++;
+ }
+ return add_successful;
+}
+
+bool LLLocalGLTFMaterialMgr::addUnit(const std::string& filename)
+{
+ LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename);
+
+ if (unit->getValid())
+ {
+ mMaterialList.push_back(unit);
+ return true;
+ }
+ 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);
+
+ delete unit;
+ unit = NULL;
+
+ return false;
+ }
+}
+
+void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id)
+{
+ if (!mMaterialList.empty())
+ {
+ std::vector<LLLocalGLTFMaterial*> to_delete;
+ for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++)
+ { /* finding which ones we want deleted and making a separate list */
+ LLLocalGLTFMaterial* unit = *iter;
+ if (unit->getTrackingID() == tracking_id)
+ {
+ to_delete.push_back(unit);
+ }
+ }
+
+ for (std::vector<LLLocalGLTFMaterial*>::iterator del_iter = to_delete.begin();
+ del_iter != to_delete.end(); del_iter++)
+ { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */
+ LLLocalGLTFMaterial* unit = *del_iter;
+ mMaterialList.remove(unit);
+ delete unit;
+ unit = NULL;
+ }
+ }
+}
+
+LLUUID LLLocalGLTFMaterialMgr::getWorldID(LLUUID tracking_id)
+{
+ LLUUID world_id = LLUUID::null;
+
+ for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++)
+ {
+ LLLocalGLTFMaterial* unit = *iter;
+ if (unit->getTrackingID() == tracking_id)
+ {
+ world_id = unit->getWorldID();
+ }
+ }
+
+ return world_id;
+}
+
+bool LLLocalGLTFMaterialMgr::isLocal(const LLUUID world_id)
+{
+ for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++)
+ {
+ LLLocalGLTFMaterial* unit = *iter;
+ if (unit->getWorldID() == world_id)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id)
+{
+ std::string filename = "";
+
+ for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++)
+ {
+ LLLocalGLTFMaterial* unit = *iter;
+ if (unit->getTrackingID() == tracking_id)
+ {
+ filename = unit->getFilename();
+ }
+ }
+
+ return filename;
+}
+
+// probably shouldn't be here, but at the moment this mirrors lllocalbitmaps
+void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl)
+{
+ if (ctrl)
+ {
+ if (!mMaterialList.empty())
+ {
+ std::string icon_name = LLInventoryIcon::getIconName(
+ LLAssetType::AT_MATERIAL,
+ LLInventoryType::IT_NONE);
+
+ for (local_list_iter iter = mMaterialList.begin();
+ iter != mMaterialList.end(); iter++)
+ {
+ LLSD element;
+
+ element["columns"][0]["column"] = "icon";
+ element["columns"][0]["type"] = "icon";
+ element["columns"][0]["value"] = icon_name;
+
+ element["columns"][1]["column"] = "unit_name";
+ element["columns"][1]["type"] = "text";
+ element["columns"][1]["value"] = (*iter)->getShortName();
+
+ LLSD data;
+ data["id"] = (*iter)->getTrackingID();
+ data["type"] = (S32)LLAssetType::AT_MATERIAL;
+ element["value"] = data;
+
+ ctrl->addElement(element);
+ }
+ }
+ }
+
+}
+
+void LLLocalGLTFMaterialMgr::doUpdates()
+{
+ // preventing theoretical overlap in cases with huge number of loaded images.
+ mTimer.stopTimer();
+
+ for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++)
+ {
+ (*iter)->updateSelf();
+ }
+
+ mTimer.startTimer();
+}
+
diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h
new file mode 100644
index 0000000000..7f5b06e10a
--- /dev/null
+++ b/indra/newview/lllocalgltfmaterials.h
@@ -0,0 +1,125 @@
+/**
+ * @file lllocalrendermaterials.h
+ * @brief Local GLTF materials header
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LOCALGLTFMATERIALS_H
+#define LL_LOCALGLTFMATERIALS_H
+
+#include "lleventtimer.h"
+#include "llpointer.h"
+
+class LLScrollListCtrl;
+class LLGLTFMaterial;
+class LLViewerObject;
+class LLViewerFetchedTexture;
+
+class LLLocalGLTFMaterial
+{
+public: /* main */
+ LLLocalGLTFMaterial(std::string filename);
+ ~LLLocalGLTFMaterial();
+
+public: /* accessors */
+ std::string getFilename();
+ std::string getShortName();
+ LLUUID getTrackingID();
+ LLUUID getWorldID();
+ bool getValid();
+
+public:
+ bool updateSelf();
+
+private:
+ bool loadMaterial(LLPointer<LLGLTFMaterial> raw);
+
+private: /* private enums */
+ enum ELinkStatus
+ {
+ LS_ON,
+ LS_BROKEN,
+ };
+
+ enum EExtension
+ {
+ ET_MATERIAL_GLTF,
+ ET_MATERIAL_GLB,
+ };
+
+private: /* members */
+ std::string mFilename;
+ std::string mShortName;
+ LLUUID mTrackingID;
+ LLUUID mWorldID;
+ bool mValid;
+ LLSD mLastModified;
+ EExtension mExtension;
+ ELinkStatus mLinkStatus;
+ S32 mUpdateRetries;
+
+ // material needs to maintain textures
+ LLPointer<LLViewerFetchedTexture> mAlbedoFetched;
+ LLPointer<LLViewerFetchedTexture> mNormalFetched;
+ LLPointer<LLViewerFetchedTexture> mMRFetched;
+ LLPointer<LLViewerFetchedTexture> mEmissiveFetched;
+};
+
+class LLLocalGLTFMaterialTimer : public LLEventTimer
+{
+public:
+ LLLocalGLTFMaterialTimer();
+ ~LLLocalGLTFMaterialTimer();
+
+public:
+ void startTimer();
+ void stopTimer();
+ bool isRunning();
+ BOOL tick();
+};
+
+class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr>
+{
+ LLSINGLETON(LLLocalGLTFMaterialMgr);
+ ~LLLocalGLTFMaterialMgr();
+public:
+ bool addUnit();
+ bool addUnit(const std::vector<std::string>& filenames);
+ bool addUnit(const std::string& filename);
+ void delUnit(LLUUID tracking_id);
+
+ LLUUID getWorldID(LLUUID tracking_id);
+ bool isLocal(LLUUID world_id);
+ std::string getFilename(LLUUID tracking_id);
+
+ void feedScrollList(LLScrollListCtrl* ctrl);
+ void doUpdates();
+
+private:
+ std::list<LLLocalGLTFMaterial*> mMaterialList;
+ LLLocalGLTFMaterialTimer mTimer;
+ typedef std::list<LLLocalGLTFMaterial*>::iterator local_list_iter;
+};
+
+#endif // LL_LOCALGLTFMATERIALS_H
+
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 7b17fb5fdf..2052f252b3 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -55,6 +55,7 @@
#include "llfloaterperms.h"
#include "tinygltf/tiny_gltf.h"
+#include "lltinygltfhelper.h"
#include <strstream>
@@ -1018,18 +1019,15 @@ void LLMaterialEditor::onCancelMsgCallback(const LLSD& notification, const LLSD&
class LLMaterialFilePicker : public LLFilePickerThread
{
public:
- LLMaterialFilePicker(LLMaterialEditor* me);
+ LLMaterialFilePicker();
virtual void notify(const std::vector<std::string>& filenames);
- void loadMaterial(const std::string& filename);
static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata);
-private:
- LLMaterialEditor* mME;
+
};
-LLMaterialFilePicker::LLMaterialFilePicker(LLMaterialEditor* me)
+LLMaterialFilePicker::LLMaterialFilePicker()
: LLFilePickerThread(LLFilePicker::FFLOAD_MATERIAL)
{
- mME = me;
}
void LLMaterialFilePicker::notify(const std::vector<std::string>& filenames)
@@ -1042,82 +1040,20 @@ void LLMaterialFilePicker::notify(const std::vector<std::string>& filenames)
if (filenames.size() > 0)
{
- loadMaterial(filenames[0]);
- }
-}
-
-const tinygltf::Image* get_image_from_texture_index(const tinygltf::Model& model, S32 texture_index)
-{
- if (texture_index >= 0)
- {
- S32 source_idx = model.textures[texture_index].source;
- if (source_idx >= 0)
+ LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor");
+ if (me)
{
- return &(model.images[source_idx]);
+ me->loadMaterialFromFile(filenames[0]);
}
}
-
- return nullptr;
-}
-
-static LLImageRaw* get_texture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name)
-{
- const tinygltf::Image* image = get_image_from_texture_index(model, texture_index);
- LLImageRaw* rawImage = nullptr;
-
- if (image != nullptr &&
- image->bits == 8 &&
- !image->image.empty() &&
- image->component <= 4)
- {
- name = image->name;
- rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component);
- rawImage->verticalFlip();
- }
-
- return rawImage;
-}
-
-static void strip_alpha_channel(LLPointer<LLImageRaw>& img)
-{
- if (img->getComponents() == 4)
- {
- LLImageRaw* tmp = new LLImageRaw(img->getWidth(), img->getHeight(), 3);
- tmp->copyUnscaled4onto3(img);
- img = tmp;
- }
-}
-
-// copy red channel from src_img to dst_img
-// PRECONDITIONS:
-// dst_img must be 3 component
-// src_img and dst_image must have the same dimensions
-static void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img)
-{
- llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight());
- llassert(dst_img->getComponents() == 3);
-
- U32 pixel_count = dst_img->getWidth() * dst_img->getHeight();
- U8* src = src_img->getData();
- U8* dst = dst_img->getData();
- S8 src_components = src_img->getComponents();
-
- for (U32 i = 0; i < pixel_count; ++i)
- {
- dst[i * 3] = src[i * src_components];
- }
}
-static void pack_textures(tinygltf::Model& model, tinygltf::Material& material,
+static void pack_textures(
LLPointer<LLImageRaw>& albedo_img,
LLPointer<LLImageRaw>& normal_img,
LLPointer<LLImageRaw>& mr_img,
LLPointer<LLImageRaw>& emissive_img,
LLPointer<LLImageRaw>& occlusion_img,
- LLPointer<LLViewerFetchedTexture>& albedo_tex,
- LLPointer<LLViewerFetchedTexture>& normal_tex,
- LLPointer<LLViewerFetchedTexture>& mr_tex,
- LLPointer<LLViewerFetchedTexture>& emissive_tex,
LLPointer<LLImageJ2C>& albedo_j2c,
LLPointer<LLImageJ2C>& normal_j2c,
LLPointer<LLImageJ2C>& mr_j2c,
@@ -1125,76 +1061,31 @@ static void pack_textures(tinygltf::Model& model, tinygltf::Material& material,
{
if (albedo_img)
{
- albedo_tex = LLViewerTextureManager::getFetchedTexture(albedo_img, FTType::FTT_LOCAL_FILE, true);
albedo_j2c = LLViewerTextureList::convertToUploadFile(albedo_img);
}
if (normal_img)
{
- strip_alpha_channel(normal_img);
- normal_tex = LLViewerTextureManager::getFetchedTexture(normal_img, FTType::FTT_LOCAL_FILE, true);
normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img);
}
if (mr_img)
{
- strip_alpha_channel(mr_img);
-
- if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
- {
- // occlusion is a distinct texture from pbrMetallicRoughness
- // pack into mr red channel
- int occlusion_idx = material.occlusionTexture.index;
- int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
- if (occlusion_idx != mr_idx)
- {
- //scale occlusion image to match resolution of mr image
- occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
-
- copy_red_channel(occlusion_img, mr_img);
- }
- }
- }
- else if (occlusion_img)
- {
- //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over
- mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3);
- mr_img->clear(255, 255, 255);
- copy_red_channel(occlusion_img, mr_img);
-
- }
-
- if (mr_img)
- {
- mr_tex = LLViewerTextureManager::getFetchedTexture(mr_img, FTType::FTT_LOCAL_FILE, true);
mr_j2c = LLViewerTextureList::convertToUploadFile(mr_img);
}
if (emissive_img)
{
- strip_alpha_channel(emissive_img);
- emissive_tex = LLViewerTextureManager::getFetchedTexture(emissive_img, FTType::FTT_LOCAL_FILE, true);
emissive_j2c = LLViewerTextureList::convertToUploadFile(emissive_img);
}
}
-static LLColor4 get_color(const std::vector<double>& in)
-{
- LLColor4 out;
- for (S32 i = 0; i < llmin((S32) in.size(), 4); ++i)
- {
- out.mV[i] = in[i];
- }
-
- return out;
-}
-
void LLMaterialFilePicker::textureLoadedCallback(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata)
{
}
-void LLMaterialFilePicker::loadMaterial(const std::string& filename)
+void LLMaterialEditor::loadMaterialFromFile(const std::string& filename)
{
tinygltf::TinyGLTF loader;
std::string error_msg;
@@ -1240,90 +1131,91 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename)
model_out.materials.resize(1);
// get albedo texture
- LLPointer<LLImageRaw> albedo_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName);
+ LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mAlbedoName);
// get normal map
- LLPointer<LLImageRaw> normal_img = get_texture(folder, model_in, material_in.normalTexture.index, mME->mNormalName);
+ LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mNormalName);
// get metallic-roughness texture
- LLPointer<LLImageRaw> mr_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName);
+ LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mMetallicRoughnessName);
// get emissive texture
- LLPointer<LLImageRaw> emissive_img = get_texture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName);
+ LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mEmissiveName);
// get occlusion map if needed
LLPointer<LLImageRaw> occlusion_img;
if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index)
{
std::string tmp;
- occlusion_img = get_texture(folder, model_in, material_in.occlusionTexture.index, tmp);
+ occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index, tmp);
}
- pack_textures(model_in, material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img,
- mME->mAlbedoFetched, mME->mNormalFetched, mME->mMetallicRoughnessFetched, mME->mEmissiveFetched,
- mME->mAlbedoJ2C, mME->mNormalJ2C, mME->mMetallicRoughnessJ2C, mME->mEmissiveJ2C);
+ LLTinyGLTFHelper::initFetchedTextures(material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img,
+ mAlbedoFetched, mNormalFetched, mMetallicRoughnessFetched, mEmissiveFetched);
+ pack_textures(albedo_img, normal_img, mr_img, emissive_img, occlusion_img,
+ mAlbedoJ2C, mNormalJ2C, mMetallicRoughnessJ2C, mEmissiveJ2C);
LLUUID albedo_id;
- if (mME->mAlbedoFetched.notNull())
+ if (mAlbedoFetched.notNull())
{
- mME->mAlbedoFetched->forceToSaveRawImage(0, F32_MAX);
- albedo_id = mME->mAlbedoFetched->getID();
+ mAlbedoFetched->forceToSaveRawImage(0, F32_MAX);
+ albedo_id = mAlbedoFetched->getID();
- if (mME->mAlbedoName.empty())
+ if (mAlbedoName.empty())
{
- mME->mAlbedoName = MATERIAL_ALBEDO_DEFAULT_NAME;
+ mAlbedoName = MATERIAL_ALBEDO_DEFAULT_NAME;
}
}
LLUUID normal_id;
- if (mME->mNormalFetched.notNull())
+ if (mNormalFetched.notNull())
{
- mME->mNormalFetched->forceToSaveRawImage(0, F32_MAX);
- normal_id = mME->mNormalFetched->getID();
+ mNormalFetched->forceToSaveRawImage(0, F32_MAX);
+ normal_id = mNormalFetched->getID();
- if (mME->mNormalName.empty())
+ if (mNormalName.empty())
{
- mME->mNormalName = MATERIAL_NORMAL_DEFAULT_NAME;
+ mNormalName = MATERIAL_NORMAL_DEFAULT_NAME;
}
}
LLUUID mr_id;
- if (mME->mMetallicRoughnessFetched.notNull())
+ if (mMetallicRoughnessFetched.notNull())
{
- mME->mMetallicRoughnessFetched->forceToSaveRawImage(0, F32_MAX);
- mr_id = mME->mMetallicRoughnessFetched->getID();
+ mMetallicRoughnessFetched->forceToSaveRawImage(0, F32_MAX);
+ mr_id = mMetallicRoughnessFetched->getID();
- if (mME->mMetallicRoughnessName.empty())
+ if (mMetallicRoughnessName.empty())
{
- mME->mMetallicRoughnessName = MATERIAL_METALLIC_DEFAULT_NAME;
+ mMetallicRoughnessName = MATERIAL_METALLIC_DEFAULT_NAME;
}
}
LLUUID emissive_id;
- if (mME->mEmissiveFetched.notNull())
+ if (mEmissiveFetched.notNull())
{
- mME->mEmissiveFetched->forceToSaveRawImage(0, F32_MAX);
- emissive_id = mME->mEmissiveFetched->getID();
+ mEmissiveFetched->forceToSaveRawImage(0, F32_MAX);
+ emissive_id = mEmissiveFetched->getID();
- if (mME->mEmissiveName.empty())
+ if (mEmissiveName.empty())
{
- mME->mEmissiveName = MATERIAL_EMISSIVE_DEFAULT_NAME;
+ mEmissiveName = MATERIAL_EMISSIVE_DEFAULT_NAME;
}
}
- mME->setAlbedoId(albedo_id);
- mME->setAlbedoUploadId(albedo_id);
- mME->setMetallicRoughnessId(mr_id);
- mME->setMetallicRoughnessUploadId(mr_id);
- mME->setEmissiveId(emissive_id);
- mME->setEmissiveUploadId(emissive_id);
- mME->setNormalId(normal_id);
- mME->setNormalUploadId(normal_id);
+ setAlbedoId(albedo_id);
+ setAlbedoUploadId(albedo_id);
+ setMetallicRoughnessId(mr_id);
+ setMetallicRoughnessUploadId(mr_id);
+ setEmissiveId(emissive_id);
+ setEmissiveUploadId(emissive_id);
+ setNormalId(normal_id);
+ setNormalUploadId(normal_id);
- mME->setFromGltfModel(model_in);
+ setFromGltfModel(model_in);
- mME->setFromGltfMetaData(filename_lc, model_in);
+ setFromGltfMetaData(filename_lc, model_in);
- mME->setHasUnsavedChanges(true);
- mME->openFloater();
+ setHasUnsavedChanges(true);
+ openFloater();
- mME->applyToSelection();
+ applyToSelection();
}
bool LLMaterialEditor::setFromGltfModel(tinygltf::Model& model, bool set_textures)
@@ -1389,8 +1281,8 @@ bool LLMaterialEditor::setFromGltfModel(tinygltf::Model& model, bool set_texture
setAlphaMode(material_in.alphaMode);
setAlphaCutoff(material_in.alphaCutoff);
- setAlbedoColor(get_color(material_in.pbrMetallicRoughness.baseColorFactor));
- setEmissiveColor(get_color(material_in.emissiveFactor));
+ setAlbedoColor(LLTinyGLTFHelper::getColor(material_in.pbrMetallicRoughness.baseColorFactor));
+ setEmissiveColor(LLTinyGLTFHelper::getColor(material_in.emissiveFactor));
setMetalnessFactor(material_in.pbrMetallicRoughness.metallicFactor);
setRoughnessFactor(material_in.pbrMetallicRoughness.roughnessFactor);
@@ -1612,7 +1504,7 @@ void LLMaterialEditor::setFromGltfMetaData(const std::string& filename, tinygltf
void LLMaterialEditor::importMaterial()
{
- (new LLMaterialFilePicker(this))->getFile();
+ (new LLMaterialFilePicker())->getFile();
}
class LLRemderMaterialFunctor : public LLSelectedTEFunctor
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index cf31eb5095..59ae00e565 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -50,7 +50,7 @@ public:
void setFromGltfMetaData(const std::string& filename, tinygltf::Model& model);
// open a file dialog and select a gltf/glb file for import
- void importMaterial();
+ static void importMaterial();
// for live preview, apply current material to currently selected object
void applyToSelection();
@@ -60,6 +60,7 @@ public:
void setFromGLTFMaterial(LLGLTFMaterial* mat);
void loadAsset() override;
+ void loadMaterialFromFile(const std::string& filename);
static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status);
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 4febb72c6c..de94da290d 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -1177,7 +1177,7 @@ void LLOutfitGallery::uploadPhoto(LLUUID outfit_id)
{
return;
}
- (new LLFilePickerReplyThread(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false);
}
void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id)
diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h
index 5629438415..3c27964ec5 100644
--- a/indra/newview/llplacesinventorypanel.h
+++ b/indra/newview/llplacesinventorypanel.h
@@ -40,7 +40,7 @@ public:
{
Params()
{
- filter_asset_type = "landmark";
+ filter_asset_types = "landmark";
}
};
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index a32dc8beda..e4b4b597ca 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -1199,7 +1199,7 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
void LLScriptEdCore::onBtnLoadFromFile( void* data )
{
- (new LLFilePickerReplyThread(boost::bind(&LLScriptEdCore::loadScriptFromFile, _1, data), LLFilePicker::FFLOAD_SCRIPT, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLScriptEdCore::loadScriptFromFile, _1, data), LLFilePicker::FFLOAD_SCRIPT, false);
}
void LLScriptEdCore::loadScriptFromFile(const std::vector<std::string>& filenames, void* data)
@@ -1240,7 +1240,7 @@ void LLScriptEdCore::onBtnSaveToFile( void* userdata )
if( self->mSaveCallback )
{
- (new LLFilePickerReplyThread(boost::bind(&LLScriptEdCore::saveScriptToFile, _1, userdata), LLFilePicker::FFSAVE_SCRIPT, self->mScriptName))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLScriptEdCore::saveScriptToFile, _1, userdata), LLFilePicker::FFSAVE_SCRIPT, self->mScriptName);
}
}
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index cd7b93aba7..7804a13cb5 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -296,7 +296,7 @@ void LLPreviewTexture::saveAs()
return;
std::string filename = getItem() ? LLDir::getScrubbedFileName(getItem()->getName()) : LLStringUtil::null;
- (new LLFilePickerReplyThread(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNG, filename))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNG, filename);
}
void LLPreviewTexture::saveTextureToFile(const std::vector<std::string>& filenames)
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index e8ff14daac..2757f54ea9 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -41,12 +41,15 @@
#include "llfolderviewmodel.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "lllineeditor.h"
+#include "llmaterialeditor.h"
#include "llui.h"
#include "llviewerinventory.h"
+#include "llviewermenufile.h" // LLFilePickerReplyThread
#include "llpermissions.h"
#include "llsaleinfo.h"
#include "llassetstorage.h"
@@ -69,19 +72,12 @@
#include "llradiogroup.h"
#include "llfloaterreg.h"
#include "lllocalbitmaps.h"
+#include "lllocalgltfmaterials.h"
#include "llerror.h"
#include "llavatarappearancedefines.h"
-static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
-
-//static const char CURRENT_IMAGE_NAME[] = "Current Texture";
-//static const char WHITE_IMAGE_NAME[] = "Blank Texture";
-//static const char NO_IMAGE_NAME[] = "None";
-
-
-
//static
bool get_is_predefined_texture(LLUUID asset_id)
{
@@ -417,23 +413,29 @@ BOOL LLFloaterTexturePicker::postBuild()
childSetCommitCallback("show_folders_check", onShowFolders, this);
getChildView("show_folders_check")->setVisible( FALSE);
- mFilterEdit = getChild<LLFilterEditor>("inventory search editor");
- mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2));
+ mFilterEdit = getChild<LLFilterEditor>("inventory search editor");
+ mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2));
mInventoryPanel = getChild<LLInventoryPanel>("inventory panel");
+ mTextureMaterialsCombo = getChild<LLComboBox>("textures_material_combo");
+ mTextureMaterialsCombo->setCommitCallback(onSelectTextureMaterials, this);
+
+ // set the combo box to the first entry in the list (currently textures and materials)
+ mTextureMaterialsCombo->selectByValue(0);
+
mModeSelector = getChild<LLComboBox>("mode_selection");
mModeSelector->setCommitCallback(onModeSelect, this);
mModeSelector->selectByValue(0);
if(mInventoryPanel)
{
- U32 filter_types = 0x0;
- filter_types |= 0x1 << LLInventoryType::IT_TEXTURE;
- filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT;
+ // to avoid having to make an assumption about which option is
+ // selected at startup, we call the same function that is triggered
+ // when a texture/materials/both choice is made and let it take care
+ // of setting the filters
+ onSelectTextureMaterials(0, this);
- mInventoryPanel->setFilterTypes(filter_types);
- //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss.
mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask);
mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2));
mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
@@ -466,7 +468,9 @@ BOOL LLFloaterTexturePicker::postBuild()
mLocalScrollCtrl = getChild<LLScrollListCtrl>("l_name_list");
mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this);
+ mLocalScrollCtrl->clearRows();
LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl);
+ LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(mLocalScrollCtrl);
mNoCopyTextureSelected = FALSE;
@@ -743,8 +747,18 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata)
{
if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty())
{
- LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
- local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
+ LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
+ LLUUID temp_id = data["id"];
+ S32 asset_type = data["type"].asInteger();
+
+ if (LLAssetType::AT_MATERIAL == asset_type)
+ {
+ local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id);
+ }
+ else
+ {
+ local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id);
+ }
}
}
@@ -817,6 +831,7 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
self->getChild<LLButton>("Blank")->setVisible(index == 0 ? TRUE : FALSE);
self->getChild<LLButton>("None")->setVisible(index == 0 ? TRUE : FALSE);
self->getChild<LLButton>("Pipette")->setVisible(index == 0 ? TRUE : FALSE);
+ self->getChild<LLComboBox>("textures_material_combo")->setVisible(index == 0 ? TRUE : FALSE);
self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE);
self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == 0 ? TRUE : FALSE);
@@ -891,11 +906,9 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata)
// static
void LLFloaterTexturePicker::onBtnAdd(void* userdata)
{
- if (LLLocalBitmapMgr::getInstance()->addUnit() == true)
- {
- LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
- LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl);
- }
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)userdata;
+
+ LLFilePickerReplyThread::startPicker(boost::bind(&onPickerCallback, _1, self->getHandle()), LLFilePicker::FFLOAD_ALL, true);
}
// static
@@ -906,22 +919,34 @@ void LLFloaterTexturePicker::onBtnRemove(void* userdata)
if (!selected_items.empty())
{
+
for(std::vector<LLScrollListItem*>::iterator iter = selected_items.begin();
iter != selected_items.end(); iter++)
{
LLScrollListItem* list_item = *iter;
if (list_item)
{
- LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID();
- LLLocalBitmapMgr::getInstance()->delUnit(tracking_id);
+ LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
+ LLUUID tracking_id = data["id"];
+ S32 asset_type = data["type"].asInteger();
+
+ if (LLAssetType::AT_MATERIAL == asset_type)
+ {
+ LLLocalGLTFMaterialMgr::getInstance()->delUnit(tracking_id);
+ }
+ else
+ {
+ LLLocalBitmapMgr::getInstance()->delUnit(tracking_id);
+ }
}
}
self->getChild<LLButton>("l_rem_btn")->setEnabled(false);
self->getChild<LLButton>("l_upl_btn")->setEnabled(false);
+ self->mLocalScrollCtrl->clearRows();
LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl);
+ LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl);
}
-
}
// static
@@ -937,15 +962,31 @@ void LLFloaterTexturePicker::onBtnUpload(void* userdata)
/* currently only allows uploading one by one, picks the first item from the selection list. (not the vector!)
in the future, it might be a good idea to check the vector size and if more than one units is selected - opt for multi-image upload. */
-
- LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN);
- std::string filename = LLLocalBitmapMgr::getInstance()->getFilename(tracking_id);
- if (!filename.empty())
- {
- LLFloaterReg::showInstance("upload_image", LLSD(filename));
- }
+ LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
+ LLUUID tracking_id = data["id"];
+ S32 asset_type = data["type"].asInteger();
+ if (LLAssetType::AT_MATERIAL == asset_type)
+ {
+ std::string filename = LLLocalGLTFMaterialMgr::getInstance()->getFilename(tracking_id);
+ if (!filename.empty())
+ {
+ LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor");
+ if (me)
+ {
+ me->loadMaterialFromFile(filename);
+ }
+ }
+ }
+ else
+ {
+ std::string filename = LLLocalBitmapMgr::getInstance()->getFilename(tracking_id);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_image", LLSD(filename));
+ }
+ }
}
//static
@@ -961,8 +1002,20 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
if (has_selection)
{
- LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN);
- LLUUID inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id);
+ LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue();
+ LLUUID tracking_id = data["id"];
+ S32 asset_type = data["type"].asInteger();
+ LLUUID inworld_id;
+
+ if (LLAssetType::AT_MATERIAL == asset_type)
+ {
+ inworld_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(tracking_id);
+ }
+ else
+ {
+ inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id);
+ }
+
if (self->mSetImageAssetIDCallback)
{
self->mSetImageAssetIDCallback(inworld_id);
@@ -1136,6 +1189,38 @@ void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string )
mInventoryPanel->setFilterSubString(search_string);
}
+void LLFloaterTexturePicker::onSelectTextureMaterials(LLUICtrl* ctrl, void *userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)userdata;
+ int index = self->mTextureMaterialsCombo->getValue().asInteger();
+
+ // IMPORTANT: make sure these match the entries in floater_texture_ctrl.xml
+ // for the textures_material_combo combo box
+ const int textures_and_materials = 0;
+ const int textures_only = 1;
+ const int materials_only = 2;
+
+ U32 filter_types = 0x0;
+
+ if (index == textures_and_materials)
+ {
+ filter_types |= 0x1 << LLInventoryType::IT_TEXTURE;
+ filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT;
+ filter_types |= 0x1 << LLInventoryType::IT_MATERIAL;
+ }
+ else if (index == textures_only)
+ {
+ filter_types |= 0x1 << LLInventoryType::IT_TEXTURE;
+ filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT;
+ }
+ else if (index == materials_only)
+ {
+ filter_types |= 0x1 << LLInventoryType::IT_MATERIAL;
+ }
+
+ self->mInventoryPanel->setFilterTypes(filter_types);
+}
+
void LLFloaterTexturePicker::setLocalTextureEnabled(BOOL enabled)
{
mModeSelector->setEnabledByValue(1, enabled);
@@ -1163,6 +1248,36 @@ void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled)
onModeSelect(0, this);
}
+void LLFloaterTexturePicker::onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle)
+{
+ std::vector<std::string>::const_iterator iter = filenames.begin();
+ while (iter != filenames.end())
+ {
+ if (!iter->empty())
+ {
+ std::string temp_exten = gDirUtilp->getExtension(*iter);
+ if (temp_exten == "gltf" || temp_exten == "glb")
+ {
+ LLLocalGLTFMaterialMgr::getInstance()->addUnit(*iter);
+ }
+ else
+ {
+ LLLocalBitmapMgr::getInstance()->addUnit(*iter);
+ }
+ }
+ iter++;
+ }
+
+ // Todo: this should referesh all pickers, not just a current one
+ if (!handle.isDead())
+ {
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)handle.get();
+ self->mLocalScrollCtrl->clearRows();
+ LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl);
+ LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl);
+ }
+}
+
void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te )
{
LLUUID inventory_item_id = findItemID(te.getID(), TRUE);
@@ -1494,9 +1609,9 @@ void LLTextureCtrl::onFloaterClose()
void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
{
- LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
- if( floaterp && getEnabled())
+ if( floaterp && getEnabled())
{
if (op == TEXTURE_CANCEL)
mViewModel->resetDirty();
@@ -1517,15 +1632,64 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
}
else
{
- mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
- LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL;
- mImageAssetID = floaterp->getAssetID();
- LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL;
+ mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
+ LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL;
+ mImageAssetID = floaterp->getAssetID();
+ LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL;
}
if (op == TEXTURE_SELECT && mOnSelectCallback)
{
- mOnSelectCallback( this, LLSD() );
+ // determine if the selected item in inventory is a material
+ // by finding the item in inventory and inspecting its (IT_) type
+ LLUUID item_id = floaterp->findItemID(floaterp->getAssetID(), FALSE);
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if (item)
+ {
+ if (item->getInventoryType() == LLInventoryType::IT_MATERIAL)
+ {
+ // ask the selection manager for the list of selected objects
+ // to which the material will be applied.
+ LLObjectSelectionHandle selectedObjectsHandle = LLSelectMgr::getInstance()->getSelection();
+ if (selectedObjectsHandle.notNull())
+ {
+ LLObjectSelection* selectedObjects = selectedObjectsHandle.get();
+ if (!selectedObjects->isEmpty())
+ {
+ // we have a selection - iterate over it
+ for (LLObjectSelection::valid_iterator obj_iter = selectedObjects->valid_begin();
+ obj_iter != selectedObjects->valid_end();
+ ++obj_iter)
+ {
+ LLSelectNode* object = *obj_iter;
+ LLViewerObject* viewer_object = object->getObject();
+ if (viewer_object)
+ {
+ // the asset ID of the material we want to apply
+ // the the selected objects
+ LLUUID asset_id = item->getAssetUUID();
+
+ // iterate over the faces in the object
+ // TODO: consider the case where user has
+ // selected only certain faces
+ S32 num_faces = viewer_object->getNumTEs();
+ for (S32 face = 0; face < num_faces; face++)
+ {
+ viewer_object->setRenderMaterialID(face, asset_id);
+ dialog_refresh_all();
+ }
+ viewer_object->sendTEUpdate();
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ // original behavior for textures, not materials
+ {
+ mOnSelectCallback(this, LLSD());
+ }
}
else if (op == TEXTURE_CANCEL && mOnCancelCallback)
{
@@ -1536,8 +1700,10 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
// If the "no_commit_on_selection" parameter is set
// we commit only when user presses OK in the picker
// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
- if (mCommitOnSelection || op == TEXTURE_SELECT)
- onCommit();
+ if (mCommitOnSelection || op == TEXTURE_SELECT)
+ {
+ onCommit();
+ }
}
}
}
@@ -1670,7 +1836,7 @@ void LLTextureCtrl::draw()
}
else//mImageAssetID == LLUUID::null
{
- mTexturep = NULL;
+ mTexturep = NULL;
}
// Border
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index a234124c08..b77ff98d80 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -340,9 +340,13 @@ public:
static void onBakeTextureSelect(LLUICtrl* ctrl, void *userdata);
static void onHideBaseMeshRegionCheck(LLUICtrl* ctrl, void *userdata);
+ static void onSelectTextureMaterials(LLUICtrl* ctrl, void *userdata);
+
void setLocalTextureEnabled(BOOL enabled);
void setBakeTextureEnabled(BOOL enabled);
+ static void onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle);
+
protected:
LLPointer<LLViewerTexture> mTexturep;
LLView* mOwner;
@@ -365,6 +369,7 @@ protected:
BOOL mActive;
LLFilterEditor* mFilterEdit;
+ LLComboBox* mTextureMaterialsCombo;
LLInventoryPanel* mInventoryPanel;
PermissionMask mImmediateFilterPermMask;
PermissionMask mDnDFilterPermMask;
diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp
new file mode 100644
index 0000000000..935f8e7794
--- /dev/null
+++ b/indra/newview/lltinygltfhelper.cpp
@@ -0,0 +1,245 @@
+/**
+ * @file lltinygltfhelper.cpp
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltinygltfhelper.h"
+
+#include "llimage.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+
+void strip_alpha_channel(LLPointer<LLImageRaw>& img)
+{
+ if (img->getComponents() == 4)
+ {
+ LLImageRaw* tmp = new LLImageRaw(img->getWidth(), img->getHeight(), 3);
+ tmp->copyUnscaled4onto3(img);
+ img = tmp;
+ }
+}
+
+// copy red channel from src_img to dst_img
+// PRECONDITIONS:
+// dst_img must be 3 component
+// src_img and dst_image must have the same dimensions
+void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img)
+{
+ llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight());
+ llassert(dst_img->getComponents() == 3);
+
+ U32 pixel_count = dst_img->getWidth() * dst_img->getHeight();
+ U8* src = src_img->getData();
+ U8* dst = dst_img->getData();
+ S8 src_components = src_img->getComponents();
+
+ for (U32 i = 0; i < pixel_count; ++i)
+ {
+ dst[i * 3] = src[i * src_components];
+ }
+}
+
+void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material,
+ LLPointer<LLImageRaw>& albedo_img,
+ LLPointer<LLImageRaw>& normal_img,
+ LLPointer<LLImageRaw>& mr_img,
+ LLPointer<LLImageRaw>& emissive_img,
+ LLPointer<LLImageRaw>& occlusion_img,
+ LLPointer<LLViewerFetchedTexture>& albedo_tex,
+ LLPointer<LLViewerFetchedTexture>& normal_tex,
+ LLPointer<LLViewerFetchedTexture>& mr_tex,
+ LLPointer<LLViewerFetchedTexture>& emissive_tex)
+{
+ if (albedo_img)
+ {
+ albedo_tex = LLViewerTextureManager::getFetchedTexture(albedo_img, FTType::FTT_LOCAL_FILE, true);
+ }
+
+ if (normal_img)
+ {
+ strip_alpha_channel(normal_img);
+ normal_tex = LLViewerTextureManager::getFetchedTexture(normal_img, FTType::FTT_LOCAL_FILE, true);
+ }
+
+ if (mr_img)
+ {
+ strip_alpha_channel(mr_img);
+
+ if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
+ {
+ // occlusion is a distinct texture from pbrMetallicRoughness
+ // pack into mr red channel
+ int occlusion_idx = material.occlusionTexture.index;
+ int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
+ if (occlusion_idx != mr_idx)
+ {
+ //scale occlusion image to match resolution of mr image
+ occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
+
+ copy_red_channel(occlusion_img, mr_img);
+ }
+ }
+ }
+ else if (occlusion_img)
+ {
+ //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over
+ mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3);
+ mr_img->clear(255, 255, 255);
+ copy_red_channel(occlusion_img, mr_img);
+ }
+
+ if (mr_img)
+ {
+ mr_tex = LLViewerTextureManager::getFetchedTexture(mr_img, FTType::FTT_LOCAL_FILE, true);
+ }
+
+ if (emissive_img)
+ {
+ strip_alpha_channel(emissive_img);
+ emissive_tex = LLViewerTextureManager::getFetchedTexture(emissive_img, FTType::FTT_LOCAL_FILE, true);
+ }
+}
+
+void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model)
+{
+ S32 index;
+
+ auto& material_in = model.materials[0];
+
+ // get albedo texture
+ index = material_in.pbrMetallicRoughness.baseColorTexture.index;
+ if (index >= 0)
+ {
+ mat->mAlbedoId.set(model.images[index].uri);
+ }
+ else
+ {
+ mat->mAlbedoId.setNull();
+ }
+
+ // get normal map
+ index = material_in.normalTexture.index;
+ if (index >= 0)
+ {
+ mat->mNormalId.set(model.images[index].uri);
+ }
+ else
+ {
+ mat->mNormalId.setNull();
+ }
+
+ // get metallic-roughness texture
+ index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index;
+ if (index >= 0)
+ {
+ mat->mMetallicRoughnessId.set(model.images[index].uri);
+ }
+ else
+ {
+ mat->mMetallicRoughnessId.setNull();
+ }
+
+ // get emissive texture
+ index = material_in.emissiveTexture.index;
+ if (index >= 0)
+ {
+ mat->mEmissiveId.set(model.images[index].uri);
+ }
+ else
+ {
+ mat->mEmissiveId.setNull();
+ }
+
+ mat->setAlphaMode(material_in.alphaMode);
+ mat->mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f);
+
+ mat->mAlbedoColor = getColor(material_in.pbrMetallicRoughness.baseColorFactor);
+ mat->mEmissiveColor = getColor(material_in.emissiveFactor);
+
+ mat->mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f);
+ mat->mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f);
+
+ mat->mDoubleSided = material_in.doubleSided;
+}
+
+LLColor4 LLTinyGLTFHelper::getColor(const std::vector<double>& in)
+{
+ LLColor4 out;
+ for (S32 i = 0; i < llmin((S32)in.size(), 4); ++i)
+ {
+ out.mV[i] = in[i];
+ }
+
+ return out;
+}
+
+const tinygltf::Image * LLTinyGLTFHelper::getImageFromTextureIndex(const tinygltf::Model & model, S32 texture_index)
+{
+ if (texture_index >= 0)
+ {
+ S32 source_idx = model.textures[texture_index].source;
+ if (source_idx >= 0)
+ {
+ return &(model.images[source_idx]);
+ }
+ }
+
+ return nullptr;
+}
+
+LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name)
+{
+ const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index);
+ LLImageRaw* rawImage = nullptr;
+
+ if (image != nullptr &&
+ image->bits == 8 &&
+ !image->image.empty() &&
+ image->component <= 4)
+ {
+ name = image->name;
+ rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component);
+ rawImage->verticalFlip();
+ }
+
+ return rawImage;
+}
+
+LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index)
+{
+ const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index);
+ LLImageRaw* rawImage = nullptr;
+
+ if (image != nullptr &&
+ image->bits == 8 &&
+ !image->image.empty() &&
+ image->component <= 4)
+ {
+ rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component);
+ rawImage->verticalFlip();
+ }
+
+ return rawImage;
+}
diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h
new file mode 100644
index 0000000000..a25fdac41d
--- /dev/null
+++ b/indra/newview/lltinygltfhelper.h
@@ -0,0 +1,55 @@
+/**
+ * @file lltinygltfhelper.h
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#pragma once
+
+#include "llgltfmaterial.h"
+#include "llpointer.h"
+#include "tinygltf/tiny_gltf.h"
+
+class LLImageRaw;
+class LLViewerFetchedTexture;
+
+namespace LLTinyGLTFHelper
+{
+ void setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model);
+ 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);
+ LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index);
+
+ void initFetchedTextures(tinygltf::Material& material,
+ LLPointer<LLImageRaw>& albedo_img,
+ LLPointer<LLImageRaw>& normal_img,
+ LLPointer<LLImageRaw>& mr_img,
+ LLPointer<LLImageRaw>& emissive_img,
+ LLPointer<LLImageRaw>& occlusion_img,
+ LLPointer<LLViewerFetchedTexture>& albedo_tex,
+ LLPointer<LLViewerFetchedTexture>& normal_tex,
+ LLPointer<LLViewerFetchedTexture>& mr_tex,
+ LLPointer<LLViewerFetchedTexture>& emissive_tex);
+}
+
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 148a76d93b..ffa2ce865e 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -249,6 +249,16 @@ LLFilePickerReplyThread::~LLFilePickerReplyThread()
delete mFailureSignal;
}
+void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb)
+{
+ (new LLFilePickerReplyThread(cb, filter, get_multiple, failure_cb))->getFile();
+}
+
+void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ESaveFilter filter, const std::string & proposed_name, const file_picked_signal_t::slot_type & failure_cb)
+{
+ (new LLFilePickerReplyThread(cb, filter, proposed_name, failure_cb))->getFile();
+}
+
void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames)
{
if (filenames.empty())
@@ -571,7 +581,7 @@ class LLFileUploadImage : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false);
return true;
}
};
@@ -589,11 +599,7 @@ class LLFileUploadMaterial : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor");
- if (me)
- {
- me->importMaterial();
- }
+ LLMaterialEditor::importMaterial();
return TRUE;
}
};
@@ -606,7 +612,7 @@ class LLFileUploadSound : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false);
return true;
}
};
@@ -619,7 +625,7 @@ class LLFileUploadAnim : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false);
return true;
}
};
@@ -632,7 +638,7 @@ class LLFileUploadBulk : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- (new LLFilePickerReplyThread(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true);
return true;
}
};
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index beeac418d9..5c2caf9c51 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -115,14 +115,18 @@ class LLFilePickerReplyThread : public LLFilePickerThread
public:
typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t;
-
- LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
- LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
- ~LLFilePickerReplyThread();
+
+ static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
+ static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
virtual void notify(const std::vector<std::string>& filenames);
private:
+ LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
+ LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t());
+ ~LLFilePickerReplyThread();
+
+private:
LLFilePicker::ELoadFilter mLoadFilter;
LLFilePicker::ESaveFilter mSaveFilter;
file_picked_signal_t* mFilePickedSignal;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index efe23d7295..0d9670d9ca 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -569,15 +569,14 @@ void LLViewerShaderMgr::setShaders()
mShaderLevel[SHADER_DEFERRED] = deferred_class;
mShaderLevel[SHADER_TRANSFORM] = transform_class;
- BOOL loaded = loadBasicShaders();
- if (loaded)
+ std::string shader_name = loadBasicShaders();
+ if (shader_name.empty())
{
LL_INFOS() << "Loaded basic shaders." << LL_ENDL;
}
else
{
- LL_ERRS() << "Unable to load basic shaders, verify graphics driver installed and current." << LL_ENDL;
- llassert(loaded);
+ LL_ERRS() << "Unable to load basic shader " << shader_name << ", verify graphics driver installed and current." << LL_ENDL;
reentrance = false; // For hygiene only, re-try probably helps nothing
return;
}
@@ -585,7 +584,7 @@ void LLViewerShaderMgr::setShaders()
gPipeline.mShadersLoaded = true;
// Load all shaders to set max levels
- loaded = loadShadersEnvironment();
+ BOOL loaded = loadShadersEnvironment();
if (loaded)
{
@@ -831,7 +830,7 @@ void LLViewerShaderMgr::unloadShaders()
gPipeline.mShadersLoaded = false;
}
-BOOL LLViewerShaderMgr::loadBasicShaders()
+std::string LLViewerShaderMgr::loadBasicShaders()
{
// Load basic dependency shaders first
// All of these have to load for any shaders to function
@@ -917,8 +916,8 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
// Note usage of GL_VERTEX_SHADER_ARB
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0)
{
- LL_SHADER_LOADING_WARNS() << "Failed to load vertex shader " << shaders[i].first << LL_ENDL;
- return FALSE;
+ LL_WARNS("Shader") << "Failed to load vertex shader " << shaders[i].first << LL_ENDL;
+ return shaders[i].first;
}
}
@@ -978,12 +977,12 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
// Note usage of GL_FRAGMENT_SHADER_ARB
if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0)
{
- LL_SHADER_LOADING_WARNS() << "Failed to load fragment shader " << shaders[i].first << LL_ENDL;
- return FALSE;
+ LL_WARNS("Shader") << "Failed to load fragment shader " << shaders[i].first << LL_ENDL;
+ return shaders[i].first;
}
}
- return TRUE;
+ return std::string();
}
BOOL LLViewerShaderMgr::loadShadersEnvironment()
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 87d90b49a9..ef49074959 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -49,7 +49,11 @@ public:
void setShaders();
void unloadShaders();
S32 getShaderLevel(S32 type);
- BOOL loadBasicShaders();
+
+ // loadBasicShaders in case of a failure returns
+ // name of a file error happened at, otherwise
+ // returns an empty string
+ std::string loadBasicShaders();
BOOL loadShadersEffects();
BOOL loadShadersDeferred();
BOOL loadShadersObject();
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index fead2e52b2..99394e550c 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -1,10 +1,10 @@
/**
- * @file llviewertexturelinumimagest.h
+ * @file llviewertexturelist.h
* @brief Object for managing the list of images within a region
*
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2022, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 48ad02321b..aa8d58cc8a 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -4667,8 +4667,8 @@ void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picke
else
pick_type = LLFilePicker::FFSAVE_ALL;
- (new LLFilePickerReplyThread(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name,
- boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb)))->getFile();
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name,
+ boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb));
}
else
{
diff --git a/indra/newview/skins/default/xui/en/floater_my_environments.xml b/indra/newview/skins/default/xui/en/floater_my_environments.xml
index 6aff387dcb..db81c8bba2 100644
--- a/indra/newview/skins/default/xui/en/floater_my_environments.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_environments.xml
@@ -119,7 +119,7 @@
follows="all"
layout="topleft"
name="pnl_settings"
- filter_asset_type="settings"/>
+ filter_asset_types="settings"/>
</panel>
</layout_panel>
<layout_panel
diff --git a/indra/newview/skins/default/xui/en/floater_settings_picker.xml b/indra/newview/skins/default/xui/en/floater_settings_picker.xml
index 3a26c3b547..8931269fe7 100644
--- a/indra/newview/skins/default/xui/en/floater_settings_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_settings_picker.xml
@@ -89,7 +89,7 @@
top="1"
right="-4"
bottom="-1"
- filter_asset_type="settings" />
+ filter_asset_types="settings" />
</panel>
</layout_panel>
<layout_panel name="pnl_combo"
diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index 3a66911389..18c226ed58 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -137,7 +137,29 @@
value="Preview Disabled"
word_wrap="true"
visible="false"
- width="87" />
+ width="87" />
+ <combo_box
+ follows="left|top|right"
+ height="23"
+ label="Choose Textures, Materials or LIFE!"
+ layout="topleft"
+ left="175"
+ name="textures_material_combo"
+ top="20"
+ width="231">
+ <combo_box.item
+ label="Materials &amp; Textures"
+ name="Materials_Textures"
+ value="0" />
+ <combo_box.item
+ label="Textures"
+ name="Textures"
+ value="1" />
+ <combo_box.item
+ label="Materials"
+ name="Materials"
+ value="2" />
+ </combo_box>
<filter_editor
follows="left|top|right"
height="23"
@@ -145,21 +167,21 @@
layout="topleft"
left="175"
name="inventory search editor"
- top="20"
+ top="48"
width="231" />
- <asset_filtered_inv_panel
- allow_multi_select="false"
+ <asset_filtered_inv_panel
+ allow_multi_select="false"
bg_visible="true"
bg_alpha_color="DkGray2"
border="false"
follows="all"
- height="233"
+ height="195"
layout="topleft"
left_delta="0"
name="inventory panel"
top_pad="4"
width="231"
- filter_asset_type="texture"/>
+ filter_asset_types="texture|material"/>
<check_box
height="14"
initial_value="false"
@@ -218,8 +240,8 @@
multi_select="true"
search_column="1"
visible="false">
+ <column name="icon" label="" width="20" />
<column name="unit_name" label="Name" dynamicwidth="true" />
- <column name="unit_id_HIDDEN" label="ID" width="0" />
</scroll_list>
<!-- middle: bake mode -->
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 24a934fbb8..c618c5bf32 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9804,6 +9804,15 @@ Attempt cancelled.
<notification
icon="alertmodal.tga"
+ name="LocalGLTFVerifyFail"
+ persist="true"
+ type="notify">
+Attempted to add an invalid or unreadable GLTF material [FNAME] which could not be opened or decoded.
+Attempt cancelled.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="PathfindingReturnMultipleItems"
type="alertmodal">
You are returning [NUM_ITEMS] items. Are you sure you want to continue?