From 0d217dc73c6530dcbceb306c4609e2d72da6d70b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 20 Aug 2022 01:04:42 +0300 Subject: SL-17653 Local gltf materials #2 --- indra/newview/CMakeLists.txt | 8 +- indra/newview/llfloaterautoreplacesettings.cpp | 4 +- indra/newview/llfloatereditextdaycycle.cpp | 2 +- indra/newview/llfloaterfixedenvironment.cpp | 4 +- indra/newview/llfloaterspellchecksettings.cpp | 2 +- indra/newview/llfloateruipreview.cpp | 4 +- indra/newview/lllocalbitmaps.cpp | 92 ++- indra/newview/lllocalbitmaps.h | 2 + indra/newview/lllocalgltfmaterials.cpp | 712 ++++++++++++++++++++ indra/newview/lllocalgltfmaterials.h | 134 ++++ indra/newview/lllocalrendermaterials.cpp | 734 --------------------- indra/newview/lllocalrendermaterials.h | 136 ---- indra/newview/llmaterialeditor.cpp | 97 +-- indra/newview/llmaterialeditor.h | 3 +- indra/newview/lloutfitgallery.cpp | 2 +- indra/newview/llpreviewscript.cpp | 4 +- indra/newview/llpreviewtexture.cpp | 2 +- indra/newview/lltexturectrl.cpp | 133 +++- indra/newview/lltexturectrl.h | 2 + indra/newview/llviewermenufile.cpp | 24 +- indra/newview/llviewermenufile.h | 12 +- indra/newview/llviewerwindow.cpp | 4 +- .../skins/default/xui/en/floater_texture_ctrl.xml | 1 + 23 files changed, 1117 insertions(+), 1001 deletions(-) create mode 100644 indra/newview/lllocalgltfmaterials.cpp create mode 100644 indra/newview/lllocalgltfmaterials.h delete mode 100644 indra/newview/lllocalrendermaterials.cpp delete mode 100644 indra/newview/lllocalrendermaterials.h (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e72536e781..950697a72a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -394,7 +394,7 @@ set(viewer_SOURCE_FILES lllistcontextmenu.cpp lllistview.cpp lllocalbitmaps.cpp - lllocalrendermaterials.cpp + lllocalgltfmaterials.cpp lllocationhistory.cpp lllocationinputctrl.cpp lllogchat.cpp @@ -608,7 +608,7 @@ set(viewer_SOURCE_FILES lltextureinfodetails.cpp lltexturestats.cpp lltextureview.cpp - lltinygltfhelper.cpp + lltinygltfhelper.cpp lltoast.cpp lltoastalertpanel.cpp lltoastgroupnotifypanel.cpp @@ -1038,7 +1038,7 @@ set(viewer_HEADER_FILES lllistcontextmenu.h lllistview.h lllocalbitmaps.h - lllocalrendermaterials.h + lllocalgltfmaterials.h lllocationhistory.h lllocationinputctrl.h lllogchat.h @@ -1243,7 +1243,7 @@ set(viewer_HEADER_FILES lltextureinfodetails.h lltexturestats.h lltextureview.h - lltinygltfhelper.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& 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& 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& 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& 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& 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& 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& filenames) @@ -1077,7 +1077,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector& 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& filenames) diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 5a17332fde..6d22a3af52 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& filenames) +{ + bool add_successful = false; + std::vector::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,18 @@ 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(); + + element["columns"][2]["column"] = "unit_id_HIDDEN"; + element["columns"][2]["type"] = "text"; + element["columns"][2]["value"] = (*iter)->getTrackingID(); 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(); public: bool addUnit(); + bool addUnit(const std::vector& 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..14772dd792 --- /dev/null +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -0,0 +1,712 @@ +/** + * @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 + +/* time headers */ +#include +#include + +/* misc headers */ +#include "llagentwearables.h" +#include "llface.h" +#include "llfilepicker.h" +#include "llgltfmateriallist.h" +#include "llimagedimensionsinfo.h" +#include "llinventoryicon.h" +#include "lllocaltextureobject.h" +#include "llmaterialmgr.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltexlayerparams.h" +#include "lltinygltfhelper.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewerdisplay.h" +#include "llviewerobjectlist.h" +#include "llviewerobject.h" +#include "pipeline.h" +#include "tinygltf/tiny_gltf.h" + +/*=======================================*/ +/* Formal declarations, constants, etc. */ +/*=======================================*/ + +static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; +static const BOOL LL_LOCAL_USE_MIPMAPS = true; +static const S32 LL_LOCAL_DISCARD_LEVEL = 0; +static const bool LL_LOCAL_SLAM_FOR_DEBUG = true; +static const bool LL_LOCAL_REPLACE_ON_DEL = true; +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(UT_FIRSTUSE); +} + +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(EUpdateType optional_firstupdate) +{ + 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 raw_material = new LLGLTFMaterial(); + if (loadMaterial(raw_material)) + { + // decode is successful, we can safely proceed. + LLUUID old_id = LLUUID::null; + if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) + { + old_id = mWorldID; + } + mWorldID.generate(); + mLastModified = new_last_modified; + + gGLTFMaterialList.addMaterial(mWorldID, raw_material); + + if (optional_firstupdate != UT_FIRSTUSE) + { + // seek out everything old_id uses and replace it with mWorldID + replaceIDs(old_id, mWorldID); + + // remove old_id from material list + gGLTFMaterialList.removeMaterial(old_id); + } + + 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 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 albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); + // get normal map + LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index); + // get metallic-roughness texture + LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index); + // get emissive texture + LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index); + // get occlusion map if needed + LLPointer 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; +} + +void LLLocalGLTFMaterial::replaceIDs(LLUUID old_id, LLUUID new_id) +{ + // checking for misuse. + if (old_id == new_id) + { + LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" + << "Texture UUID: " << old_id.asString() << LL_ENDL; + return; + } + + // processing updates per channel; makes the process scalable. + // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. + updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); + updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); + updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); + + // default safeguard image for layers + if (new_id == IMG_DEFAULT) + { + new_id = IMG_DEFAULT_AVATAR; + } +} + +// this function sorts the faces from a getFaceList[getNumFaces] into a list of objects +// in order to prevent multiple sendTEUpdate calls per object during updateUserPrims +std::vector LLLocalGLTFMaterial::prepUpdateObjects(LLUUID old_id, U32 channel) +{ + std::vector obj_list; + // todo: find a way to update materials + /* + LLGLTFMaterial* old_material = gGLTFMaterialList.getMaterial(old_id); + + for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) + { + // getting an object from a face + LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; + + if(face_to_object) + { + LLViewerObject* affected_object = face_to_object->getViewerObject(); + + if(affected_object) + { + + // we have an object, we'll take it's UUID and compare it to + // whatever we already have in the returnable object list. + // if there is a match - we do not add (to prevent duplicates) + LLUUID mainlist_obj_id = affected_object->getID(); + bool add_object = true; + + // begin looking for duplicates + std::vector::iterator objlist_iter = obj_list.begin(); + for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) + { + LLViewerObject* obj = *objlist_iter; + if (obj->getID() == mainlist_obj_id) + { + add_object = false; // duplicate found. + } + } + // end looking for duplicates + + if(add_object) + { + obj_list.push_back(affected_object); + } + + } + + } + + } // end of face-iterating for() + + */ + return obj_list; +} + +void LLLocalGLTFMaterial::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) +{ + /*std::vector objectlist = prepUpdateObjects(old_id, channel); + for(std::vector::iterator object_iterator = objectlist.begin(); + object_iterator != objectlist.end(); object_iterator++) + { + LLViewerObject* object = *object_iterator; + + if(object) + { + bool update_tex = false; + bool update_mat = false; + S32 num_faces = object->getNumFaces(); + + for (U8 face_iter = 0; face_iter < num_faces; face_iter++) + { + if (object->mDrawable) + { + LLFace* face = object->mDrawable->getFace(face_iter); + if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) + { + // these things differ per channel, unless there already is a universal + // texture setting function to setTE that takes channel as a param? + // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap + switch(channel) + { + case LLRender::DIFFUSE_MAP: + { + object->setTETexture(face_iter, new_id); + update_tex = true; + break; + } + + case LLRender::NORMAL_MAP: + { + object->setTENormalMap(face_iter, new_id); + update_mat = true; + update_tex = true; + break; + } + + case LLRender::SPECULAR_MAP: + { + object->setTESpecularMap(face_iter, new_id); + update_mat = true; + update_tex = true; + break; + } + } + // end switch + + } + } + } + + if (update_tex) + { + object->sendTEUpdate(); + } + + if (update_mat) + { + object->mDrawable->getVOVolume()->faceMappingChanged(); + } + } + } + */ +} + +/*=======================================*/ +/* 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& filenames) +{ + bool add_successful = false; + std::vector::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("LocalBitmapsVerifyFail", notif_args); + + delete unit; + unit = NULL; + + return false; + } +} + +void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id) +{ + if (!mMaterialList.empty()) + { + std::vector 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::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; +} + +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(); + + element["columns"][2]["column"] = "unit_id_HIDDEN"; + element["columns"][2]["type"] = "text"; + element["columns"][2]["value"] = (*iter)->getTrackingID(); + + 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..231231a344 --- /dev/null +++ b/indra/newview/lllocalgltfmaterials.h @@ -0,0 +1,134 @@ +/** + * @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: /* self update public section */ + enum EUpdateType + { + UT_FIRSTUSE, + UT_REGUPDATE + }; + + bool updateSelf(EUpdateType = UT_REGUPDATE); + +private: /* self update private section */ + bool loadMaterial(LLPointer raw); + void replaceIDs(LLUUID old_id, LLUUID new_id); + std::vector prepUpdateObjects(LLUUID old_id, U32 channel); + void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); + +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 mAlbedoFetched; + LLPointer mNormalFetched; + LLPointer mMRFetched; + LLPointer mEmissiveFetched; +}; + +class LLLocalGLTFMaterialTimer : public LLEventTimer +{ +public: + LLLocalGLTFMaterialTimer(); + ~LLLocalGLTFMaterialTimer(); + +public: + void startTimer(); + void stopTimer(); + bool isRunning(); + BOOL tick(); +}; + +class LLLocalGLTFMaterialMgr : public LLSingleton +{ + LLSINGLETON(LLLocalGLTFMaterialMgr); + ~LLLocalGLTFMaterialMgr(); +public: + bool addUnit(); + bool addUnit(const std::vector& 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 mMaterialList; + LLLocalGLTFMaterialTimer mTimer; + typedef std::list::iterator local_list_iter; +}; + +#endif // LL_LOCALGLTFMATERIALS_H + diff --git a/indra/newview/lllocalrendermaterials.cpp b/indra/newview/lllocalrendermaterials.cpp deleted file mode 100644 index aada61a056..0000000000 --- a/indra/newview/lllocalrendermaterials.cpp +++ /dev/null @@ -1,734 +0,0 @@ -/** - * @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 "lllocalrendermaterials.h" - -/* boost: will not compile unless equivalent is undef'd, beware. */ -#include "fix_macros.h" -#include - -/* time headers */ -#include -#include - -/* misc headers */ -#include "llagentwearables.h" -#include "llface.h" -#include "llfilepicker.h" -#include "llgltfmateriallist.h" -#include "llimagedimensionsinfo.h" -#include "lllocaltextureobject.h" -#include "llmaterialmgr.h" -#include "llnotificationsutil.h" -#include "llscrolllistctrl.h" -#include "lltexlayerparams.h" -#include "lltinygltfhelper.h" -#include "lltrans.h" -#include "llviewercontrol.h" -#include "llviewerdisplay.h" -#include "llviewerobjectlist.h" -#include "llviewerobject.h" -#include "llviewerwearable.h" -#include "llvoavatarself.h" -#include "llvovolume.h" -#include "pipeline.h" -#include "tinygltf/tiny_gltf.h" - -/*=======================================*/ -/* Formal declarations, constants, etc. */ -/*=======================================*/ - -static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; -static const BOOL LL_LOCAL_USE_MIPMAPS = true; -static const S32 LL_LOCAL_DISCARD_LEVEL = 0; -static const bool LL_LOCAL_SLAM_FOR_DEBUG = true; -static const bool LL_LOCAL_REPLACE_ON_DEL = true; -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(UT_FIRSTUSE); -} - -LLLocalGLTFMaterial::~LLLocalGLTFMaterial() -{ - // replace IDs with defaults, if set to do so. - if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 - { - replaceIDs(mWorldID, IMG_DEFAULT); - LLLocalGLTFMaterialMgr::getInstance()->doRebake(); - } - - // 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(EUpdateType optional_firstupdate) -{ - 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 raw_material = new LLGLTFMaterial(); - if (loadMaterial(raw_material)) - { - // decode is successful, we can safely proceed. - LLUUID old_id = LLUUID::null; - if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) - { - old_id = mWorldID; - } - mWorldID.generate(); - mLastModified = new_last_modified; - - gGLTFMaterialList.addMaterial(mWorldID, raw_material); - - if (optional_firstupdate != UT_FIRSTUSE) - { - // seek out everything old_id uses and replace it with mWorldID - replaceIDs(old_id, mWorldID); - - // remove old_id from material list - gGLTFMaterialList.removeMaterial(old_id); - } - - 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 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 albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); - // get normal map - LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index); - // get metallic-roughness texture - LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index); - // get emissive texture - LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index); - // get occlusion map if needed - LLPointer 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); - - mat->mAlbedoId = mAlbedoFetched->getID(); - mat->mNormalId = mNormalFetched->getID(); - mat->mMetallicRoughnessId = mMRFetched->getID(); - 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; -} - -void LLLocalGLTFMaterial::replaceIDs(LLUUID old_id, LLUUID new_id) -{ - // checking for misuse. - if (old_id == new_id) - { - LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" - << "Texture UUID: " << old_id.asString() << LL_ENDL; - return; - } - - // processing updates per channel; makes the process scalable. - // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. - updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); - updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); - updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); - - // default safeguard image for layers - if (new_id == IMG_DEFAULT) - { - new_id = IMG_DEFAULT_AVATAR; - } -} - -// this function sorts the faces from a getFaceList[getNumFaces] into a list of objects -// in order to prevent multiple sendTEUpdate calls per object during updateUserPrims -std::vector LLLocalGLTFMaterial::prepUpdateObjects(LLUUID old_id, U32 channel) -{ - std::vector obj_list; - // todo: find a way to update materials - /* - LLGLTFMaterial* old_material = gGLTFMaterialList.getMaterial(old_id); - - for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) - { - // getting an object from a face - LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; - - if(face_to_object) - { - LLViewerObject* affected_object = face_to_object->getViewerObject(); - - if(affected_object) - { - - // we have an object, we'll take it's UUID and compare it to - // whatever we already have in the returnable object list. - // if there is a match - we do not add (to prevent duplicates) - LLUUID mainlist_obj_id = affected_object->getID(); - bool add_object = true; - - // begin looking for duplicates - std::vector::iterator objlist_iter = obj_list.begin(); - for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) - { - LLViewerObject* obj = *objlist_iter; - if (obj->getID() == mainlist_obj_id) - { - add_object = false; // duplicate found. - } - } - // end looking for duplicates - - if(add_object) - { - obj_list.push_back(affected_object); - } - - } - - } - - } // end of face-iterating for() - - */ - return obj_list; -} - -void LLLocalGLTFMaterial::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) -{ - /*std::vector objectlist = prepUpdateObjects(old_id, channel); - for(std::vector::iterator object_iterator = objectlist.begin(); - object_iterator != objectlist.end(); object_iterator++) - { - LLViewerObject* object = *object_iterator; - - if(object) - { - bool update_tex = false; - bool update_mat = false; - S32 num_faces = object->getNumFaces(); - - for (U8 face_iter = 0; face_iter < num_faces; face_iter++) - { - if (object->mDrawable) - { - LLFace* face = object->mDrawable->getFace(face_iter); - if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) - { - // these things differ per channel, unless there already is a universal - // texture setting function to setTE that takes channel as a param? - // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap - switch(channel) - { - case LLRender::DIFFUSE_MAP: - { - object->setTETexture(face_iter, new_id); - update_tex = true; - break; - } - - case LLRender::NORMAL_MAP: - { - object->setTENormalMap(face_iter, new_id); - update_mat = true; - update_tex = true; - break; - } - - case LLRender::SPECULAR_MAP: - { - object->setTESpecularMap(face_iter, new_id); - update_mat = true; - update_tex = true; - break; - } - } - // end switch - - } - } - } - - if (update_tex) - { - object->sendTEUpdate(); - } - - if (update_mat) - { - object->mDrawable->getVOVolume()->faceMappingChanged(); - } - } - } - */ -} - -/*=======================================*/ -/* 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_IMAGE)) - { - mTimer.stopTimer(); - - std::string filename = picker.getFirstFile(); - while (!filename.empty()) - { - if (!checkTextureDimensions(filename)) - { - filename = picker.getNextFile(); - continue; - } - - LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename); - - if (unit->getValid()) - { - mMaterialList.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; - } - - filename = picker.getNextFile(); - } - - mTimer.startTimer(); - } - - return add_successful; -} - -bool LLLocalGLTFMaterialMgr::checkTextureDimensions(std::string filename) -{ - std::string exten = gDirUtilp->getExtension(filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - std::string mImageLoadError; - LLImageDimensionsInfo image_info; - if (!image_info.load(filename, codec)) - { - return false; - } - - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - - if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) - { - LLStringUtil::format_map_t args; - args["WIDTH"] = llformat("%d", max_width); - args["HEIGHT"] = llformat("%d", max_height); - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); - - LLSD notif_args; - notif_args["REASON"] = mImageLoadError; - LLNotificationsUtil::add("CannotUploadTexture", notif_args); - - return false; - } - - return true; -} - -void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id) -{ - if (!mMaterialList.empty()) - { - std::vector 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::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; -} - -void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl) -{ - if (ctrl) - { - ctrl->clearRows(); - - if (!mMaterialList.empty()) - { - for (local_list_iter iter = mMaterialList.begin(); - iter != mMaterialList.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(); - - ctrl->addElement(element); - } - } - } - -} - -void LLLocalGLTFMaterialMgr::doUpdates() -{ - // preventing theoretical overlap in cases with huge number of loaded images. - mTimer.stopTimer(); - mNeedsRebake = false; - - for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) - { - (*iter)->updateSelf(); - } - - doRebake(); - mTimer.startTimer(); -} - -void LLLocalGLTFMaterialMgr::setNeedsRebake() -{ - mNeedsRebake = true; -} - -void LLLocalGLTFMaterialMgr::doRebake() -{ /* separated that from doUpdates to insure a rebake can be called separately during deletion */ - if (mNeedsRebake) - { - gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); - mNeedsRebake = false; - } -} - diff --git a/indra/newview/lllocalrendermaterials.h b/indra/newview/lllocalrendermaterials.h deleted file mode 100644 index ea1edbb7b1..0000000000 --- a/indra/newview/lllocalrendermaterials.h +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @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_LOCALRENDERMATERIALS_H -#define LL_LOCALRENDERMATERIALS_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: /* self update public section */ - enum EUpdateType - { - UT_FIRSTUSE, - UT_REGUPDATE - }; - - bool updateSelf(EUpdateType = UT_REGUPDATE); - -private: /* self update private section */ - bool loadMaterial(LLPointer raw); - void replaceIDs(LLUUID old_id, LLUUID new_id); - std::vector prepUpdateObjects(LLUUID old_id, U32 channel); - void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); - -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 mAlbedoFetched; - LLPointer mNormalFetched; - LLPointer mMRFetched; - LLPointer mEmissiveFetched; -}; - -class LLLocalGLTFMaterialTimer : public LLEventTimer -{ -public: - LLLocalGLTFMaterialTimer(); - ~LLLocalGLTFMaterialTimer(); - -public: - void startTimer(); - void stopTimer(); - bool isRunning(); - BOOL tick(); -}; - -class LLLocalGLTFMaterialMgr : public LLSingleton -{ - LLSINGLETON(LLLocalGLTFMaterialMgr); - ~LLLocalGLTFMaterialMgr(); -public: - bool addUnit(); - void delUnit(LLUUID tracking_id); - bool checkTextureDimensions(std::string filename); - - LLUUID getWorldID(LLUUID tracking_id); - bool isLocal(LLUUID world_id); - std::string getFilename(LLUUID tracking_id); - - void feedScrollList(LLScrollListCtrl* ctrl); - void doUpdates(); - void setNeedsRebake(); - void doRebake(); - -private: - std::list mMaterialList; - LLLocalGLTFMaterialTimer mTimer; - bool mNeedsRebake; - typedef std::list::iterator local_list_iter; -}; - -#endif // LL_LOCALRENDERMATERIALS_H - diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 9743976e33..95f96c95f2 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1019,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& 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& filenames) @@ -1043,7 +1040,11 @@ void LLMaterialFilePicker::notify(const std::vector& filenames) if (filenames.size() > 0) { - loadMaterial(filenames[0]); + LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); + if (me) + { + me->loadMaterialFromFile(filenames[0]); + } } } @@ -1114,7 +1115,7 @@ void LLMaterialFilePicker::textureLoadedCallback(BOOL success, LLViewerFetchedTe } -void LLMaterialFilePicker::loadMaterial(const std::string& filename) +void LLMaterialEditor::loadMaterialFromFile(const std::string& filename) { tinygltf::TinyGLTF loader; std::string error_msg; @@ -1160,13 +1161,13 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename) model_out.materials.resize(1); // get albedo texture - LLPointer albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName); + LLPointer albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mAlbedoName); // get normal map - LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mME->mNormalName); + LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mNormalName); // get metallic-roughness texture - LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName); + LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mMetallicRoughnessName); // get emissive texture - LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName); + LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mEmissiveName); // get occlusion map if needed LLPointer occlusion_img; if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index) @@ -1176,75 +1177,75 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename) } LLTinyGLTFHelper::initFetchedTextures(material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img, - mME->mAlbedoFetched, mME->mNormalFetched, mME->mMetallicRoughnessFetched, mME->mEmissiveFetched); + mAlbedoFetched, mNormalFetched, mMetallicRoughnessFetched, mEmissiveFetched); pack_textures(albedo_img, normal_img, mr_img, emissive_img, occlusion_img, - mME->mAlbedoJ2C, mME->mNormalJ2C, mME->mMetallicRoughnessJ2C, mME->mEmissiveJ2C); + 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) @@ -1533,7 +1534,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& filenames, LLUUID outfit_id) 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& 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& filenames) diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 1d3c61c21e..a9a8d84ab5 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,12 +72,14 @@ #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 S32 LOCAL_ICON_ID_COLUMN = 0; +static const S32 LOCAL_TRACKING_ID_COLUMN = 2; //static const char CURRENT_IMAGE_NAME[] = "Current Texture"; //static const char WHITE_IMAGE_NAME[] = "Blank Texture"; @@ -472,7 +477,9 @@ BOOL LLFloaterTexturePicker::postBuild() mLocalScrollCtrl = getChild("l_name_list"); mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this); + mLocalScrollCtrl->clearRows(); LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl); + LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(mLocalScrollCtrl); mNoCopyTextureSelected = FALSE; @@ -749,8 +756,21 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata) { if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty()) { + std::string icon_name = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_ICON_ID_COLUMN)->getValue().asString(); LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); - local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id); + + std::string mat_icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_NONE); + + if (mat_icon_name == icon_name) + { + local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id); + } + else + { + local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id); + } } } @@ -898,11 +918,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 @@ -913,22 +931,37 @@ void LLFloaterTexturePicker::onBtnRemove(void* userdata) if (!selected_items.empty()) { + std::string mat_icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_NONE); + for(std::vector::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); + std::string icon_name = list_item->getColumn(LOCAL_ICON_ID_COLUMN)->getValue().asString(); + LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); + + // todo: works, but need a better way to distinguish material from texture + if (icon_name == mat_icon_name) + { + LLLocalGLTFMaterialMgr::getInstance()->delUnit(tracking_id); + } + else + { + LLLocalBitmapMgr::getInstance()->delUnit(tracking_id); + } } } self->getChild("l_rem_btn")->setEnabled(false); self->getChild("l_upl_btn")->setEnabled(false); + self->mLocalScrollCtrl->clearRows(); LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); + LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } - } // static @@ -944,15 +977,34 @@ 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. */ - + + std::string icon_name = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_ICON_ID_COLUMN)->getValue().asString(); 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)); - } + std::string mat_icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_NONE); + if (mat_icon_name == icon_name) + { + 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 @@ -968,8 +1020,23 @@ 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); + std::string icon_name = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_ICON_ID_COLUMN)->getValue().asString(); + LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); + LLUUID inworld_id; + + std::string mat_icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_NONE); + + if (icon_name == mat_icon_name) + { + inworld_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(tracking_id); + } + else + { + inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); + } + if (self->mSetImageAssetIDCallback) { self->mSetImageAssetIDCallback(inworld_id); @@ -1202,6 +1269,36 @@ void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled) onModeSelect(0, this); } +void LLFloaterTexturePicker::onPickerCallback(const std::vector& filenames, LLHandle handle) +{ + std::vector::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); diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index cfd5c4bd29..b77ff98d80 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -345,6 +345,8 @@ public: void setLocalTextureEnabled(BOOL enabled); void setBakeTextureEnabled(BOOL enabled); + static void onPickerCallback(const std::vector& filenames, LLHandle handle); + protected: LLPointer mTexturep; LLView* mOwner; 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& 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,13 +115,17 @@ class LLFilePickerReplyThread : public LLFilePickerThread public: typedef boost::signals2::signal& 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& 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; 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_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml index 5ab31b404e..a1b614d1af 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -240,6 +240,7 @@ multi_select="true" search_column="1" visible="false"> + -- cgit v1.2.3