diff options
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 & 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? |