From 001f2915ea24a030b9a6fb26a3ecbeedee6402bc Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Mon, 6 Nov 2023 16:15:52 -0600 Subject: [PATCH 01/77] SL-20570 Fix for lossy (and square) normal maps when importing GLTF materials. --- indra/newview/llmaterialeditor.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 7a65231a2d..5be1aa08ab 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1622,17 +1622,9 @@ static void pack_textures( if (normal_img) { - normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img); - - LLPointer test; - test = LLViewerTextureList::convertToUploadFile(normal_img, 1024, true); - - S32 lossy_bytes = normal_j2c->getDataSize(); - S32 lossless_bytes = test->getDataSize(); - - LL_DEBUGS("MaterialEditor") << llformat("Lossless vs Lossy: (%d/%d) = %.2f", lossless_bytes, lossy_bytes, (F32)lossless_bytes / lossy_bytes) << LL_ENDL; - - normal_j2c = test; + // create a losslessly compressed version of the normal map + normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img, 1024, false, true); + LL_DEBUGS("MaterialEditor") << "Normal: " << normal_j2c->getDataSize() << LL_ENDL; } if (mr_img) From e7b71cd8a10898320cf3e0aebc05bfdec3d2ffa3 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 8 Nov 2023 11:50:46 -0600 Subject: [PATCH 02/77] SL-20582 Fix for overriding to alpha mode blend not working. Incidental decruft of dead code (thanks, Rye!) --- indra/llprimitive/llgltfmaterial.cpp | 1 + indra/llprimitive/llprimitive.cpp | 36 ---------------------------- indra/llprimitive/llprimitive.h | 5 +--- 3 files changed, 2 insertions(+), 40 deletions(-) diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index f42c11ee21..c1f2a04154 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -715,6 +715,7 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data) if (am.isInteger()) { mAlphaMode = (AlphaMode) am.asInteger(); + mOverrideAlphaMode = true; } const LLSD& ac = data["ac"]; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 350d84ae6c..904747af2d 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -2376,42 +2376,6 @@ void LLRenderMaterialParams::copy(const LLNetworkData& data) mEntries = param.mEntries; } -LLSD LLRenderMaterialParams::asLLSD() const -{ - LLSD ret; - - for (int i = 0; i < mEntries.size(); ++i) - { - ret[i]["te_idx"] = mEntries[i].te_idx; - ret[i]["id"] = mEntries[i].id; - } - - return ret; -} - -bool LLRenderMaterialParams::fromLLSD(LLSD& sd) -{ - if (sd.isArray()) - { - mEntries.resize(sd.size()); - for (int i = 0; i < sd.size(); ++i) - { - if (sd[i].has("te_idx") && sd.has("id")) - { - mEntries[i].te_idx = sd[i]["te_idx"].asInteger(); - mEntries[i].id = sd[i]["id"].asUUID(); - } - else - { - return false; - } - } - - return true; - } - - return false; -} void LLRenderMaterialParams::setMaterial(U8 te, const LLUUID& id) { diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index d2adfa4a3d..0b7dbd703a 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -382,10 +382,7 @@ public: BOOL unpack(LLDataPacker& dp) override; bool operator==(const LLNetworkData& data) const override; void copy(const LLNetworkData& data) override; - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - + void setMaterial(U8 te_idx, const LLUUID& id); const LLUUID& getMaterial(U8 te_idx) const; From de844bfce11ea46d428d775d377460db8a2cf54b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 7 Nov 2023 23:20:40 +0200 Subject: [PATCH 03/77] SL-20569 Notify user when reflection probe can't be selected --- indra/newview/llpanelvolume.cpp | 17 +++++++++++++++++ .../skins/default/xui/en/notifications.xml | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index d6c36bbfb7..d47383b29a 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -746,6 +746,21 @@ void LLPanelVolume::sendIsLight() LL_INFOS() << "update light sent" << LL_ENDL; } +void notify_cant_select_reflection_probe() +{ + static bool show_notification = true; + if (show_notification) + { + // show only once per session if not ignored + show_notification = false; + if (!gSavedSettings.getBOOL("SelectReflectionProbes")) + { + LLNotificationsUtil::add("CantSelectReflectionProbe"); + } + // else: user used the setting, don't show again this session + } +} + void LLPanelVolume::sendIsReflectionProbe() { LLViewerObject* objectp = mObject; @@ -764,6 +779,7 @@ void LLPanelVolume::sendIsReflectionProbe() } else { + notify_cant_select_reflection_probe(); volobjp->setIsReflectionProbe(value); } } @@ -780,6 +796,7 @@ void LLPanelVolume::doSendIsReflectionProbe(const LLSD & notification, const LLS } LLVOVolume* volobjp = (LLVOVolume*)objectp; + notify_cant_select_reflection_probe(); volobjp->setIsReflectionProbe(true); { // has become a reflection probe, slam to a 10m sphere and pop up a message diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d1838fc7ef..16fc79b77d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7013,6 +7013,19 @@ Please try again. Not connected to a materials capable region. + + + You have placed a reflection probe, but option for selecting reflection probes is disabled. To be able to select reflection probes enable Build > Options > Select Reflection Probes. + confirm + + + Date: Wed, 8 Nov 2023 02:05:33 +0200 Subject: [PATCH 04/77] SL-20569 Notify user when reflection probe can't be selected #2 --- indra/newview/llpanelvolume.cpp | 19 ++----------------- .../skins/default/xui/en/notifications.xml | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index d47383b29a..b1d3ac2245 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -746,21 +746,6 @@ void LLPanelVolume::sendIsLight() LL_INFOS() << "update light sent" << LL_ENDL; } -void notify_cant_select_reflection_probe() -{ - static bool show_notification = true; - if (show_notification) - { - // show only once per session if not ignored - show_notification = false; - if (!gSavedSettings.getBOOL("SelectReflectionProbes")) - { - LLNotificationsUtil::add("CantSelectReflectionProbe"); - } - // else: user used the setting, don't show again this session - } -} - void LLPanelVolume::sendIsReflectionProbe() { LLViewerObject* objectp = mObject; @@ -779,7 +764,7 @@ void LLPanelVolume::sendIsReflectionProbe() } else { - notify_cant_select_reflection_probe(); + LLNotificationsUtil::add("CantSelectReflectionProbe"); volobjp->setIsReflectionProbe(value); } } @@ -796,7 +781,7 @@ void LLPanelVolume::doSendIsReflectionProbe(const LLSD & notification, const LLS } LLVOVolume* volobjp = (LLVOVolume*)objectp; - notify_cant_select_reflection_probe(); + LLNotificationsUtil::add("CantSelectReflectionProbe"); volobjp->setIsReflectionProbe(true); { // has become a reflection probe, slam to a 10m sphere and pop up a message diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 16fc79b77d..6c841ac049 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7018,7 +7018,7 @@ Please try again. name="CantSelectReflectionProbe" type="alertmodal"> - You have placed a reflection probe, but option for selecting reflection probes is disabled. To be able to select reflection probes enable Build > Options > Select Reflection Probes. + You have placed a reflection probe, but 'Select Reflection Probes' is disabled. To be able to select reflection probes, check Build > Options > Select Reflection Probes. confirm Date: Thu, 9 Nov 2023 00:39:34 +0200 Subject: [PATCH 05/77] SL-20228 When a reflection probe is unchecked in a link set, it should stop being phantom --- indra/newview/llpanelvolume.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index b1d3ac2245..f58aab3080 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -764,7 +764,20 @@ void LLPanelVolume::sendIsReflectionProbe() } else { - LLNotificationsUtil::add("CantSelectReflectionProbe"); + if (value) + { + LLNotificationsUtil::add("CantSelectReflectionProbe"); + } + else if (objectp->flagPhantom()) + { + LLViewerObject* root = objectp->getRootEdit(); + bool in_linkeset = root != objectp || objectp->numChildren() > 0; + if (in_linkeset) + { + // In linkset with a phantom flag + objectp->setFlags(FLAGS_PHANTOM, FALSE); + } + } volobjp->setIsReflectionProbe(value); } } @@ -1213,6 +1226,17 @@ void LLPanelVolume::onPasteLight() } else { + if (objectp->flagPhantom()) + { + LLViewerObject* root = objectp->getRootEdit(); + bool in_linkeset = root != objectp || objectp->numChildren() > 0; + if (in_linkeset) + { + // In linkset with a phantom flag + objectp->setFlags(FLAGS_PHANTOM, FALSE); + } + } + volobjp->setIsReflectionProbe(false); } } From 711354c2f526421b7cd2918f584731624a9995e5 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Thu, 2 Nov 2023 09:55:44 -0700 Subject: [PATCH 06/77] SL-20553: Save material button in build floater now depends on agent inventory rather than object inventory --- indra/newview/llmaterialeditor.cpp | 92 ++++++++++++++++++++++++++---- indra/newview/llpanelface.cpp | 65 ++++++++++++++++++--- indra/newview/llpanelface.h | 6 +- 3 files changed, 142 insertions(+), 21 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 5be1aa08ab..bae4afb7e6 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -38,6 +38,7 @@ #include "llgltfmateriallist.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" +#include "llinventoryfunctions.h" #include "lllocalgltfmaterials.h" #include "llnotificationsutil.h" #include "lltexturectrl.h" @@ -1796,8 +1797,49 @@ void LLMaterialEditor::loadLive() } } +namespace +{ + // Which inventory to consult for item permissions + enum class ItemSource + { + // Consult the permissions of the item in the object's inventory. If + // the item is not present, then usage of the asset is allowed. + OBJECT, + // Consult the permissions of the item in the agent's inventory. If + // the item is not present, then usage of the asset is not allowed. + AGENT + }; + + class LLAssetIDMatchesWithPerms : public LLInventoryCollectFunctor + { + public: + LLAssetIDMatchesWithPerms(const LLUUID& asset_id, const std::vector& ops) : mAssetID(asset_id), mOps(ops) {} + virtual ~LLAssetIDMatchesWithPerms() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (!item || item->getAssetUUID() != mAssetID) + { + return false; + } + LLPermissions item_permissions = item->getPermissions(); + for (PermissionBit op : mOps) + { + if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } + } + return true; + } + + protected: + LLUUID mAssetID; + std::vector mOps; + }; +}; + // *NOTE: permissions_out includes user preferences for new item creation (LLFloaterPerms) -bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector& ops, LLPermissions& permissions_out, LLViewerInventoryItem*& item_out) +bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector& ops, const ItemSource item_source, LLPermissions& permissions_out, LLViewerInventoryItem*& item_out) { if (!LLMaterialEditor::capabilitiesAvailable()) { @@ -1830,19 +1872,45 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vectorgetInventoryItemByAsset(func.mMaterialId); - - LLPermissions item_permissions; - if (item_out) + // Look for the item to base permissions off of + item_out = nullptr; + if (func.mMaterialId != LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) { - item_permissions.set(item_out->getPermissions()); - for (PermissionBit op : ops) + LLAssetIDMatchesWithPerms item_has_perms(func.mMaterialId, ops); + if (item_source == ItemSource::OBJECT) { - if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE)) + item_out = selected_object->getInventoryItemByAsset(func.mMaterialId); + if (item_out && !item_has_perms(nullptr, item_out)) { return false; } } + else + { + llassert(item_source == ItemSource::AGENT); + + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + // *NOTE: PBRPickerAgentListener will need + // to be changed if checking the trash is + // disabled + LLInventoryModel::INCLUDE_TRASH, + item_has_perms); + if (items.empty()) + { + return false; + } + item_out = items[0]; + } + } + + LLPermissions item_permissions; + if (item_out) + { + item_permissions = item_out->getPermissions(); // Update flags for new owner if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) { @@ -1913,7 +1981,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() @@ -1921,7 +1989,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out); } bool LLMaterialEditor::canClipboardObjectsMaterial() @@ -1947,7 +2015,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() @@ -1955,7 +2023,7 @@ void LLMaterialEditor::saveObjectsMaterialAs() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 9150b89de3..02c00e7f87 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1880,15 +1880,55 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } +// One-off listener that updates the build floater UI when the agent inventory adds or removes an item +class PBRPickerAgentListener : public LLInventoryObserver +{ +protected: + bool mChangePending = true; +public: + PBRPickerAgentListener() : LLInventoryObserver() + { + gInventory.addObserver(this); + } + + const bool isListening() + { + return mChangePending; + } + + void changed(U32 mask) override + { + if (!(mask & (ADD | REMOVE))) + { + return; + } + + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + gInventory.removeObserver(this); + mChangePending = false; + } + + ~PBRPickerAgentListener() override + { + gInventory.removeObserver(this); + mChangePending = false; + + LLInventoryObserver::~LLInventoryObserver(); + } +}; + // One-off listener that updates the build floater UI when the prim inventory updates -class PBRPickerItemListener : public LLVOInventoryListener +class PBRPickerObjectListener : public LLVOInventoryListener { protected: LLViewerObject* mObjectp; bool mChangePending = true; public: - PBRPickerItemListener(LLViewerObject* object) + PBRPickerObjectListener(LLViewerObject* object) : mObjectp(object) { registerVOInventoryListener(mObjectp, nullptr); @@ -1912,7 +1952,7 @@ public: mChangePending = false; } - ~PBRPickerItemListener() + ~PBRPickerObjectListener() { removeVOInventoryListener(); mChangePending = false; @@ -1931,9 +1971,9 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, // pbr material LLTextureCtrl* pbr_ctrl = findChild("pbr_control"); + LLUUID pbr_id; if (pbr_ctrl) { - LLUUID pbr_id; LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr, has_pbr_material, has_faces_without_pbr); pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE); @@ -1956,14 +1996,25 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, if (objectp->isInventoryPending()) { // Reuse the same listener when possible - if (!mInventoryListener || !mInventoryListener->isListeningFor(objectp)) + if (!mVOInventoryListener || !mVOInventoryListener->isListeningFor(objectp)) { - mInventoryListener = std::make_unique(objectp); + mVOInventoryListener = std::make_unique(objectp); } } else { - mInventoryListener = nullptr; + mVOInventoryListener = nullptr; + } + if (!identical_pbr || pbr_id.isNull() || pbr_id == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + { + mAgentInventoryListener = nullptr; + } + else + { + if (!mAgentInventoryListener || !mAgentInventoryListener->isListening()) + { + mAgentInventoryListener = std::make_unique(); + } } const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index d36662c11b..5ca6a95699 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -53,7 +53,8 @@ class LLMaterialID; class LLMediaCtrl; class LLMenuButton; -class PBRPickerItemListener; +class PBRPickerAgentListener; +class PBRPickerObjectListener; // Represents an edit for use in replicating the op across one or more materials in the selection set. // @@ -508,7 +509,8 @@ private: static Selection sMaterialOverrideSelection; - std::unique_ptr mInventoryListener; + std::unique_ptr mAgentInventoryListener; + std::unique_ptr mVOInventoryListener; public: #if defined(DEF_GET_MAT_STATE) From 2d69611c470e8ca0f85f6ad5857799ca2536f193 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 3 Nov 2023 09:57:19 -0700 Subject: [PATCH 07/77] SL-20553: Fix save material to inventory not working with new agent-based permissions --- indra/newview/llmaterialeditor.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index bae4afb7e6..cc7e69d60c 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1852,6 +1852,10 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vectorgetSelection()->applyToTEs(&func, true /*first applicable*/); + if (item_source == ItemSource::AGENT) + { + func.mObjectId = LLUUID::null; + } LLViewerObject* selected_object = func.mObject; if (!selected_object) { @@ -1879,11 +1883,12 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vectorgetInventoryItemByAsset(func.mMaterialId); - if (item_out && !item_has_perms(nullptr, item_out)) + LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); + if (item && !item_has_perms(nullptr, item)) { return false; } + item_out = item; } else { @@ -2118,8 +2123,9 @@ void LLMaterialEditor::saveObjectsMaterialAs(const LLGLTFMaterial* render_materi } else { - if (item_id.notNull()) + if (item_id.notNull() && object_id.notNull()) { + llassert(false); // *TODO: Remove this code path if unused // Copy existing item from object inventory, and create new composite asset on top of it LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback, _1, _2, permissions, object_id, item_id)); } From ee8b96f3ef55d10f5b84e368c052692a362ebcbc Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 3 Nov 2023 13:49:47 -0700 Subject: [PATCH 08/77] SL-20553: Clean up dead code --- indra/newview/llmaterialeditor.cpp | 58 +-------------------------- indra/newview/llmaterialeditor.h | 1 - indra/newview/llviewerinventory.cpp | 61 ----------------------------- indra/newview/llviewerinventory.h | 5 --- 4 files changed, 2 insertions(+), 123 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index cc7e69d60c..958925c9e4 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2123,65 +2123,11 @@ void LLMaterialEditor::saveObjectsMaterialAs(const LLGLTFMaterial* render_materi } else { - if (item_id.notNull() && object_id.notNull()) - { - llassert(false); // *TODO: Remove this code path if unused - // Copy existing item from object inventory, and create new composite asset on top of it - LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback, _1, _2, permissions, object_id, item_id)); - } - else - { - LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions)); - } + llassert(object_id.isNull()); // Case for copying item from object inventory is no longer implemented + LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions)); } } -// static -void LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions, const LLUUID& object_id, const LLUUID& item_id) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 != option) - { - return; - } - - LLSD asset; - asset["version"] = LLGLTFMaterial::ASSET_VERSION; - asset["type"] = LLGLTFMaterial::ASSET_TYPE; - // This is the string serialized from LLGLTFMaterial::asJSON - asset["data"] = notification["payload"]["data"]; - - std::ostringstream str; - LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY); - - LLViewerObject* object = gObjectList.findObject(object_id); - if (!object) - { - return; - } - const LLInventoryItem* item = object->getInventoryItem(item_id); - if (!item) - { - return; - } - - std::string new_name = response["message"].asString(); - LLInventoryObject::correctInventoryName(new_name); - if (new_name.empty()) - { - return; - } - - const LLUUID destination_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL); - - LLPointer cb = new LLObjectsMaterialItemCallback(permissions, str.str(), new_name); - // NOTE: This should be an item copy. Saving a material to an inventory should be disabled when the associated material is no-copy. - move_or_copy_inventory_from_object(destination_id, - object_id, - item_id, - cb); -} - // static void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions) { diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 1c40fcc348..2e25a9ca3d 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -116,7 +116,6 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static bool canSaveObjectsMaterial(); static bool canClipboardObjectsMaterial(); static void saveObjectsMaterialAs(); - static void onCopyObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions, const LLUUID& object_id, const LLUUID& item_id); static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions); static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 5ee613d49d..1b70e5f84f 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1658,67 +1658,6 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, } } -void move_or_copy_inventory_from_object(const LLUUID& destination_id, - const LLUUID& object_id, - const LLUUID& item_id, - LLPointer cb) -{ - LLViewerObject* object = gObjectList.findObject(object_id); - if (!object) - { - return; - } - const LLInventoryItem* item = object->getInventoryItem(item_id); - if (!item) - { - return; - } - - class LLItemAddedObserver : public LLInventoryObserver - { - public: - LLItemAddedObserver(const LLUUID& copied_asset_id, LLPointer cb) - : LLInventoryObserver(), - mAssetId(copied_asset_id), - mCallback(cb) - { - } - - void changed(U32 mask) override - { - if((mask & (LLInventoryObserver::ADD)) == 0) - { - return; - } - for (const LLUUID& changed_id : gInventory.getChangedIDs()) - { - LLViewerInventoryItem* changed_item = gInventory.getItem(changed_id); - if (changed_item->getAssetUUID() == mAssetId) - { - changeComplete(changed_item->getUUID()); - return; - } - } - } - - private: - void changeComplete(const LLUUID& item_id) - { - mCallback->fire(item_id); - gInventory.removeObserver(this); - delete this; - } - - LLUUID mAssetId; - LLPointer mCallback; - }; - - const LLUUID& asset_id = item->getAssetUUID(); - LLItemAddedObserver* observer = new LLItemAddedObserver(asset_id, cb); - gInventory.addObserver(observer); - object->moveInventory(destination_id, item_id); -} - void create_new_item(const std::string& name, const LLUUID& parent_id, LLAssetType::EType asset_type, diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index bce8da0a69..e043285ffb 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -463,11 +463,6 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, const LLInventoryItem *src, U32 callback_id = 0); -void move_or_copy_inventory_from_object(const LLUUID& destination_id, - const LLUUID& object_id, - const LLUUID& item_id, - LLPointer cb); - void menu_create_inventory_item(LLInventoryPanel* root, LLFolderBridge* bridge, const LLSD& userdata, From 6ba5954d66523cedf5e69928e223f9820bd141ac Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 3 Nov 2023 13:54:05 -0700 Subject: [PATCH 09/77] SL-20553: Permissions touch-up --- indra/newview/llmaterialeditor.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 958925c9e4..2f31889f32 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1968,13 +1968,24 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector Date: Tue, 7 Nov 2023 17:33:00 -0800 Subject: [PATCH 10/77] SL-20553: Fix inventory item not updating with correct permission label in UI --- indra/newview/llinventorymodel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 74a5442586..ca13b9eb03 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1465,6 +1465,10 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { mask |= LLInventoryObserver::LABEL; } + if (old_item->getPermissions() != item->getPermissions()) + { + mask |= LLInventoryObserver::INTERNAL; + } old_item->copyViewerItem(item); if (update_parent_on_server) { From 4ad7e250f3302a6158378a5acbf88ac27dd95ced Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 8 Nov 2023 14:51:48 -0800 Subject: [PATCH 11/77] SL-20553: Fix assert --- indra/newview/llmaterialeditor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 2f31889f32..2f4c29446e 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1878,7 +1878,8 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector Date: Wed, 8 Nov 2023 16:23:36 -0800 Subject: [PATCH 12/77] SL-20553: Fix new material item still sometimes not updating in UI --- indra/newview/llmaterialeditor.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 2f4c29446e..8f016b9125 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1313,16 +1313,22 @@ public: return; } + // Name may or may not have already been applied + const bool changed_name = item->getName() != mNewName; // create_inventory_item/copy_inventory_item don't allow presetting some permissions, fix it now - item->setPermissions(mPermissions); - item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - if (item->getName() != mNewName) + const bool changed_permissions = item->getPermissions() != mPermissions; + const bool changed = changed_name || changed_permissions; + LLSD updates; + if (changed) { - LLSD updates; - updates["name"] = mNewName; + if (changed_name) + { + updates["name"] = mNewName; + } + if (changed_permissions) + { + updates["permissions"] = ll_create_sd_from_permissions(mPermissions); + } update_inventory_item(inv_item_id, updates, NULL); } @@ -1332,10 +1338,16 @@ public: inv_item_id, LLAssetType::AT_MATERIAL, mAssetData, - [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) + [changed, updates](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) { // done callback LL_INFOS("Material") << "inventory item uploaded. item: " << item_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL; + + // *HACK: Sometimes permissions do not stick in the UI. They are correct on the server-side, though. + if (changed) + { + update_inventory_item(new_item_id, updates, NULL); + } }, nullptr // failure callback, floater already closed ); From 8d538ef77b395e2f8ba6d4f89c2633dd57124c04 Mon Sep 17 00:00:00 2001 From: cosmic-linden <111533034+cosmic-linden@users.noreply.github.com> Date: Tue, 14 Nov 2023 08:06:45 -0800 Subject: [PATCH 13/77] SL-18343: Simple interim GLTF material preview - base color only (#511) --- indra/newview/llfetchedgltfmaterial.cpp | 54 +++++++++++++++++++++++++ indra/newview/llfetchedgltfmaterial.h | 5 +++ indra/newview/lltexturectrl.cpp | 36 +++++++++++++---- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index fc9d42bfb6..b6d62d1d12 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -29,6 +29,8 @@ #include "llviewertexturelist.h" #include "llavatarappearancedefines.h" +#include "llviewerobject.h" +#include "llselectmgr.h" #include "llshadermgr.h" #include "pipeline.h" @@ -175,3 +177,55 @@ void LLFetchedGLTFMaterial::materialComplete() materialCompleteCallbacks.clear(); materialCompleteCallbacks.shrink_to_fit(); } + +LLPointer LLFetchedGLTFMaterial::getUITexture() +{ + if (mFetching) + { + return nullptr; + } + + auto fetch_texture_for_ui = [](LLPointer& img, const LLUUID& id) + { + if (id.notNull()) + { + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) + { + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (obj) + { + LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id); + img = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + } + + } + else + { + img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + } + if (img) + { + img->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + img->forceToSaveRawImage(0); + } + }; + + fetch_texture_for_ui(mBaseColorTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + fetch_texture_for_ui(mNormalTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); + fetch_texture_for_ui(mMetallicRoughnessTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); + fetch_texture_for_ui(mEmissiveTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); + + if ((mBaseColorTexture && (mBaseColorTexture->getRawImageLevel() != 0)) || + (mNormalTexture && (mNormalTexture->getRawImageLevel() != 0)) || + (mMetallicRoughnessTexture && (mMetallicRoughnessTexture->getRawImageLevel() != 0)) || + (mEmissiveTexture && (mEmissiveTexture->getRawImageLevel() != 0))) + { + return nullptr; + } + + // *HACK: Use one of the PBR texture components as the preview texture for now + mPreviewTexture = mBaseColorTexture; + + return mPreviewTexture; +} diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index 1668657281..eb9639723a 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -50,12 +50,17 @@ public: bool isFetching() const { return mFetching; } + LLPointer getUITexture(); + // Textures used for fetching/rendering LLPointer mBaseColorTexture; LLPointer mNormalTexture; LLPointer mMetallicRoughnessTexture; LLPointer mEmissiveTexture; + // Texture used for previewing the material in the UI + LLPointer mPreviewTexture; + protected: // Lifetime management diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 10667b02d9..50e2f5e1d9 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -719,17 +719,27 @@ void LLFloaterTexturePicker::draw() // If the floater is focused, don't apply its alpha to the texture (STORM-677). const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - if( mTexturep ) + LLViewerTexture* texture = nullptr; + if (mGLTFMaterial) + { + texture = mGLTFMaterial->getUITexture(); + } + else + { + texture = mTexturep.get(); + } + + if( texture ) { - if( mTexturep->getComponents() == 4 ) + if( texture->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior, alpha ); } - gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha ); + gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), texture, UI_VERTEX_COLOR % alpha ); // Pump the priority - mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + texture->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); } else if (!mFallbackImage.isNull()) { @@ -2131,11 +2141,21 @@ void LLTextureCtrl::draw() if (texture.isNull()) { - texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + if (mInventoryPickType == LLTextureCtrl::PICK_MATERIAL) + { + LLPointer material = gGLTFMaterialList.getMaterial(mImageAssetID); + if (material) + { + texture = material->getUITexture(); + } + } + else + { + texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + texture->forceToSaveRawImage(0); + } } - - texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - texture->forceToSaveRawImage(0) ; mTexturep = texture; } From 0edb7cad6bdeaf02cbd89d1f2dd38c47d6078c03 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 14 Nov 2023 13:33:11 -0600 Subject: [PATCH 14/77] SL-20340 Fix for off-by-epsilon hack falling off when serializing overrides as LLSD. (#513) --- indra/llprimitive/llgltfmaterial.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index c1f2a04154..9945c230a2 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -691,24 +691,44 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data) if (bc.isDefined()) { mBaseColor.setValue(bc); + if (mBaseColor == getDefaultBaseColor()) + { + // HACK -- nudge by epsilon if we receive a default value (indicates override to default) + mBaseColor.mV[3] -= FLT_EPSILON; + } } const LLSD& ec = data["ec"]; if (ec.isDefined()) { mEmissiveColor.setValue(ec); + if (mEmissiveColor == getDefaultEmissiveColor()) + { + // HACK -- nudge by epsilon if we receive a default value (indicates override to default) + mEmissiveColor.mV[0] += FLT_EPSILON; + } } const LLSD& mf = data["mf"]; if (mf.isReal()) { mMetallicFactor = mf.asReal(); + if (mMetallicFactor == getDefaultMetallicFactor()) + { + // HACK -- nudge by epsilon if we receive a default value (indicates override to default) + mMetallicFactor -= FLT_EPSILON; + } } const LLSD& rf = data["rf"]; if (rf.isReal()) { mRoughnessFactor = rf.asReal(); + if (mRoughnessFactor == getDefaultRoughnessFactor()) + { + // HACK -- nudge by epsilon if we receive a default value (indicates override to default) + mRoughnessFactor -= FLT_EPSILON; + } } const LLSD& am = data["am"]; @@ -722,6 +742,11 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data) if (ac.isReal()) { mAlphaCutoff = ac.asReal(); + if (mAlphaCutoff == getDefaultAlphaCutoff()) + { + // HACK -- nudge by epsilon if we receive a default value (indicates override to default) + mAlphaCutoff -= FLT_EPSILON; + } } const LLSD& ds = data["ds"]; From f98fa678205a4575ea2590994c863527c29c2ab9 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 16 Nov 2023 10:18:42 +0100 Subject: [PATCH 15/77] SL-20563 Add 'No Post' option to Snapshot floater --- indra/newview/llfloatersnapshot.cpp | 18 ++++++++++++++++-- indra/newview/llfloatersnapshot.h | 1 + .../skins/default/xui/en/floater_snapshot.xml | 12 ++++++++++-- .../skins/default/xui/en/menu_viewer.xml | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 6b9d4580dc..4806fe9625 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -461,8 +461,8 @@ void LLFloaterSnapshotBase::ImplBase::onClickAutoSnap(LLUICtrl *ctrl, void* data { LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl; gSavedSettings.setBOOL( "AutoSnapshot", check->get() ); - - LLFloaterSnapshotBase *view = (LLFloaterSnapshotBase *)data; + + LLFloaterSnapshotBase *view = (LLFloaterSnapshotBase *)data; if (view) { view->impl->checkAutoSnapshot(view->getPreviewView()); @@ -470,6 +470,17 @@ void LLFloaterSnapshotBase::ImplBase::onClickAutoSnap(LLUICtrl *ctrl, void* data } } +// static +void LLFloaterSnapshotBase::ImplBase::onClickNoPost(LLUICtrl *ctrl, void* data) +{ + BOOL no_post = ((LLCheckBoxCtrl*)ctrl)->get(); + gSavedSettings.setBOOL("RenderDisablePostProcessing", no_post); + + LLFloaterSnapshotBase* view = (LLFloaterSnapshotBase*)data; + view->getPreviewView()->updateSnapshot(TRUE, TRUE); + view->impl->updateControls(view); +} + // static void LLFloaterSnapshotBase::ImplBase::onClickFilter(LLUICtrl *ctrl, void* data) { @@ -997,6 +1008,9 @@ BOOL LLFloaterSnapshot::postBuild() getChild("auto_snapshot_check")->setValue(gSavedSettings.getBOOL("AutoSnapshot")); childSetCommitCallback("auto_snapshot_check", ImplBase::onClickAutoSnap, this); + getChild("no_post_check")->setValue(gSavedSettings.getBOOL("RenderDisablePostProcessing")); + childSetCommitCallback("no_post_check", ImplBase::onClickNoPost, this); + getChild("retract_btn")->setCommitCallback(boost::bind(&LLFloaterSnapshot::onExtendFloater, this)); getChild("extend_btn")->setCommitCallback(boost::bind(&LLFloaterSnapshot::onExtendFloater, this)); diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 7fc62a2746..89cb2bc809 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -100,6 +100,7 @@ public: static void onClickNewSnapshot(void* data); static void onClickAutoSnap(LLUICtrl *ctrl, void* data); + static void onClickNoPost(LLUICtrl *ctrl, void* data); static void onClickFilter(LLUICtrl *ctrl, void* data); static void onClickUICheck(LLUICtrl *ctrl, void* data); static void onClickHUDCheck(LLUICtrl *ctrl, void* data); diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index fcd24d83bb..0866594625 100644 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -115,7 +115,7 @@ top_delta="0" width="31" /> + From bdb53fd56d56c659941e7e63f83cefc366acef6d Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 16 Nov 2023 16:46:12 -0600 Subject: [PATCH 16/77] SL-20611 Make haze effect local lights -- move sky and water haze to their own passes and unify sky and water haze in forward rendering shaders. --- indra/llrender/llshadermgr.cpp | 20 +- .../shaders/class1/deferred/fullbrightF.glsl | 16 +- .../shaders/class1/environment/waterFogF.glsl | 52 ++- .../windlight/atmosphericsHelpersV.glsl | 1 - .../class1/windlight/atmosphericsV.glsl | 1 - .../class1/windlight/atmosphericsVarsF.glsl | 2 +- .../class1/windlight/atmosphericsVarsV.glsl | 11 - .../windlight/atmosphericsVarsWaterF.glsl | 50 -- .../windlight/atmosphericsVarsWaterV.glsl | 81 ---- .../shaders/class2/deferred/alphaF.glsl | 14 +- .../shaders/class2/deferred/pbralphaF.glsl | 15 +- .../class3/deferred/fullbrightShinyF.glsl | 3 + .../shaders/class3/deferred/hazeF.glsl | 109 +++++ .../shaders/class3/deferred/materialF.glsl | 16 +- .../shaders/class3/deferred/softenLightF.glsl | 34 -- .../shaders/class3/deferred/waterHazeF.glsl | 58 +++ .../class3/environment/underWaterF.glsl | 4 +- .../shaders/class3/environment/waterF.glsl | 3 +- indra/newview/lldrawpoolalpha.cpp | 10 +- indra/newview/lldrawpoolavatar.cpp | 9 +- indra/newview/lldrawpoolmaterials.cpp | 9 +- indra/newview/lldrawpoolsimple.cpp | 8 - indra/newview/llsettingsvo.cpp | 2 +- indra/newview/llviewercamera.cpp | 51 +- indra/newview/llviewershadermgr.cpp | 439 ++---------------- indra/newview/llviewershadermgr.h | 11 +- indra/newview/pipeline.cpp | 66 ++- 27 files changed, 366 insertions(+), 729 deletions(-) delete mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl delete mode 100644 indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl create mode 100644 indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0e7f9e1331..f14216f3d8 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -81,14 +81,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->calculatesAtmospherics) { - if (features->hasWaterFog) - { - if (!shader->attachVertexObject("windlight/atmosphericsVarsWaterV.glsl")) - { - return FALSE; - } - } - else if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl")) + if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl")) { return FALSE; } @@ -201,14 +194,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if(features->calculatesAtmospherics || features->hasGamma || features->isDeferred) { - if (features->hasWaterFog) - { - if (!shader->attachFragmentObject("windlight/atmosphericsVarsWaterF.glsl")) - { - return FALSE; - } - } - else if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl")) + if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl")) { return FALSE; } @@ -292,7 +278,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } // NOTE order of shader object attaching is VERY IMPORTANT!!! - if (features->hasWaterFog) + if (features->hasWaterFog || features->hasAtmospherics) { if (!shader->attachFragmentObject("environment/waterFogF.glsl")) { diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 5d58cc91cd..2798c59f1c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -35,9 +35,7 @@ in vec3 vary_position; in vec4 vertex_color; in vec2 vary_texcoord0; -#ifdef WATER_FOG -vec4 applyWaterFogView(vec3 pos, vec4 color); -#endif +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); vec3 srgb_to_linear(vec3 cs); vec3 linear_to_srgb(vec3 cl); @@ -86,18 +84,14 @@ void main() calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten); #endif -#ifdef WATER_FOG - - vec4 fogged = applyWaterFogView(pos, vec4(color.rgb, final_alpha)); - color.rgb = fogged.rgb; - color.a = fogged.a; -#else - color.a = final_alpha; -#endif #ifndef IS_HUD color.rgb = srgb_to_linear(color.rgb); color.rgb = atmosFragLighting(color.rgb, additive, atten); + + vec4 fogged = applyWaterFogViewLinear(pos, vec4(color.rgb, final_alpha)); + color.rgb = fogged.rgb; + color.a = fogged.a; #endif frag_color = max(color, vec4(0)); diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl index cfdb393b34..140e01cc2a 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl @@ -30,12 +30,12 @@ uniform vec4 waterFogColor; uniform float waterFogDensity; uniform float waterFogKS; -vec3 getPositionEye(); - vec3 srgb_to_linear(vec3 col); vec3 linear_to_srgb(vec3 col); -vec4 applyWaterFogView(vec3 pos, vec4 color) +// get a water fog color that will apply the appropriate haze to a color given +// a blend function of (ONE, SOURCE_ALPHA) +vec4 getWaterFogViewNoClip(vec3 pos) { vec3 view = normalize(pos); //normalize view vector @@ -67,38 +67,44 @@ vec4 applyWaterFogView(vec3 pos, vec4 color) float L = min(t1/t2*t3, 1.0); float D = pow(0.98, l*kd); - - color.rgb = color.rgb * D + kc.rgb * L; - return color; + return vec4(srgb_to_linear(kc.rgb*L), D); } -vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color, vec3 sunlit) +vec4 getWaterFogView(vec3 pos) { - color.rgb = linear_to_srgb(color.rgb); - color = applyWaterFogView(pos, color); - color.rgb = srgb_to_linear(color.rgb); + if (dot(pos, waterPlane.xyz) + waterPlane.w > 0.0) + { + return vec4(0,0,0,1); + } + + return getWaterFogViewNoClip(pos); +} + +vec4 applyWaterFogView(vec3 pos, vec4 color) +{ + vec4 fogged = getWaterFogView(pos); + + color.rgb = color.rgb * fogged.a + fogged.rgb; + return color; } -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit) +vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color) +{ + vec4 fogged = getWaterFogViewNoClip(pos); + color.rgb *= fogged.a; + color.rgb += fogged.rgb; + return color; +} + +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color) { if (dot(pos, waterPlane.xyz) + waterPlane.w > 0.0) { return color; } - return applyWaterFogViewLinearNoClip(pos, color, sunlit); -} - -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color) -{ - return applyWaterFogViewLinear(pos, color, vec3(1)); -} - -vec4 applyWaterFog(vec4 color) -{ - //normalize view vector - return applyWaterFogViewLinear(getPositionEye(), color); + return applyWaterFogViewLinearNoClip(pos, color); } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl index 6ecbfaecb1..4f88aed765 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl @@ -30,7 +30,6 @@ vec3 getSunlitColor(); vec3 getAmblitColor(); vec3 getAdditiveColor(); vec3 getAtmosAttenuation(); -vec3 getPositionEye(); uniform float scene_light_strength; diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl index cc3617ba61..7b59e07243 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl @@ -42,7 +42,6 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou void calcAtmospherics(vec3 inPositionEye) { vec3 P = inPositionEye; - setPositionEye(P); vec3 tmpsunlit = vec3(1); vec3 tmpamblit = vec3(1); vec3 tmpaddlit = vec3(1); diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl index 34669a6796..9d5f60b313 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl @@ -44,5 +44,5 @@ vec3 getAdditiveColor() vec3 getAtmosAttenuation() { - return vec3(vary_AtmosAttenuation); + return vary_AtmosAttenuation; } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl index 1b854d80b3..0617bc9908 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl @@ -31,7 +31,6 @@ vec3 additive_color; vec3 atmos_attenuation; vec3 sunlit_color; vec3 amblit_color; -vec3 position_eye; vec3 getSunlitColor() { @@ -51,16 +50,6 @@ vec3 getAtmosAttenuation() return atmos_attenuation; } -vec3 getPositionEye() -{ - return position_eye; -} - -void setPositionEye(vec3 v) -{ - position_eye = v; -} - void setSunlitColor(vec3 v) { sunlit_color = v; diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl deleted file mode 100644 index 7a6741fe0e..0000000000 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file class2\wl\atmosphericVarsWaterF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -in vec3 vary_PositionEye; -in vec3 vary_AdditiveColor; -in vec3 vary_AtmosAttenuation; - -vec3 getSunlitColor() -{ - return vec3(0,0,0); -} -vec3 getAmblitColor() -{ - return vec3(0,0,0); -} -vec3 getAdditiveColor() -{ - return vary_AdditiveColor; -} -vec3 getAtmosAttenuation() -{ - return vary_AtmosAttenuation; -} -vec3 getPositionEye() -{ - return vary_PositionEye; -} - diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl deleted file mode 100644 index 23c3aed4d8..0000000000 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file class2\wl\atmosphericVarsWaterV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -out vec3 vary_PositionEye; -out vec3 vary_AdditiveColor; -out vec3 vary_AtmosAttenuation; - -vec3 atmos_attenuation; -vec3 sunlit_color; -vec3 amblit_color; - -vec3 getSunlitColor() -{ - return sunlit_color; -} -vec3 getAmblitColor() -{ - return amblit_color; -} - -vec3 getAdditiveColor() -{ - return vary_AdditiveColor; -} -vec3 getAtmosAttenuation() -{ - return atmos_attenuation; -} - -vec3 getPositionEye() -{ - return vary_PositionEye; -} - -void setPositionEye(vec3 v) -{ - vary_PositionEye = v; -} - -void setSunlitColor(vec3 v) -{ - sunlit_color = v; -} - -void setAmblitColor(vec3 v) -{ - amblit_color = v; -} - -void setAdditiveColor(vec3 v) -{ - vary_AdditiveColor = v; -} - -void setAtmosAttenuation(vec3 v) -{ - atmos_attenuation = v; - vary_AtmosAttenuation = v; -} diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index b63f3b60f9..07fa5cd01c 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -65,9 +65,7 @@ uniform vec3 light_diffuse[8]; void waterClip(vec3 pos); -#ifdef WATER_FOG -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit); -#endif +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); vec3 srgb_to_linear(vec3 c); vec3 linear_to_srgb(vec3 c); @@ -270,12 +268,6 @@ void main() color.rgb *= diffuse_linear.rgb; - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - -#ifdef WATER_FOG - color = applyWaterFogViewLinear(pos.xyz, color, sunlit_linear); -#endif // WATER_FOG - vec4 light = vec4(0,0,0,0); #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diffuse_linear.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w); @@ -291,6 +283,10 @@ void main() // sum local light contrib in linear colorspace color.rgb += light.rgb; + color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); + + color = applyWaterFogViewLinear(pos.xyz, color); + #endif // #else // FOR_IMPOSTOR #ifdef IS_HUD diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl index 35d752be02..80c1769b15 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl @@ -84,9 +84,7 @@ vec3 linear_to_srgb(vec3 c); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); vec3 atmosFragLightingLinear(vec3 color, vec3 additive, vec3 atten); -#ifdef WATER_FOG -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit); -#endif +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); @@ -228,13 +226,6 @@ void main() color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten); - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - -#ifdef WATER_FOG - vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear); - color = temp.rgb; -#endif - vec3 light = vec3(0); // Punctual lights @@ -250,7 +241,11 @@ void main() color.rgb += light.rgb; + color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); + vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0)); + color = temp.rgb; + float a = basecolor.a*vertex_color.a; frag_color = max(vec4(color.rgb,a), vec4(0)); diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 5483a4e29c..6446015b03 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -40,6 +40,8 @@ in vec3 vary_position; uniform samplerCube environmentMap; vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten); +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); + void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten); vec3 linear_to_srgb(vec3 c); @@ -84,6 +86,7 @@ void main() applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity); color.rgb = atmosFragLighting(color.rgb, additive, atten); + color = applyWaterFogViewLinear(pos.xyz, color); #endif color.a = 1.0; diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl new file mode 100644 index 0000000000..7b77a2f5fb --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -0,0 +1,109 @@ +/** + * @file class3/deferred/hazeF.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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$ + */ + +out vec4 frag_color; + +uniform sampler2D normalMap; + +// Inputs +uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform int sun_up_factor; +in vec2 vary_fragcoord; + +vec3 getNorm(vec2 pos_screen); +vec4 getPositionWithDepth(vec2 pos_screen, float depth); +void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); + +float getDepth(vec2 pos_screen); + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +uniform vec4 waterPlane; + +uniform int cube_snapshot; + +uniform float sky_hdr_scale; + +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = getDepth(tc.xy); + vec4 pos = getPositionWithDepth(tc, depth); + vec4 norm = texture(normalMap, tc); + norm.xyz = getNorm(tc); + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + vec3 color = vec3(0); + float bloom = 0.0; + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + + calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten); + + vec3 sunlit_linear = srgb_to_linear(sunlit); + vec3 amblit_linear = amblit; + + bool do_atmospherics = false; + + // mask off atmospherics below water + if (dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0) + { + do_atmospherics = true; + } + + vec3 irradiance = vec3(0); + vec3 radiance = vec3(0); + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + { + } + else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) + { + //should only be true of WL sky, just port over base color value + discard; + } + + float alpha = 0.0; + + if (do_atmospherics) + { + alpha = atten.r; + color = srgb_to_linear(additive*2.0); + color *= sky_hdr_scale; + } + else + { + color = vec3(0,0,0); + alpha = 1.0; + } + + frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results + frag_color.a = alpha; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index acff03ec4b..1880f0c870 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -37,9 +37,7 @@ uniform float emissive_brightness; // fullbright flag, 1.0 == fullbright, 0.0 otherwise uniform int sun_up_factor; -#ifdef WATER_FOG -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit); -#endif +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten); vec3 scaleSoftClipFragLinear(vec3 l); @@ -386,13 +384,6 @@ void main() glare += cur_glare; } - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - -#ifdef WATER_FOG - vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear); - color = temp.rgb; -#endif - vec3 npos = normalize(-pos.xyz); vec3 light = vec3(0, 0, 0); @@ -408,6 +399,11 @@ void main() color += light; + color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); + + vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0)); + color = temp.rgb; + glare *= 1.0-emissive; glare = min(glare, 1.0); float al = max(diffcol.a, glare) * vertex_color.a; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 35e99c5bd2..5e8fe9301a 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -83,10 +83,6 @@ uniform vec4 waterPlane; uniform int cube_snapshot; -#ifdef WATER_FOG -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); -#endif - uniform float sky_hdr_scale; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); @@ -167,18 +163,6 @@ void main() vec3 sunlit_linear = srgb_to_linear(sunlit); vec3 amblit_linear = amblit; - bool do_atmospherics = false; - -#ifndef WATER_FOG - // when above water, mask off atmospherics below water - if (dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0) - { - do_atmospherics = true; - } -#else - do_atmospherics = true; -#endif - vec3 irradiance = vec3(0); vec3 radiance = vec3(0); @@ -203,11 +187,6 @@ void main() vec3 v = -normalize(pos.xyz); color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten); - - if (do_atmospherics) - { - color = atmosFragLightingLinear(color, additive, atten); - } } else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) { @@ -273,21 +252,8 @@ void main() { // add environment map applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity); } - - - if (do_atmospherics) - { - color = atmosFragLightingLinear(color, additive, atten); - } } - - - #ifdef WATER_FOG - vec4 fogged = applyWaterFogViewLinear(pos.xyz, vec4(color, bloom)); - color = fogged.rgb; - #endif - frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl new file mode 100644 index 0000000000..f63d70cbd7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -0,0 +1,58 @@ +/** + * @file class3/deferred/waterHazeF.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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$ + */ + +out vec4 frag_color; + +// Inputs +in vec2 vary_fragcoord; + +uniform sampler2D normalMap; + +vec4 getPositionWithDepth(vec2 pos_screen, float depth); +float getDepth(vec2 pos_screen); + +vec4 getWaterFogView(vec3 pos); + +void main() +{ + vec2 tc = vary_fragcoord.xy; + float depth = getDepth(tc.xy); + vec4 pos = getPositionWithDepth(tc, depth); + vec4 norm = texture(normalMap, tc); + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + { + } + else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) + { + //should only be true of WL sky, just port over base color value + discard; + } + + vec4 fogged = getWaterFogView(pos.xyz); + + frag_color.rgb = max(fogged.rgb, vec3(0)); //output linear since local lights will be added to this shader's results + frag_color.a = fogged.a; +} diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index e99ad5b474..924f356f35 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -55,7 +55,7 @@ in vec4 littleWave; in vec4 view; in vec3 vary_position; -vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color, vec3 sunlit); +vec4 applyWaterFogViewLinearNoClip(vec3 pos, vec4 color); void main() { @@ -77,5 +77,5 @@ void main() vec4 fb = vec4(waterFogColorLinear, 0.0); #endif - frag_color = max(applyWaterFogViewLinearNoClip(vary_position, fb, vec3(1)), vec4(0)); + frag_color = max(applyWaterFogViewLinearNoClip(vary_position, fb), vec4(0)); } diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index ddade462be..af0460fa8b 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -34,7 +34,7 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); vec3 scaleSoftClipFragLinear(vec3 l); vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit); +vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); // PBR interface vec2 BRDF(float NoV, float roughness); @@ -223,7 +223,6 @@ void main() refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); } - fb = applyWaterFogViewLinear(refPos, fb, sunlit); #else vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0), sunlit_linear); #endif diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 052a1d796a..41dc95a8cb 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -178,27 +178,24 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram : - (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterAlphaProgram : (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram : &gDeferredFullbrightAlphaMaskAlphaProgram; prepare_alpha_shader(fullbright_shader, true, true, water_sign); simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : - (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram : &gDeferredAlphaProgram; prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms) - LLGLSLShader* materialShader = LLPipeline::sUnderWaterRender ? gDeferredMaterialWaterProgram : gDeferredMaterialProgram; + LLGLSLShader* materialShader = gDeferredMaterialProgram; for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) { prepare_alpha_shader(&materialShader[i], false, true, water_sign); } pbr_shader = - (LLPipeline::sUnderWaterRender) ? &gDeferredPBRAlphaWaterProgram : (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : &gDeferredPBRAlphaProgram; @@ -727,11 +724,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) llassert(mask < LLMaterial::SHADER_COUNT); target_shader = &(gDeferredMaterialProgram[mask]); - - if (LLPipeline::sUnderWaterRender) - { - target_shader = &(gDeferredMaterialWaterProgram[mask]); - } } else if (!params.mFullbright) { diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 342b76d93b..7f6409dbde 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -509,14 +509,7 @@ void LLDrawPoolAvatar::beginRigid() if (gPipeline.shadersLoaded()) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram; - } - else - { - sVertexProgram = &gObjectAlphaMaskNoColorProgram; - } + sVertexProgram = &gObjectAlphaMaskNoColorProgram; if (sVertexProgram != NULL) { //eyeballs render with the specular shader diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 6a7e05ac74..c0e4ed38c1 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -82,14 +82,7 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass) U32 idx = shader_idx[pass]; - if (LLPipeline::sUnderWaterRender) - { - mShader = &(gDeferredMaterialWaterProgram[idx]); - } - else - { - mShader = &(gDeferredMaterialProgram[idx]); - } + mShader = &(gDeferredMaterialProgram[idx]); if (rigged) { diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index a89c9d4561..696618f75b 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -193,10 +193,6 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass) { shader = &gHUDFullbrightProgram; } - else if (LLPipeline::sUnderWaterRender) - { - shader = &gDeferredFullbrightWaterProgram; - } else { shader = &gDeferredFullbrightProgram; @@ -225,10 +221,6 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass) { shader = &gHUDFullbrightAlphaMaskProgram; } - else if (LLPipeline::sUnderWaterRender) - { - shader = &gDeferredFullbrightAlphaMaskWaterProgram; - } else { shader = &gDeferredFullbrightAlphaMaskProgram; diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 42587658a6..2f65f3dec3 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -983,7 +983,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) LLEnvironment& env = LLEnvironment::instance(); - auto group = LLGLSLShader::SG_WATER; + auto group = LLGLSLShader::SG_ANY; LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[group]; { diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index b37f08283d..b926631ebe 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -50,6 +50,7 @@ #include "llquaternion.h" #include "llwindow.h" // getPixelAspectRatio() #include "lltracerecording.h" +#include "llenvironment.h" // System includes #include // for setprecision @@ -96,35 +97,37 @@ LLViewerCamera::LLViewerCamera() : LLCamera() gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2)); } -void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, - const LLVector3 &up_direction, - const LLVector3 &point_of_interest) +void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, const LLVector3 &up_direction, const LLVector3 &point_of_interest) { - // do not update if avatar didn't move - if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate()) - { - return; - } + // do not update if avatar didn't move + if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate()) + { + return; + } - LLVector3 last_position; - LLVector3 last_axis; - last_position = getOrigin(); - last_axis = getAtAxis(); + LLVector3 last_position; + LLVector3 last_axis; + last_position = getOrigin(); + last_axis = getAtAxis(); - mLastPointOfInterest = point_of_interest; + mLastPointOfInterest = point_of_interest; - LLViewerRegion * regp = gAgent.getRegion(); - F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; + LLViewerRegion *regp = gAgent.getRegion(); + F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; - LLVector3 origin = center; - if (origin.mV[2] > water_height) - { - origin.mV[2] = llmax(origin.mV[2], water_height+0.20f); - } - else - { - origin.mV[2] = llmin(origin.mV[2], water_height-0.20f); - } + LLVector3 origin = center; + + if (LLEnvironment::instance().getCurrentWater()->getFogMod() != 1.f) + { + if (origin.mV[2] > water_height) + { + origin.mV[2] = llmax(origin.mV[2], water_height + 0.20f); + } + else + { + origin.mV[2] = llmin(origin.mV[2], water_height - 0.20f); + } + } setOriginAndLookAt(origin, up_direction, point_of_interest); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index cdf5e2875f..e6e80e9532 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -99,7 +99,6 @@ LLGLSLShader gSkinnedObjectFullbrightAlphaMaskProgram; LLGLSLShader gObjectBumpProgram; LLGLSLShader gSkinnedObjectBumpProgram; LLGLSLShader gObjectAlphaMaskNoColorProgram; -LLGLSLShader gObjectAlphaMaskNoColorWaterProgram; //environment shaders LLGLSLShader gWaterProgram; @@ -138,7 +137,6 @@ LLGLSLShader gDeferredSkinnedDiffuseProgram; LLGLSLShader gDeferredSkinnedBumpProgram; LLGLSLShader gDeferredBumpProgram; LLGLSLShader gDeferredTerrainProgram; -LLGLSLShader gDeferredTerrainWaterProgram; LLGLSLShader gDeferredTreeProgram; LLGLSLShader gDeferredTreeShadowProgram; LLGLSLShader gDeferredSkinnedTreeShadowProgram; @@ -149,9 +147,10 @@ LLGLSLShader gDeferredMultiLightProgram[16]; LLGLSLShader gDeferredSpotLightProgram; LLGLSLShader gDeferredMultiSpotLightProgram; LLGLSLShader gDeferredSunProgram; +LLGLSLShader gHazeProgram; +LLGLSLShader gHazeWaterProgram; LLGLSLShader gDeferredBlurLightProgram; LLGLSLShader gDeferredSoftenProgram; -LLGLSLShader gDeferredSoftenWaterProgram; LLGLSLShader gDeferredShadowProgram; LLGLSLShader gDeferredSkinnedShadowProgram; LLGLSLShader gDeferredShadowCubeProgram; @@ -171,8 +170,6 @@ LLGLSLShader gHUDAlphaProgram; LLGLSLShader gDeferredSkinnedAlphaProgram; LLGLSLShader gDeferredAlphaImpostorProgram; LLGLSLShader gDeferredSkinnedAlphaImpostorProgram; -LLGLSLShader gDeferredAlphaWaterProgram; -LLGLSLShader gDeferredSkinnedAlphaWaterProgram; LLGLSLShader gDeferredAvatarEyesProgram; LLGLSLShader gDeferredFullbrightProgram; LLGLSLShader gHUDFullbrightProgram; @@ -180,12 +177,6 @@ LLGLSLShader gDeferredFullbrightAlphaMaskProgram; LLGLSLShader gHUDFullbrightAlphaMaskProgram; LLGLSLShader gDeferredFullbrightAlphaMaskAlphaProgram; LLGLSLShader gHUDFullbrightAlphaMaskAlphaProgram; -LLGLSLShader gDeferredFullbrightWaterProgram; -LLGLSLShader gDeferredSkinnedFullbrightWaterProgram; -LLGLSLShader gDeferredFullbrightWaterAlphaProgram; -LLGLSLShader gDeferredSkinnedFullbrightWaterAlphaProgram; -LLGLSLShader gDeferredFullbrightAlphaMaskWaterProgram; -LLGLSLShader gDeferredSkinnedFullbrightAlphaMaskWaterProgram; LLGLSLShader gDeferredEmissiveProgram; LLGLSLShader gDeferredSkinnedEmissiveProgram; LLGLSLShader gDeferredPostProgram; @@ -215,7 +206,6 @@ LLGLSLShader gDeferredBufferVisualProgram; // Deferred materials shaders LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; -LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; LLGLSLShader gHUDPBROpaqueProgram; LLGLSLShader gPBRGlowProgram; LLGLSLShader gPBRGlowSkinnedProgram; @@ -224,8 +214,6 @@ LLGLSLShader gDeferredSkinnedPBROpaqueProgram; LLGLSLShader gHUDPBRAlphaProgram; LLGLSLShader gDeferredPBRAlphaProgram; LLGLSLShader gDeferredSkinnedPBRAlphaProgram; -LLGLSLShader gDeferredPBRAlphaWaterProgram; -LLGLSLShader gDeferredSkinnedPBRAlphaWaterProgram; //helper for making a rigged variant of a given shader bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) @@ -258,30 +246,22 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram); mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram); mShaderList.push_back(&gObjectAlphaMaskNoColorProgram); - mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram); mShaderList.push_back(&gUnderWaterProgram); mShaderList.push_back(&gDeferredSunProgram); + mShaderList.push_back(&gHazeProgram); + mShaderList.push_back(&gHazeWaterProgram); mShaderList.push_back(&gDeferredSoftenProgram); - mShaderList.push_back(&gDeferredSoftenWaterProgram); mShaderList.push_back(&gDeferredAlphaProgram); mShaderList.push_back(&gHUDAlphaProgram); mShaderList.push_back(&gDeferredSkinnedAlphaProgram); mShaderList.push_back(&gDeferredAlphaImpostorProgram); mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram); - mShaderList.push_back(&gDeferredAlphaWaterProgram); - mShaderList.push_back(&gDeferredSkinnedAlphaWaterProgram); mShaderList.push_back(&gDeferredFullbrightProgram); mShaderList.push_back(&gHUDFullbrightProgram); mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram); mShaderList.push_back(&gHUDFullbrightAlphaMaskProgram); mShaderList.push_back(&gDeferredFullbrightAlphaMaskAlphaProgram); mShaderList.push_back(&gHUDFullbrightAlphaMaskAlphaProgram); - mShaderList.push_back(&gDeferredFullbrightWaterProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightWaterProgram); - mShaderList.push_back(&gDeferredFullbrightWaterAlphaProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightWaterAlphaProgram); - mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskWaterProgram); mShaderList.push_back(&gDeferredFullbrightShinyProgram); mShaderList.push_back(&gHUDFullbrightShinyProgram); mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram); @@ -291,17 +271,14 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredEmissiveProgram); mShaderList.push_back(&gDeferredSkinnedEmissiveProgram); mShaderList.push_back(&gDeferredAvatarEyesProgram); - mShaderList.push_back(&gDeferredTerrainWaterProgram); - mShaderList.push_back(&gDeferredAvatarAlphaProgram); + mShaderList.push_back(&gDeferredAvatarAlphaProgram); mShaderList.push_back(&gDeferredWLSkyProgram); mShaderList.push_back(&gDeferredWLCloudProgram); mShaderList.push_back(&gDeferredWLMoonProgram); mShaderList.push_back(&gDeferredWLSunProgram); mShaderList.push_back(&gDeferredPBRAlphaProgram); - mShaderList.push_back(&gDeferredPBRAlphaWaterProgram); mShaderList.push_back(&gHUDPBRAlphaProgram); mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram); - mShaderList.push_back(&gDeferredSkinnedPBRAlphaWaterProgram); mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma mShaderList.push_back(&gNoPostGammaCorrectProgram); mShaderList.push_back(&gLegacyPostGammaCorrectProgram); @@ -594,7 +571,6 @@ std::string LLViewerShaderMgr::loadBasicShaders() vector< pair > shaders; shaders.push_back( make_pair( "windlight/atmosphericsVarsV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); - shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); shaders.push_back( make_pair( "windlight/atmosphericsHelpersV.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); shaders.push_back( make_pair( "lighting/lightFuncV.glsl", mShaderLevel[SHADER_LIGHTING] ) ); shaders.push_back( make_pair( "lighting/sumLightsV.glsl", sum_lights_class ) ); @@ -674,7 +650,6 @@ std::string LLViewerShaderMgr::loadBasicShaders() std::vector index_channels; index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsWaterF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsHelpersF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/gammaF.glsl", mShaderLevel[SHADER_WINDLIGHT]) ); index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); @@ -908,7 +883,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedBumpProgram.unload(); gDeferredImpostorProgram.unload(); gDeferredTerrainProgram.unload(); - gDeferredTerrainWaterProgram.unload(); gDeferredLightProgram.unload(); for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; ++i) { @@ -919,7 +893,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSunProgram.unload(); gDeferredBlurLightProgram.unload(); gDeferredSoftenProgram.unload(); - gDeferredSoftenWaterProgram.unload(); gDeferredShadowProgram.unload(); gDeferredSkinnedShadowProgram.unload(); gDeferredShadowCubeProgram.unload(); @@ -937,20 +910,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAlphaProgram.unload(); gHUDAlphaProgram.unload(); gDeferredSkinnedAlphaProgram.unload(); - gDeferredAlphaWaterProgram.unload(); - gDeferredSkinnedAlphaWaterProgram.unload(); gDeferredFullbrightProgram.unload(); gHUDFullbrightProgram.unload(); gDeferredFullbrightAlphaMaskProgram.unload(); gHUDFullbrightAlphaMaskProgram.unload(); gDeferredFullbrightAlphaMaskAlphaProgram.unload(); gHUDFullbrightAlphaMaskAlphaProgram.unload(); - gDeferredFullbrightWaterProgram.unload(); - gDeferredSkinnedFullbrightWaterProgram.unload(); - gDeferredFullbrightWaterAlphaProgram.unload(); - gDeferredSkinnedFullbrightWaterAlphaProgram.unload(); - gDeferredFullbrightAlphaMaskWaterProgram.unload(); - gDeferredSkinnedFullbrightAlphaMaskWaterProgram.unload(); gDeferredEmissiveProgram.unload(); gDeferredSkinnedEmissiveProgram.unload(); gDeferredAvatarEyesProgram.unload(); @@ -984,7 +949,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) { gDeferredMaterialProgram[i].unload(); - gDeferredMaterialWaterProgram[i].unload(); } gHUDPBROpaqueProgram.unload(); @@ -993,8 +957,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSkinnedPBROpaqueProgram.unload(); gDeferredPBRAlphaProgram.unload(); gDeferredSkinnedPBRAlphaProgram.unload(); - gDeferredPBRAlphaWaterProgram.unload(); - gDeferredSkinnedPBRAlphaWaterProgram.unload(); return TRUE; } @@ -1084,15 +1046,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; - for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) { if (success) @@ -1158,77 +1111,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredMaterialProgram[i].createShader(NULL, NULL); llassert(success); } - - if (success) - { - mShaderList.push_back(&gDeferredMaterialWaterProgram[i]); - - gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i); - - U32 alpha_mode = i & 0x3; - - gDeferredMaterialWaterProgram[i].mShaderFiles.clear(); - gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER)); - gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER)); - gDeferredMaterialWaterProgram[i].mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER; - - gDeferredMaterialWaterProgram[i].clearPermutations(); - - bool has_normal_map = (i & 0x8) > 0; - bool has_specular_map = (i & 0x4) > 0; - - if (has_normal_map) - { - gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", "1"); - } - - if (has_specular_map) - { - gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", "1"); - } - - gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); - if (alpha_mode != 0) - { - gDeferredMaterialWaterProgram[i].mFeatures.hasAlphaMask = true; - gDeferredMaterialWaterProgram[i].addPermutation("HAS_ALPHA_MASK", "1"); - } - - if (use_sun_shadow) - { - gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", "1"); - } - - bool has_skin = i & 0x10; - if (has_skin) - { - gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1"); - } - else - { - gDeferredMaterialWaterProgram[i].mRiggedVariant = &(gDeferredMaterialWaterProgram[i + 0x10]); - } - gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1"); - - gDeferredMaterialWaterProgram[i].mFeatures.hasReflectionProbes = true; - gDeferredMaterialWaterProgram[i].mFeatures.hasWaterFog = true; - gDeferredMaterialWaterProgram[i].mFeatures.hasSrgb = true; - gDeferredMaterialWaterProgram[i].mFeatures.encodesNormal = true; - gDeferredMaterialWaterProgram[i].mFeatures.calculatesAtmospherics = true; - gDeferredMaterialWaterProgram[i].mFeatures.hasAtmospherics = true; - gDeferredMaterialWaterProgram[i].mFeatures.hasGamma = true; - - gDeferredMaterialWaterProgram[i].mFeatures.hasShadows = use_sun_shadow; - - if (has_skin) - { - gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true; - } - - success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms); - llassert(success); - } } gDeferredMaterialProgram[1].mFeatures.hasLighting = true; @@ -1240,15 +1122,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; - if (success) { gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader"; @@ -1356,62 +1229,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() shader->mRiggedVariant->mFeatures.hasLighting = true; } - if (success) - { - LLGLSLShader* shader = &gDeferredPBRAlphaWaterProgram; - shader->mName = "Deferred PBR Alpha Underwater Shader"; - - shader->mFeatures.calculatesLighting = false; - shader->mFeatures.hasLighting = false; - shader->mFeatures.isAlphaLighting = true; - shader->mFeatures.hasWaterFog = true; - shader->mFeatures.hasSrgb = true; - shader->mFeatures.encodesNormal = true; - shader->mFeatures.calculatesAtmospherics = true; - shader->mFeatures.hasAtmospherics = true; - shader->mFeatures.hasGamma = true; - shader->mFeatures.hasShadows = use_sun_shadow; - shader->mFeatures.isDeferred = true; // include deferredUtils - shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED]; - - shader->mShaderGroup = LLGLSLShader::SG_WATER; - - shader->mShaderFiles.clear(); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER)); - shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER)); - - shader->clearPermutations(); - - U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; - shader->addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); - shader->addPermutation("HAS_NORMAL_MAP", "1"); - shader->addPermutation("HAS_SPECULAR_MAP", "1"); // PBR: Packed: Occlusion, Metal, Roughness - shader->addPermutation("HAS_EMISSIVE_MAP", "1"); - shader->addPermutation("USE_VERTEX_COLOR", "1"); - shader->addPermutation("WATER_FOG", "1"); - - if (use_sun_shadow) - { - shader->addPermutation("HAS_SUN_SHADOW", "1"); - } - - shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaWaterProgram); - if (success) - { - success = shader->createShader(NULL, NULL); - } - llassert(success); - - // Alpha Shader Hack - // See: LLRender::syncMatrices() - shader->mFeatures.calculatesLighting = true; - shader->mFeatures.hasLighting = true; - - shader->mRiggedVariant->mFeatures.calculatesLighting = true; - shader->mRiggedVariant->mFeatures.hasLighting = true; - } - if (success) { LLGLSLShader* shader = &gHUDPBRAlphaProgram; @@ -1737,68 +1554,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() } } - if (success) - { - LLGLSLShader* shader[] = { - &gDeferredAlphaWaterProgram, - &gDeferredSkinnedAlphaWaterProgram - }; - - gDeferredAlphaWaterProgram.mRiggedVariant = &gDeferredSkinnedAlphaWaterProgram; - - gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader"; - gDeferredSkinnedAlphaWaterProgram.mName = "Deferred Skinned Alpha Underwater Shader"; - - for (int i = 0; i < 2 && success; ++i) - { - shader[i]->mFeatures.calculatesLighting = false; - shader[i]->mFeatures.hasLighting = false; - shader[i]->mFeatures.isAlphaLighting = true; - shader[i]->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - shader[i]->mFeatures.hasWaterFog = true; - shader[i]->mFeatures.hasSrgb = true; - shader[i]->mFeatures.encodesNormal = true; - shader[i]->mFeatures.calculatesAtmospherics = true; - shader[i]->mFeatures.hasAtmospherics = true; - shader[i]->mFeatures.hasGamma = true; - shader[i]->mFeatures.hasShadows = use_sun_shadow; - shader[i]->mFeatures.hasReflectionProbes = true; - shader[i]->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - shader[i]->mShaderGroup = LLGLSLShader::SG_WATER; - shader[i]->mShaderFiles.clear(); - shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER)); - shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER)); - - shader[i]->clearPermutations(); - shader[i]->addPermutation("USE_INDEXED_TEX", "1"); - shader[i]->addPermutation("WATER_FOG", "1"); - shader[i]->addPermutation("USE_VERTEX_COLOR", "1"); - shader[i]->addPermutation("HAS_ALPHA_MASK", "1"); - if (use_sun_shadow) - { - shader[i]->addPermutation("HAS_SUN_SHADOW", "1"); - } - - if (i == 1) - { // rigged variant - shader[i]->mFeatures.hasObjectSkinning = true; - shader[i]->addPermutation("HAS_SKIN", "1"); - } - else - { - shader[i]->mRiggedVariant = shader[1]; - } - shader[i]->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - - success = shader[i]->createShader(NULL, NULL); - llassert(success); - - // Hack - shader[i]->mFeatures.calculatesLighting = true; - shader[i]->mFeatures.hasLighting = true; - } - } - if (success) { gDeferredAvatarEyesProgram.mName = "Deferred Avatar Eyes Shader"; @@ -1825,6 +1580,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightProgram.mFeatures.hasGamma = true; gDeferredFullbrightProgram.mFeatures.hasAtmospherics = true; gDeferredFullbrightProgram.mFeatures.hasSrgb = true; + gDeferredFullbrightProgram.mFeatures.hasWaterFog = true; gDeferredFullbrightProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredFullbrightProgram.mShaderFiles.clear(); gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); @@ -1860,6 +1616,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasAtmospherics = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasSrgb = true; + gDeferredFullbrightAlphaMaskProgram.mFeatures.hasWaterFog = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredFullbrightAlphaMaskProgram.mShaderFiles.clear(); gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); @@ -1933,71 +1690,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() llassert(success); } - if (success) - { - gDeferredFullbrightWaterProgram.mName = "Deferred Fullbright Underwater Shader"; - gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true; - gDeferredFullbrightWaterProgram.mFeatures.hasAtmospherics = true; - gDeferredFullbrightWaterProgram.mFeatures.hasWaterFog = true; - gDeferredFullbrightWaterProgram.mFeatures.hasSrgb = true; - gDeferredFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - gDeferredFullbrightWaterProgram.mShaderFiles.clear(); - gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); - gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER)); - gDeferredFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1"); - success = make_rigged_variant(gDeferredFullbrightWaterProgram, gDeferredSkinnedFullbrightWaterProgram); - success = success && gDeferredFullbrightWaterProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredFullbrightWaterAlphaProgram.mName = "Deferred Fullbright Underwater Alpha Shader"; - gDeferredFullbrightWaterAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.hasGamma = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.hasAtmospherics = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.hasWaterFog = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.hasSrgb = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.isDeferred = true; - gDeferredFullbrightWaterAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - gDeferredFullbrightWaterAlphaProgram.mShaderFiles.clear(); - gDeferredFullbrightWaterAlphaProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); - gDeferredFullbrightWaterAlphaProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER)); - gDeferredFullbrightWaterAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredFullbrightWaterAlphaProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredFullbrightWaterAlphaProgram.clearPermutations(); - gDeferredFullbrightWaterAlphaProgram.addPermutation("WATER_FOG", "1"); - gDeferredFullbrightWaterAlphaProgram.addPermutation("IS_ALPHA", "1"); - success = make_rigged_variant(gDeferredFullbrightWaterAlphaProgram, gDeferredSkinnedFullbrightWaterAlphaProgram); - success = success && gDeferredFullbrightWaterAlphaProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader"; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasAtmospherics = true; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasWaterFog = true; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasSrgb = true; - gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.clear(); - gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); - gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER)); - gDeferredFullbrightAlphaMaskWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredFullbrightAlphaMaskWaterProgram.clearPermutations(); - gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1"); - gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1"); - success = make_rigged_variant(gDeferredFullbrightAlphaMaskWaterProgram, gDeferredSkinnedFullbrightAlphaMaskWaterProgram); - success = success && gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL); - llassert(success); - } - if (success) { gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader"; @@ -2084,40 +1776,53 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() llassert(success); } - if (success) - { - gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader"; - gDeferredSoftenWaterProgram.mShaderFiles.clear(); - gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER)); - gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER)); + if (success) + { + gHazeProgram.mName = "Haze Shader"; + gHazeProgram.mShaderFiles.clear(); + gHazeProgram.mFeatures.hasSrgb = true; + gHazeProgram.mFeatures.calculatesAtmospherics = true; + gHazeProgram.mFeatures.hasAtmospherics = true; + gHazeProgram.mFeatures.hasGamma = true; + gHazeProgram.mFeatures.isDeferred = true; + gHazeProgram.mFeatures.hasShadows = use_sun_shadow; + gHazeProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; - gDeferredSoftenWaterProgram.clearPermutations(); - gDeferredSoftenWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1"); - gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredSoftenWaterProgram.mFeatures.hasWaterFog = true; - gDeferredSoftenWaterProgram.mFeatures.hasSrgb = true; - gDeferredSoftenWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredSoftenWaterProgram.mFeatures.hasAtmospherics = true; - gDeferredSoftenWaterProgram.mFeatures.hasGamma = true; - gDeferredSoftenWaterProgram.mFeatures.isDeferred = true; - gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow; - gDeferredSoftenWaterProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; + gHazeProgram.clearPermutations(); + gHazeProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER)); + gHazeProgram.mShaderFiles.push_back(make_pair("deferred/hazeF.glsl", GL_FRAGMENT_SHADER)); - if (use_sun_shadow) - { - gDeferredSoftenWaterProgram.addPermutation("HAS_SUN_SHADOW", "1"); - } + gHazeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - if (gSavedSettings.getBOOL("RenderDeferredSSAO")) - { //if using SSAO, take screen space light map into account as if shadows are enabled - gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2); - gDeferredSoftenWaterProgram.addPermutation("HAS_SSAO", "1"); - } + success = gHazeProgram.createShader(NULL, NULL); + llassert(success); + } + + + if (success) + { + gHazeWaterProgram.mName = "Water Haze Shader"; + gHazeWaterProgram.mShaderFiles.clear(); + gHazeWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gHazeWaterProgram.mFeatures.hasWaterFog = true; + gHazeWaterProgram.mFeatures.hasSrgb = true; + gHazeWaterProgram.mFeatures.calculatesAtmospherics = true; + gHazeWaterProgram.mFeatures.hasAtmospherics = true; + gHazeWaterProgram.mFeatures.hasGamma = true; + gHazeWaterProgram.mFeatures.isDeferred = true; + gHazeWaterProgram.mFeatures.hasShadows = use_sun_shadow; + gHazeWaterProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; + + gHazeWaterProgram.clearPermutations(); + gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER)); + gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterHazeF.glsl", GL_FRAGMENT_SHADER)); + + gHazeWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + success = gHazeWaterProgram.createShader(NULL, NULL); + llassert(success); + } - success = gDeferredSoftenWaterProgram.createShader(NULL, NULL); - llassert(success); - } if (success) { @@ -2277,31 +1982,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() llassert(success); } - if (success) - { - gDeferredTerrainWaterProgram.mName = "Deferred Terrain Underwater Shader"; - gDeferredTerrainWaterProgram.mFeatures.encodesNormal = true; - gDeferredTerrainWaterProgram.mFeatures.hasSrgb = true; - gDeferredTerrainWaterProgram.mFeatures.calculatesLighting = false; - gDeferredTerrainWaterProgram.mFeatures.hasLighting = false; - gDeferredTerrainWaterProgram.mFeatures.isAlphaLighting = true; - gDeferredTerrainWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - gDeferredTerrainWaterProgram.mFeatures.hasWaterFog = true; - gDeferredTerrainWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredTerrainWaterProgram.mFeatures.hasAtmospherics = true; - gDeferredTerrainWaterProgram.mFeatures.hasGamma = true; - - gDeferredTerrainWaterProgram.mShaderFiles.clear(); - gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER)); - gDeferredTerrainWaterProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER)); - gDeferredTerrainWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - gDeferredTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredTerrainWaterProgram.clearPermutations(); - gDeferredTerrainWaterProgram.addPermutation("WATER_FOG", "1"); - success = gDeferredTerrainWaterProgram.createShader(NULL, NULL); - llassert(success); - } - if (success) { gDeferredAvatarProgram.mName = "Deferred Avatar Shader"; @@ -2331,6 +2011,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.isDeferred = true; gDeferredAvatarAlphaProgram.mFeatures.hasShadows = true; gDeferredAvatarAlphaProgram.mFeatures.hasReflectionProbes = true; + gDeferredAvatarAlphaProgram.mFeatures.hasWaterFog = true; gDeferredAvatarAlphaProgram.mShaderFiles.clear(); gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER)); @@ -2660,24 +2341,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectAlphaMaskNoColorProgram.createShader(NULL, NULL); } - if (success) - { - gObjectAlphaMaskNoColorWaterProgram.mName = "No color alpha mask Water Shader"; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.calculatesLighting = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasWaterFog = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasAtmospherics = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasLighting = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.disableTextureIndex = true; - gObjectAlphaMaskNoColorWaterProgram.mFeatures.hasAlphaMask = true; - gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.clear(); - gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleNoColorV.glsl", GL_VERTEX_SHADER)); - gObjectAlphaMaskNoColorWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER)); - gObjectAlphaMaskNoColorWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectAlphaMaskNoColorWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectAlphaMaskNoColorWaterProgram.createShader(NULL, NULL); - } - if (success) { gImpostorProgram.mName = "Impostor Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index b0b9719d76..04da7e48ae 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -175,7 +175,6 @@ extern LLGLSLShader gSkinnedObjectFullbrightAlphaMaskProgram; extern LLGLSLShader gObjectBumpProgram; extern LLGLSLShader gSkinnedObjectBumpProgram; extern LLGLSLShader gObjectAlphaMaskNoColorProgram; -extern LLGLSLShader gObjectAlphaMaskNoColorWaterProgram; //environment shaders extern LLGLSLShader gWaterProgram; @@ -211,7 +210,6 @@ extern LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseProgram; extern LLGLSLShader gDeferredBumpProgram; extern LLGLSLShader gDeferredTerrainProgram; -extern LLGLSLShader gDeferredTerrainWaterProgram; extern LLGLSLShader gDeferredTreeProgram; extern LLGLSLShader gDeferredTreeShadowProgram; extern LLGLSLShader gDeferredLightProgram; @@ -219,10 +217,11 @@ extern LLGLSLShader gDeferredMultiLightProgram[LL_DEFERRED_MULTI_LIGHT_COUNT]; extern LLGLSLShader gDeferredSpotLightProgram; extern LLGLSLShader gDeferredMultiSpotLightProgram; extern LLGLSLShader gDeferredSunProgram; +extern LLGLSLShader gHazeProgram; +extern LLGLSLShader gHazeWaterProgram; extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; -extern LLGLSLShader gDeferredSoftenWaterProgram; extern LLGLSLShader gDeferredShadowProgram; extern LLGLSLShader gDeferredShadowCubeProgram; extern LLGLSLShader gDeferredShadowAlphaMaskProgram; @@ -251,10 +250,6 @@ extern LLGLSLShader gDeferredFullbrightAlphaMaskProgram; extern LLGLSLShader gHUDFullbrightAlphaMaskProgram; extern LLGLSLShader gDeferredFullbrightAlphaMaskAlphaProgram; extern LLGLSLShader gHUDFullbrightAlphaMaskAlphaProgram; -extern LLGLSLShader gDeferredAlphaWaterProgram; -extern LLGLSLShader gDeferredFullbrightWaterProgram; -extern LLGLSLShader gDeferredFullbrightWaterAlphaProgram; -extern LLGLSLShader gDeferredFullbrightAlphaMaskWaterProgram; extern LLGLSLShader gDeferredEmissiveProgram; extern LLGLSLShader gDeferredAvatarEyesProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; @@ -271,12 +266,10 @@ extern LLGLSLShader gDeferredBufferVisualProgram; // Deferred materials shaders extern LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; -extern LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; extern LLGLSLShader gHUDPBROpaqueProgram; extern LLGLSLShader gPBRGlowProgram; extern LLGLSLShader gDeferredPBROpaqueProgram; extern LLGLSLShader gDeferredPBRAlphaProgram; -extern LLGLSLShader gDeferredPBRAlphaWaterProgram; extern LLGLSLShader gHUDPBRAlphaProgram; #endif diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9266c84540..52afe16799 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7875,7 +7875,7 @@ void LLPipeline::renderDeferredLighting() if (RenderDeferredAtmospheric) { // apply sunlight contribution - LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram; + LLGLSLShader &soften_shader = gDeferredSoftenProgram; LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics"); LL_PROFILE_GPU_ZONE("atmospherics"); @@ -7904,7 +7904,7 @@ void LLPipeline::renderDeferredLighting() mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); } - unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); + unbindDeferredShader(gDeferredSoftenProgram); } static LLCachedControl local_light_count(gSavedSettings, "RenderLocalLightCount", 256); @@ -8056,7 +8056,7 @@ void LLPipeline::renderDeferredLighting() LLVector4a center; center.load3(drawablep->getPositionAgent().mV); - const F32 *c = center.getF32ptr(); + const F32* c = center.getF32ptr(); F32 s = volume->getLightRadius() * 1.5f; sVisibleLightCount++; @@ -8105,8 +8105,8 @@ void LLPipeline::renderDeferredLighting() U32 idx = count - 1; bindDeferredShader(gDeferredMultiLightProgram[idx]); gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); - gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat *) light); - gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat *) col); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*)light); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*)col); gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); far_z = 0.f; count = 0; @@ -8124,11 +8124,11 @@ void LLPipeline::renderDeferredLighting() for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) { - LLDrawable *drawablep = *iter; - LLVOVolume *volume = drawablep->getVOVolume(); - LLVector3 center = drawablep->getPositionAgent(); - F32 * c = center.mV; - F32 light_size_final = volume->getLightRadius() * 1.5f; + LLDrawable* drawablep = *iter; + LLVOVolume* volume = drawablep->getVOVolume(); + LLVector3 center = drawablep->getPositionAgent(); + F32* c = center.mV; + F32 light_size_final = volume->getLightRadius() * 1.5f; F32 light_falloff_final = volume->getLightFalloff(DEFERRED_LIGHT_FALLOFF); sVisibleLightCount++; @@ -8154,12 +8154,56 @@ void LLPipeline::renderDeferredLighting() } + + if (RenderDeferredAtmospheric) + { + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA); + gGL.setColorMask(true, false); + + for (U32 i = 0; i < 2; ++i) + { + // apply haze + LLGLSLShader &haze_shader = i == 0 ? gHazeProgram : gHazeWaterProgram; + + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - haze"); + LL_PROFILE_GPU_ZONE("haze"); + bindDeferredShader(haze_shader); + + static LLCachedControl ssao_scale(gSavedSettings, "RenderSSAOIrradianceScale", 0.5f); + static LLCachedControl ssao_max(gSavedSettings, "RenderSSAOIrradianceMax", 0.25f); + static LLStaticHashedString ssao_scale_str("ssao_irradiance_scale"); + static LLStaticHashedString ssao_max_str("ssao_irradiance_max"); + + haze_shader.uniform1f(ssao_scale_str, ssao_scale); + haze_shader.uniform1f(ssao_max_str, ssao_max); + + LLEnvironment &environment = LLEnvironment::instance(); + haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + haze_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); + + haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); + + { + LLGLDepthTest depth(GL_FALSE); + + // full screen blit + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + unbindDeferredShader(haze_shader); + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + gGL.setColorMask(true, true); } { // render non-deferred geometry (alpha, fullbright, glow) LLGLDisable blend(GL_BLEND); - //LLGLDisable stencil(GL_STENCIL_TEST); pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, From 964f9e74d5e97fc46fc74d6afff97dad5c6381c3 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Fri, 17 Nov 2023 10:10:58 -0600 Subject: [PATCH 17/77] SL-20611 followup -- remove now unused glsl files. Fix transparent water. --- indra/llrender/llglslshader.h | 1 - indra/llrender/llshadermgr.cpp | 74 ++++--------------- .../class1/lighting/lightWaterAlphaMaskF.glsl | 51 ------------- .../lightWaterAlphaMaskNonIndexedF.glsl | 55 -------------- .../shaders/class1/lighting/lightWaterF.glsl | 42 ----------- .../lighting/lightWaterNonIndexedF.glsl | 44 ----------- .../shaders/class1/objects/simpleWaterF.glsl | 33 --------- .../shaders/class3/environment/waterF.glsl | 2 +- indra/newview/llviewershadermgr.cpp | 14 +--- 9 files changed, 18 insertions(+), 298 deletions(-) delete mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl delete mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl delete mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl delete mode 100644 indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl delete mode 100644 indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index b8071248e2..43d095f73a 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -41,7 +41,6 @@ public: bool hasLighting = false; // implies no transport (it's possible to have neither though) bool isAlphaLighting = false; // indicates lighting shaders need not be linked in (lighting performed directly in alpha shader to match deferred lighting functions) bool isSpecular = false; - bool hasWaterFog = false; // implies no gamma bool hasTransport = false; // implies no lighting (it's possible to have neither though) bool hasSkinning = false; bool hasObjectSkinning = false; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index f14216f3d8..f78be910d2 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -278,7 +278,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } // NOTE order of shader object attaching is VERY IMPORTANT!!! - if (features->hasWaterFog || features->hasAtmospherics) + if (features->hasAtmospherics) { if (!shader->attachFragmentObject("environment/waterFogF.glsl")) { @@ -288,82 +288,40 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasLighting) { - if (features->hasWaterFog) + if (features->disableTextureIndex) { - if (features->disableTextureIndex) + if (features->hasAlphaMask) { - if (features->hasAlphaMask) + if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl")) { - if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl")) - { - return FALSE; - } - } - else - { - if (!shader->attachFragmentObject("lighting/lightWaterNonIndexedF.glsl")) - { - return FALSE; - } + return FALSE; } } - else + else { - if (features->hasAlphaMask) + if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl")) { - if (!shader->attachFragmentObject("lighting/lightWaterAlphaMaskF.glsl")) - { - return FALSE; - } + return FALSE; } - else - { - if (!shader->attachFragmentObject("lighting/lightWaterF.glsl")) - { - return FALSE; - } - } - shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } - - else + else { - if (features->disableTextureIndex) + if (features->hasAlphaMask) { - if (features->hasAlphaMask) + if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl")) { - if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl")) - { - return FALSE; - } - } - else - { - if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl")) - { - return FALSE; - } + return FALSE; } } - else + else { - if (features->hasAlphaMask) + if (!shader->attachFragmentObject("lighting/lightF.glsl")) { - if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl")) - { - return FALSE; - } + return FALSE; } - else - { - if (!shader->attachFragmentObject("lighting/lightF.glsl")) - { - return FALSE; - } - } - shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl deleted file mode 100644 index 670b3ddaf1..0000000000 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file class1\lighting\lightWaterAlphaMaskF.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - */ - -out vec4 frag_color; - -uniform float minimum_alpha; - -vec3 atmosLighting(vec3 light); -vec4 applyWaterFog(vec4 color); - -in vec4 vertex_color; -in vec2 vary_texcoord0; - -void default_lighting_water() -{ - vec4 color = diffuseLookup(vary_texcoord0.xy); - - if (color.a < minimum_alpha) - { - discard; - } - - color.rgb *= vertex_color.rgb; - - color.rgb = atmosLighting(color.rgb); - - frag_color = max(applyWaterFog(color), vec4(0)); -} - diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl deleted file mode 100644 index 2e5ed57014..0000000000 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file class1\lighting\lightWaterAlphaMaskNonIndexedF.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - */ - -out vec4 frag_color; - -uniform float minimum_alpha; - -uniform sampler2D diffuseMap; - -vec3 atmosLighting(vec3 light); -vec4 applyWaterFog(vec4 color); - -in vec4 vertex_color; -in vec2 vary_texcoord0; - -void default_lighting_water() -{ - vec4 color = texture(diffuseMap,vary_texcoord0.xy); - - if (color.a < minimum_alpha) - { - discard; - } - - color.rgb *= vertex_color.rgb; - - color.rgb = atmosLighting(color.rgb); - - color = applyWaterFog(color); - - frag_color = max(color, vec4(0)); -} - diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl deleted file mode 100644 index 09b4a6e317..0000000000 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file class1\lighting\lightWaterF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -out vec4 frag_color; - -in vec4 vertex_color; -in vec2 vary_texcoord0; - -vec3 atmosLighting(vec3 light); -vec4 applyWaterFog(vec4 color); - -void default_lighting_water() -{ - vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; - - color.rgb = atmosLighting(color.rgb); - - frag_color = max(applyWaterFog(color), vec4(0)); -} - diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl deleted file mode 100644 index 4888fa547c..0000000000 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file class1\lighting\lightWaterNonIndexedF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -out vec4 frag_color; - -in vec4 vertex_color; -in vec2 vary_texcoord0; - -uniform sampler2D diffuseMap; - -vec3 atmosLighting(vec3 light); -vec4 applyWaterFog(vec4 color); - -void default_lighting_water() -{ - vec4 color = texture(diffuseMap,vary_texcoord0.xy) * vertex_color; - - color.rgb = atmosLighting(color.rgb); - - frag_color = max(applyWaterFog(color), vec4(0)); -} - diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl deleted file mode 100644 index 2e87ac5bbc..0000000000 --- a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file simpleWaterF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - - - -void default_lighting_water(); - -void main() -{ - default_lighting_water(); -} diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index af0460fa8b..8bc5f3cc50 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -224,7 +224,7 @@ void main() } #else - vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0), sunlit_linear); + vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0)); #endif // fudge sample on other side of water to be a tad darker diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index e6e80e9532..2c2ae022d7 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -664,12 +664,8 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); - index_channels.push_back(ch); shaders.push_back( make_pair( "lighting/lightWaterAlphaMaskF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); for (U32 i = 0; i < shaders.size(); i++) { @@ -707,7 +703,6 @@ BOOL LLViewerShaderMgr::loadShadersWater() gWaterProgram.mName = "Water Shader"; gWaterProgram.mFeatures.calculatesAtmospherics = true; gWaterProgram.mFeatures.hasAtmospherics = true; - gWaterProgram.mFeatures.hasWaterFog = true; gWaterProgram.mFeatures.hasGamma = true; gWaterProgram.mFeatures.hasSrgb = true; gWaterProgram.mFeatures.hasReflectionProbes = true; @@ -738,7 +733,6 @@ BOOL LLViewerShaderMgr::loadShadersWater() gWaterEdgeProgram.mName = "Water Edge Shader"; gWaterEdgeProgram.mFeatures.calculatesAtmospherics = true; gWaterEdgeProgram.mFeatures.hasAtmospherics = true; - gWaterEdgeProgram.mFeatures.hasWaterFog = true; gWaterEdgeProgram.mFeatures.hasGamma = true; gWaterEdgeProgram.mFeatures.hasSrgb = true; gWaterEdgeProgram.mFeatures.hasReflectionProbes = true; @@ -768,7 +762,7 @@ BOOL LLViewerShaderMgr::loadShadersWater() //load under water vertex shader gUnderWaterProgram.mName = "Underwater Shader"; gUnderWaterProgram.mFeatures.calculatesAtmospherics = true; - gUnderWaterProgram.mFeatures.hasWaterFog = true; + gUnderWaterProgram.mFeatures.hasAtmospherics = true; gUnderWaterProgram.mShaderFiles.clear(); gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER)); gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/underWaterF.glsl", GL_FRAGMENT_SHADER)); @@ -1457,7 +1451,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasGamma = true; shader->mFeatures.hasShadows = use_sun_shadow; shader->mFeatures.hasReflectionProbes = true; - shader->mFeatures.hasWaterFog = true; shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; shader->mShaderFiles.clear(); @@ -1580,7 +1573,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightProgram.mFeatures.hasGamma = true; gDeferredFullbrightProgram.mFeatures.hasAtmospherics = true; gDeferredFullbrightProgram.mFeatures.hasSrgb = true; - gDeferredFullbrightProgram.mFeatures.hasWaterFog = true; gDeferredFullbrightProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredFullbrightProgram.mShaderFiles.clear(); gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); @@ -1616,7 +1608,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasAtmospherics = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.hasSrgb = true; - gDeferredFullbrightAlphaMaskProgram.mFeatures.hasWaterFog = true; gDeferredFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredFullbrightAlphaMaskProgram.mShaderFiles.clear(); gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER)); @@ -1804,7 +1795,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gHazeWaterProgram.mName = "Water Haze Shader"; gHazeWaterProgram.mShaderFiles.clear(); gHazeWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gHazeWaterProgram.mFeatures.hasWaterFog = true; gHazeWaterProgram.mFeatures.hasSrgb = true; gHazeWaterProgram.mFeatures.calculatesAtmospherics = true; gHazeWaterProgram.mFeatures.hasAtmospherics = true; @@ -1969,7 +1959,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredTerrainProgram.mFeatures.hasLighting = false; gDeferredTerrainProgram.mFeatures.isAlphaLighting = true; gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - gDeferredTerrainProgram.mFeatures.hasWaterFog = true; gDeferredTerrainProgram.mFeatures.calculatesAtmospherics = true; gDeferredTerrainProgram.mFeatures.hasAtmospherics = true; gDeferredTerrainProgram.mFeatures.hasGamma = true; @@ -2011,7 +2000,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.isDeferred = true; gDeferredAvatarAlphaProgram.mFeatures.hasShadows = true; gDeferredAvatarAlphaProgram.mFeatures.hasReflectionProbes = true; - gDeferredAvatarAlphaProgram.mFeatures.hasWaterFog = true; gDeferredAvatarAlphaProgram.mShaderFiles.clear(); gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER)); From ba1f87b36e91668b6f87bc996b06db79f2763901 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 17 Nov 2023 13:26:08 -0800 Subject: [PATCH 18/77] SL-20553: Fix crash in ~PBRPickerAgentListener --- indra/newview/llpanelface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 02c00e7f87..bf54d17111 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1915,8 +1915,6 @@ public: { gInventory.removeObserver(this); mChangePending = false; - - LLInventoryObserver::~LLInventoryObserver(); } }; From 70eda83fb08c5c4e8b0ea95868243d744c6e88e9 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 20 Nov 2023 21:25:06 +0100 Subject: [PATCH 19/77] SL-20563 Add 'No Post' option to Snapshot floater --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llfloatersnapshot.cpp | 4 ++-- indra/newview/llsnapshotlivepreview.cpp | 2 ++ indra/newview/llviewerdisplay.cpp | 5 +++-- indra/newview/llviewermenufile.cpp | 6 ++++-- indra/newview/llviewerwindow.cpp | 9 ++++++--- indra/newview/llviewerwindow.h | 4 ++-- indra/newview/pipeline.cpp | 6 ++++-- 8 files changed, 34 insertions(+), 13 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b9025ef7cd..00b59f9a4d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -533,6 +533,17 @@ Value 0 + RenderSnapshotNoPost + + Comment + Disable tone mapping and exposure correction when snapshot is being rendered + Persist + 1 + Type + Boolean + Value + 0 + AutomaticFly Comment diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 4806fe9625..ca2069cbfc 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -474,7 +474,7 @@ void LLFloaterSnapshotBase::ImplBase::onClickAutoSnap(LLUICtrl *ctrl, void* data void LLFloaterSnapshotBase::ImplBase::onClickNoPost(LLUICtrl *ctrl, void* data) { BOOL no_post = ((LLCheckBoxCtrl*)ctrl)->get(); - gSavedSettings.setBOOL("RenderDisablePostProcessing", no_post); + gSavedSettings.setBOOL("RenderSnapshotNoPost", no_post); LLFloaterSnapshotBase* view = (LLFloaterSnapshotBase*)data; view->getPreviewView()->updateSnapshot(TRUE, TRUE); @@ -1008,7 +1008,7 @@ BOOL LLFloaterSnapshot::postBuild() getChild("auto_snapshot_check")->setValue(gSavedSettings.getBOOL("AutoSnapshot")); childSetCommitCallback("auto_snapshot_check", ImplBase::onClickAutoSnap, this); - getChild("no_post_check")->setValue(gSavedSettings.getBOOL("RenderDisablePostProcessing")); + getChild("no_post_check")->setValue(gSavedSettings.getBOOL("RenderSnapshotNoPost")); childSetCommitCallback("no_post_check", ImplBase::onClickNoPost, this); getChild("retract_btn")->setCommitCallback(boost::bind(&LLFloaterSnapshot::onExtendFloater, this)); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index b7a1832b17..2ff8f50277 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -559,6 +559,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, + gSavedSettings.getBOOL("RenderSnapshotNoPost"), mSnapshotBufferType) ) { raw = NULL ; @@ -718,6 +719,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"), gSavedSettings.getBOOL("RenderHUDInSnapshot"), FALSE, + gSavedSettings.getBOOL("RenderSnapshotNoPost"), previewp->mSnapshotBufferType, previewp->getMaxImageSize())) { diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 04ca62e0ec..a936012781 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -100,6 +100,7 @@ BOOL gResizeShadowTexture = FALSE; BOOL gWindowResized = FALSE; BOOL gSnapshot = FALSE; BOOL gCubeSnapshot = FALSE; +BOOL gSnapshotNoPost = FALSE; BOOL gShaderProfileFrame = FALSE; // This is how long the sim will try to teleport you before giving up. @@ -410,13 +411,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gResizeShadowTexture = FALSE; } + gSnapshot = for_snapshot; + if (LLPipeline::sRenderDeferred) { //hack to make sky show up in deferred snapshots for_snapshot = FALSE; } - gSnapshot = for_snapshot; - LLGLSDefault gls_default; LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index e2791ba128..5461e0f362 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -863,8 +863,9 @@ class LLFileTakeSnapshotToDisk : public view_listener_t S32 width = gViewerWindow->getWindowWidthRaw(); S32 height = gViewerWindow->getWindowHeightRaw(); - bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); - bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + BOOL render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot"); + BOOL render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot"); + BOOL render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); BOOL high_res = gSavedSettings.getBOOL("HighResSnapshot"); if (high_res) @@ -884,6 +885,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t render_ui, render_hud, FALSE, + render_no_post, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ba2b6e1c7c..ed671fe849 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -229,6 +229,7 @@ extern BOOL gDisplaySwapBuffers; extern BOOL gDepthDirty; extern BOOL gResizeScreenTexture; extern BOOL gCubeSnapshot; +extern BOOL gSnapshotNoPost; LLViewerWindow *gViewerWindow = NULL; @@ -4875,16 +4876,16 @@ void LLViewerWindow::resetSnapshotLoc() const gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string()); } -BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type) +BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, BOOL no_post, LLSnapshotModel::ESnapshotLayerType type) { - return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, show_hud, do_rebuild, type); + return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, show_hud, do_rebuild, no_post, type); } // Saves the image from the screen to a raw image // Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy // the results over to the final raw image. BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, - BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) + BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, BOOL no_post, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) { if (!raw) { @@ -4901,6 +4902,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei } // PRE SNAPSHOT + gSnapshotNoPost = no_post; gDisplaySwapBuffers = FALSE; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT); @@ -5131,6 +5133,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei } gDisplaySwapBuffers = FALSE; + gSnapshotNoPost = FALSE; gDepthDirty = TRUE; // POST SNAPSHOT diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 6e8a5b2f4e..ccef006a07 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -362,7 +362,7 @@ public: BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, - BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); + BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, BOOL no_post = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); BOOL simpleSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, const int num_render_passes); @@ -380,7 +380,7 @@ public: // special implementation of simpleSnapshot for reflection maps BOOL reflectionSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes); - BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, BOOL no_post, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9266c84540..64d247a202 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -211,6 +211,7 @@ extern S32 gBoxFrame; extern BOOL gDisplaySwapBuffers; extern BOOL gDebugGL; extern BOOL gCubeSnapshot; +extern BOOL gSnapshotNoPost; bool gAvatarBacklight = false; @@ -6791,7 +6792,7 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { { LL_PROFILE_GPU_ZONE("gamma correct"); - static LLCachedControl no_post(gSavedSettings, "RenderDisablePostProcessing", false); + static LLCachedControl buildNoPost(gSavedSettings, "RenderDisablePostProcessing", false); LLGLDepthTest depth(GL_FALSE, GL_FALSE); @@ -6801,7 +6802,8 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - LLGLSLShader& shader = no_post && gFloaterTools->isAvailable() ? gNoPostGammaCorrectProgram : // no post (no gamma, no exposure, no tonemapping) + bool no_post = gSnapshotNoPost || (buildNoPost && gFloaterTools->isAvailable()); + LLGLSLShader& shader = no_post ? gNoPostGammaCorrectProgram : // no post (no gamma, no exposure, no tonemapping) psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f ? gLegacyPostGammaCorrectProgram : gDeferredPostGammaCorrectProgram; From f35127faa03b438b5348c56c9e04b7b1a2c698ea Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Mon, 20 Nov 2023 10:18:27 -0500 Subject: [PATCH 20/77] Fix failure to save the normalized translation data during collada upload --- indra/llprimitive/lldaeloader.cpp | 3 ++- indra/llprimitive/llmodel.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 46e1cb4922..2e4b013b77 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -2584,7 +2584,8 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector& mo next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod]; next->getVolumeFaces() = remainder; next->mNormalizedScale = ret->mNormalizedScale; - + next->mNormalizedTranslation = ret->mNormalizedTranslation; + if ( ret->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES) { next->mMaterialList.assign(ret->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, ret->mMaterialList.end()); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index ee493968de..99a5697a84 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -52,7 +52,8 @@ const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); LLModel::LLModel(LLVolumeParams& params, F32 detail) : LLVolume(params, detail), - mNormalizedScale(1,1,1), + mNormalizedScale(1,1,1), + mNormalizedTranslation(0, 0, 0), mPelvisOffset( 0.0f ), mStatus(NO_ERRORS), mSubmodelID(0) From 86df22a031527ffb8edbcc5bca93a2e7735dfae6 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 27 Nov 2023 15:01:01 +0200 Subject: [PATCH 21/77] SL-20639 increase floater width to accommodate adding new option --- indra/newview/skins/default/xui/en/floater_snapshot.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index 0866594625..1a1131e24c 100644 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -5,7 +5,7 @@ can_minimize="true" can_resize="false" can_close="true" - height="455" + height="475" layout="topleft" name="Snapshot" single_instance="true" @@ -241,7 +241,7 @@ Date: Tue, 28 Nov 2023 14:31:27 +0200 Subject: [PATCH 22/77] SL-20645 don't show the warning when 'Select Reflection Probes' is enabled --- indra/newview/llpanelvolume.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index f58aab3080..595609b4de 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -746,6 +746,14 @@ void LLPanelVolume::sendIsLight() LL_INFOS() << "update light sent" << LL_ENDL; } +void notify_cant_select_reflection_probe() +{ + if (!gSavedSettings.getBOOL("SelectReflectionProbes")) + { + LLNotificationsUtil::add("CantSelectReflectionProbe"); + } +} + void LLPanelVolume::sendIsReflectionProbe() { LLViewerObject* objectp = mObject; @@ -766,7 +774,7 @@ void LLPanelVolume::sendIsReflectionProbe() { if (value) { - LLNotificationsUtil::add("CantSelectReflectionProbe"); + notify_cant_select_reflection_probe(); } else if (objectp->flagPhantom()) { @@ -794,7 +802,7 @@ void LLPanelVolume::doSendIsReflectionProbe(const LLSD & notification, const LLS } LLVOVolume* volobjp = (LLVOVolume*)objectp; - LLNotificationsUtil::add("CantSelectReflectionProbe"); + notify_cant_select_reflection_probe(); volobjp->setIsReflectionProbe(true); { // has become a reflection probe, slam to a 10m sphere and pop up a message From b96ca755b36737eb07645df7b172be002d9509f2 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 29 Nov 2023 16:46:10 +0200 Subject: [PATCH 23/77] SL-20647 don't allow dragging 'no mod' material into the picker of an attached object --- indra/newview/llpanelface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index bf54d17111..e7b856f743 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1981,6 +1981,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, if (objectp->isAttachment()) { pbr_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + pbr_ctrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); } else { From e100556a59b6184bf0d89a58621c2990b90f6231 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Wed, 29 Nov 2023 12:56:48 -0800 Subject: [PATCH 24/77] increment viewer version after DRTVWR-559 release --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 9fe9ff9d99..21c8c7b46b 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.0.1 +7.1.1 From 88aefc95eace0bb8ea21cb44514d41d98bdf74cc Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 30 Nov 2023 17:47:46 +0200 Subject: [PATCH 25/77] SL-20655 FIXED Texture permissions not enforced in Material floaters --- indra/newview/llmaterialeditor.cpp | 8 ++++---- indra/newview/llpanelface.cpp | 3 +-- indra/newview/lltexturectrl.cpp | 6 ++++++ indra/newview/lltexturectrl.h | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 70e21cae73..292ddb765f 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -436,10 +436,10 @@ BOOL LLMaterialEditor::postBuild() if (!gAgent.isGodlike()) { // Only allow fully permissive textures - mBaseColorTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - mMetallicTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - mEmissiveTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - mNormalTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mBaseColorTextureCtrl->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mMetallicTextureCtrl->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mEmissiveTextureCtrl->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mNormalTextureCtrl->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); } // Texture callback diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index e7b856f743..ffcc4be290 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1980,8 +1980,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, if (objectp->isAttachment()) { - pbr_ctrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); - pbr_ctrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + pbr_ctrl->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); } else { diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index f302426a43..28e01c6c21 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1715,6 +1715,12 @@ void LLTextureCtrl::setImmediateFilterPermMask(PermissionMask mask) } } +void LLTextureCtrl::setFilterPermissionMasks(PermissionMask mask) +{ + setImmediateFilterPermMask(mask); + setDnDFilterPermMask(mask); +} + void LLTextureCtrl::setVisible( BOOL visible ) { if( !visible ) diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index c47df5accb..7a96eea60d 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -196,6 +196,7 @@ public: void setDnDFilterPermMask(PermissionMask mask) { mDnDFilterPermMask = mask; } PermissionMask getImmediateFilterPermMask() { return mImmediateFilterPermMask; } + void setFilterPermissionMasks(PermissionMask mask); void closeDependentFloater(); From 68875523e09f9fe06fc4b3cd5225995bb13966c3 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 30 Nov 2023 12:01:45 -0600 Subject: [PATCH 26/77] SL-20611 Incorporate water haze into new post effect atmospherics goodness --- .../shaders/class1/deferred/fullbrightF.glsl | 6 +- .../shaders/class3/deferred/hazeF.glsl | 16 +- .../shaders/class3/deferred/waterHazeF.glsl | 13 +- .../shaders/class3/deferred/waterHazeV.glsl | 59 +++++++ .../class3/environment/underWaterF.glsl | 4 +- .../shaders/class3/environment/waterF.glsl | 3 - indra/newview/lldrawpool.cpp | 8 + indra/newview/lldrawpool.h | 5 +- indra/newview/lleventpoll.cpp | 22 ++- indra/newview/llsettingsvo.cpp | 10 ++ indra/newview/llviewercamera.cpp | 22 ++- indra/newview/llviewershadermgr.cpp | 2 +- indra/newview/pipeline.cpp | 156 ++++++++++++------ indra/newview/pipeline.h | 10 ++ 14 files changed, 255 insertions(+), 81 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 2798c59f1c..1de8b25a7d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -82,12 +82,12 @@ void main() vec3 additive; vec3 atten; calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten); -#endif - -#ifndef IS_HUD color.rgb = srgb_to_linear(color.rgb); + +#ifdef IS_ALPHA color.rgb = atmosFragLighting(color.rgb, additive, atten); +#endif vec4 fogged = applyWaterFogViewLinear(pos, vec4(color.rgb, final_alpha)); color.rgb = fogged.rgb; diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl index 7b77a2f5fb..e8f7d73f1f 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -68,23 +68,21 @@ void main() calcAtmosphericVarsLinear(pos.xyz, norm.xyz, light_dir, sunlit, amblit, additive, atten); vec3 sunlit_linear = srgb_to_linear(sunlit); - vec3 amblit_linear = amblit; - + + // mask off atmospherics below water (when camera is under water) bool do_atmospherics = false; - - // mask off atmospherics below water - if (dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0) + + if (dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0 || + dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0) { do_atmospherics = true; } + vec3 irradiance = vec3(0); vec3 radiance = vec3(0); - if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) - { - } - else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) + if (depth >= 1.0) { //should only be true of WL sky, just port over base color value discard; diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index f63d70cbd7..025bcdaf3e 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -26,7 +26,7 @@ out vec4 frag_color; // Inputs -in vec2 vary_fragcoord; +in vec4 vary_fragcoord; uniform sampler2D normalMap; @@ -37,20 +37,11 @@ vec4 getWaterFogView(vec3 pos); void main() { - vec2 tc = vary_fragcoord.xy; + vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5; float depth = getDepth(tc.xy); vec4 pos = getPositionWithDepth(tc, depth); vec4 norm = texture(normalMap, tc); - if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) - { - } - else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) - { - //should only be true of WL sky, just port over base color value - discard; - } - vec4 fogged = getWaterFogView(pos.xyz); frag_color.rgb = max(fogged.rgb, vec3(0)); //output linear since local lights will be added to this shader's results diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl new file mode 100644 index 0000000000..16381a5d51 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeV.glsl @@ -0,0 +1,59 @@ +/** + * @file class3/deferred/waterHazeV.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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$ + */ + +in vec3 position; + +uniform vec2 screen_res; + +out vec4 vary_fragcoord; + +// forwards +void setAtmosAttenuation(vec3 c); +void setAdditiveColor(vec3 c); + +uniform vec4 waterPlane; + +uniform int above_water; + +uniform mat4 modelview_projection_matrix; + +void main() +{ + //transform vertex + vec4 pos = vec4(position.xyz, 1.0); + + if (above_water > 0) + { + pos = modelview_projection_matrix*pos; + } + + gl_Position = pos; + + // appease OSX GLSL compiler/linker by touching all the varyings we said we would + setAtmosAttenuation(vec3(1)); + setAdditiveColor(vec3(0)); + + vary_fragcoord = pos; +} diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index 924f356f35..ddb1b79681 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -77,5 +77,7 @@ void main() vec4 fb = vec4(waterFogColorLinear, 0.0); #endif - frag_color = max(applyWaterFogViewLinearNoClip(vary_position, fb), vec4(0)); + fb = applyWaterFogViewLinearNoClip(vary_position, fb); + + frag_color = max(fb, vec4(0)); } diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index 8bc5f3cc50..f53bc2e13e 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -32,7 +32,6 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); #endif vec3 scaleSoftClipFragLinear(vec3 l); -vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); @@ -281,8 +280,6 @@ void main() color = ((1.0 - f) * color) + fb.rgb; - color = atmosFragLightingLinear(color, additive, atten); - float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05); frag_color = max(vec4(color, spec), vec4(0)); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index fca0f1c978..50210b06c4 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -320,6 +320,14 @@ void LLFacePool::addFaceReference(LLFace *facep) } } +void LLFacePool::pushFaceGeometry() +{ + for (LLFace* const& face : mDrawFace) + { + face->renderIndexed(); + } +} + BOOL LLFacePool::verify() const { BOOL ok = TRUE; diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 5414dba6bf..4300670445 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -118,8 +118,8 @@ public: virtual LLViewerTexture* getTexture() = 0; virtual BOOL isFacePool() { return FALSE; } virtual void resetDrawOrders() = 0; + virtual void pushFaceGeometry() {} -protected: S32 mShaderLevel; S32 mId; U32 mType; // Type of draw pool @@ -429,6 +429,9 @@ public: BOOL isFacePool() { return TRUE; } + // call drawIndexed on every draw face + void pushFaceGeometry(); + friend class LLFace; friend class LLPipeline; public: diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 26782e53f0..670a780fdd 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -102,6 +102,7 @@ namespace Details void LLEventPollImpl::handleMessage(const LLSD& content) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; std::string msg_name = content["message"]; LLSD message; message["sender"] = mSenderIp; @@ -149,6 +150,12 @@ namespace Details mAdapter = httpAdapter; + LL::WorkQueue::ptr_t main_queue = nullptr; + +#if 1 + main_queue = LL::WorkQueue::getInstance("mainloop"); +#endif + // continually poll for a server update until we've been flagged as // finished while (!mDone) @@ -266,13 +273,26 @@ namespace Details // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << acknowledge << ")" << LL_ENDL; + LLSD::array_const_iterator i = events.beginArray(); LLSD::array_const_iterator end = events.endArray(); for (; i != end; ++i) { if (i->has("message")) { - handleMessage(*i); + if (main_queue) + { // shuttle to a sensible spot in the main thread instead + // of wherever this coroutine happens to be executing + const LLSD& msg = *i; + main_queue->post([this, msg]() + { + handleMessage(msg); + }); + } + else + { + handleMessage(*i); + } } } } diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 2f65f3dec3..7009fb98ab 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -63,6 +63,7 @@ #include #include "llinventoryobserver.h" #include "llinventorydefines.h" +#include "llworld.h" #include "lltrans.h" @@ -989,6 +990,15 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) { F32 water_height = env.getWaterHeight(); + if (LLViewerCamera::instance().cameraUnderWater()) + { // when the camera is under water, use the water height at the camera position + LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(LLViewerCamera::instance().getOrigin()); + if (region) + { + water_height = region->getWaterHeight(); + } + } + //transform water plane to eye space glh::vec3f norm(0.f, 0.f, 1.f); glh::vec3f p(0.f, 0.f, water_height); diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index b926631ebe..4134e35f87 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -112,12 +112,16 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, const LLVecto mLastPointOfInterest = point_of_interest; - LLViewerRegion *regp = gAgent.getRegion(); - F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; + LLViewerRegion* regp = LLWorld::instance().getRegionFromPosAgent(getOrigin()); + if (!regp) + { + regp = gAgent.getRegion(); + } + + F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; LLVector3 origin = center; - if (LLEnvironment::instance().getCurrentWater()->getFogMod() != 1.f) { if (origin.mV[2] > water_height) { @@ -758,11 +762,19 @@ LLVector3 LLViewerCamera::roundToPixel(const LLVector3 &pos_agent) BOOL LLViewerCamera::cameraUnderWater() const { - if(!gAgent.getRegion()) + LLViewerRegion* regionp = LLWorld::instance().getRegionFromPosAgent(getOrigin()); + + if (!regionp) + { + regionp = gAgent.getRegion(); + } + + if(!regionp) { return FALSE ; } - return getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight(); + + return getOrigin().mV[VZ] < regionp->getWaterHeight(); } BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 2c2ae022d7..3225299493 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -1804,7 +1804,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gHazeWaterProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; gHazeWaterProgram.clearPermutations(); - gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER)); + gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterHazeV.glsl", GL_VERTEX_SHADER)); gHazeWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterHazeF.glsl", GL_FRAGMENT_SHADER)); gHazeWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 52afe16799..7b1e5a55d1 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3877,6 +3877,20 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) LLGLEnable cull(GL_CULL_FACE); + bool done_atmospherics = LLPipeline::sRenderingHUDs; //skip atmospherics on huds + bool done_water_haze = done_atmospherics; + + // do atmospheric haze just before post water alpha + U32 atmospherics_pass = LLDrawPool::POOL_ALPHA_POST_WATER; + + if (LLPipeline::sUnderWaterRender) + { // if under water, do atmospherics just before the water pass + atmospherics_pass = LLDrawPool::POOL_WATER; + } + + // do water haze just before pre water alpha + U32 water_haze_pass = LLDrawPool::POOL_ALPHA_PRE_WATER; + calcNearbyLights(camera); setupHWLights(); @@ -3896,6 +3910,18 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) cur_type = poolp->getType(); + if (cur_type >= atmospherics_pass && !done_atmospherics) + { // do atmospherics against depth buffer before rendering alpha + doAtmospherics(); + done_atmospherics = true; + } + + if (cur_type >= water_haze_pass && !done_water_haze) + { // do water haze against depth buffer before rendering alpha + doWaterHaze(); + done_water_haze = true; + } + pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { @@ -8153,52 +8179,6 @@ void LLPipeline::renderDeferredLighting() } } - - - if (RenderDeferredAtmospheric) - { - LLGLEnable blend(GL_BLEND); - gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA); - gGL.setColorMask(true, false); - - for (U32 i = 0; i < 2; ++i) - { - // apply haze - LLGLSLShader &haze_shader = i == 0 ? gHazeProgram : gHazeWaterProgram; - - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - haze"); - LL_PROFILE_GPU_ZONE("haze"); - bindDeferredShader(haze_shader); - - static LLCachedControl ssao_scale(gSavedSettings, "RenderSSAOIrradianceScale", 0.5f); - static LLCachedControl ssao_max(gSavedSettings, "RenderSSAOIrradianceMax", 0.25f); - static LLStaticHashedString ssao_scale_str("ssao_irradiance_scale"); - static LLStaticHashedString ssao_max_str("ssao_irradiance_max"); - - haze_shader.uniform1f(ssao_scale_str, ssao_scale); - haze_shader.uniform1f(ssao_max_str, ssao_max); - - LLEnvironment &environment = LLEnvironment::instance(); - haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - haze_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); - - haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); - - { - LLGLDepthTest depth(GL_FALSE); - - // full screen blit - mScreenTriangleVB->setBuffer(); - mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - - unbindDeferredShader(haze_shader); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - gGL.setColorMask(true, true); } @@ -8254,6 +8234,90 @@ void LLPipeline::renderDeferredLighting() gGL.setColorMask(true, true); } +void LLPipeline::doAtmospherics() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + + if (RenderDeferredAtmospheric) + { + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA); + + gGL.setColorMask(true, true); + + // apply haze + LLGLSLShader& haze_shader = gHazeProgram; + + LL_PROFILE_GPU_ZONE("haze"); + bindDeferredShader(haze_shader); + + LLEnvironment& environment = LLEnvironment::instance(); + haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + haze_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); + + haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); + + LLGLDepthTest depth(GL_FALSE); + + // full screen blit + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + unbindDeferredShader(haze_shader); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } +} + +void LLPipeline::doWaterHaze() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + + if (RenderDeferredAtmospheric) + { + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA); + + gGL.setColorMask(true, true); + + // apply haze + LLGLSLShader& haze_shader = gHazeWaterProgram; + + LL_PROFILE_GPU_ZONE("haze"); + bindDeferredShader(haze_shader); + + haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); + + static LLStaticHashedString above_water_str("above_water"); + haze_shader.uniform1i(above_water_str, sUnderWaterRender ? -1 : 1); + + if (LLPipeline::sUnderWaterRender) + { + LLGLDepthTest depth(GL_FALSE); + + // full screen blit + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + else + { + //render water patches like LLDrawPoolWater does + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_LEQUAL); + LLGLDisable cull(GL_CULL_FACE); + + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); + + mWaterPool->pushFaceGeometry(); + } + + unbindDeferredShader(haze_shader); + + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } +} + void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) { //construct frustum diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 6e4c9c7a97..bbed7cad92 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -318,6 +318,16 @@ public: void unbindReflectionProbes(LLGLSLShader& shader); void renderDeferredLighting(); + + // apply atmospheric haze based on contents of color and depth buffer + // should be called just before rendering water when camera is under water + // and just before rendering alpha when camera is above water + void doAtmospherics(); + + // apply water haze based on contents of color and depth buffer + // should be called just before rendering pre-water alpha objects + void doWaterHaze(); + void postDeferredGammaCorrect(LLRenderTarget* screen_target); void generateSunShadow(LLCamera& camera); From c573d27e5baf23adbc14153c4d65a581f55febb4 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Fri, 1 Dec 2023 14:49:22 -0600 Subject: [PATCH 27/77] SL-20611 Followup -- fix for water rendering twice. Add comments around LLEventPoll hack. --- indra/newview/lleventpoll.cpp | 2 ++ indra/newview/llspatialpartition.cpp | 11 ++++++ indra/newview/llworld.cpp | 52 ---------------------------- indra/newview/llworld.h | 2 -- indra/newview/pipeline.cpp | 7 ---- 5 files changed, 13 insertions(+), 61 deletions(-) diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 670a780fdd..6ffc8f7bdd 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -152,6 +152,8 @@ namespace Details LL::WorkQueue::ptr_t main_queue = nullptr; + // HACK -- grab the mainloop workqueue to move execution of the handler + // to a place that's safe in the main thread #if 1 main_queue = LL::WorkQueue::getInstance("mainloop"); #endif diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index a63d46f502..9f30d60fed 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -64,6 +64,9 @@ bool LLSpatialGroup::sNoDelete = false; static F32 sLastMaxTexPriority = 1.f; static F32 sCurMaxTexPriority = 1.f; +// enable expensive sanity checks around redundant drawable and group insertion to LLCullResult +#define LL_DEBUG_CULL_RESULT 0 + //static counter for frame to switch LOD on void sg_assert(BOOL expr) @@ -4015,6 +4018,10 @@ void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) { +#if LL_DEBUG_CULL_RESULT + // group must NOT be in the drawble groups list already + llassert(std::find(&mDrawableGroups[0], mDrawableGroupsEnd, group) == mDrawableGroupsEnd); +#endif if (mDrawableGroupsSize < mDrawableGroupsAllocated) { mDrawableGroups[mDrawableGroupsSize] = group; @@ -4029,6 +4036,10 @@ void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) void LLCullResult::pushDrawable(LLDrawable* drawable) { +#if LL_DEBUG_CULL_RESULT + // drawable must NOT be in the visible list already + llassert(std::find(&mVisibleList[0], mVisibleListEnd, drawable) == mVisibleListEnd); +#endif if (mVisibleListSize < mVisibleListAllocated) { mVisibleList[mVisibleListSize] = drawable; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 709a457862..9381211e9b 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -883,58 +883,6 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh } } -void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - if (!gAgent.getRegion()) - { - return; - } - - if (mRegionList.empty()) - { - LL_WARNS() << "No regions!" << LL_ENDL; - return; - } - - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) - { - LLViewerRegion* regionp = *iter; - LLVOWater* waterp = regionp->getLand().getWaterObj(); - if (waterp && waterp->mDrawable) - { - waterp->mDrawable->setVisible(camera); - cull->pushDrawable(waterp->mDrawable); - } - } - - if (include_void_water) - { - for (std::list >::iterator iter = mHoleWaterObjects.begin(); - iter != mHoleWaterObjects.end(); ++ iter) - { - LLVOWater* waterp = (*iter).get(); - if (waterp && waterp->mDrawable) - { - waterp->mDrawable->setVisible(camera); - cull->pushDrawable(waterp->mDrawable); - } - } - } - - S32 dir; - for (dir = 0; dir < EDGE_WATER_OBJECTS_COUNT; dir++) - { - LLVOWater* waterp = mEdgeWaterObjects[dir]; - if (waterp && waterp->mDrawable) - { - waterp->mDrawable->setVisible(camera); - cull->pushDrawable(waterp->mDrawable); - } - } -} - void LLWorld::clearHoleWaterObjects() { for (std::list >::iterator iter = mHoleWaterObjects.begin(); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index f78cbcaa48..2878d10f5e 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -140,8 +140,6 @@ public: LLViewerTexture *getDefaultWaterTexture(); void updateWaterObjects(); - void precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water); - void waterHeightRegionInfo(std::string const& sim_name, F32 water_height); void shiftRegions(const LLVector3& offset); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 76414b5e4e..50cd4adb73 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2311,13 +2311,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result) gSky.mVOWLSkyp->mDrawable->setVisible(camera); sCull->pushDrawable(gSky.mVOWLSkyp->mDrawable); } - - bool render_water = !sReflectionRender && (hasRenderType(LLPipeline::RENDER_TYPE_WATER) || hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)); - - if (render_water) - { - LLWorld::getInstance()->precullWaterObjects(camera, sCull, render_water); - } } void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) From e0cfa61f726f8227922c52ef2c112d93271fc966 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 3 Dec 2023 15:02:31 +0100 Subject: [PATCH 28/77] Fix ignore text for reflection tests being disabled --- indra/newview/skins/default/xui/en/notifications.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a4ac4a9e2d..23cd242be1 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7516,7 +7516,7 @@ Please try again. You have placed a reflection probe, but 'Select Reflection Probes' is disabled. To be able to select reflection probes, check Build > Options > Select Reflection Probes. confirm From 81a86874048cd709883d1e4e332a35a27dd0a9cc Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 3 Dec 2023 15:02:48 +0100 Subject: [PATCH 29/77] Update German translation --- indra/newview/skins/default/xui/de/floater_snapshot.xml | 1 + indra/newview/skins/default/xui/de/menu_viewer.xml | 2 +- indra/newview/skins/default/xui/de/notifications.xml | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/de/floater_snapshot.xml b/indra/newview/skins/default/xui/de/floater_snapshot.xml index 4bdc110d79..1400c69b4b 100644 --- a/indra/newview/skins/default/xui/de/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/de/floater_snapshot.xml @@ -64,6 +64,7 @@ + diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 359c559c2c..e0623f3b31 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -242,7 +242,7 @@ - + diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 9301948b53..a7592604d6 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2843,6 +2843,10 @@ Bitte erneut versuchen. Nicht mit einer Region verbunden, die Material unterstützt. + + Sie haben einen Reflexionstest platziert, aber „Reflexionstests auswählen“ ist deaktiviert. Um Reflexionstests auswählen zu können, aktivieren Sie im Menü Bauen > Optionen > Reflexionstests auswählen. + + Skript fehlt in Datenbank. From 6aeaa4024e685945f69d6af09602e9d33977a4bf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 4 Dec 2023 23:31:37 +0200 Subject: [PATCH 30/77] SL-20569 Fix notification's description in preferences --- indra/newview/skins/default/xui/en/notifications.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6c841ac049..33979885b3 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6178,7 +6178,7 @@ Are you sure you want to delete them? Delete the image for this item? There is no undo. confirm @@ -7021,7 +7021,7 @@ Please try again. You have placed a reflection probe, but 'Select Reflection Probes' is disabled. To be able to select reflection probes, check Build > Options > Select Reflection Probes. confirm From 4a8a3100a978989f246b7f837e8a45968908d27b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 5 Dec 2023 00:29:17 +0200 Subject: [PATCH 31/77] SL-20681 fix spelling on exit prompt --- indra/newview/skins/default/xui/en/notifications.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 33979885b3..d642ea162c 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1534,7 +1534,7 @@ Delete pick <nolink>[PICK]</nolink>? icon="alert.tga" name="ProfileUnsavedChanges" type="alertmodal"> - You have usaved changes. + You have unsaved changes. confirm save Date: Mon, 4 Dec 2023 16:50:06 -0600 Subject: [PATCH 32/77] SL-20611 Followup -- fix edge cases with transparent objects around eye/object above/below water. --- .../shaders/class1/deferred/fullbrightF.glsl | 21 ++++++------ .../shaders/class1/environment/waterFogF.glsl | 34 +++++++++++++++++++ .../shaders/class2/deferred/alphaF.glsl | 9 ++--- .../class3/deferred/fullbrightShinyF.glsl | 2 -- .../shaders/class3/deferred/materialF.glsl | 9 ++--- 5 files changed, 48 insertions(+), 27 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 1de8b25a7d..8b2a69b924 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -35,19 +35,19 @@ in vec3 vary_position; in vec4 vertex_color; in vec2 vary_texcoord0; -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); - vec3 srgb_to_linear(vec3 cs); vec3 linear_to_srgb(vec3 cl); -vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten); -void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten); #ifdef HAS_ALPHA_MASK uniform float minimum_alpha; #endif #ifdef IS_ALPHA +uniform vec4 waterPlane; void waterClip(vec3 pos); +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, + out vec3 atten); +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); #endif void main() @@ -77,21 +77,20 @@ void main() vec3 pos = vary_position; #ifndef IS_HUD + color.rgb = srgb_to_linear(color.rgb); + color.a = final_alpha; +#ifdef IS_ALPHA + vec3 sunlit; vec3 amblit; vec3 additive; vec3 atten; calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten); - color.rgb = srgb_to_linear(color.rgb); - -#ifdef IS_ALPHA - color.rgb = atmosFragLighting(color.rgb, additive, atten); + color.rgb = applySkyAndWaterFog(pos, additive, atten, color).rgb; + #endif - vec4 fogged = applyWaterFogViewLinear(pos, vec4(color.rgb, final_alpha)); - color.rgb = fogged.rgb; - color.a = fogged.a; #endif frag_color = max(color, vec4(0)); diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl index 140e01cc2a..f796bb5f3f 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl @@ -33,6 +33,8 @@ uniform float waterFogKS; vec3 srgb_to_linear(vec3 col); vec3 linear_to_srgb(vec3 col); +vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten); + // get a water fog color that will apply the appropriate haze to a color given // a blend function of (ONE, SOURCE_ALPHA) vec4 getWaterFogViewNoClip(vec3 pos) @@ -108,3 +110,35 @@ vec4 applyWaterFogViewLinear(vec3 pos, vec4 color) return applyWaterFogViewLinearNoClip(pos, color); } +// for post deferred shaders, apply sky and water fog in a way that is consistent with +// the deferred rendering haze post effects +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color) +{ + bool eye_above_water = dot(vec3(0), waterPlane.xyz) + waterPlane.w > 0.0; + bool obj_above_water = dot(pos.xyz, waterPlane.xyz) + waterPlane.w > 0.0; + + if (eye_above_water) + { + if (!obj_above_water) + { + color.rgb = applyWaterFogViewLinearNoClip(pos, color).rgb; + } + else + { + color.rgb = atmosFragLighting(color.rgb, additive, atten); + } + } + else + { + if (obj_above_water) + { + color.rgb = atmosFragLighting(color.rgb, additive, atten); + } + else + { + color.rgb = applyWaterFogViewLinearNoClip(pos, color).rgb; + } + } + + return color; +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 07fa5cd01c..acd32a81b3 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -65,14 +65,11 @@ uniform vec3 light_diffuse[8]; void waterClip(vec3 pos); -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); - vec3 srgb_to_linear(vec3 c); vec3 linear_to_srgb(vec3 c); vec2 encode_normal (vec3 n); -vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten); - +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); #ifdef HAS_SUN_SHADOW @@ -283,9 +280,7 @@ void main() // sum local light contrib in linear colorspace color.rgb += light.rgb; - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - - color = applyWaterFogViewLinear(pos.xyz, color); + color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, color).rgb; #endif // #else // FOR_IMPOSTOR diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 6446015b03..8430cca325 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -85,8 +85,6 @@ void main() color.rgb = srgb_to_linear(color.rgb); applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity); - color.rgb = atmosFragLighting(color.rgb, additive, atten); - color = applyWaterFogViewLinear(pos.xyz, color); #endif color.a = 1.0; diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 1880f0c870..ec1e49eeb4 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -37,9 +37,7 @@ uniform float emissive_brightness; // fullbright flag, 1.0 == fullbright, 0.0 otherwise uniform int sun_up_factor; -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); - -vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten); +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); vec3 scaleSoftClipFragLinear(vec3 l); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); @@ -399,10 +397,7 @@ void main() color += light; - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - - vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0)); - color = temp.rgb; + color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; glare *= 1.0-emissive; glare = min(glare, 1.0); From 18f42a659b98741a9d8c05731a8137080c9094b5 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Mon, 4 Dec 2023 17:01:01 -0600 Subject: [PATCH 33/77] SL-20611 Followup -- fix edge cases with transparent PBR objects around eye/object above/below water. --- .../shaders/class2/deferred/pbralphaF.glsl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl index 80c1769b15..003dd05e6f 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl @@ -82,9 +82,7 @@ vec3 srgb_to_linear(vec3 c); vec3 linear_to_srgb(vec3 c); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); -vec3 atmosFragLightingLinear(vec3 color, vec3 additive, vec3 atten); - -vec4 applyWaterFogViewLinear(vec3 pos, vec4 color); +vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); @@ -241,10 +239,7 @@ void main() color.rgb += light.rgb; - color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); - - vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0)); - color = temp.rgb; + color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb; float a = basecolor.a*vertex_color.a; @@ -300,6 +295,7 @@ void main() float a = basecolor.a*vertex_color.a; color += colorEmissive; + color = linear_to_srgb(color); frag_color = max(vec4(color.rgb,a), vec4(0)); } From c28eb36a2c09f31f491676c8548dfa1c19277ce2 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 5 Dec 2023 19:50:25 -0600 Subject: [PATCH 34/77] SL-20654 Fix for box probes sometimes glitching out at the corners. Incidental fix for crash when mWaterPool is null. --- .../deferred/postDeferredGammaCorrect.glsl | 2 +- indra/newview/llreflectionmap.cpp | 11 +++++++++- indra/newview/llreflectionmapmanager.cpp | 21 +++++++++++++------ indra/newview/pipeline.cpp | 5 ++++- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index 64e6bc9da2..3443785e1a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -106,7 +106,7 @@ vec3 toneMap(vec3 color) color *= exposure * exp_scale; // mix ACES and Linear here as a compromise to avoid over-darkening legacy content - color = mix(toneMapACES_Hill(color), color, 0.333); + color = mix(toneMapACES_Hill(color), color, 0.3); #endif return color; diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index ec54fa1165..a26445b4bc 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -167,7 +167,16 @@ void LLReflectionMap::autoAdjustOrigin() { mPriority = 1; mOrigin.load3(mViewerObject->getPositionAgent().mV); - mRadius = mViewerObject->getScale().mV[0]*0.5f; + + if (mViewerObject->getVolume() && ((LLVOVolume*)mViewerObject)->getReflectionProbeIsBox()) + { + LLVector3 s = mViewerObject->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f)); + mRadius = s.magVec(); + } + else + { + mRadius = mViewerObject->getScale().mV[0] * 0.5f; + } } } diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 72f7e23b0c..69674417c1 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -252,14 +252,12 @@ void LLReflectionMapManager::update() continue; } - if (probe != mDefaultProbe && + if (probe != mDefaultProbe && (!probe->isRelevant() || mPaused)) { // skip irrelevant probes (or all non-default probes if paused) continue; } - - LLVector4a d; if (probe != mDefaultProbe) @@ -999,10 +997,21 @@ void LLReflectionMapManager::updateUniforms() llassert(refmap->mCubeIndex >= 0); // should always be true, if not, getReflectionMaps is bugged { - if (refmap->mViewerObject) + if (refmap->mViewerObject && refmap->mViewerObject->getVolume()) { // have active manual probes live-track the object they're associated with - refmap->mOrigin.load3(refmap->mViewerObject->getPositionAgent().mV); - refmap->mRadius = refmap->mViewerObject->getScale().mV[0] * 0.5f; + LLVOVolume* vobj = (LLVOVolume*)refmap->mViewerObject; + + refmap->mOrigin.load3(vobj->getPositionAgent().mV); + + if (vobj->getReflectionProbeIsBox()) + { + LLVector3 s = vobj->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f)); + refmap->mRadius = s.magVec(); + } + else + { + refmap->mRadius = refmap->mViewerObject->getScale().mV[0] * 0.5f; + } } modelview.affineTransform(refmap->mOrigin, oa); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 50cd4adb73..bf4f0083ff 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8303,7 +8303,10 @@ void LLPipeline::doWaterHaze() gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); - mWaterPool->pushFaceGeometry(); + if (mWaterPool) + { + mWaterPool->pushFaceGeometry(); + } } unbindDeferredShader(haze_shader); From a27740bbb2da04b14016de1398178df4fb970bcd Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 27 Nov 2023 17:59:16 +0100 Subject: [PATCH 35/77] SL-19655 BugSplat Crash: LLGLState::checkStates (2427) --- indra/newview/pipeline.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bf4f0083ff..f8812d9750 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3821,10 +3821,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) poolp->endDeferredPass(i); LLVertexBuffer::unbind(); - if (gDebugGL || gDebugPipeline) - { - LLGLState::checkStates(); - } + LLGLState::checkStates(); } } else From d05b80817b4c7ada2b3934f0d8c814fc67c50c8e Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 6 Dec 2023 10:33:32 -0600 Subject: [PATCH 36/77] SL-20611 Followup -- fix banding in water fog (thanks, Rye!) --- indra/newview/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bf4f0083ff..8c3cf09098 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -789,7 +789,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (LLPipeline::sRenderTransparentWater) { //water reflection texture - mWaterDis.allocate(resX, resY, GL_RGBA, true); + mWaterDis.allocate(resX, resY, GL_RGBA16F, true); } if (RenderUIBuffer) From 18919ef585082becd984eb4d90310cd317babfc9 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Wed, 6 Dec 2023 18:04:29 +0100 Subject: [PATCH 37/77] BUG-234706 Fix unstable performance on nvidia systems by always enabling Threaded Optimization via driver application profile (#564) --- indra/newview/llappviewerwin32.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 8cf80f388b..41101e79a6 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -369,6 +369,35 @@ void ll_nvapi_init(NvDRSSessionHandle hSession) nvapi_error(status); return; } + + // enable Threaded Optimization instead of letting the driver decide + status = NvAPI_DRS_GetSetting(hSession, hProfile, OGL_THREAD_CONTROL_ID, &drsSetting); + if (status == NVAPI_SETTING_NOT_FOUND || (status == NVAPI_OK && drsSetting.u32CurrentValue != OGL_THREAD_CONTROL_ENABLE)) + { + drsSetting.version = NVDRS_SETTING_VER; + drsSetting.settingId = OGL_THREAD_CONTROL_ID; + drsSetting.settingType = NVDRS_DWORD_TYPE; + drsSetting.u32CurrentValue = OGL_THREAD_CONTROL_ENABLE; + status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + // Now we apply (or save) our changes to the system + status = NvAPI_DRS_SaveSettings(hSession); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + } + else if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } } //#define DEBUGGING_SEH_FILTER 1 From 300d7629d8bbd02844a5380cc97aae2d229fdf0a Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 6 Dec 2023 11:58:45 -0600 Subject: [PATCH 38/77] SL-20664 Potential fix for crash on startup in switchContext --- indra/llwindow/llwindowwin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 42ec4ee29d..057d7a700e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1929,7 +1929,7 @@ void LLWindowWin32::toggleVSync(bool enable_vsync) LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(0); } - else + else if (wglSwapIntervalEXT) { LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; wglSwapIntervalEXT(1); From 7398efb1f4ccf36f9c107e920f38c3096cca2f2f Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Fri, 8 Dec 2023 20:15:47 +0200 Subject: [PATCH 39/77] SL-20701 FIXED Build tool texture tab shows incorrect material parameters in some cases --- indra/newview/llpanelface.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ffcc4be290..f0f66831cb 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1094,7 +1094,21 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) prev_obj_id = objectp->getID(); } } - + else + { + if (prev_obj_id != objectp->getID()) + { + if (has_pbr_material && (mComboMatMedia->getCurrentIndex() == MATMEDIA_MATERIAL)) + { + mComboMatMedia->selectNthItem(MATMEDIA_PBR); + } + else if (!has_pbr_material && (mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR)) + { + mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL); + } + prev_obj_id = objectp->getID(); + } + } mComboMatMedia->setEnabled(editable); LLRadioGroup* radio_mat_type = getChild("radio_material_type"); From 2c2d60bbc36c58314d36770349c2f904c848e582 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Fri, 8 Dec 2023 12:36:55 -0600 Subject: [PATCH 40/77] SL-20674 Fix for textures ignoring texture scale when determining what resolution to be. --- indra/newview/llviewertexture.cpp | 3 --- indra/newview/llviewertexturelist.cpp | 8 +++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ec6f2c848f..56bba51692 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2124,9 +2124,6 @@ bool LLViewerFetchedTexture::updateFetch() } } - llassert(mRawImage.notNull() || !mIsRawImageValid); - llassert(mRawImage.notNull() || !mNeedsCreateTexture); - return mIsFetching ? true : false; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index f898fb7142..9a6d40ab0a 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -899,6 +899,13 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag { F32 vsize = face->getPixelArea(); + // scale desired texture resolution higher or lower depending on texture scale + const LLTextureEntry* te = face->getTextureEntry(); + F32 min_scale = te ? llmin(fabsf(te->getScaleS()), fabsf(te->getScaleT())) : 1.f; + min_scale = llmax(min_scale*min_scale, 0.1f); + + vsize /= min_scale; + #if LL_DARWIN vsize /= 1.f + LLViewerTexture::sDesiredDiscardBias*(1.f+face->getDrawable()->mDistanceWRTCamera*bias_distance_scale); #else @@ -916,7 +923,6 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag // if a GLTF material is present, ignore that face // as far as this texture stats go, but update the GLTF material // stats - const LLTextureEntry* te = face->getTextureEntry(); LLFetchedGLTFMaterial* mat = te ? (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial() : nullptr; llassert(mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr); if (mat) From f3b87145775d3803306036d1e31fa39177f2600e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 11 Dec 2023 15:28:25 -0600 Subject: [PATCH 41/77] SL-20611 Followup -- fix for artifacts on water surface from GPUs that don't like to read from a depth buffer that is bound for writing --- .../shaders/class3/deferred/waterHazeF.glsl | 16 +++++++ .../class3/environment/underWaterF.glsl | 1 - .../shaders/class3/environment/waterF.glsl | 6 +-- indra/newview/lldrawpoolwater.cpp | 9 +--- indra/newview/pipeline.cpp | 45 ++++++++++++++++--- indra/newview/pipeline.h | 2 +- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index 025bcdaf3e..13619a82d3 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -35,10 +35,26 @@ float getDepth(vec2 pos_screen); vec4 getWaterFogView(vec3 pos); +uniform int above_water; + void main() { vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5; float depth = getDepth(tc.xy); + + if (above_water > 0) + { + // we want to depth test when the camera is above water, but some GPUs have a hard time + // with depth testing against render targets that are bound for sampling in the same shader + // so we do it manually here + + float cur_depth = vary_fragcoord.z/vary_fragcoord.w*0.5+0.5; + if (cur_depth > depth) + { + discard; + } + } + vec4 pos = getPositionWithDepth(tc, depth); vec4 norm = texture(normalMap, tc); diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index ddb1b79681..223e55eb69 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -30,7 +30,6 @@ uniform sampler2D bumpMap; #ifdef TRANSPARENT_WATER uniform sampler2D screenTex; -uniform sampler2D screenDepth; #endif uniform vec4 fogCol; diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index f53bc2e13e..b364e454e8 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -76,7 +76,7 @@ uniform sampler2D bumpMap2; uniform float blend_factor; #ifdef TRANSPARENT_WATER uniform sampler2D screenTex; -uniform sampler2D screenDepth; +uniform sampler2D depthMap; #endif uniform sampler2D refTex; @@ -210,7 +210,7 @@ void main() #ifdef TRANSPARENT_WATER vec4 fb = texture(screenTex, distort2); - float depth = texture(screenDepth, distort2).r; + float depth = texture(depthMap, distort2).r; vec3 refPos = getPositionWithNDC(vec3(distort2*2.0-vec2(1.0), depth*2.0-1.0)); if (refPos.z > pos.z-0.05) @@ -218,7 +218,7 @@ void main() //we sampled an above water sample, don't distort distort2 = distort; fb = texture(screenTex, distort2); - depth = texture(screenDepth, distort2).r; + depth = texture(depthMap, distort2).r; refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 14f3142e1b..ca93815de7 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -206,7 +206,7 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) } } - gPipeline.bindDeferredShader(*shader); + gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis); //bind normal map S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); @@ -238,7 +238,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) // bind reflection texture from RenderTarget S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); - S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH); F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] }; @@ -255,11 +254,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); } - if (screenDepth > -1) - { - gGL.getTexUnit(screenDepth)->bind(&gPipeline.mWaterDis, true); - } - if (mShaderLevel == 1) { fog_color.mV[VW] = log(fog_density) / log(2); @@ -342,7 +336,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) shader->disableTexture(LLShaderMgr::BUMP_MAP); shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); shader->disableTexture(LLShaderMgr::WATER_REFTEX); - shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); // clean up gPipeline.unbindDeferredShader(*shader); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 2e55b65c82..b24a8106cc 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7476,7 +7476,7 @@ void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader) } } -void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target) +void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target, LLRenderTarget* depth_target) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLRenderTarget* deferred_target = &mRT->deferredScreen; @@ -7515,7 +7515,14 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_target->getUsage()); if (channel > -1) { - gGL.getTexUnit(channel)->bind(deferred_target, TRUE); + if (depth_target) + { + gGL.getTexUnit(channel)->bind(depth_target, TRUE); + } + else + { + gGL.getTexUnit(channel)->bind(deferred_target, TRUE); + } stop_glerror(); } @@ -8232,16 +8239,42 @@ void LLPipeline::doAtmospherics() if (RenderDeferredAtmospheric) { + if (!sUnderWaterRender) + { + // copy depth buffer for use in haze shader (use water displacement map as temp storage) + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + + LLRenderTarget& src = gPipeline.mRT->screen; + LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen; + LLRenderTarget& dst = gPipeline.mWaterDis; + + mRT->screen.flush(); + dst.bindTarget(); + gCopyDepthProgram.bind(); + + S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH); + + gGL.getTexUnit(diff_map)->bind(&src); + gGL.getTexUnit(depth_map)->bind(&depth_src, true); + + gGL.setColorMask(false, false); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + dst.flush(); + mRT->screen.bindTarget(); + } + LLGLEnable blend(GL_BLEND); gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA); - gGL.setColorMask(true, true); // apply haze LLGLSLShader& haze_shader = gHazeProgram; LL_PROFILE_GPU_ZONE("haze"); - bindDeferredShader(haze_shader); + bindDeferredShader(haze_shader, nullptr, sUnderWaterRender ? nullptr : &mWaterDis); LLEnvironment& environment = LLEnvironment::instance(); haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); @@ -8294,7 +8327,7 @@ void LLPipeline::doWaterHaze() else { //render water patches like LLDrawPoolWater does - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_LEQUAL); + /*LLGLDepthTest depth(GL_FALSE); LLGLDisable cull(GL_CULL_FACE); gGLLastMatrix = NULL; @@ -8303,7 +8336,7 @@ void LLPipeline::doWaterHaze() if (mWaterPool) { mWaterPool->pushFaceGeometry(); - } + }*/ } unbindDeferredShader(haze_shader); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index bbed7cad92..88a7eab813 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -306,7 +306,7 @@ public: // if setup is true, wil lset texture compare mode function and filtering options void bindShadowMaps(LLGLSLShader& shader); void bindDeferredShaderFast(LLGLSLShader& shader); - void bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target = nullptr); + void bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target = nullptr, LLRenderTarget* depth_target = nullptr); void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep); void unbindDeferredShader(LLGLSLShader& shader); From 4ca23735d906c69742f4bf362eb97b87831c2ece Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 11 Dec 2023 15:40:33 -0600 Subject: [PATCH 42/77] SL-20611 Followup -- reenable water haze --- indra/newview/pipeline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b24a8106cc..f448983ac2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8327,7 +8327,7 @@ void LLPipeline::doWaterHaze() else { //render water patches like LLDrawPoolWater does - /*LLGLDepthTest depth(GL_FALSE); + LLGLDepthTest depth(GL_FALSE); LLGLDisable cull(GL_CULL_FACE); gGLLastMatrix = NULL; @@ -8336,7 +8336,7 @@ void LLPipeline::doWaterHaze() if (mWaterPool) { mWaterPool->pushFaceGeometry(); - }*/ + } } unbindDeferredShader(haze_shader); From 1f7f30aea4bb67bc9de9a6354085b7f0b0849617 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 11 Dec 2023 15:49:51 -0600 Subject: [PATCH 43/77] SL-20611 Brute force fix for water haze -- paid for by cycles saved by not drawing water twice, but needs a better long term solution. --- indra/newview/pipeline.cpp | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index f448983ac2..adad22d0a8 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -787,10 +787,8 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) resY /= res_mod; } - if (LLPipeline::sRenderTransparentWater) - { //water reflection texture - mWaterDis.allocate(resX, resY, GL_RGBA16F, true); - } + //water reflection texture (always needed as scratch space whether or not transparent water is enabled) + mWaterDis.allocate(resX, resY, GL_RGBA16F, true); if (RenderUIBuffer) { @@ -8239,7 +8237,6 @@ void LLPipeline::doAtmospherics() if (RenderDeferredAtmospheric) { - if (!sUnderWaterRender) { // copy depth buffer for use in haze shader (use water displacement map as temp storage) LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); @@ -8274,7 +8271,7 @@ void LLPipeline::doAtmospherics() LLGLSLShader& haze_shader = gHazeProgram; LL_PROFILE_GPU_ZONE("haze"); - bindDeferredShader(haze_shader, nullptr, sUnderWaterRender ? nullptr : &mWaterDis); + bindDeferredShader(haze_shader, nullptr, &mWaterDis); LLEnvironment& environment = LLEnvironment::instance(); haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); @@ -8300,6 +8297,32 @@ void LLPipeline::doWaterHaze() if (RenderDeferredAtmospheric) { + // copy depth buffer for use in haze shader (use water displacement map as temp storage) + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + + LLRenderTarget& src = gPipeline.mRT->screen; + LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen; + LLRenderTarget& dst = gPipeline.mWaterDis; + + mRT->screen.flush(); + dst.bindTarget(); + gCopyDepthProgram.bind(); + + S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH); + + gGL.getTexUnit(diff_map)->bind(&src); + gGL.getTexUnit(depth_map)->bind(&depth_src, true); + + gGL.setColorMask(false, false); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + dst.flush(); + mRT->screen.bindTarget(); + } + LLGLEnable blend(GL_BLEND); gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA); @@ -8309,7 +8332,7 @@ void LLPipeline::doWaterHaze() LLGLSLShader& haze_shader = gHazeWaterProgram; LL_PROFILE_GPU_ZONE("haze"); - bindDeferredShader(haze_shader); + bindDeferredShader(haze_shader, nullptr, &mWaterDis); haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); From e62a4dc8b4cdac5038c1fb8e5428248a3e195509 Mon Sep 17 00:00:00 2001 From: Henri Beauchamp Date: Tue, 12 Dec 2023 01:41:42 +0100 Subject: [PATCH 44/77] Fix for semi-transparent HUDs rendering opaque This commit fixes a bug introduced with commit 6472b75bcd70470fe5775d1cf6eb70a75b3d76e5 where the fullbrightF.glsl shader fails to set color.a to final_alpha for HUDs. --- .../app_settings/shaders/class1/deferred/fullbrightF.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 8b2a69b924..a6fab10791 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -76,9 +76,9 @@ void main() vec3 pos = vary_position; + color.a = final_alpha; #ifndef IS_HUD color.rgb = srgb_to_linear(color.rgb); - color.a = final_alpha; #ifdef IS_ALPHA vec3 sunlit; From 2d3b52d02ee72d94c6299220c05e5f5343979da3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 13 Dec 2023 00:48:05 +0200 Subject: [PATCH 45/77] SL-20715 Mapping mode and specular color not copied correctly and fixed diffuse alpha --- indra/newview/llpanelface.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index f0f66831cb..91cc177fd5 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -4290,6 +4290,7 @@ void LLPanelFace::onCopyTexture() te_data["te"]["bumpmap"] = tep->getBumpmap(); te_data["te"]["bumpshiny"] = tep->getBumpShiny(); te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + te_data["te"]["texgen"] = tep->getTexGen(); te_data["te"]["pbr"] = objectp->getRenderMaterialID(te); if (tep->getGLTFMaterialOverride() != nullptr) { @@ -4685,6 +4686,11 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) { objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); } + if (te_data["te"].has("texgen")) + { + objectp->setTETexGen(te, (U8)te_data["te"]["texgen"].asInteger()); + } + // PBR/GLTF if (te_data["te"].has("pbr")) { @@ -4796,11 +4802,11 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); - LLColor4 spec_color(te_data["material"]["SpecColor"]); + LLColor4U spec_color(te_data["material"]["SpecColor"]); LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); - LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["DiffuseAlphaMode"].asInteger(), te, object_id); if (te_data.has("te") && te_data["te"].has("shiny")) { objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); From 60196f6ab3697c5b6cff6b2c856449d94d56ddee Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 13 Dec 2023 12:47:04 -0600 Subject: [PATCH 46/77] SL-20611 Followup -- fix for impostors being invisible. --- indra/newview/pipeline.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index adad22d0a8..3a1edb0d00 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -8235,6 +8235,11 @@ void LLPipeline::doAtmospherics() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (sImpostorRender) + { // do not attempt atmospherics on impostors + return; + } + if (RenderDeferredAtmospheric) { { @@ -8294,6 +8299,10 @@ void LLPipeline::doAtmospherics() void LLPipeline::doWaterHaze() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (sImpostorRender) + { // do not attempt water haze on impostors + return; + } if (RenderDeferredAtmospheric) { From fefdd5aef92e0ba7f37147d7ba057b3b0459c4bf Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 13 Dec 2023 14:47:40 -0600 Subject: [PATCH 47/77] SL-20730 Scrub nans from haze alpha --- indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl | 4 ++-- .../app_settings/shaders/class3/deferred/waterHazeF.glsl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl index e8f7d73f1f..229f332b36 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -102,6 +102,6 @@ void main() alpha = 1.0; } - frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results - frag_color.a = alpha; + frag_color = max(vec4(color.rgb, alpha), vec4(0)); //output linear since local lights will be added to this shader's results + } diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index 13619a82d3..f6b8299f91 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -60,6 +60,6 @@ void main() vec4 fogged = getWaterFogView(pos.xyz); - frag_color.rgb = max(fogged.rgb, vec3(0)); //output linear since local lights will be added to this shader's results - frag_color.a = fogged.a; + frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results + } From 88b228a94defd1d1cc88ef814290369cf870dca1 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 13 Dec 2023 13:39:12 -0800 Subject: [PATCH 48/77] Credit Henri for HUD fix --- doc/contributions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index af8b259c74..2fbe8ab7cc 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -596,6 +596,7 @@ Henri Beauchamp SL-15175 SL-19110 SL-19159 + [NO JIRA] (fullbright HUD alpha fix) herina Bode Hikkoshi Sakai VWR-429 From feece92f2bb7525a7b2a99170ed60a40fac7777e Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 14 Dec 2023 14:58:20 +0200 Subject: [PATCH 49/77] SL-20717 Add PBR to Advanced > Rendering Types --- indra/newview/llviewermenu.cpp | 4 ++++ indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 553eaaf9b2..9db9d97ddc 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -787,6 +787,10 @@ U32 render_type_from_string(std::string render_type) { return LLPipeline::RENDER_TYPE_BUMP; } + else if ("pbr" == render_type) + { + return LLPipeline::RENDER_TYPE_GLTF_PBR; + } else { return 0; diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 2c4b03251a..660f4b62c7 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2162,6 +2162,16 @@ function="World.EnvPreset" function="Advanced.ToggleRenderType" parameter="bump" /> + + + + Date: Thu, 14 Dec 2023 17:41:57 +0200 Subject: [PATCH 50/77] SL-20715 Mask cutoff not copied corretly in build tools --- indra/newview/llpanelface.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 91cc177fd5..5f8071d3eb 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -4759,8 +4759,6 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) { LLUUID object_id = objectp->getID(); - LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); - // Normal // Replace placeholders with target's if (te_data["material"].has("NormMapNoCopy")) @@ -4807,6 +4805,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["DiffuseAlphaMode"].asInteger(), te, object_id); + LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["AlphaMaskCutoff"].asInteger(), te, object_id); if (te_data.has("te") && te_data["te"].has("shiny")) { objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); From 9212e0944203fdbdefbaae01a89600a0050b3a36 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 14 Dec 2023 10:22:31 -0600 Subject: [PATCH 51/77] SL-20730 Patch another potential source of NaNs --- .../newview/app_settings/shaders/class1/deferred/emissiveF.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl index 9e61b6b894..c95f791dbf 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl @@ -34,6 +34,6 @@ void main() { // NOTE: when this shader is used, only alpha is being written to float a = diffuseLookup(vary_texcoord0.xy).a*vertex_color.a; - frag_color = vec4(0, 0, 0, a); + frag_color = max(vec4(0, 0, 0, a), vec4(0)); } From 8b86e2ad1b1326cb3e98acd857dc93f4f1455b8c Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 14 Dec 2023 14:11:46 -0600 Subject: [PATCH 52/77] SL-20611 Followup -- fix for depth based atmospheric mask making atmospherics effect sun/moon/clouds --- .../newview/app_settings/shaders/class3/deferred/hazeF.glsl | 3 +-- indra/newview/lldrawpool.h | 6 +++--- indra/newview/lldrawpoolwlsky.cpp | 3 +++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl index 229f332b36..0b154e82ad 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -78,13 +78,12 @@ void main() do_atmospherics = true; } - vec3 irradiance = vec3(0); vec3 radiance = vec3(0); if (depth >= 1.0) { - //should only be true of WL sky, just port over base color value + //should only be true of sky, clouds, sun/moon, and stars discard; } diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 4300670445..0925a01439 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -53,7 +53,9 @@ public: // before grass, so grass should be the first alpha masked pool. Other ordering should be done // based on fill rate and likelihood to occlude future passes (faster, large occluders first). // - POOL_SIMPLE = 1, + POOL_SKY = 1, + POOL_WL_SKY, + POOL_SIMPLE, POOL_FULLBRIGHT, POOL_BUMP, POOL_TERRAIN, @@ -64,8 +66,6 @@ public: POOL_TREE, POOL_ALPHA_MASK, POOL_FULLBRIGHT_ALPHA_MASK, - POOL_SKY, - POOL_WL_SKY, POOL_AVATAR, POOL_CONTROL_AV, // Animesh POOL_GLOW, diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 05ee328e43..b14235f25c 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -87,6 +87,9 @@ void LLDrawPoolWLSky::endDeferredPass(S32 pass) cloud_shader = nullptr; sun_shader = nullptr; moon_shader = nullptr; + + // clear the depth buffer so haze shaders can use unwritten depth as a mask + glClear(GL_DEPTH_BUFFER_BIT); } void LLDrawPoolWLSky::renderDome(const LLVector3& camPosLocal, F32 camHeightLocal, LLGLSLShader * shader) const From a26a2cc3f562ae79890be24eb4b7a9567e959a91 Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Wed, 27 Dec 2023 18:32:06 +0100 Subject: [PATCH 53/77] Add Materials to inventory filter dropdown --- indra/newview/llpanelmaininventory.cpp | 1 + indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml | 1 + indra/newview/skins/default/xui/en/panel_main_inventory.xml | 1 + indra/newview/skins/starlight/xui/en/panel_main_inventory.xml | 1 + indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml | 1 + indra/newview/skins/vintage/xui/en/panel_main_inventory.xml | 1 + 6 files changed, 6 insertions(+) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 9e7ec05e1c..065001e96b 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -208,6 +208,7 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) mFilterMap["filter_type_snapshots"] = 0x01 << LLInventoryType::IT_SNAPSHOT; mFilterMap["filter_type_meshes"] = 0x01 << LLInventoryType::IT_MESH; mFilterMap["filter_type_settings"] = 0x01 << LLInventoryType::IT_SETTINGS; + mFilterMap["filter_type_materials"] = 0x01 << LLInventoryType::IT_MATERIAL; // initialize empty filter mask mFilterMask = 0; diff --git a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml index 5837a3608d..e429ee46c7 100644 --- a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml @@ -736,6 +736,7 @@ + diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index cb40abf334..40e19b4ecc 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -180,6 +180,7 @@ + diff --git a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml index 425d93a530..bd8dc1e9a8 100644 --- a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml @@ -179,6 +179,7 @@ + diff --git a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml index 27eb1dc6c4..51b724c764 100644 --- a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml @@ -181,6 +181,7 @@ + diff --git a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml index e9d7e6639c..8d052caef9 100644 --- a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml @@ -784,6 +784,7 @@ + From d21a733858ae78cd5fec02765b450029e3d81e5c Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Wed, 27 Dec 2023 18:47:17 +0100 Subject: [PATCH 54/77] Remove Meshes from inventory filter dropdown as raw mesh assets are not exposed to the user --- indra/newview/llpanelmaininventory.cpp | 1 - indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml | 1 - indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml | 1 - indra/newview/skins/ansastorm/xui/es/panel_main_inventory.xml | 1 - indra/newview/skins/ansastorm/xui/pl/panel_main_inventory.xml | 1 - indra/newview/skins/ansastorm/xui/ru/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/az/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/de/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/en/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/es/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/fr/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/it/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/ja/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/pl/panel_main_inventory.xml | 1 - indra/newview/skins/default/xui/ru/panel_main_inventory.xml | 1 - indra/newview/skins/starlight/xui/en/panel_main_inventory.xml | 1 - indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/de/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/en/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/es/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/fr/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/it/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/ja/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/pl/panel_main_inventory.xml | 1 - indra/newview/skins/vintage/xui/ru/panel_main_inventory.xml | 1 - 25 files changed, 25 deletions(-) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 065001e96b..2687d574c5 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -206,7 +206,6 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p) mFilterMap["filter_type_sounds"] = 0x01 << LLInventoryType::IT_SOUND; mFilterMap["filter_type_textures"] = 0x01 << LLInventoryType::IT_TEXTURE; mFilterMap["filter_type_snapshots"] = 0x01 << LLInventoryType::IT_SNAPSHOT; - mFilterMap["filter_type_meshes"] = 0x01 << LLInventoryType::IT_MESH; mFilterMap["filter_type_settings"] = 0x01 << LLInventoryType::IT_SETTINGS; mFilterMap["filter_type_materials"] = 0x01 << LLInventoryType::IT_MATERIAL; diff --git a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml index c20ad85a5c..1fe3154319 100644 --- a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml @@ -110,7 +110,6 @@ - diff --git a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml index e429ee46c7..63596de5fa 100644 --- a/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/en/panel_main_inventory.xml @@ -737,7 +737,6 @@ - diff --git a/indra/newview/skins/ansastorm/xui/es/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/es/panel_main_inventory.xml index 418e5978ce..c336d30872 100644 --- a/indra/newview/skins/ansastorm/xui/es/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/es/panel_main_inventory.xml @@ -82,7 +82,6 @@ - diff --git a/indra/newview/skins/ansastorm/xui/pl/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/pl/panel_main_inventory.xml index b9d066633a..1ccf340066 100644 --- a/indra/newview/skins/ansastorm/xui/pl/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/pl/panel_main_inventory.xml @@ -109,7 +109,6 @@ - diff --git a/indra/newview/skins/ansastorm/xui/ru/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/ru/panel_main_inventory.xml index c3e431c567..1973b9e42b 100644 --- a/indra/newview/skins/ansastorm/xui/ru/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/ru/panel_main_inventory.xml @@ -97,7 +97,6 @@ - diff --git a/indra/newview/skins/default/xui/az/panel_main_inventory.xml b/indra/newview/skins/default/xui/az/panel_main_inventory.xml index daa5c08f3a..2871d62738 100644 --- a/indra/newview/skins/default/xui/az/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/az/panel_main_inventory.xml @@ -37,7 +37,6 @@ - diff --git a/indra/newview/skins/default/xui/de/panel_main_inventory.xml b/indra/newview/skins/default/xui/de/panel_main_inventory.xml index cd575a4119..ebb0954347 100644 --- a/indra/newview/skins/default/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/de/panel_main_inventory.xml @@ -41,7 +41,6 @@ - diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index 40e19b4ecc..eda12fb3f4 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -181,7 +181,6 @@ - diff --git a/indra/newview/skins/default/xui/es/panel_main_inventory.xml b/indra/newview/skins/default/xui/es/panel_main_inventory.xml index 1362f469a4..b521cb9e45 100644 --- a/indra/newview/skins/default/xui/es/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/es/panel_main_inventory.xml @@ -36,7 +36,6 @@ - diff --git a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml index 93a58514c4..23855bfe2f 100644 --- a/indra/newview/skins/default/xui/fr/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/fr/panel_main_inventory.xml @@ -34,7 +34,6 @@ - diff --git a/indra/newview/skins/default/xui/it/panel_main_inventory.xml b/indra/newview/skins/default/xui/it/panel_main_inventory.xml index 1ad2b550c0..6bdafc4443 100644 --- a/indra/newview/skins/default/xui/it/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/it/panel_main_inventory.xml @@ -38,7 +38,6 @@ - diff --git a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml index 6f914cbcb2..d8d781037a 100644 --- a/indra/newview/skins/default/xui/ja/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/ja/panel_main_inventory.xml @@ -31,7 +31,6 @@ - diff --git a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml index afea372723..85a42300ef 100644 --- a/indra/newview/skins/default/xui/pl/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/pl/panel_main_inventory.xml @@ -42,7 +42,6 @@ - diff --git a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml index cf8ac67e8d..9386086786 100644 --- a/indra/newview/skins/default/xui/ru/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/ru/panel_main_inventory.xml @@ -42,7 +42,6 @@ - diff --git a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml index bd8dc1e9a8..9f9279d5e3 100644 --- a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml @@ -180,7 +180,6 @@ - diff --git a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml index 51b724c764..37a1a95953 100644 --- a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml @@ -182,7 +182,6 @@ - diff --git a/indra/newview/skins/vintage/xui/de/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/de/panel_main_inventory.xml index 9a470da319..eab9799085 100644 --- a/indra/newview/skins/vintage/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/de/panel_main_inventory.xml @@ -102,7 +102,6 @@ - diff --git a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml index 8d052caef9..00497c92ec 100644 --- a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml @@ -785,7 +785,6 @@ - diff --git a/indra/newview/skins/vintage/xui/es/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/es/panel_main_inventory.xml index 6a5c6ff9e4..959449bcc2 100644 --- a/indra/newview/skins/vintage/xui/es/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/es/panel_main_inventory.xml @@ -82,7 +82,6 @@ - diff --git a/indra/newview/skins/vintage/xui/fr/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/fr/panel_main_inventory.xml index 2f985e7d4f..b69c5c4ac3 100644 --- a/indra/newview/skins/vintage/xui/fr/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/fr/panel_main_inventory.xml @@ -93,7 +93,6 @@ - diff --git a/indra/newview/skins/vintage/xui/it/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/it/panel_main_inventory.xml index adc482d548..f6af585c33 100644 --- a/indra/newview/skins/vintage/xui/it/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/it/panel_main_inventory.xml @@ -143,7 +143,6 @@ - diff --git a/indra/newview/skins/vintage/xui/ja/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/ja/panel_main_inventory.xml index b5a9a58a8b..435ed06b73 100644 --- a/indra/newview/skins/vintage/xui/ja/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/ja/panel_main_inventory.xml @@ -104,7 +104,6 @@ - diff --git a/indra/newview/skins/vintage/xui/pl/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/pl/panel_main_inventory.xml index 33e27e827c..4a4b5cbcde 100644 --- a/indra/newview/skins/vintage/xui/pl/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/pl/panel_main_inventory.xml @@ -114,7 +114,6 @@ - diff --git a/indra/newview/skins/vintage/xui/ru/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/ru/panel_main_inventory.xml index a621bc3cdd..3092e53280 100644 --- a/indra/newview/skins/vintage/xui/ru/panel_main_inventory.xml +++ b/indra/newview/skins/vintage/xui/ru/panel_main_inventory.xml @@ -94,7 +94,6 @@ - From f3b589705b60b38e8946fae508ca135be7419f45 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 27 Dec 2023 19:03:43 +0100 Subject: [PATCH 55/77] Update German translation --- indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml | 3 ++- indra/newview/skins/default/xui/de/panel_main_inventory.xml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml index 1fe3154319..150baf3c18 100644 --- a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml @@ -110,7 +110,8 @@ - + + diff --git a/indra/newview/skins/default/xui/de/panel_main_inventory.xml b/indra/newview/skins/default/xui/de/panel_main_inventory.xml index ebb0954347..fe79176257 100644 --- a/indra/newview/skins/default/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/de/panel_main_inventory.xml @@ -41,6 +41,7 @@ + From 68ef687727082f277cf7ede368038868b012386b Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 27 Dec 2023 19:21:19 +0100 Subject: [PATCH 56/77] Crap! Somebody noticed... --- indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml index 150baf3c18..0daf2b5c6b 100644 --- a/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml +++ b/indra/newview/skins/ansastorm/xui/de/panel_main_inventory.xml @@ -110,7 +110,7 @@ - + From 7db1a5ce49f350e6c11da305fc2cb81437add5d3 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 27 Dec 2023 18:21:14 +0000 Subject: [PATCH 57/77] fail means fail --- .github/workflows/build_viewer.yml | 27 ++++++++++++++++++++++++++- scripts/configure_firestorm.sh | 11 +++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index d0a6255abf..790d3d8a56 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 - id: py312 + id: py311 with: python-version: '3.11.6' cache: 'pip' @@ -267,6 +267,31 @@ jobs: path: | build-darwin-*/newview/*.dmg build-darwin-*/newview/*.bz2 + post-windows-symbols: + needs: build + runs-on: ubuntu-latest + steps: + - name: Post Windows symbols + uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 + with: + username: ${{ secrets.BUGSPLAT_USER }} + password: ${{ secrets.BUGSPLAT_PASS }} + database: "SecondLife_Viewer_2018" + channel: ${{ needs.build.outputs.viewer_channel }} + version: ${{ needs.build.outputs.viewer_version }} + + post-mac-symbols: + needs: build + runs-on: ubuntu-latest + steps: + - name: Post Mac symbols + uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 + with: + username: ${{ secrets.BUGSPLAT_USER }} + password: ${{ secrets.BUGSPLAT_PASS }} + database: "SecondLife_Viewer_2018" + channel: ${{ needs.build.outputs.viewer_channel }} + version: ${{ needs.build.outputs.viewer_version }} deploy: runs-on: ubuntu-latest needs: build_matrix diff --git a/scripts/configure_firestorm.sh b/scripts/configure_firestorm.sh index 1255293d54..6b2111506a 100755 --- a/scripts/configure_firestorm.sh +++ b/scripts/configure_firestorm.sh @@ -594,6 +594,11 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then echo "Setting startup project via vstool" ../indra/tools/vstool/VSTool.exe --solution Firestorm.sln --startup firestorm-bin --workingdir firestorm-bin "..\\..\\indra\\newview" --config $BTYPE fi + # Check the return code of the build command + if [ $? -ne 0 ]; then + echo "Configure failed!" + exit 1 + fi fi if [ $WANTS_BUILD -eq $TRUE ] ; then echo "Building $TARGET_PLATFORM..." @@ -625,6 +630,12 @@ if [ $WANTS_BUILD -eq $TRUE ] ; then -verbosity:normal -toolsversion:15.0 -p:"VCBuildAdditionalOptions= /incremental" fi fi + # Check the return code of the build command + if [ $? -ne 0 ]; then + echo "Build failed!" + exit 1 + fi fi echo "finished" +exit 0 From b6d55cc43b4d2cbd279a3c4104f002e0768206a6 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 28 Dec 2023 12:28:27 +0000 Subject: [PATCH 58/77] quick patch - not a fix, these will not run clean up variable declarations and prep for bugsplat sym upload bash variables hate whitespace --- .github/workflows/build_viewer.yml | 76 +++++++++++++++++++----------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 790d3d8a56..6e4f51bc8d 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -9,11 +9,17 @@ on: - "*preview" schedule: - cron: '00 03 * * *' # Run every day at 3am UTC -env: +env: AUTOBUILD_VARIABLES_FILE: ${{github.workspace}}/build-variables/variables EXTRA_ARGS: -DUSE_FMODSTUDIO=ON -DUSE_KDU=ON --crashreporting build_secrets_checkout: ${{github.workspace}}/signing XZ_DEFAULTS: -T0 + FS_RELEASE_TYPE: Unknown + platform: Unknown + fallback_platform: ${platform} + FS_RELEASE_CHAN: ${FS_RELEASE_TYPE}x64 + FS_GRID: "GRID FLAGS NOT SET" + jobs: build_matrix: strategy: @@ -22,6 +28,9 @@ jobs: grid: [sl,os] addrsize: [64] runs-on: ${{ matrix.os }} + outputs: + viewer_channel: ${{ steps.channel.outputs.viewer_channel }} + viewer_version: ${{ steps.version.outputs.viewer_version }} steps: - name: Install Bash 4 and GNU sed on Mac if: runner.os == 'macOS' @@ -38,7 +47,7 @@ jobs: - uses: actions/setup-python@v4 id: py311 with: - python-version: '3.11.6' + python-version: '3.11' cache: 'pip' - name: Install python requirements @@ -90,6 +99,7 @@ jobs: shell: bash - name: find channel from Branch name + id: channel run: | if [[ "${{ github.ref_name }}" == Firestorm* ]]; then FS_RELEASE_TYPE=Release @@ -110,6 +120,7 @@ jobs: echo "FS_RELEASE_TYPE=${FS_RELEASE_TYPE}" >> $GITHUB_ENV echo "FS_RELEASE_CHAN=${FS_RELEASE_CHAN}" >> $GITHUB_ENV echo "Building for channel ${FS_RELEASE_CHAN}" + viewer_channel=${FS_RELEASE_CHAN} shell: bash - name: Get the code @@ -238,9 +249,18 @@ jobs: shell: bash - name: build + id: build run: autobuild build -c ReleaseFS -A${{matrix.addrsize}} --no-configure shell: bash - + - name: Extract version number + id: version + shell: bash + run: | + if [ -r "indra/newview/viewer_version.txt" ] + then + viewer_version="$(<"$build_dir/newview/viewer_version.txt")" + echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" + fi - name: Publish artifacts if: runner.os == 'Windows' uses: actions/upload-artifact@v3 @@ -267,31 +287,31 @@ jobs: path: | build-darwin-*/newview/*.dmg build-darwin-*/newview/*.bz2 - post-windows-symbols: - needs: build - runs-on: ubuntu-latest - steps: - - name: Post Windows symbols - uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 - with: - username: ${{ secrets.BUGSPLAT_USER }} - password: ${{ secrets.BUGSPLAT_PASS }} - database: "SecondLife_Viewer_2018" - channel: ${{ needs.build.outputs.viewer_channel }} - version: ${{ needs.build.outputs.viewer_version }} - - post-mac-symbols: - needs: build - runs-on: ubuntu-latest - steps: - - name: Post Mac symbols - uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 - with: - username: ${{ secrets.BUGSPLAT_USER }} - password: ${{ secrets.BUGSPLAT_PASS }} - database: "SecondLife_Viewer_2018" - channel: ${{ needs.build.outputs.viewer_channel }} - version: ${{ needs.build.outputs.viewer_version }} + # post-windows-symbols: + # needs: build_matrix + # runs-on: ubuntu-latest + # steps: + # - name: Post Windows symbols + # uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 + # with: + # username: ${{ secrets.BUGSPLAT_USER }} + # password: ${{ secrets.BUGSPLAT_PASS }} + # database: "firestorm_release" + # channel: ${{ needs.build_matrix.outputs.viewer_channel }} + # version: ${{ needs.build_matrix.outputs.viewer_version }} + + # post-mac-symbols: + # needs: build_matrix + # runs-on: ubuntu-latest + # steps: + # - name: Post Mac symbols + # uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 + # with: + # username: ${{ secrets.BUGSPLAT_USER }} + # password: ${{ secrets.BUGSPLAT_PASS }} + # database: "firestorm_release" + # channel: ${{ needs.build_matrix.outputs.viewer_channel }} + # version: ${{ needs.build_matrix.outputs.viewer_version }} deploy: runs-on: ubuntu-latest needs: build_matrix From 5198af498a9a06a5ea2dd0bd40fe559d3c27bc19 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 28 Dec 2023 15:09:33 +0000 Subject: [PATCH 59/77] switch windows python back to defaults --- .github/workflows/build_viewer.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 6e4f51bc8d..656bd6dc36 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -47,10 +47,16 @@ jobs: - uses: actions/setup-python@v4 id: py311 with: - python-version: '3.11' + python-version: '3.11.6' cache: 'pip' - - name: Install python requirements + - name: Install python requirements (windows only) + if: runner.os == 'Windows' + run: | + python3 -m pip install -r requirements.txt --user + echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Install python requirements (non-windows) + if: runner.os != 'Windows' run: | python3 -m pip install -r requirements.txt python -m pip install -r requirements.txt From 88a005a268c19933f88091550ac9aecac51abf32 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 28 Dec 2023 17:52:39 +0000 Subject: [PATCH 60/77] use latest autobuild and llsd/llbase --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 308ed7a4cd..c157ec2b54 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -llbase==1.2.11 -autobuild==3.9.1 -llsd==1.2.1 \ No newline at end of file +llbase +autobuild +llsd \ No newline at end of file From 549e7ff3c14643660d0d7d82705a94c9ea9cf001 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 28 Dec 2023 18:31:33 +0000 Subject: [PATCH 61/77] ensure python & python3 have the same requirements set --- .github/workflows/build_viewer.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 656bd6dc36..94d4fc3195 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -54,6 +54,7 @@ jobs: if: runner.os == 'Windows' run: | python3 -m pip install -r requirements.txt --user + python -m pip install -r requirements.txt --user echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Install python requirements (non-windows) if: runner.os != 'Windows' From 5aa47877a2b81402b963fc9e860fd186dc9b03c0 Mon Sep 17 00:00:00 2001 From: Beq Date: Fri, 29 Dec 2023 02:08:42 +0000 Subject: [PATCH 62/77] Export python binary in ENV to satisfy CMake Use env var to force the python version set python for Cmake and remove python cache --- .github/workflows/build_viewer.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 94d4fc3195..f0e980c678 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -19,6 +19,7 @@ env: fallback_platform: ${platform} FS_RELEASE_CHAN: ${FS_RELEASE_TYPE}x64 FS_GRID: "GRID FLAGS NOT SET" + PYTHON: jobs: build_matrix: @@ -47,20 +48,18 @@ jobs: - uses: actions/setup-python@v4 id: py311 with: - python-version: '3.11.6' - cache: 'pip' + python-version: '3.11' - - name: Install python requirements (windows only) - if: runner.os == 'Windows' + - name: Set PYTHON environment for CMake run: | - python3 -m pip install -r requirements.txt --user - python -m pip install -r requirements.txt --user - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Install python requirements (non-windows) - if: runner.os != 'Windows' + echo "PYTHON=${{ steps.py311.outputs.python-path }}" >> $GITHUB_ENV + shell: bash + + - name: Install python requirements run: | python3 -m pip install -r requirements.txt python -m pip install -r requirements.txt + # export the new python to the environment var $PYTHON - name: Check python version run: python -V @@ -322,6 +321,9 @@ jobs: deploy: runs-on: ubuntu-latest needs: build_matrix + env: + FS_BUILD_WEBHOOK_URL: + FS_RELEASE_FOLDER: if: always() steps: - name: Checkout files From 99851ed459ed996154be9398c66de99802db4434 Mon Sep 17 00:00:00 2001 From: Beq Date: Fri, 29 Dec 2023 14:40:51 +0000 Subject: [PATCH 63/77] disable viewer_version extraction rule for now --- .github/workflows/build_viewer.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index f0e980c678..e4d0f3aa52 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -258,15 +258,15 @@ jobs: id: build run: autobuild build -c ReleaseFS -A${{matrix.addrsize}} --no-configure shell: bash - - name: Extract version number - id: version - shell: bash - run: | - if [ -r "indra/newview/viewer_version.txt" ] - then - viewer_version="$(<"$build_dir/newview/viewer_version.txt")" - echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" - fi + # - name: Extract version number + # id: version + # shell: bash + # run: | + # if [ -r "indra/newview/viewer_version.txt" ] + # then + # viewer_version="$(<"$build_dir/newview/viewer_version.txt")" + # echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" + # fi - name: Publish artifacts if: runner.os == 'Windows' uses: actions/upload-artifact@v3 From 6eef91e09570557c81660e65053147a996124f71 Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Fri, 29 Dec 2023 20:16:39 +0100 Subject: [PATCH 64/77] Fix wrong include --- indra/newview/llfloaterinspect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 8afc10b757..b9a34345f1 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -49,7 +49,7 @@ // [/RLVa:KB] // PoundLife - Improved Object Inspect #include "llresmgr.h" -#include "lltexturectrl.h" +#include "lltextbase.h" #include "llviewerobjectlist.h" //gObjectList #include "llviewertexturelist.h" // PoundLife END From 485e9701b881a297470004bd3a1308de862eb7ad Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Fri, 29 Dec 2023 20:18:32 +0100 Subject: [PATCH 65/77] Remove unnecessary include and class forward declaration --- indra/newview/llpanelobject.cpp | 1 - indra/newview/llpanelobject.h | 1 - 2 files changed, 2 deletions(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 906784be8d..faf6c5d1b4 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -42,7 +42,6 @@ #include "llbutton.h" #include "llcalc.h" #include "llcheckboxctrl.h" -#include "llcolorswatch.h" #include "llcombobox.h" #include "llfocusmgr.h" #include "llmanipscale.h" diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 69a5d70b11..2aff1a776e 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -40,7 +40,6 @@ class LLButton; class LLMenuButton; class LLViewerObject; class LLComboBox; -class LLColorSwatchCtrl; class LLTextureCtrl; class LLInventoryItem; class LLUUID; From fdeddfcdf25629a88c332c08acab99e17375c4ee Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Fri, 29 Dec 2023 20:21:58 +0100 Subject: [PATCH 66/77] Remove unnecessary include --- indra/newview/llfloaterautoreplacesettings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp index 516a4d15d6..a0e43ca1a7 100644 --- a/indra/newview/llfloaterautoreplacesettings.cpp +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -33,7 +33,6 @@ #include "llagent.h" #include "llpanel.h" #include "llbutton.h" -#include "llcolorswatch.h" #include "llcombobox.h" #include "llview.h" #include "llbufferstream.h" From 8776d50ef4e8f6b522a9dad48cced664eecc268c Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Fri, 29 Dec 2023 20:28:05 +0100 Subject: [PATCH 67/77] Add label / caption color support to color swatches --- indra/newview/llcolorswatch.cpp | 21 ++++++++++++++++++++- indra/newview/llcolorswatch.h | 12 ++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 036ff17074..d772a92745 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -52,6 +52,8 @@ LLColorSwatchCtrl::Params::Params() border_color("border_color"), label_width("label_width", -1), label_height("label_height", -1), + text_enabled_color("text_enabled_color"), // Add label/caption colors + text_disabled_color("text_disabled_color"), // Add label/caption colors caption_text("caption_text"), border("border") { @@ -66,6 +68,8 @@ LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p) mOnCancelCallback(p.cancel_callback()), mOnSelectCallback(p.select_callback()), mBorderColor(p.border_color()), + mTextEnabledColor(p.text_enabled_color), // Add label/caption colors + mTextDisabledColor(p.text_disabled_color), // Add label/caption colors mLabelWidth(p.label_width), mLabelHeight(p.label_height) { @@ -95,6 +99,8 @@ LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p) params.rect(border_rect); mBorder = LLUICtrlFactory::create (params); addChild(mBorder); + + updateLabelColor(); // Add label/caption colors } LLColorSwatchCtrl::~LLColorSwatchCtrl () @@ -250,12 +256,18 @@ void LLColorSwatchCtrl::draw() } } + mCaption->setEnabled(getEnabled() && isInEnabledChain()); // Add label/caption colors + LLUICtrl::draw(); } void LLColorSwatchCtrl::setEnabled( BOOL enabled ) { - mCaption->setEnabled( enabled ); + // Add label/caption colors + // mCaption->setEnabled( enabled ); + mCaption->setEnabled(enabled && isInEnabledChain()); + // + LLView::setEnabled( enabled ); if (!enabled) @@ -374,3 +386,10 @@ void LLColorSwatchCtrl::showPicker(BOOL take_focus) } } +// Add label/caption colors +void LLColorSwatchCtrl::updateLabelColor() +{ + mCaption->setColor(mTextEnabledColor.get()); + mCaption->setReadOnlyColor(mTextDisabledColor.get()); +} +// diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index a17cab486a..5c0afe3d1f 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -62,6 +62,10 @@ public: Optional caption_text; Optional border; + + Optional text_enabled_color; // Add label/caption colors + Optional text_disabled_color; // Add label/caption colors + Params(); }; @@ -100,7 +104,12 @@ public: static void onColorChanged ( void* data, EColorPickOp pick_op = COLOR_CHANGE ); void closeFloaterColorPicker(); + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } // Add label/caption colors + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor(); } // Add label/caption colors + protected: + void updateLabelColor(); // Add label/caption colors + bool mValid; LLColor4 mColor; LLUIColor mBorderColor; @@ -116,6 +125,9 @@ protected: LLPointer mAlphaGradientImage; LLPointer mFallbackImage; + + LLUIColor mTextEnabledColor; // Add label/caption colors + LLUIColor mTextDisabledColor; // Add label/caption colors }; #endif // LL_LLBUTTON_H From d75ba744a8018314d8405537329b7f8466aadafb Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Fri, 29 Dec 2023 20:29:58 +0100 Subject: [PATCH 68/77] Also add the required parameters to the skin ... --- indra/newview/skins/default/xui/en/widgets/color_swatch.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/newview/skins/default/xui/en/widgets/color_swatch.xml b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml index ab3de1eaab..3611670121 100644 --- a/indra/newview/skins/default/xui/en/widgets/color_swatch.xml +++ b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml @@ -1,6 +1,9 @@ + Date: Fri, 29 Dec 2023 20:32:28 +0100 Subject: [PATCH 69/77] Add label / caption color support to texture picker, fix label width setting and remember to also add the required parameters to the skin --- indra/newview/lltexturectrl.cpp | 27 ++++++++++++++----- indra/newview/lltexturectrl.h | 13 +++++++++ .../default/xui/en/widgets/texture_picker.xml | 3 +++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index c26b4c7c53..4142ad6927 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1759,6 +1759,8 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mDefaultImageAssetID(p.default_image_id), mDefaultImageName(p.default_image_name), mFallbackImage(p.fallback_image), + mTextEnabledColor(p.text_enabled_color), // Add label/caption colors + mTextDisabledColor(p.text_disabled_color), // Add label/caption colors // Mask texture if desired mIsMasked(FALSE) { @@ -1774,7 +1776,10 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) LLTextBox::Params params(p.caption_text); params.name(p.label); - params.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 )); + // Fix label width + // params.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 )); + params.rect(LLRect( 0, BTN_HEIGHT_SMALL, p.label_width == -1 ? getRect().getWidth() : p.label_width, 0 )); + // params.initial_value(p.label()); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); mCaption = LLUICtrlFactory::create (params); @@ -1812,6 +1817,8 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) addChild(mBorder); mLoadingPlaceholderString = LLTrans::getString("texture_loading"); + + updateLabelColor(); // Add label/caption colors } LLTextureCtrl::~LLTextureCtrl() @@ -1896,7 +1903,10 @@ void LLTextureCtrl::setEnabled( BOOL enabled ) closeDependentFloater(); } - mCaption->setEnabled( enabled ); + // Add label/caption colors + // mCaption->setEnabled( enabled ); + mCaption->setEnabled(enabled && isInEnabledChain()); + // // Texture preview mode //LLView::setEnabled( enabled ); @@ -2421,6 +2431,8 @@ void LLTextureCtrl::draw() } } + mCaption->setEnabled(getEnabled() && isInEnabledChain()); // Add label/caption colors + LLUICtrl::draw(); } @@ -2527,7 +2539,10 @@ LLSD LLTextureCtrl::getValue() const return LLSD(getImageAssetID()); } - - - - +// Add label/caption colors +void LLTextureCtrl::updateLabelColor() +{ + mCaption->setColor(mTextEnabledColor.get()); + mCaption->setReadOnlyColor(mTextDisabledColor.get()); +} +// diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 146949d3f7..3b4e61f11f 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -115,6 +115,9 @@ public: Optional border; Optional show_caption; // leave some room underneath the image for the caption + Optional text_enabled_color; // Add label/caption colors + Optional text_disabled_color; // Add label/caption colors + Params() : image_id("image"), default_image_id("default_image_id"), @@ -127,6 +130,8 @@ public: fallback_image("fallback_image"), multiselect_text("multiselect_text"), show_caption("show_caption", true), // leave some room underneath the image for the caption + text_enabled_color("text_enabled_color"), // Add label/caption colors + text_disabled_color("text_disabled_color"), // Add label/caption colors caption_text("caption_text"), border("border") {} @@ -243,10 +248,15 @@ public: // Mask texture if desired void setIsMasked(BOOL masked) { mIsMasked = masked; } + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } // Add label/caption colors + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor(); } // Add label/caption colors + private: BOOL allowDrop(LLInventoryItem* item, EDragAndDropType cargo_type, std::string& tooltip_msg); BOOL doDrop(LLInventoryItem* item); + void updateLabelColor(); // Add label/caption colors + private: drag_n_drop_callback mDragCallback; drag_n_drop_callback mDropCallback; @@ -286,6 +296,9 @@ private: // Mask texture if desired BOOL mIsMasked; + + LLUIColor mTextEnabledColor; // Add label/caption colors + LLUIColor mTextDisabledColor; // Add label/caption colors }; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/skins/default/xui/en/widgets/texture_picker.xml b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml index 1511116ba6..eea5f54fe5 100644 --- a/indra/newview/skins/default/xui/en/widgets/texture_picker.xml +++ b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml @@ -1,8 +1,11 @@ + Date: Sun, 31 Dec 2023 14:06:25 +0100 Subject: [PATCH 70/77] It's 2024... basically... almost... --- FIRESTORM-SOURCE_LICENSE_HEADER.txt | 4 ++-- autobuild.xml | 2 +- indra/newview/CMakeLists.txt | 2 +- indra/newview/English.lproj/InfoPlist.strings | 2 +- indra/newview/res/viewerRes.rc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FIRESTORM-SOURCE_LICENSE_HEADER.txt b/FIRESTORM-SOURCE_LICENSE_HEADER.txt index 19eedbfa2e..44f7834caf 100644 --- a/FIRESTORM-SOURCE_LICENSE_HEADER.txt +++ b/FIRESTORM-SOURCE_LICENSE_HEADER.txt @@ -2,9 +2,9 @@ * @file * @brief * - * $LicenseInfo:firstyear=2023&license=fsviewerlgpl$ + * $LicenseInfo:firstyear=2024&license=fsviewerlgpl$ * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2020, The Phoenix Firestorm Project, Inc. + * Copyright (C) 2024, The Phoenix Firestorm Project, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/autobuild.xml b/autobuild.xml index e4537d0c91..4476b4ef8a 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -4088,7 +4088,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors license_file docs/LICENSE-source.txt copyright - Copyright (c) 2023, The Phoenix Firestorm Project, Inc. + Copyright (c) 2024, The Phoenix Firestorm Project, Inc. version_file newview/viewer_version.txt name diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index de3bf0b5ff..9c046e3a2a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2532,7 +2532,7 @@ if (DARWIN) set(MACOSX_BUNDLE_BUNDLE_NAME "Firestorm") set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") - set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010-2023 The Phoenix Firestorm Project, Inc.") + set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010-2024 The Phoenix Firestorm Project, Inc.") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "Firestorm.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "LLApplication") diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index 1afe5749be..b19cda2ddd 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -3,4 +3,4 @@ CFBundleName = "Firestorm"; CFBundleShortVersionString = "Firestorm version %%VERSION%%"; -CFBundleGetInfoString = "Firestorm version %%VERSION%%, Copyright 2010-2023 The Phoenix Firestorm Project, Inc."; +CFBundleGetInfoString = "Firestorm version %%VERSION%%, Copyright 2010-2024 The Phoenix Firestorm Project, Inc."; diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index dd0da75631..ade5c477c7 100755 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -161,7 +161,7 @@ BEGIN VALUE "FileDescription", "Firestorm" VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" VALUE "InternalName", "Firestorm" - VALUE "LegalCopyright", "Copyright \251 2010-2023, The Phoenix Firestorm Project, Inc." + VALUE "LegalCopyright", "Copyright \251 2010-2024, The Phoenix Firestorm Project, Inc." VALUE "OriginalFilename", "Firestorm.exe" VALUE "ProductName", "Firestorm" VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" From 5e759054ca52e7aa36f6e6c49defce1bd3282baa Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 1 Jan 2024 16:22:15 +0100 Subject: [PATCH 71/77] FIRE-33578: Reset defaults doesn't reset materials upload folder --- indra/newview/fspanelprefs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/fspanelprefs.cpp b/indra/newview/fspanelprefs.cpp index 40c2c3bc2e..0f2bf603bd 100644 --- a/indra/newview/fspanelprefs.cpp +++ b/indra/newview/fspanelprefs.cpp @@ -283,4 +283,5 @@ void FSPanelPrefs::onResetDefaultFolders() gSavedPerAccountSettings.getControl("TextureUploadFolder")->resetToDefault(true); gSavedPerAccountSettings.getControl("SoundUploadFolder")->resetToDefault(true); gSavedPerAccountSettings.getControl("AnimationUploadFolder")->resetToDefault(true); + gSavedPerAccountSettings.getControl("PBRUploadFolder")->resetToDefault(true); } From 8d59c0b1a3fd35027118ef34b18e61b31e5ba15a Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 2 Jan 2024 17:38:47 +0100 Subject: [PATCH 72/77] Add readme file --- README.md | 29 +++++++++++++++++++++++++++++ doc/firestorm_256.png | Bin 0 -> 146136 bytes 2 files changed, 29 insertions(+) create mode 100644 README.md create mode 100644 doc/firestorm_256.png diff --git a/README.md b/README.md new file mode 100644 index 0000000000..cb09b89340 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ + + Firestorm Viewer Logo + + +**[Firestorm](https://www.firestormviewer.org/) is a free client for 3D virtual worlds such as Second Life and various OpenSim worlds where users can create, connect and chat with others from around the world.** This repository contains the official source code for the Firestorm viewer. + +## Open Source + +Firestorm is a third party viewer derived from the official [Second Life](https://github.com/secondlife/viewer) client. The client codebase has been open source since 2007 and is available under the LGPL license. + +## Download + +Pre-built versions of the viewer releases for Windows, Mac and Linux can be downloaded from the [official website](https://www.firestormviewer.org/choose-your-platform/). + +## Build Instructions + +Build instructions for each operating system can be found in the official [wiki](https://wiki.firestormviewer.org/). + +- [Windows](https://wiki.firestormviewer.org/fs_compiling_firestorm_windows) + +- [Mac](https://wiki.firestormviewer.org/fs_compiling_firestorm_macos) + +- [Linux](https://wiki.firestormviewer.org/fs_compiling_firestorm_linux) + +Please note that we do not provide support for compiling the viewer or issues resulting from using a self-compiled viewer. However, there is a self-compilers group within Second Life that can be joined to ask questions related to compiling the viewer: [Firestorm Self Compilers](secondlife:///app/group/2014ce4c-5393-fb67-83ac-910db84c273c/about) + +## Contribute + +Help make Firestorm better! You can get involved with improvements by filing bugs and suggesting enhancements via [JIRA](https://jira.firestormviewer.org) or creating pull requests. diff --git a/doc/firestorm_256.png b/doc/firestorm_256.png new file mode 100644 index 0000000000000000000000000000000000000000..c440137b72b7d2ab2d6c475fa1e296694d3ce367 GIT binary patch literal 146136 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 O0000 Date: Sun, 7 Jan 2024 16:34:14 +0100 Subject: [PATCH 73/77] Fix some... --- indra/newview/piemenu.cpp | 53 +++++++++++++++++--------------------- indra/newview/piemenu.h | 4 +-- indra/newview/pieslice.cpp | 8 +++--- indra/newview/pieslice.h | 6 ++--- 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/indra/newview/piemenu.cpp b/indra/newview/piemenu.cpp index 4b802811e8..6b90f3bd47 100644 --- a/indra/newview/piemenu.cpp +++ b/indra/newview/piemenu.cpp @@ -45,20 +45,23 @@ static PieChildRegistry::Register pie_r2("pie_slice"); static PieChildRegistry::Register pie_r3("pie_separator"); // pie slice label text positioning -const S32 PIE_X[] = {64, 45, 0, -45, -63, -45, 0, 45}; -const S32 PIE_Y[] = { 0, 44, 73, 44, 0, -44, -73, -44}; +constexpr S32 PIE_X[] = {64, 45, 0, -45, -63, -45, 0, 45}; +constexpr S32 PIE_Y[] = { 0, 44, 73, 44, 0, -44, -73, -44}; -const S32 PIE_INNER_SIZE = 20; // radius of the inner pie circle -const F32 PIE_POPUP_FACTOR = 1.7f; // pie menu size factor on popup -const F32 PIE_POPUP_TIME = 0.25f; // time to shrink from popup size to regular size -const S32 PIE_OUTER_SIZE = 96; // radius of the outer pie circle -const F32 PIE_OUTER_SHADE_FACTOR = 1.09f; // size factor of the outer shading ring -const F32 PIE_SLICE_DIVIDER_WIDTH = 0.04f; // width of a slice divider in radians -const F32 PIE_MAX_SLICES_F = F32(PIE_MAX_SLICES); +constexpr S32 PIE_INNER_SIZE = 20; // radius of the inner pie circle +constexpr F32 PIE_POPUP_FACTOR = 1.7f; // pie menu size factor on popup +constexpr F32 PIE_POPUP_TIME = 0.25f; // time to shrink from popup size to regular size +constexpr S32 PIE_OUTER_SIZE = 96; // radius of the outer pie circle +constexpr F32 PIE_OUTER_SHADE_FACTOR = 1.09f; // size factor of the outer shading ring +constexpr F32 PIE_SLICE_DIVIDER_WIDTH = 0.04f; // width of a slice divider in radians +constexpr F32 PIE_MAX_SLICES_F = F32(PIE_MAX_SLICES); PieMenu::PieMenu(const LLMenuGL::Params& p) : LLMenuGL(p), - mCurrentSegment(-1) + mCurrentSegment(-1), + mOldSlice(nullptr), + mSlice(nullptr), + mFirstClick(true) { LL_DEBUGS("Pie") << "PieMenu::PieMenu()" << LL_ENDL; @@ -75,12 +78,6 @@ PieMenu::PieMenu(const LLMenuGL::Params& p) : // set slices pointer to our own slices mSlices = &mMySlices; - - // this will be the first click on the menu - mFirstClick = true; - - // clean initialisation - mSlice = NULL; } bool PieMenu::addChild(LLView* child, S32 tab_group) @@ -92,7 +89,7 @@ bool PieMenu::addChild(LLView* child, S32 tab_group) } // add a new slice to the menu - mSlices->push_back(child); + mSlices->emplace_back(child); // tell the view that our menu has changed and reshape it back to correct size LLUICtrl::addChild(child); @@ -205,18 +202,17 @@ void PieMenu::show(S32 x, S32 y, LLView* spawning_view) mSlices = &mMySlices; // reset enable update checks for slices - for (slice_list_t::iterator it = mSlices->begin(); it != mSlices->end(); ++it) + for (auto slice : *mSlices) { - PieSlice* resetSlice = dynamic_cast(*it); - if (resetSlice) + if (auto resetSlice = dynamic_cast(slice); resetSlice) { resetSlice->resetUpdateEnabledCheck(); } } // cleanup - mSlice = NULL; - mOldSlice = NULL; + mSlice = nullptr; + mOldSlice = nullptr; // draw the menu on screen setVisible(TRUE); @@ -262,7 +258,7 @@ void PieMenu::draw() gGL.pushMatrix(); // save the widget's rectangle for later use - LLRect r = getRect(); + const LLRect& r = getRect(); // initialize pie scale factor for popup effect F32 factor = getScaleFactor(); @@ -300,7 +296,7 @@ void PieMenu::draw() borderColor %= 0.f; } - S32 steps = 100; + constexpr S32 steps = 100; // move origin point to the center of our rectangle LLUI::instance().translate(r.getWidth() / 2.f, r.getHeight() / 2.f); @@ -313,7 +309,7 @@ void PieMenu::draw() cur_item_iter = mSlices->begin(); // clear current slice pointer - mSlice = NULL; + mSlice = nullptr; // current slice number is 0 S32 num = 0; @@ -539,10 +535,9 @@ BOOL PieMenu::handleMouseButtonUp(S32 x, S32 y, MASK mask) // swap out the list of items for the ones in the submenu mSlices = ¤tSubmenu->mMySlices; // reset enable update checks for slices - for (slice_list_t::iterator it = mSlices->begin(); it != mSlices->end(); ++it) + for (auto slice : *mSlices) { - PieSlice* resetSlice = dynamic_cast(*it); - if (resetSlice) + if (auto resetSlice = dynamic_cast(slice); resetSlice) { resetSlice->resetUpdateEnabledCheck(); } @@ -564,7 +559,7 @@ BOOL PieMenu::handleMouseButtonUp(S32 x, S32 y, MASK mask) // release mouse capture after the first click if we still have it grabbed if (hasMouseCapture()) { - gFocusMgr.setMouseCapture(NULL); + gFocusMgr.setMouseCapture(nullptr); } // give control back to the system diff --git a/indra/newview/piemenu.h b/indra/newview/piemenu.h index 1efa77b278..5348431dad 100644 --- a/indra/newview/piemenu.h +++ b/indra/newview/piemenu.h @@ -31,7 +31,7 @@ #include "llmenugl.h" #include "llframetimer.h" -const S32 PIE_MAX_SLICES = 8; +constexpr S32 PIE_MAX_SLICES = 8; // PieChildRegistry contains a list of allowed child types for the XUI definition struct PieChildRegistry : public LLChildRegistry @@ -76,7 +76,7 @@ public: void hide(); // our item list type definition - typedef std::list slice_list_t; + typedef std::vector slice_list_t; // the actual item list slice_list_t mMySlices; // pointer to the currently used list diff --git a/indra/newview/pieslice.cpp b/indra/newview/pieslice.cpp index 2380333ced..e7fd8fe8cc 100644 --- a/indra/newview/pieslice.cpp +++ b/indra/newview/pieslice.cpp @@ -135,21 +135,21 @@ std::string PieSlice::getLabel() const } // accessor -void PieSlice::setLabel(const std::string& newLabel) +void PieSlice::setLabel(std::string_view newLabel) { mLabel = newLabel; } // accessor -bool PieSlice::getStartAutohide() +bool PieSlice::getStartAutohide() const { return mStartAutohide; } // accessor -bool PieSlice::getAutohide() +bool PieSlice::getAutohide() const { - return mStartAutohide | mAutohide; + return mStartAutohide || mAutohide; } void PieSlice::resetUpdateEnabledCheck() diff --git a/indra/newview/pieslice.h b/indra/newview/pieslice.h index 0b5381ec8d..82fbe0f44f 100644 --- a/indra/newview/pieslice.h +++ b/indra/newview/pieslice.h @@ -66,13 +66,13 @@ public: // accessor to expose the label to the outside (value is the same as label) std::string getLabel() const; - void setLabel(const std::string& newLabel); + void setLabel(std::string_view newLabel); LLSD getValue() const; void setValue(const LLSD& value); // accessor to expose the autohide feature - bool getStartAutohide(); - bool getAutohide(); + bool getStartAutohide() const; + bool getAutohide() const; // callback connection for the onCommit method to launch the specified function boost::signals2::connection setClickCallback(const commit_signal_t::slot_type& cb) From 084ee08f9bacef488a0cf1dba95d3bb7d7b205b1 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 7 Jan 2024 16:46:15 +0100 Subject: [PATCH 74/77] Fix some more... --- indra/newview/vjfloaterlocalmesh.cpp | 6 ++--- indra/newview/vjlocalmesh.cpp | 13 +++++----- indra/newview/vjlocalmeshimportdae.cpp | 35 +++++++++++++------------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/indra/newview/vjfloaterlocalmesh.cpp b/indra/newview/vjfloaterlocalmesh.cpp index 697a3842d9..2890280140 100644 --- a/indra/newview/vjfloaterlocalmesh.cpp +++ b/indra/newview/vjfloaterlocalmesh.cpp @@ -461,7 +461,7 @@ void LLFloaterLocalMesh::showLog() LLUUID file_id = scroll_ctrl_selected_column->getValue().asUUID(); auto log = LLLocalMeshSystem::getInstance()->getFileLog(file_id); - for (auto log_string : log) + for (const auto& log_string : log) { mLogPanel->appendText(log_string, true); } @@ -600,7 +600,7 @@ void LLFloaterLocalMesh::reloadLowerUI() if (!selected_file_id.isNull()) { const auto& fileinfo_vector = LLLocalMeshSystem::getInstance()->getFileInfoVector(); - for (auto fileinfo : fileinfo_vector) + for (const auto& fileinfo : fileinfo_vector) { if (selected_file_id == fileinfo.mLocalID) { @@ -672,7 +672,7 @@ void LLFloaterLocalMesh::reloadLowerUI() // and if it is loaded & active, fill object list if (selected_file_active && (!selected_object_list.empty())) { - for (auto object_name : selected_object_list) + for (const auto& object_name : selected_object_list) { objectlist_combo_box->addSimpleElement(object_name); } diff --git a/indra/newview/vjlocalmesh.cpp b/indra/newview/vjlocalmesh.cpp index 656525e0ab..f2f10671ca 100644 --- a/indra/newview/vjlocalmesh.cpp +++ b/indra/newview/vjlocalmesh.cpp @@ -267,7 +267,7 @@ void LLLocalMeshObject::fillVolume(LLLocalMeshFileLOD lod) new_face.allocateWeights(current_submesh->getSkin().size()); for (size_t weight_iter = 0; weight_iter < current_submesh->getSkin().size(); ++weight_iter) { - auto current_local_weight = current_submesh->getSkin()[weight_iter]; + const auto& current_local_weight = current_submesh->getSkin()[weight_iter]; LLVector4 current_v4_weight; for (int joint_iter = 0; joint_iter < 4; ++joint_iter) @@ -434,10 +434,9 @@ void LLLocalMeshFile::reloadLocalMeshObjects(bool initial_load) // clear it first just in case mSavedObjectSculptIDs.clear(); - for (auto& local_object : mLoadedObjectList) + for (const auto& local_object : mLoadedObjectList) { - auto id = local_object->getVolumeParams().getSculptID(); - mSavedObjectSculptIDs.push_back(id); + mSavedObjectSculptIDs.emplace_back(local_object->getVolumeParams().getSculptID()); } } @@ -546,7 +545,7 @@ void LLLocalMeshFile::reloadLocalMeshObjects(bool initial_load) change_happened = true; } - auto importer_log = importer_result.second; + const auto& importer_log = importer_result.second; log.reserve(log.size() + importer_log.size()); log.insert(log.end(), importer_log.begin(), importer_log.end()); break; @@ -708,9 +707,9 @@ void LLLocalMeshFile::updateVObjects() { for (size_t object_iter = 0; object_iter < mSavedObjectSculptIDs.size(); ++object_iter) { - auto local_obj_sculpt_id = mSavedObjectSculptIDs[object_iter]; + const auto& local_obj_sculpt_id = mSavedObjectSculptIDs[object_iter]; auto affected_vobject_ids = gObjectList.findMeshObjectsBySculptID(local_obj_sculpt_id); - for (auto current_vobject_id : affected_vobject_ids) + for (const auto& current_vobject_id : affected_vobject_ids) { auto target_object_ptr = static_cast(gObjectList.findObject(current_vobject_id)); diff --git a/indra/newview/vjlocalmeshimportdae.cpp b/indra/newview/vjlocalmeshimportdae.cpp index 8661496df9..8671db5d03 100644 --- a/indra/newview/vjlocalmeshimportdae.cpp +++ b/indra/newview/vjlocalmeshimportdae.cpp @@ -541,7 +541,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll extra_names.insert(extra_names.end(), more_extra_names.begin(), more_extra_names.end()); // add the extras to jointmap - for (auto extra_name : extra_names) + for (const auto& extra_name : extra_names) { joint_map[extra_name] = extra_name; } @@ -657,7 +657,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll auto name_source = current_source->getName_array(); if (name_source) { - auto list_of_names = name_source->getValue(); + const auto& list_of_names = name_source->getValue(); for (size_t joint_name_iter = 0; joint_name_iter < list_of_names.getCount(); ++joint_name_iter) { std::string current_name = list_of_names.get(joint_name_iter); @@ -674,7 +674,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll continue; } - auto list_of_names = id_source->getValue(); + const auto& list_of_names = id_source->getValue(); for (size_t joint_name_iter = 0; joint_name_iter < list_of_names.getCount(); ++joint_name_iter) { std::string current_name = list_of_names.get(joint_name_iter).getID(); @@ -729,7 +729,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll } LLMatrix4 newinverse = LLMatrix4(skininfop->mInvBindMatrix[jointname_number_iter].getF32ptr()); - auto joint_translation = joint_transforms[name_lookup].getTranslation(); + const auto& joint_translation = joint_transforms[name_lookup].getTranslation(); newinverse.setTranslation(joint_translation); skininfop->mAlternateBindMatrix.push_back( LLMatrix4a(newinverse) ); } @@ -755,7 +755,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll } std::vector transformed_positions; - auto vertex_input_array = raw_vertex_array->getInput_array(); + const auto& vertex_input_array = raw_vertex_array->getInput_array(); for (size_t vertex_input_iterator = 0; vertex_input_iterator < vertex_input_array.getCount(); ++vertex_input_iterator) { @@ -820,7 +820,7 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll return false; } - auto weight_inputs = current_weights->getInput_array(); + const auto& weight_inputs = current_weights->getInput_array(); domFloat_array* vertex_weights = nullptr; for (size_t weight_input_iter = 0; weight_input_iter < weight_inputs.getCount(); ++weight_input_iter) @@ -923,18 +923,18 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll }; auto& faces = current_object->getFaces(mLod); - for (auto& current_face : faces) + for (const auto& current_face : faces) { - auto& positions = current_face->getPositions(); + const auto& positions = current_face->getPositions(); auto& weights = current_face->getSkin(); - for (auto& current_position : positions) + for (const auto& current_position : positions) { int found_iterator = -1; for (size_t internal_position_iter = 0; internal_position_iter < transformed_positions.size(); ++internal_position_iter) { - auto& internal_position = transformed_positions[internal_position_iter]; + const auto& internal_position = transformed_positions[internal_position_iter]; if (soft_compare(current_position, internal_position, F_ALMOST_ZERO)) { found_iterator = internal_position_iter; @@ -947,9 +947,9 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll continue; } - auto cjoints = skinweight_data[transformed_positions[found_iterator]]; + const auto& cjoints = skinweight_data[transformed_positions[found_iterator]]; - LLLocalMeshFace::LLLocalMeshSkinUnit new_wght; + LLLocalMeshFace::LLLocalMeshSkinUnit new_wght{}; // first init all joints to -1, in case below we get less than 4 influences. for (size_t tjidx = 0; tjidx < 4; ++tjidx) @@ -966,13 +966,13 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll */ for (size_t jidx = 0; jidx < cjoints.size(); ++jidx) { - auto cjoint = cjoints[jidx]; + const auto& cjoint = cjoints[jidx]; new_wght.mJointIndices[jidx] = cjoint.mJointIdx; new_wght.mJointWeights[jidx] = llclamp((F32)cjoint.mWeight, 0.f, 0.999f); } - weights.push_back(new_wght); + weights.emplace_back(new_wght); } } skininfop->updateHash(); @@ -1019,8 +1019,7 @@ void LLLocalMeshImportDAE::processSkeletonJoint(domNode* current_node, std::map< if (!current_transformation) // no queries worked { daeSIDResolver jointResolver_matrix(current_node, "./matrix"); - auto joint_transform_matrix = daeSafeCast(jointResolver_matrix.getElement()); - if (joint_transform_matrix) + if (auto joint_transform_matrix = daeSafeCast(jointResolver_matrix.getElement()); joint_transform_matrix) { LLMatrix4 workingTransform; domFloat4x4 domArray = joint_transform_matrix->getValue(); @@ -1332,7 +1331,7 @@ bool LLLocalMeshImportDAE::readMesh_Triangle(LLLocalMeshFace* data_out, const do { // compare to check if you find one with matching normal and uv values size_t seeker_index = std::distance(repeat_map_position_iterable.begin(), seeker_position); - for (auto repeat_vtx_data : repeat_map_data[seeker_index]) + for (const auto& repeat_vtx_data : repeat_map_data[seeker_index]) { if (repeat_vtx_data.vtx_normal_data != attr_normal) { @@ -1563,7 +1562,7 @@ bool LLLocalMeshImportDAE::readMesh_Polylist(LLLocalMeshFace* data_out, const do { // compare to check if you find one with matching normal and uv values int seeker_index = std::distance(repeat_map_position_iterable.begin(), seeker_position); - for (auto repeat_vtx_data : repeat_map_data[seeker_index]) + for (const auto& repeat_vtx_data : repeat_map_data[seeker_index]) { if (repeat_vtx_data.vtx_normal_data != attr_normal) { From cfcbd6fc5458218090b6986e7f3a818135d73aa9 Mon Sep 17 00:00:00 2001 From: Zi Ree Date: Sun, 7 Jan 2024 18:45:08 +0100 Subject: [PATCH 75/77] Linux: selectively disable a few compiler warnings that are most likely bogus --- indra/newview/llface.cpp | 11 +++++++++++ indra/newview/llfasttimerview.cpp | 23 ++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index a1d0b920d7..4775686fc0 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1995,7 +1995,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, while (src < end) { LLVector4a normal; +// GCC12 warning: maybe-uninitialized - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif +// mat_normal.rotate(*src++, normal); +// GCC12 warning: maybe-uninitialized - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic pop +#endif +// normal.store4a(normals); normals += 4; } diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5cb2c89172..d710eafb68 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1223,9 +1223,20 @@ void LLFastTimerView::drawLegend() S32 scroll_offset = 0; // element's y offset from top of the inner scroll's rect ft_display_idx.clear(); std::map display_line; +// GCC12 warning: nonnull - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" +#endif +// for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != block_timer_tree_df_iterator_t(); ++it) +// GCC12 warning: nonnull - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic pop +#endif +// { BlockTimerStatHandle* idp = (*it); // Needed to figure out offsets and parenting @@ -1338,10 +1349,20 @@ void LLFastTimerView::generateUniqueColors() sTimerColors[FTM_FRAME.getIndex()] = LLColor4::grey; F32 hue = 0.f; - +// GCC12 warning: nonnull - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" +#endif +// for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != block_timer_tree_df_iterator_t(); ++it) +// GCC12 warning: nonnull - probably bogus +#if defined(__GNUC__) && (__GNUC__ >= 12) +#pragma GCC diagnostic pop +#endif +// { BlockTimerStatHandle* idp = (*it); From 7a0168c93179d14bdd1b9cef82f0231656338ef0 Mon Sep 17 00:00:00 2001 From: Beq Date: Sun, 7 Jan 2024 21:07:51 +0000 Subject: [PATCH 76/77] Add texture cache monitor to the texture view shows used vs max. --- indra/newview/lltextureview.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index f90fd6d0ab..6434944109 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -572,7 +572,8 @@ void LLGLTexMemBar::draw() // Texture memory bars S32 bar_left = 0; - S32 bar_width = 200; + constexpr S32 bar_width = 200; + constexpr S32 bar_space = 10; S32 top = line_height*6 - 2 + v_offset; S32 bottom = top - 6; S32 left = bar_left; @@ -585,7 +586,7 @@ void LLGLTexMemBar::draw() text = "VRAM"; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*6, text_color, LLFontGL::LEFT, LLFontGL::TOP); - left = left + 35; + left += 35; right = left + bar_width; gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); @@ -601,6 +602,29 @@ void LLGLTexMemBar::draw() gl_rect_2d(left, top, right, bottom, color); // + // Texture cache bars + bar_left = left + bar_width + bar_space; + left = bar_left; + // VRAM Mem Bar + text = "CACHE"; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*6, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + left += 35; + right = left + bar_width; + + gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); + gl_rect_2d(left, top, right, bottom); + + color = (cache_usage < cache_max_usage * 0.8f)? LLColor4::green : + (cache_usage < cache_max_usage)? LLColor4::yellow : LLColor4::red; + color[VALPHA] = .75f; + + bar_scale = (F32)bar_width / cache_max_usage; + right = left + llfloor(cache_usage * bar_scale); + + gl_rect_2d(left, top, right, bottom, color); + // U32 cache_read(0U), cache_write(0U), res_wait(0U); LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait); From 77395eddc911e0801e50fd693f7bbaee8046aa95 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 8 Jan 2024 14:22:05 -0500 Subject: [PATCH 77/77] Increment viewer version to 7.1.3 following promotion of DRTVWR-596 --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 0e7b60da8a..1996c50447 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.2 \ No newline at end of file +7.1.3