From f842aeac30c1b3abad76201d5c5f9318fd0c960e Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Wed, 17 Aug 2022 10:29:33 -0700 Subject: SL-17699 Add upport for materials to texture picker. A work in progress but I am about to make some larger changes to inventory code so I wanted to secure this first --- indra/newview/lltexturectrl.cpp | 43 ++++++++++++++++++++-- indra/newview/lltexturectrl.h | 3 ++ .../skins/default/xui/en/floater_texture_ctrl.xml | 30 +++++++++++++-- 3 files changed, 69 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index e8ff14daac..a0d4667827 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -417,8 +417,12 @@ BOOL LLFloaterTexturePicker::postBuild() childSetCommitCallback("show_folders_check", onShowFolders, this); getChildView("show_folders_check")->setVisible( FALSE); - mFilterEdit = getChild("inventory search editor"); - mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); + mFilterEdit = getChild("inventory search editor"); + mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); + + mTextureMaterialsCombo = getChild("textures_material_combo"); + mTextureMaterialsCombo->setCommitCallback(onSelectTextureMaterials, this); + mTextureMaterialsCombo->selectByValue(0); mInventoryPanel = getChild("inventory panel"); @@ -430,7 +434,7 @@ BOOL LLFloaterTexturePicker::postBuild() { U32 filter_types = 0x0; filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; - filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; + filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; mInventoryPanel->setFilterTypes(filter_types); //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. @@ -817,6 +821,7 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata) self->getChild("Blank")->setVisible(index == 0 ? TRUE : FALSE); self->getChild("None")->setVisible(index == 0 ? TRUE : FALSE); self->getChild("Pipette")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild("textures_material_combo")->setVisible(index == 0 ? TRUE : FALSE); self->getChild("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE); self->getChild("inventory panel")->setVisible(index == 0 ? TRUE : FALSE); @@ -1136,6 +1141,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); diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index a234124c08..cfd5c4bd29 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -340,6 +340,8 @@ 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); @@ -365,6 +367,7 @@ protected: BOOL mActive; LLFilterEditor* mFilterEdit; + LLComboBox* mTextureMaterialsCombo; LLInventoryPanel* mInventoryPanel; PermissionMask mImmediateFilterPermMask; PermissionMask mDnDFilterPermMask; 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..7d23034a09 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" /> + + + + + - Date: Wed, 17 Aug 2022 11:01:23 -0700 Subject: SL-17699 Add upport for materials to texture picker. A work in progress but I am about to make some larger changes to inventory code so I wanted to secure this first (missed a change) --- indra/newview/skins/default/xui/en/floater_texture_ctrl.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') 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 7d23034a09..b47ade5d98 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -169,7 +169,7 @@ name="inventory search editor" top="48" width="231" /> - Date: Wed, 17 Aug 2022 22:03:14 +0300 Subject: SL-17699 Multiple asset types support for LLAssetFilteredInventoryPanel --- indra/newview/llinventorypanel.cpp | 62 +++++++++++++++++++--- indra/newview/llinventorypanel.h | 7 +-- indra/newview/llplacesinventorypanel.h | 2 +- .../default/xui/en/floater_my_environments.xml | 2 +- .../default/xui/en/floater_settings_picker.xml | 2 +- .../skins/default/xui/en/floater_texture_ctrl.xml | 2 +- 6 files changed, 62 insertions(+), 15 deletions(-) (limited to 'indra/newview') 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 > tokenizer; + boost::char_separator 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 { - Mandatory filter_asset_type; + Mandatory 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/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/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"/> + filter_asset_types="settings" /> + filter_asset_types="texture|material"/> Date: Wed, 17 Aug 2022 12:20:15 -0700 Subject: SL-17699 Add upport for materials to texture picker. Temporarilyly change the filtered inventory panel to a regular one so that materials show too. A fix for this that lets us revert to the asset_filtered version is in progress and will be pulled in soon - then this change too will be reverted --- indra/newview/skins/default/xui/en/floater_texture_ctrl.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') 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 b47ade5d98..7d23034a09 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -169,7 +169,7 @@ name="inventory search editor" top="48" width="231" /> - Date: Wed, 17 Aug 2022 12:21:01 -0700 Subject: SL-17699 Add upport for materials to texture picker. MAke sure the default (index 0) option is selected and update filters accordingly at startup --- indra/newview/lltexturectrl.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index a0d4667827..d9ecfbc81d 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -420,11 +420,13 @@ BOOL LLFloaterTexturePicker::postBuild() mFilterEdit = getChild("inventory search editor"); mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); + mInventoryPanel = getChild("inventory panel"); + mTextureMaterialsCombo = getChild("textures_material_combo"); mTextureMaterialsCombo->setCommitCallback(onSelectTextureMaterials, this); - mTextureMaterialsCombo->selectByValue(0); - mInventoryPanel = getChild("inventory panel"); + // set the combo box to the first entry in the list (currently textures and materials) + mTextureMaterialsCombo->selectByValue(0); mModeSelector = getChild("mode_selection"); mModeSelector->setCommitCallback(onModeSelect, this); @@ -432,12 +434,12 @@ BOOL LLFloaterTexturePicker::postBuild() 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); -- cgit v1.2.3 From 339e1d200f7fd5f8be715722369295220da2079b Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Wed, 17 Aug 2022 13:49:10 -0700 Subject: SL-17699 Add upport for materials to texture picker: restore the asset filtered inventory panel and pull in @Caladbolg's fix to make it work with more than 1 asset type from here https://bitbucket.org/lindenlab/viewer/commits/0ab6dfa12eb04238d82c7a4aea7390cbd28beacd --- indra/newview/llinventorypanel.cpp | 62 +++++++++++++++++++--- indra/newview/llinventorypanel.h | 7 +-- indra/newview/llplacesinventorypanel.h | 2 +- .../default/xui/en/floater_my_environments.xml | 2 +- .../default/xui/en/floater_settings_picker.xml | 2 +- .../skins/default/xui/en/floater_texture_ctrl.xml | 6 +-- 6 files changed, 64 insertions(+), 17 deletions(-) (limited to 'indra/newview') 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 > tokenizer; + boost::char_separator 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 { - Mandatory filter_asset_type; + Mandatory 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/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/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"/> + filter_asset_types="settings" /> - + filter_asset_types="texture|material"/> Date: Fri, 19 Aug 2022 13:14:51 -0700 Subject: https://jira.secondlife.com/browse/SL-17699 Integrate GLTF materials with build floater texture tab: First pass - some edge cases remaining. User can now edit an object or set of objects, choose a material and have it apply as expected --- indra/newview/lltexturectrl.cpp | 71 +++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index d9ecfbc81d..1d3c61c21e 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1533,9 +1533,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(); @@ -1556,15 +1556,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) { @@ -1575,8 +1624,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(); + } } } } @@ -1709,7 +1760,7 @@ void LLTextureCtrl::draw() } else//mImageAssetID == LLUUID::null { - mTexturep = NULL; + mTexturep = NULL; } // Border -- cgit v1.2.3 From 664ba53e4ce8510345e490cedf4401f6655f38fc Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 15 Jun 2022 16:00:21 +0300 Subject: SL-17584 Make setShaders crashes more informative --- indra/newview/llviewershadermgr.cpp | 21 ++++++++++----------- indra/newview/llviewershadermgr.h | 6 +++++- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'indra/newview') 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(); -- cgit v1.2.3 From 4bb419031c130402a5589ff698e28e230a0c123a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 19 Aug 2022 01:45:47 +0300 Subject: SL-17653 Basic local gltf materials --- indra/newview/CMakeLists.txt | 4 + indra/newview/llgltfmateriallist.cpp | 87 +--- indra/newview/llgltfmateriallist.h | 3 + indra/newview/lllocalrendermaterials.cpp | 734 +++++++++++++++++++++++++++++++ indra/newview/lllocalrendermaterials.h | 136 ++++++ indra/newview/llmaterialeditor.cpp | 103 +---- indra/newview/lltinygltfhelper.cpp | 245 +++++++++++ indra/newview/lltinygltfhelper.h | 55 +++ indra/newview/llviewertexturelist.h | 6 +- 9 files changed, 1204 insertions(+), 169 deletions(-) create mode 100644 indra/newview/lllocalrendermaterials.cpp create mode 100644 indra/newview/lllocalrendermaterials.h create mode 100644 indra/newview/lltinygltfhelper.cpp create mode 100644 indra/newview/lltinygltfhelper.h (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b67bc91277..e72536e781 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 + lllocalrendermaterials.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 + lllocalrendermaterials.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/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 LLGLTFMaterialList gGLTFMaterialList; -static LLColor4 get_color(const std::vector& 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/lllocalrendermaterials.cpp b/indra/newview/lllocalrendermaterials.cpp new file mode 100644 index 0000000000..aada61a056 --- /dev/null +++ b/indra/newview/lllocalrendermaterials.cpp @@ -0,0 +1,734 @@ +/** + * @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 new file mode 100644 index 0000000000..ea1edbb7b1 --- /dev/null +++ b/indra/newview/lllocalrendermaterials.h @@ -0,0 +1,136 @@ +/** + * @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 7b17fb5fdf..9743976e33 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 @@ -1046,38 +1047,6 @@ void LLMaterialFilePicker::notify(const std::vector& filenames) } } -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) - { - return &(model.images[source_idx]); - } - } - - 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& img) { if (img->getComponents() == 4) @@ -1108,16 +1077,12 @@ static void copy_red_channel(LLPointer& src_img, LLPointer& albedo_img, LLPointer& normal_img, LLPointer& mr_img, LLPointer& emissive_img, LLPointer& occlusion_img, - LLPointer& albedo_tex, - LLPointer& normal_tex, - LLPointer& mr_tex, - LLPointer& emissive_tex, LLPointer& albedo_j2c, LLPointer& normal_j2c, LLPointer& mr_j2c, @@ -1125,70 +1090,25 @@ 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& 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) { } @@ -1240,23 +1160,24 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename) model_out.materials.resize(1); // get albedo texture - LLPointer albedo_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName); + LLPointer albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName); // get normal map - LLPointer normal_img = get_texture(folder, model_in, material_in.normalTexture.index, mME->mNormalName); + LLPointer normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mME->mNormalName); // get metallic-roughness texture - LLPointer mr_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName); + LLPointer mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName); // get emissive texture - LLPointer emissive_img = get_texture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName); + LLPointer emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName); // get occlusion map if needed LLPointer 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, + LLTinyGLTFHelper::initFetchedTextures(material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img, + mME->mAlbedoFetched, mME->mNormalFetched, mME->mMetallicRoughnessFetched, mME->mEmissiveFetched); + pack_textures(albedo_img, normal_img, mr_img, emissive_img, occlusion_img, mME->mAlbedoJ2C, mME->mNormalJ2C, mME->mMetallicRoughnessJ2C, mME->mEmissiveJ2C); LLUUID albedo_id; @@ -1389,8 +1310,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); 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& 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& src_img, LLPointer& 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& albedo_img, + LLPointer& normal_img, + LLPointer& mr_img, + LLPointer& emissive_img, + LLPointer& occlusion_img, + LLPointer& albedo_tex, + LLPointer& normal_tex, + LLPointer& mr_tex, + LLPointer& 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& 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& 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& albedo_img, + LLPointer& normal_img, + LLPointer& mr_img, + LLPointer& emissive_img, + LLPointer& occlusion_img, + LLPointer& albedo_tex, + LLPointer& normal_tex, + LLPointer& mr_tex, + LLPointer& emissive_tex); +} + 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 -- cgit v1.2.3 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 From 8a91c1394745a28cb78e7432eaa481b6cedd7408 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 22 Aug 2022 22:11:58 +0300 Subject: SL-17653 Local gltf materials #3 --- indra/newview/lllocalbitmaps.cpp | 7 +- indra/newview/lllocalgltfmaterials.cpp | 196 ++------------------- indra/newview/lllocalgltfmaterials.h | 15 +- indra/newview/llmaterialeditor.cpp | 30 ---- indra/newview/lltexturectrl.cpp | 53 ++---- .../skins/default/xui/en/floater_texture_ctrl.xml | 1 - .../newview/skins/default/xui/en/notifications.xml | 9 + 7 files changed, 47 insertions(+), 264 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 6d22a3af52..c3e3fd5c1b 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -1109,9 +1109,10 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) 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(); + LLSD data; + data["id"] = (*iter)->getTrackingID(); + data["type"] = (S32)LLAssetType::AT_TEXTURE; + element["value"] = data; ctrl->addElement(element); } diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp index 14772dd792..ef488e9ef4 100644 --- a/indra/newview/lllocalgltfmaterials.cpp +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -39,24 +39,15 @@ #include /* misc headers */ -#include "llagentwearables.h" -#include "llface.h" #include "llfilepicker.h" #include "llgltfmateriallist.h" -#include "llimagedimensionsinfo.h" +#include "llimage.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 "llviewertexture.h" #include "tinygltf/tiny_gltf.h" /*=======================================*/ @@ -64,10 +55,6 @@ /*=======================================*/ 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; /*=======================================*/ @@ -104,7 +91,7 @@ LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename) /* 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); + mValid = updateSelf(); } LLLocalGLTFMaterial::~LLLocalGLTFMaterial() @@ -140,7 +127,7 @@ bool LLLocalGLTFMaterial::getValid() } /* update functions */ -bool LLLocalGLTFMaterial::updateSelf(EUpdateType optional_firstupdate) +bool LLLocalGLTFMaterial::updateSelf() { bool updated = false; @@ -164,24 +151,14 @@ bool LLLocalGLTFMaterial::updateSelf(EUpdateType optional_firstupdate) 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(); + if (mWorldID.isNull()) + { + mWorldID.generate(); + } mLastModified = new_last_modified; + // will replace material if it already exists 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; @@ -339,151 +316,6 @@ bool LLLocalGLTFMaterial::loadMaterial(LLPointer mat) 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 */ @@ -584,7 +416,7 @@ bool LLLocalGLTFMaterialMgr::addUnit(const std::string& filename) LLSD notif_args; notif_args["FNAME"] = filename; - LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args); + LLNotificationsUtil::add("LocalGLTFVerifyFail", notif_args); delete unit; unit = NULL; @@ -663,6 +495,7 @@ std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id) return filename; } +// probably shouldn't be here, but at the moment this mirrors lllocalbitmaps void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl) { if (ctrl) @@ -686,9 +519,10 @@ void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl) 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(); + LLSD data; + data["id"] = (*iter)->getTrackingID(); + data["type"] = (S32)LLAssetType::AT_MATERIAL; + element["value"] = data; ctrl->addElement(element); } diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h index 231231a344..7f5b06e10a 100644 --- a/indra/newview/lllocalgltfmaterials.h +++ b/indra/newview/lllocalgltfmaterials.h @@ -48,20 +48,11 @@ public: /* accessors */ LLUUID getWorldID(); bool getValid(); -public: /* self update public section */ - enum EUpdateType - { - UT_FIRSTUSE, - UT_REGUPDATE - }; - - bool updateSelf(EUpdateType = UT_REGUPDATE); +public: + bool updateSelf(); -private: /* self update private section */ +private: 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 diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 95f96c95f2..2052f252b3 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1048,36 +1048,6 @@ void LLMaterialFilePicker::notify(const std::vector& filenames) } } -static void strip_alpha_channel(LLPointer& 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& src_img, LLPointer& 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( LLPointer& albedo_img, LLPointer& normal_img, diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index a9a8d84ab5..2757f54ea9 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -78,15 +78,6 @@ #include "llavatarappearancedefines.h" -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"; -//static const char NO_IMAGE_NAME[] = "None"; - - - //static bool get_is_predefined_texture(LLUUID asset_id) { @@ -756,14 +747,11 @@ 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(); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID temp_id = data["id"]; + S32 asset_type = data["type"].asInteger(); - std::string mat_icon_name = LLInventoryIcon::getIconName( - LLAssetType::AT_MATERIAL, - LLInventoryType::IT_NONE); - - if (mat_icon_name == icon_name) + if (LLAssetType::AT_MATERIAL == asset_type) { local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id); } @@ -931,9 +919,6 @@ 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++) @@ -941,11 +926,11 @@ void LLFloaterTexturePicker::onBtnRemove(void* userdata) LLScrollListItem* list_item = *iter; if (list_item) { - 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(); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); - // todo: works, but need a better way to distinguish material from texture - if (icon_name == mat_icon_name) + if (LLAssetType::AT_MATERIAL == asset_type) { LLLocalGLTFMaterialMgr::getInstance()->delUnit(tracking_id); } @@ -978,14 +963,11 @@ 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 mat_icon_name = LLInventoryIcon::getIconName( - LLAssetType::AT_MATERIAL, - LLInventoryType::IT_NONE); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); - if (mat_icon_name == icon_name) + if (LLAssetType::AT_MATERIAL == asset_type) { std::string filename = LLLocalGLTFMaterialMgr::getInstance()->getFilename(tracking_id); if (!filename.empty()) @@ -1020,15 +1002,12 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata) if (has_selection) { - 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); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); LLUUID inworld_id; - std::string mat_icon_name = LLInventoryIcon::getIconName( - LLAssetType::AT_MATERIAL, - LLInventoryType::IT_NONE); - - if (icon_name == mat_icon_name) + if (LLAssetType::AT_MATERIAL == asset_type) { inworld_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(tracking_id); } 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 a1b614d1af..18c226ed58 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -242,7 +242,6 @@ visible="false"> - 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 @@ -9802,6 +9802,15 @@ Attempted to add an invalid or unreadable image file [FNAME] which could not be Attempt cancelled. + +Attempted to add an invalid or unreadable GLTF material [FNAME] which could not be opened or decoded. +Attempt cancelled. + +