From 7947ce355964752d8385f11e2abdc4ca405c7e65 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 9 Apr 2024 00:05:05 +0300 Subject: triage#162 "Away" status is removed even by a random hover instead of having a 10 second delay to 'confirm' activity --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llappviewer.cpp | 17 +++++++++++++---- indra/newview/llviewerjoystick.cpp | 27 +++++++++++++++++++++++---- indra/newview/llviewerwindow.cpp | 20 +++++++++++++++----- 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9b9b29cd74..84a89251a4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -91,7 +91,7 @@ Type S32 Value - 300.0 + 300 AckCollectTime diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a1fecdb981..5002846262 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -454,11 +454,20 @@ void idle_afk_check() { // check idle timers F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); - if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) + LLCachedControl afk_timeout(gSavedSettings, "AFKTimeout", 300); + if (afk_timeout() && (current_idle > afk_timeout())) { - LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; - gAgent.setAFK(); + if (!gAgent.getAFK()) + { + LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; + gAgent.setAFK(); + } + else + { + // Refresh timer so that random one click or hover won't clear the status. + // But expanding the window still should lift afk status + gAwayTimer.reset(); + } } } diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e35cb26ce1..2bcec1ecee 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -806,6 +806,10 @@ void LLViewerJoystick::moveObjects(bool reset) { gAgent.clearAFK(); } + else + { + gAwayTriggerTimer.reset(); + } if (sDelta[0] || sDelta[1] || sDelta[2]) { @@ -980,6 +984,10 @@ void LLViewerJoystick::moveAvatar(bool reset) { gAgent.clearAFK(); } + else + { + gAwayTriggerTimer.reset(); + } setCameraNeedsUpdate(true); } @@ -1192,10 +1200,17 @@ void LLViewerJoystick::moveFlycam(bool reset) } // Clear AFK state if moved beyond the deadzone - if (!is_zero && gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) - { - gAgent.clearAFK(); - } + if (!is_zero) + { + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) + { + gAgent.clearAFK(); + } + else + { + gAwayTriggerTimer.reset(); + } + } sFlycamPosition += LLVector3(sDelta) * sFlycamRotation; @@ -1256,6 +1271,10 @@ bool LLViewerJoystick::toggleFlycam() { gAgent.clearAFK(); } + else + { + gAwayTriggerTimer.reset(); + } mOverrideCamera = !mOverrideCamera; if (mOverrideCamera) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 37e64dfc17..4a8edfcf89 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1425,11 +1425,17 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask mWindow->showCursorFromMouseMove(); - if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME - && !gDisconnected) - { - gAgent.clearAFK(); - } + if (!gDisconnected) + { + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) + { + gAgent.clearAFK(); + } + else + { + gAwayTriggerTimer.reset(); + } + } } void LLViewerWindow::handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask) @@ -1545,6 +1551,10 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { gAgent.clearAFK(); } + else + { + gAwayTriggerTimer.reset(); + } // *NOTE: We want to interpret KEY_RETURN later when it arrives as // a Unicode char, not as a keydown. Otherwise when client frame -- cgit v1.3 From a902138de15067a86a6aeb02fdabd094873da0b2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 10 Apr 2024 00:40:01 +0300 Subject: triage#166 Select 'No Description' when clicking on a text field Default value should be selected for replacement --- indra/llui/lltexteditor.cpp | 30 +- indra/llui/lltexteditor.h | 4 + indra/newview/llsidepaneliteminfo.cpp | 29 +- indra/newview/llsidepaneliteminfo.h | 2 + .../xui/en/floater_inventory_item_properties.xml | 421 --------------------- 5 files changed, 56 insertions(+), 430 deletions(-) delete mode 100644 indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index a247e8700a..82f99fe789 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -263,7 +263,9 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mShowEmojiHelper(p.show_emoji_helper), mEnableTooltipPaste(p.enable_tooltip_paste), mPassDelete(FALSE), - mKeepSelectionOnReturn(false) + mKeepSelectionOnReturn(false), + mSelectAllOnFocusReceived(false), + mSelectedOnFocusReceived(false) { mSourceID.generate(); @@ -385,6 +387,7 @@ void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insen setCursorPos(loc); mIsSelecting = TRUE; + mSelectedOnFocusReceived = false; mSelectionEnd = mCursorPos; mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } @@ -664,6 +667,13 @@ BOOL LLTextEditor::canSelectAll() const return TRUE; } +//virtual +void LLTextEditor::deselect() +{ + LLTextBase::deselect(); + mSelectedOnFocusReceived = false; +} + // virtual void LLTextEditor::selectAll() { @@ -681,6 +691,11 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p endSelection(); } +void LLTextEditor::setSelectAllOnFocusReceived(bool b) +{ + mSelectAllOnFocusReceived = b; +} + void LLTextEditor::insertEmoji(llwchar emoji) { LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; @@ -758,8 +773,16 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) // Delay cursor flashing resetCursorBlink(); + mSelectedOnFocusReceived = false; if (handled && !gFocusMgr.getMouseCapture()) { + if (!mask && mSelectAllOnFocusReceived) + { + mIsSelecting = false; + mSelectionStart = getLength(); + mSelectionEnd = 0; + mSelectedOnFocusReceived = true; + } gFocusMgr.setMouseCapture( this ); } return handled; @@ -2113,6 +2136,11 @@ void LLTextEditor::focusLostHelper() gEditMenuHandler = NULL; } + if (mSelectedOnFocusReceived) + { + deselect(); + } + if (mCommitOnFocusLost) { onCommit(); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 521405ec25..a4eec8874f 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -142,8 +142,10 @@ public: virtual BOOL canDoDelete() const; virtual void selectAll(); virtual BOOL canSelectAll() const; + virtual void deselect(); void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void setSelectAllOnFocusReceived(bool b); virtual bool canLoadOrSaveToFile(); @@ -331,6 +333,8 @@ private: bool mEnableTooltipPaste; bool mPassDelete; bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + bool mSelectAllOnFocusReceived; + bool mSelectedOnFocusReceived; LLUUID mSourceID; diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index d6d5a4ef2d..2045820090 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -56,6 +56,8 @@ #include "llviewerregion.h" +const char* const DEFAULT_DESC = "(No Description)"; + class PropertiesChangedCallback : public LLInventoryCallback { public: @@ -128,6 +130,7 @@ LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p) , mUpdatePendingId(-1) , mIsDirty(false) /*Not ready*/ , mParentFloater(NULL) + , mLabelItemDesc(NULL) { gInventory.addObserver(this); gIdleCallbacks.addFunction(&LLSidepanelItemInfo::onIdle, (void*)this); @@ -158,10 +161,11 @@ BOOL LLSidepanelItemInfo::postBuild() mItemTypeIcon = getChild("item_type_icon"); mLabelOwnerName = getChild("LabelOwnerName"); mLabelCreatorName = getChild("LabelCreatorName"); + mLabelItemDesc = getChild("LabelItemDesc"); getChild("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); getChild("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this)); - getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this)); + mLabelItemDesc->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this)); // Thumnail edition mChangeThumbnailBtn->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onEditThumbnail, this)); // acquired date @@ -342,10 +346,14 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards getChild("LabelItemName")->setValue(item->getName()); getChildView("LabelItemDescTitle")->setEnabled(TRUE); - getChildView("LabelItemDesc")->setEnabled(is_modifiable); - getChild("LabelItemDesc")->setValue(item->getDescription()); getChild("item_thumbnail")->setValue(item->getThumbnailUUID()); + // Asset upload substitutes empty description with a (No Description) placeholder + std::string desc = item->getDescription(); + mLabelItemDesc->setSelectAllOnFocusReceived(desc == DEFAULT_DESC); + mLabelItemDesc->setValue(desc); + mLabelItemDesc->setEnabled(is_modifiable); + LLUIImagePtr icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), FALSE); mItemTypeIcon->setImage(icon_img); @@ -927,17 +935,22 @@ void LLSidepanelItemInfo::onCommitDescription() LLViewerInventoryItem* item = findItem(); if(!item) return; - LLTextEditor* labelItemDesc = getChild("LabelItemDesc"); - if(!labelItemDesc) + if(!mLabelItemDesc) { return; } - if((item->getDescription() != labelItemDesc->getText()) && - (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))) + if (!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) + { + return; + } + std::string old_desc = item->getDescription(); + std::string new_desc = mLabelItemDesc->getText(); + if(old_desc != new_desc) { + mLabelItemDesc->setSelectAllOnFocusReceived(false); LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setDescription(labelItemDesc->getText()); + new_item->setDescription(new_desc); onCommitChanges(new_item); } } diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h index b916f44520..736420bac5 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -46,6 +46,7 @@ class LLObjectInventoryObserver; class LLViewerObject; class LLPermissions; class LLTextBox; +class LLTextEditor; class LLSidepanelItemInfo : public LLPanel, public LLInventoryObserver { @@ -105,6 +106,7 @@ private: LLIconCtrl* mItemTypeIcon; LLTextBox* mLabelOwnerName; LLTextBox* mLabelCreatorName; + LLTextEditor* mLabelItemDesc; // // UI Elements diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml deleted file mode 100644 index 850e1be372..0000000000 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ /dev/null @@ -1,421 +0,0 @@ - - - - (unknown) - - - (public) - - - You can: - - - Owner can: - - - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] - - - - Name: - - - - Description: - - - - Creator: - - - TestString PleaseIgnore - - Date: Mon, 11 Aug 2025 18:50:34 -0700 Subject: A ??) sequence was mis-interpreted by the pre-commit hooks as a trigraph sequence. --- indra/media_plugins/cef/media_plugin_cef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index d77eb83b00..3f45ac971a 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -617,7 +617,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); - // CEF 139 seems to have introduced a loading failure at the login page (only??) I haven't seen it on + // CEF 139 seems to have introduced a loading failure at the login page (only?) I haven't seen it on // any other page and it only happens about 1 in 8 times. Without this handler for the error page // (red box, error message/code/url) the page load recovers after display a brief built in error. // Not ideal but better than stopping altgoether. Will restore this once I discover the error. -- cgit v1.3 From ca069b5b4f28d465f6ff31499cfdb3aaeda618bc Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Aug 2025 22:42:34 +0300 Subject: #4522 Crash at shouldAllowFirstMediaInteraction --- indra/newview/lltoolpie.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 0fd9faab35..0a69be528f 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -1549,7 +1549,13 @@ bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool mo } // Further object detail required beyond this point - LLPermissions* perms = LLSelectMgr::getInstance()->getHoverNode()->mPermissions; + LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode(); + if (hover_node == nullptr) + { + LL_WARNS() << "No Hover node" << LL_ENDL; + return false; + } + LLPermissions* perms = hover_node->mPermissions; if(perms == nullptr) { LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL; -- cgit v1.3 From f03cd219a91740de9f406cfae5bbc15194156c78 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 11 Aug 2025 18:40:16 +0200 Subject: Fix clang compiler issues due to unused variables --- indra/llrender/llrendertarget.cpp | 16 ---------------- indra/newview/gltf/asset.cpp | 4 ++++ indra/newview/lldrawpoolwater.cpp | 2 -- indra/newview/llstartup.cpp | 2 -- indra/newview/llviewertexture.cpp | 2 -- indra/newview/llvoavatar.cpp | 8 -------- indra/newview/llvoicewebrtc.cpp | 4 ---- 7 files changed, 4 insertions(+), 34 deletions(-) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 38bc5ff331..0b0d69812f 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -492,22 +492,6 @@ U32 LLRenderTarget::getNumTextures() const void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options) { gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index), filter_options == LLTexUnit::TFO_TRILINEAR || filter_options == LLTexUnit::TFO_ANISOTROPIC); - - bool isSRGB = false; - llassert(mInternalFormat.size() > index); - switch (mInternalFormat[index]) - { - case GL_SRGB: - case GL_SRGB8: - case GL_SRGB_ALPHA: - case GL_SRGB8_ALPHA8: - isSRGB = true; - break; - - default: - break; - } - gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options); } diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index e24aea4a28..28f30ae1c9 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -589,7 +589,9 @@ bool Asset::prep() for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant) { +#ifdef SHOW_ASSERT U32 attribute_mask = 0; +#endif // for each mesh for (auto& mesh : mMeshes) { @@ -607,7 +609,9 @@ bool Asset::prep() // all primitives of a given variant and material should all have the same attribute mask llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask); +#ifdef SHOW_ASSERT attribute_mask |= primitive.mAttributeMask; +#endif } } } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 7d58511d41..cdf3244389 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -143,7 +143,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) gGL.setColorMask(true, true); LLColor3 light_diffuse(0, 0, 0); - F32 light_exp = 0.0f; LLEnvironment& environment = LLEnvironment::instance(); LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); @@ -170,7 +169,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) // Apply magic numbers translating light direction into intensities light_dir.normalize(); F32 ground_proj_sq = light_dir.mV[0] * light_dir.mV[0] + light_dir.mV[1] * light_dir.mV[1]; - light_exp = llmax(32.f, 256.f * powf(ground_proj_sq, 16.0f)); if (0.f < light_diffuse.normalize()) // Normalizing a color? Puzzling... { light_diffuse *= (1.5f + (6.f * ground_proj_sq)); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2409b71f00..ba7437798a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -342,13 +342,11 @@ void pump_idle_startup_network(void) { // while there are message to process: // process one then call display_startup() - S32 num_messages = 0; { LockMessageChecker lmc(gMessageSystem); while (lmc.checkAllMessages(gFrameCount, gServicePump)) { display_startup(); - ++num_messages; } lmc.processAcks(); } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 4a9dd1c1b6..1c3674de1d 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -524,7 +524,6 @@ void LLViewerTexture::updateClass() bool is_low = is_sys_low || over_pct > 0.f; static bool was_low = false; - static bool was_sys_low = false; if (is_low && !was_low) { @@ -542,7 +541,6 @@ void LLViewerTexture::updateClass() } was_low = is_low; - was_sys_low = is_sys_low; if (is_low) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dd59979a6c..283a80a1ed 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4766,14 +4766,6 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent) } bool visible = isVisible(); - bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing - bool is_attachment = false; - - if (is_control_avatar) - { - LLControlAvatar *cav = dynamic_cast(this); - is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects - } // For fading out the names above heads, only let the timer // run if we're visible. diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 627d759df4..72baa393cf 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2264,7 +2264,6 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) return; } - bool iceCompleted = false; LLSD body; if (!connection->mIceCandidates.empty() || connection->mIceCompleted) { @@ -2303,7 +2302,6 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) LLSD body_candidate; body_candidate["completed"] = true; body["candidate"] = body_candidate; - iceCompleted = connection->mIceCompleted; connection->mIceCompleted = false; } @@ -2926,7 +2924,6 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b return; } boost::json::object voice_data = voice_data_parsed.as_object(); - bool new_participant = false; boost::json::object mute; boost::json::object user_gain; for (auto &participant_elem : voice_data) @@ -2979,7 +2976,6 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b } } - new_participant |= joined; if (!participant && joined && (primary || !isSpatial())) { participant = LLWebRTCVoiceClient::getInstance()->addParticipantByID(mChannelID, agent_id, mRegionID); -- cgit v1.3 From e3d15a9146d375368066cdbcf2a45f40165175f1 Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Tue, 12 Aug 2025 09:02:07 -0700 Subject: Chore: Move message.xml to scripts/messages (#4501) * Move message.xml to scripts/messages Get rid of the top-level etc/ directory by moving its only contents: message.xml to scripts/messages * Move message.xml to app_settings * Remove unneeded inclusion in viewer_manifest.py --- etc/message.xml | 751 --------------------------------- indra/newview/CMakeLists.txt | 4 +- indra/newview/app_settings/message.xml | 751 +++++++++++++++++++++++++++++++++ indra/newview/viewer_manifest.py | 1 - 4 files changed, 753 insertions(+), 754 deletions(-) delete mode 100755 etc/message.xml create mode 100755 indra/newview/app_settings/message.xml diff --git a/etc/message.xml b/etc/message.xml deleted file mode 100755 index dee3fd72dd..0000000000 --- a/etc/message.xml +++ /dev/null @@ -1,751 +0,0 @@ - - - - serverDefaults - - - simulator - template - - spaceserver - template - - dataserver - template - - logDataserver - template - - inventoryDataserver - template - - rpcserver - template - - mapserver - template - - viewer - template - - - messages - - - - PacketAck - - flavor - template - trusted-sender - false - - - OpenCircuit - - flavor - llsd - trusted-sender - false - - - CloseCircuit - - flavor - template - trusted-sender - false - - - StartPingCheck - - flavor - template - trusted-sender - false - - - CompletePingCheck - - flavor - template - trusted-sender - false - - - AddCircuitCode - - flavor - template - trusted-sender - true - - - UseCircuitCode - - flavor - template - trusted-sender - false - - - CreateTrustedCircuit - - flavor - template - trusted-sender - false - - - RequestTrustedCircuit - - flavor - template - trusted-sender - true - - - - ReportAutosaveCrash - - flavor - template - trusted-sender - false - - - SetCPURatio - - flavor - template - trusted-sender - false - - - - CompleteAgentMovement - - flavor - template - trusted-sender - false - - - EconomyDataRequest - - flavor - template - trusted-sender - false - - - ViewerEffect - - flavor - template - trusted-sender - false - - - RegionHandshakeReply - - flavor - template - trusted-sender - false - - - - AgentUpdate - - flavor - template - trusted-sender - false - - - - ImagePacket - - flavor - template - trusted-sender - false - - - LayerData - - flavor - template - trusted-sender - false - - - ObjectUpdateCached - - flavor - template - trusted-sender - false - - - ObjectUpdateCompressed - - flavor - template - trusted-sender - false - - - ObjectUpdate - - flavor - template - trusted-sender - false - - - ImprovedTerseObjectUpdate - - flavor - template - trusted-sender - false - - - AvatarAnimation - - flavor - template - trusted-sender - false - - - ObjectAnimation - - flavor - template - trusted-sender - false - - - AvatarAppearance - - flavor - template - trusted-sender - false - - - - GodKickUser - - flavor - llsd - trusted-sender - false - - - RoutedMoneyBalanceReply - - flavor - llsd - trusted-sender - false - - - - EdgeDataPacket - - flavor - template - trusted-sender - true - - - CoarseLocationUpdate - - flavor - template - trusted-sender - true - only-send-latest - true - - - SimulatorLoad - - flavor - template - trusted-sender - true - - - EstablishAgentCommunication - - flavor - llsd - trusted-sender - true - - - AgentGroupDataUpdate - - flavor - llsd - trusted-sender - true - - - AgentDropGroup - - flavor - llsd - trusted-sender - true - - - ChatterBoxSessionStartReply - - flavor - llsd - trusted-sender - true - - - ChatterBoxSessionEventReply - - flavor - llsd - trusted-sender - true - - - ForceCloseChatterBoxSession - - flavor - llsd - trusted-sender - true - - - ChatterBoxSessionAgentListUpdates - - flavor - llsd - trusted-sender - true - - - ChatterBoxSessionUpdate - - flavor - llsd - trusted-sender - true - - - ChatterBoxInvitation - - flavor - llsd - trusted-sender - true - - - - ParcelVoiceInfoRequest - - flavor - llsd - trusted-sender - false - - - - DisplayNameUpdate - - flavor - llsd - trusted-sender - true - - - ParcelVoiceInfo - - flavor - llsd - trusted-sender - true - - - ParcelNavigateMedia - - flavor - llsd - trusted-sender - false - - - ParcelObjectOwnersReply - - flavor - llsd - trusted-sender - true - - - ParcelProperties - - flavor - llsd - trusted-sender - true - - - LandStatReply - - flavor - llsd - trusted-sender - true - - - PlacesReply - - flavor - llsd - trusted-sender - true - - - SetDisplayNameReply - - flavor - llsd - trusted-sender - true - - - SimConsoleResponse - - flavor - llsd - trusted-sender - true - - - DirLandReply - - flavor - llsd - trusted-sender - true - - - avatarnotesrequest - - service_name - avatar-notes - builder - template - trusted-sender - false - - - avatarclassifiedsrequest - - service_name - avatar-classifieds - builder - template - trusted-sender - false - - - avatarpicksrequest - - service_name - avatar-pick - builder - template - trusted-sender - false - - - pickinforequest - - service_name - pick-info - builder - template - trusted-sender - false - - - ProvisionVoiceAccountRequest - - flavor - llsd - trusted-sender - false - - - VoiceSignalingRequest - - flavor - llsd - trusted-sender - false - - - RequiredVoiceVersion - - flavor - llsd - trusted-sender - true - - - EnableSimulator - - flavor - llsd - trusted-sender - true - - - TeleportFinish - - flavor - llsd - trusted-sender - true - - - TeleportFailed - - flavor - llsd - trusted-sender - true - - - CrossedRegion - - flavor - llsd - trusted-sender - true - - - NavMeshStatusUpdate - - flavor - llsd - trusted-sender - true - - - AgentStateUpdate - - flavor - llsd - trusted-sender - true - - - - ScriptRunningReply - - flavor - llsd - trusted-sender - false - - - LandStatReply - - flavor - llsd - trusted-sender - false - - - StartGroupProposal - - flavor - llsd - trusted-sender - false - - - FetchInventoryDescendents - - flavor - template - trusted-sender - false - - - GroupProposalBallot - - flavor - llsd - trusted-sender - false - - - RpcScriptRequestInboundForward - - flavor - llsd - trusted-sender - false - - - ObjectPhysicsProperties - - flavor - llsd - trusted-sender - true - - - - capBans - - MapLayer - false - - MapLayerGod - false - - NewFileAgentInventory - false - - UpdateGestureAgentInventory - false - - UpdateNotecardAgentInventory - false - - UpdateScriptAgentInventory - false - - UpdateGestureTaskInventory - false - - UpdateNotecardTaskInventory - false - - UpdateScriptTaskInventory - false - - ViewerStartAuction - true - - ParcelGodReserveForNewbie - true - - SendUserReport - false - - SendUserReportWithScreenshot - false - - RequestTextureDownload - true - - EventQueueGet - false - - UntrustedSimulatorMessage - false - - SendPostcard - false - - SendPostcard2 - true - - SendPostcard3 - true - - ParcelVoiceInfoRequest - false - - ChatSessionRequest - false - - ProvisionVoiceAccountRequest - false - - VoiceSignalingRequest - false - - RemoteParcelRequest - false - - SearchStatTracking - false - - ParcelPropertiesUpdate - false - - EstateChangeInfo - true - - FetchInventoryDescendents2 - false - - FetchInventory2 - false - - FetchLibDescendents2 - false - - FetchLib2 - false - - UploadBakedTexture - true - - ObjectMedia - false - - ObjectMediaNavigate - false - - - - messageBans - - trusted - - - - untrusted - - - - - maxQueuedEvents - 100 - - diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 759a40fc08..8ed7876da1 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1664,7 +1664,7 @@ set(viewer_APPSETTINGS_FILES app_settings/toolbars.xml app_settings/trees.xml app_settings/viewerart.xml - ${CMAKE_SOURCE_DIR}/../etc/message.xml + app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg packages-info.txt featuretable.txt @@ -1758,7 +1758,7 @@ if (WINDOWS) set(COPY_INPUT_DEPENDENCIES # The following commented dependencies are determined at variably at build time. Can't do this here. - ${CMAKE_SOURCE_DIR}/../etc/message.xml + app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg ${SHARED_LIB_STAGING_DIR}/openjp2.dll ${SHARED_LIB_STAGING_DIR}/llwebrtc.dll diff --git a/indra/newview/app_settings/message.xml b/indra/newview/app_settings/message.xml new file mode 100755 index 0000000000..dee3fd72dd --- /dev/null +++ b/indra/newview/app_settings/message.xml @@ -0,0 +1,751 @@ + + + + serverDefaults + + + simulator + template + + spaceserver + template + + dataserver + template + + logDataserver + template + + inventoryDataserver + template + + rpcserver + template + + mapserver + template + + viewer + template + + + messages + + + + PacketAck + + flavor + template + trusted-sender + false + + + OpenCircuit + + flavor + llsd + trusted-sender + false + + + CloseCircuit + + flavor + template + trusted-sender + false + + + StartPingCheck + + flavor + template + trusted-sender + false + + + CompletePingCheck + + flavor + template + trusted-sender + false + + + AddCircuitCode + + flavor + template + trusted-sender + true + + + UseCircuitCode + + flavor + template + trusted-sender + false + + + CreateTrustedCircuit + + flavor + template + trusted-sender + false + + + RequestTrustedCircuit + + flavor + template + trusted-sender + true + + + + ReportAutosaveCrash + + flavor + template + trusted-sender + false + + + SetCPURatio + + flavor + template + trusted-sender + false + + + + CompleteAgentMovement + + flavor + template + trusted-sender + false + + + EconomyDataRequest + + flavor + template + trusted-sender + false + + + ViewerEffect + + flavor + template + trusted-sender + false + + + RegionHandshakeReply + + flavor + template + trusted-sender + false + + + + AgentUpdate + + flavor + template + trusted-sender + false + + + + ImagePacket + + flavor + template + trusted-sender + false + + + LayerData + + flavor + template + trusted-sender + false + + + ObjectUpdateCached + + flavor + template + trusted-sender + false + + + ObjectUpdateCompressed + + flavor + template + trusted-sender + false + + + ObjectUpdate + + flavor + template + trusted-sender + false + + + ImprovedTerseObjectUpdate + + flavor + template + trusted-sender + false + + + AvatarAnimation + + flavor + template + trusted-sender + false + + + ObjectAnimation + + flavor + template + trusted-sender + false + + + AvatarAppearance + + flavor + template + trusted-sender + false + + + + GodKickUser + + flavor + llsd + trusted-sender + false + + + RoutedMoneyBalanceReply + + flavor + llsd + trusted-sender + false + + + + EdgeDataPacket + + flavor + template + trusted-sender + true + + + CoarseLocationUpdate + + flavor + template + trusted-sender + true + only-send-latest + true + + + SimulatorLoad + + flavor + template + trusted-sender + true + + + EstablishAgentCommunication + + flavor + llsd + trusted-sender + true + + + AgentGroupDataUpdate + + flavor + llsd + trusted-sender + true + + + AgentDropGroup + + flavor + llsd + trusted-sender + true + + + ChatterBoxSessionStartReply + + flavor + llsd + trusted-sender + true + + + ChatterBoxSessionEventReply + + flavor + llsd + trusted-sender + true + + + ForceCloseChatterBoxSession + + flavor + llsd + trusted-sender + true + + + ChatterBoxSessionAgentListUpdates + + flavor + llsd + trusted-sender + true + + + ChatterBoxSessionUpdate + + flavor + llsd + trusted-sender + true + + + ChatterBoxInvitation + + flavor + llsd + trusted-sender + true + + + + ParcelVoiceInfoRequest + + flavor + llsd + trusted-sender + false + + + + DisplayNameUpdate + + flavor + llsd + trusted-sender + true + + + ParcelVoiceInfo + + flavor + llsd + trusted-sender + true + + + ParcelNavigateMedia + + flavor + llsd + trusted-sender + false + + + ParcelObjectOwnersReply + + flavor + llsd + trusted-sender + true + + + ParcelProperties + + flavor + llsd + trusted-sender + true + + + LandStatReply + + flavor + llsd + trusted-sender + true + + + PlacesReply + + flavor + llsd + trusted-sender + true + + + SetDisplayNameReply + + flavor + llsd + trusted-sender + true + + + SimConsoleResponse + + flavor + llsd + trusted-sender + true + + + DirLandReply + + flavor + llsd + trusted-sender + true + + + avatarnotesrequest + + service_name + avatar-notes + builder + template + trusted-sender + false + + + avatarclassifiedsrequest + + service_name + avatar-classifieds + builder + template + trusted-sender + false + + + avatarpicksrequest + + service_name + avatar-pick + builder + template + trusted-sender + false + + + pickinforequest + + service_name + pick-info + builder + template + trusted-sender + false + + + ProvisionVoiceAccountRequest + + flavor + llsd + trusted-sender + false + + + VoiceSignalingRequest + + flavor + llsd + trusted-sender + false + + + RequiredVoiceVersion + + flavor + llsd + trusted-sender + true + + + EnableSimulator + + flavor + llsd + trusted-sender + true + + + TeleportFinish + + flavor + llsd + trusted-sender + true + + + TeleportFailed + + flavor + llsd + trusted-sender + true + + + CrossedRegion + + flavor + llsd + trusted-sender + true + + + NavMeshStatusUpdate + + flavor + llsd + trusted-sender + true + + + AgentStateUpdate + + flavor + llsd + trusted-sender + true + + + + ScriptRunningReply + + flavor + llsd + trusted-sender + false + + + LandStatReply + + flavor + llsd + trusted-sender + false + + + StartGroupProposal + + flavor + llsd + trusted-sender + false + + + FetchInventoryDescendents + + flavor + template + trusted-sender + false + + + GroupProposalBallot + + flavor + llsd + trusted-sender + false + + + RpcScriptRequestInboundForward + + flavor + llsd + trusted-sender + false + + + ObjectPhysicsProperties + + flavor + llsd + trusted-sender + true + + + + capBans + + MapLayer + false + + MapLayerGod + false + + NewFileAgentInventory + false + + UpdateGestureAgentInventory + false + + UpdateNotecardAgentInventory + false + + UpdateScriptAgentInventory + false + + UpdateGestureTaskInventory + false + + UpdateNotecardTaskInventory + false + + UpdateScriptTaskInventory + false + + ViewerStartAuction + true + + ParcelGodReserveForNewbie + true + + SendUserReport + false + + SendUserReportWithScreenshot + false + + RequestTextureDownload + true + + EventQueueGet + false + + UntrustedSimulatorMessage + false + + SendPostcard + false + + SendPostcard2 + true + + SendPostcard3 + true + + ParcelVoiceInfoRequest + false + + ChatSessionRequest + false + + ProvisionVoiceAccountRequest + false + + VoiceSignalingRequest + false + + RemoteParcelRequest + false + + SearchStatTracking + false + + ParcelPropertiesUpdate + false + + EstateChangeInfo + true + + FetchInventoryDescendents2 + false + + FetchInventory2 + false + + FetchLibDescendents2 + false + + FetchLib2 + false + + UploadBakedTexture + true + + ObjectMedia + false + + ObjectMediaNavigate + false + + + + messageBans + + trusted + + + + untrusted + + + + + maxQueuedEvents + 100 + + diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 04c3fea93a..cf5e748513 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -63,7 +63,6 @@ class ViewerManifest(LLManifest): def construct(self): super(ViewerManifest, self).construct() self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") - self.path(src="../../etc/message.xml", dst="app_settings/message.xml") if self.is_packaging_viewer(): with self.prefix(src_dst="app_settings"): -- cgit v1.3 From 1bcdf6824ce74360b27e0ad0bc307c72171cf653 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 12 Aug 2025 19:52:23 +0300 Subject: #4473 Enable Zoom in to Self menu option in chat --- indra/newview/llchathistory.cpp | 2 +- indra/newview/llfloaterimcontainer.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index a48e22bc73..a966253c2c 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -936,7 +936,7 @@ protected: menu->setItemEnabled("Voice Call", false); menu->setItemEnabled("Chat History", false); menu->setItemEnabled("Invite Group", false); - menu->setItemEnabled("Zoom In", false); + menu->setItemEnabled("Zoom In", true); menu->setItemEnabled("Share", false); menu->setItemEnabled("Pay", false); menu->setItemEnabled("Block Unblock", false); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 4312c058a1..d821d9a4a5 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1540,6 +1540,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v // Beyond that point, if only the user agent is selected, everything is disabled if (is_single_select && (single_id == gAgentID)) { + if ("can_zoom_in" == item) + { + return true; + } if (is_moderator_option) { return enableModerateContextMenuItem(item, true); -- cgit v1.3 From ea24792fec5601162197653f6bc27de0272d18bd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 12 Aug 2025 19:55:13 +0300 Subject: #4524 LLControlVariable error --- indra/llxml/llcontrol.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index bb590ebd76..562a30e8d1 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -157,6 +157,9 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type, { if ((persist != PERSIST_NO) && mComment.empty()) { + // File isn't actually missing, but something is wrong with it + // so the main point is to warn user to reinstall + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; } //Push back versus setValue'ing here, since we don't want to call a signal yet -- cgit v1.3 From f7f06063c7fc6decbbf427b211c7cd61603aaca4 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 11 Aug 2025 16:12:35 -0700 Subject: Fix issue where p2p calls were coming up muted even thought the UI said they were not. --- indra/newview/llvoicewebrtc.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 194e855aa6..eae71ca454 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2795,8 +2795,12 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() } // update the peer connection with the various characteristics of // this connection. - // this connection will come up as muted, but will be set to the appropriate - // value later on. + // For spatial this connection will come up as muted, but will be set to the appropriate + // value later on when we determine the regions we connect to. + if (!isSpatial()) + { + mWebRTCAudioInterface->setMute(mMuted); + } mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume); LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID); setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL); -- cgit v1.3 From 9c6fd95bdb2bfd99a01c2f2a0dadcf14d3febac0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:35:48 +0300 Subject: Revert "Fix: ignore *pass-on* counters when detecting left-button grabs (#3990)" This reverts commit 65d70a8d8f211b462481e93f919a100c8b3b2af5. --- indra/newview/llagent.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 039bd4da2a..2161dbe19e 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3469,14 +3469,11 @@ void LLAgent::initOriginGlobal(const LLVector3d &origin_global) bool LLAgent::leftButtonGrabbed() const { - if (gAgentCamera.cameraMouselook()) - { - return mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0; - } - else - { - return mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0; - } + const bool camera_mouse_look = gAgentCamera.cameraMouselook(); + return (!camera_mouse_look && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0) + || (!camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); } bool LLAgent::rotateGrabbed() const -- cgit v1.3 From 922d2324d06326602fdf5770bc555e3e9f90e74b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:35:48 +0300 Subject: #4535 Revert "Fix: ignore *pass-on* counters when detecting left-button grabs (#3990)" This reverts commit 65d70a8d8f211b462481e93f919a100c8b3b2af5. --- indra/newview/llagent.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 83b3d26560..085155714a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3430,14 +3430,11 @@ void LLAgent::initOriginGlobal(const LLVector3d &origin_global) bool LLAgent::leftButtonGrabbed() const { - if (gAgentCamera.cameraMouselook()) - { - return mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0; - } - else - { - return mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0; - } + const bool camera_mouse_look = gAgentCamera.cameraMouselook(); + return (!camera_mouse_look && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0) + || (!camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); } bool LLAgent::rotateGrabbed() const -- cgit v1.3 From 82e6e42b9ee62af0e39049e3d789457fe1a41281 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 12 Aug 2025 22:13:51 +0300 Subject: #4527 Crash trying to upload a huge image Raw image permits only a 256 MB buffer so this isn't unexpected. --- indra/llimage/llimagebmp.cpp | 6 ++++++ indra/llimage/llimagedxt.cpp | 6 ++++++ indra/llimage/llimagejpeg.cpp | 6 ++++++ indra/llimagej2coj/llimagej2coj.cpp | 6 ++++++ indra/llkdu/llimagej2ckdu.cpp | 6 ++++++ indra/newview/llfloaterimagepreview.cpp | 4 +++- indra/newview/skins/default/xui/en/notifications.xml | 8 ++++++++ 7 files changed, 41 insertions(+), 1 deletion(-) diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 2a328675c2..c8f99380ea 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -558,6 +558,12 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL; } + if (raw_image->isBufferInvalid()) + { + setLastError("Invalid input, no buffer"); + return false; + } + setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components); U8 magic[14]; diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 6b960f9077..c3fd0c5aa8 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -329,6 +329,12 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_ { llassert_always(raw_image); + if (raw_image->isBufferInvalid()) + { + setLastError("Invalid input, no buffer"); + return false; + } + S32 ncomponents = raw_image->getComponents(); EFileFormat format; switch (ncomponents) diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 0e7ec365d4..effd33b410 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -491,6 +491,12 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) resetLastError(); + if (raw_image->isBufferInvalid()) + { + setLastError("Invalid input, no buffer"); + return false; + } + LLImageDataSharedLock lockIn(raw_image); LLImageDataLock lockOut(this); diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index c56e94aaa4..431f5aa001 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -897,6 +897,12 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible) { + if (raw_image.isBufferInvalid()) + { + base.setLastError("Invalid input, no buffer"); + return false; + } + JPEG2KEncode encode(comment_text, reversible); bool encoded = encode.encode(raw_image, base); if (!encoded) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 0d1f2b3006..b824fd8385 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -662,6 +662,12 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co bool vflip = true; bool hflip = false; + if (raw_image.isBufferInvalid()) + { + base.setLastError("Invalid input, no buffer"); + return false; + } + try { // Set up input image files diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 42a5df5d17..f883f04159 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -288,7 +288,9 @@ void LLFloaterImagePreview::onBtnOK() } else { - LLNotificationsUtil::add("ErrorEncodingImage"); + LLSD args; + args["REASON"] = LLImage::getLastThreadError(); + LLNotificationsUtil::add("ErrorEncodingImage", args); LL_WARNS() << "Error encoding image" << LL_ENDL; } } diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 773e7c311b..b182a241d8 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1320,6 +1320,14 @@ Error encoding snapshot. fail + + Failed to encode image, reason: [REASON] + fail + + Date: Wed, 13 Aug 2025 15:25:37 +0200 Subject: #4519 Check for "://" as schema separator in a SLURL Check for "://" as schema separator when testing if the passed in address contains a schema. A ':' alone could also indicate a port separator as part of the hostname and throw off the parsing. (#4543) --- indra/newview/llslurl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 9e567e3262..6238a1145c 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -71,10 +71,10 @@ LLSLURL::LLSLURL(const std::string& slurl) { LLURI slurl_uri; // parse the slurl as a uri - if (slurl.find(':') == std::string::npos) + if (slurl.find("://") == std::string::npos) { - // There may be no scheme ('secondlife:' etc.) passed in. In that case - // we want to normalize the slurl by putting the appropriate scheme + // There may be no scheme ('secondlife://', 'https://' etc.) passed in. In that + // case we want to normalize the slurl by putting the appropriate scheme // in front of the slurl. So, we grab the appropriate slurl base // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or // https:///region/ for Standalone grid (the word region, not the region name) -- cgit v1.3 From 024da37b8bbdf2daf7d7fa40b12229ee74b43df4 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Wed, 13 Aug 2025 13:48:55 -0400 Subject: Add support for Normalized Frametime Variation (NVFT) (#4395) * Add support for Normalized Frametime Variation (NVFT) * Add normalized period jitter --- indra/newview/llviewerstats.cpp | 30 ++++++++++++++++++++++ indra/newview/llviewerstats.h | 9 +++++++ .../newview/skins/default/xui/en/floater_stats.xml | 8 ++++++ 3 files changed, 47 insertions(+) diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index a4f308bbf9..d39d466205 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -234,6 +234,8 @@ LLTrace::SampleStatHandle FRAMETIME_JITTER_EVENTS("frametimeevents", "Numbe FRAMETIME_JITTER_EVENTS_LAST_MINUTE("frametimeeventslastmin", "Number of frametime events in the last minute."); LLTrace::SampleStatHandle NOTRMALIZED_FRAMETIME_JITTER_SESSION("normalizedframetimejitter", "Normalized frametime jitter over the session."); +LLTrace::SampleStatHandle NFTV("nftv", "Normalized frametime variation."); +LLTrace::SampleStatHandle NORMALIZED_FRAMTIME_JITTER_PERIOD("normalizedframetimejitterperiod", "Normalized frametime jitter over the last 5 seconds."); LLTrace::EventStatHandle > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); @@ -322,6 +324,8 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) sample(LLStatViewer::FRAMETIME_JITTER_CUMULATIVE, mTotalFrametimeJitter); sample(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION, mTotalFrametimeJitter / mTotalTime); + mLastNoramlizedSessionJitter = mTotalFrametimeJitter / mTotalTime; + static LLCachedControl frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f); if (time_diff - mLastTimeDiff > mLastTimeDiff * frameTimeEventThreshold()) @@ -360,6 +364,27 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) sample(LLStatViewer::FRAMETIME_JITTER_99TH, ninety_ninth_percentile); sample(LLStatViewer::FRAMETIME_JITTER_95TH, ninety_fifth_percentile); + F64 averageFrameTime = 0; + for (const auto& frame_time : mFrameTimes) + { + averageFrameTime += frame_time.value(); + } + averageFrameTime /= mFrameTimes.size(); + + sample(LLStatViewer::NFTV, frame_time_stddev / averageFrameTime); + mLastNormalizedFrametimeVariance = frame_time_stddev / averageFrameTime; + + // Add up all of the jitter values. + F64 totalJitter = 0; + for (const auto& frame_jitter : mFrameTimesJitter) + { + totalJitter += frame_jitter.value(); + } + + mLastNormalizedPeriodJitter = totalJitter / mLastFrameTimeSample; + + sample(LLStatViewer::NORMALIZED_FRAMTIME_JITTER_PERIOD, mLastNormalizedPeriodJitter); + mFrameTimes.clear(); mFrameTimesJitter.clear(); mLastFrameTimeSample = F64Seconds(0); @@ -648,6 +673,11 @@ void send_viewer_stats(bool include_preferences) // send fps only for time app spends in foreground agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); + + agent["normalized_session_jitter"] = LLViewerStats::instance().getLastNormalizedSessionJitter(); + agent["normalized_frametime_variance"] = LLViewerStats::instance().getLastNormalizedFrametimeVariance(); + agent["normalized_period_jitter"] = LLViewerStats::instance().getLastNormalizedPeriodJitter(); + agent["version"] = LLVersionInfo::instance().getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 63fb7d4a17..011269d7ee 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -271,6 +271,10 @@ public: LLTrace::Recording& getRecording() { return mRecording; } const LLTrace::Recording& getRecording() const { return mRecording; } + F64 getLastNormalizedSessionJitter() const { return mLastNoramlizedSessionJitter; } + F64 getLastNormalizedFrametimeVariance() const { return mLastNormalizedFrametimeVariance; } + F64 getLastNormalizedPeriodJitter() const { return mLastNormalizedPeriodJitter; } + private: LLTrace::Recording mRecording; @@ -286,6 +290,11 @@ private: F64Seconds mTimeSinceLastEventSample; std::vector mFrameTimes; // used for frame time stats std::vector mFrameTimesJitter; // used for frame time jitter stats + + F64 mLastNoramlizedSessionJitter; // used for frame time jitter stats + F64 mLastNormalizedFrametimeVariance; // Used when submitting jitter stats + F64 mLastNormalizedPeriodJitter; + }; static const F32 SEND_STATS_PERIOD = 300.0f; diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index f2309eb817..1600c422c3 100644 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -58,6 +58,14 @@ label="normalized sess. jitter" decimal_digits="4" stat="normalizedframetimejitter"/> + + Date: Wed, 13 Aug 2025 21:40:53 +0300 Subject: #4541 Cap image upload size to prevent issues --- indra/newview/llfloaterimagepreview.cpp | 12 ++++++++++++ indra/newview/skins/default/xui/en/strings.xml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index f883f04159..44e71e33f3 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -425,6 +425,18 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) return false; } + // raw image is limited to 256MB so need at least some upper limit that fits into that + constexpr S32 MAX_IMAGE_AREA = 8096 * 8096; + + if (image_info.getWidth() * image_info.getHeight() > MAX_IMAGE_AREA) + { + LLStringUtil::format_map_t args; + args["PIXELS"] = llformat("%dM", (S32)(MAX_IMAGE_AREA / 1000000)); + + mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + return false; + } + // Load the image LLPointer image = LLImageFormatted::createFromType(codec); if (image.isNull()) diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 21db7eba47..c48ba10cac 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3970,7 +3970,7 @@ Abuse Report [mthnum,datetime,slt]/[day,datetime,slt] none/none - Can't load images larger than [WIDTH]*[HEIGHT] + Can't load images larger than [PIXELS] pixels Incorrect image format. File is empty. Max outfit photo size is [WIDTH]*[HEIGHT]. Please resize or use another image -- cgit v1.3 From 4c65a43e1700f0a669006b08b1f4f10293f2e947 Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Thu, 14 Aug 2025 09:47:22 -0700 Subject: CMake 4.10 compatibility fixes (#4548) --- autobuild.xml | 18 +++++++++--------- indra/newview/CMakeLists.txt | 25 ++++++++++--------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index f792bac789..1d75fe5043 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1435,11 +1435,11 @@ creds github hash - 9e59c93c7110e87b4ff3db330f11a23c50e5000f + 7facda95e2f00c260513f3d4db42588fa8ba703c hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910560 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289774 name darwin64 @@ -1451,11 +1451,11 @@ creds github hash - 7ed994db5bafa9a7ad09a1b53da850a84715c65e + 01d08f13c7bc8d1b95b0330fa6833b7d8274e4d0 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910561 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289775 name linux64 @@ -1467,24 +1467,24 @@ creds github hash - 66824c02e0e5eabbfbe37bfb173360195f89697c + 6d00345c7d3471bc5f7c1218e014dd0f1a2c069b hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910562 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289778 name windows64 + copyright + Copyright (c) 2010, Linden Research, Inc. license internal license_file LICENSES/llphysicsextensions.txt - copyright - Copyright (c) 2010, Linden Research, Inc. version - 1.0.66e6919 + 1.0.11137145495 name llphysicsextensions_source diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1315baf740..62af812971 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1420,7 +1420,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n") set_source_files_properties( - llversioninfo.cpp tests/llversioninfo_test.cpp + llversioninfo.cpp tests/llversioninfo_test.cpp PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # see BuildVersion.cmake ) @@ -1635,7 +1635,7 @@ endif (WINDOWS) file(GLOB_RECURSE viewer_XUI_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/skins/*.xml) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/skins PREFIX "XUI Files" FILES ${viewer_XUI_FILES}) -set_source_files_properties(${viewer_XUI_FILES} +set_source_files_properties(${viewer_XUI_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) @@ -1643,7 +1643,7 @@ list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) file(GLOB_RECURSE viewer_SHADER_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders/*.glsl) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders PREFIX "Shaders" FILES ${viewer_SHADER_FILES}) -set_source_files_properties(${viewer_SHADER_FILES} +set_source_files_properties(${viewer_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES}) @@ -1970,7 +1970,7 @@ endif (WINDOWS) # one of these being libz where you can find four or more versions in play # at once. On Linux, libz can be found at link and run time via a number # of paths: -# +# # => -lfreetype # => libz.so.1 (on install machine, not build) # => -lSDL @@ -2046,7 +2046,7 @@ foreach(elem ${country_codes}) set(emoji_mapping_src_file "${emoji_mapping_src_folder}/${elem}/emoji_characters.xml") set(emoji_mapping_dst_file - "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") + "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY) endforeach() @@ -2148,7 +2148,7 @@ if (DARWIN) # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ set(CMAKE_MACOSX_RPATH 1) - + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES @@ -2191,9 +2191,6 @@ if (DARWIN) --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${VIEWER_BINARY_NAME} - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) @@ -2228,8 +2225,6 @@ if (DARWIN) --touch=${CMAKE_CURRENT_BINARY_DIR}/$,$,>/.${product}.bat --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt ${SIGNING_SETTING} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) endif (PACKAGE) endif (DARWIN) @@ -2269,7 +2264,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" XCODE_ATTRIBUTE_DWARF_DSYM_FOLDER_PATH "${SYMBOLS_STAGING_DIR}/dSYMs") - + add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}" COMMAND "zip" ARGS @@ -2304,7 +2299,7 @@ if (LL_TESTS) # llremoteparcelrequest.cpp llviewerhelputil.cpp llversioninfo.cpp -# llvocache.cpp +# llvocache.cpp llworldmap.cpp llworldmipmap.cpp ) @@ -2313,7 +2308,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp ) @@ -2347,7 +2342,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp ) -- cgit v1.3 From 479618097b14c477413086d6a2d4f40a411556ad Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 14 Aug 2025 21:06:31 +0300 Subject: #4541 Fix reused message it was also in use by local bitmaps --- indra/newview/llfloaterimagepreview.cpp | 2 +- indra/newview/skins/default/xui/en/strings.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 44e71e33f3..550c3adc27 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -433,7 +433,7 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) LLStringUtil::format_map_t args; args["PIXELS"] = llformat("%dM", (S32)(MAX_IMAGE_AREA / 1000000)); - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + mImageLoadError = LLTrans::getString("texture_load_area_error", args); return false; } diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index c48ba10cac..99c7d7b7d4 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3970,7 +3970,8 @@ Abuse Report [mthnum,datetime,slt]/[day,datetime,slt] none/none - Can't load images larger than [PIXELS] pixels + Can't load images larger than [PIXELS] pixels + Can't load images larger than [WIDTH]*[HEIGHT] Incorrect image format. File is empty. Max outfit photo size is [WIDTH]*[HEIGHT]. Please resize or use another image -- cgit v1.3 From 37a04baf104aa394615d8e8286522988ba56c09d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 14 Aug 2025 21:29:18 +0300 Subject: #4544 Add source format information to mesh upload statistics --- indra/newview/llfloatermodelpreview.cpp | 86 ++++++++++++++++++++++++++++++++- indra/newview/llfloatermodelpreview.h | 3 ++ indra/newview/llmeshrepository.cpp | 15 ++++-- indra/newview/llmeshrepository.h | 8 ++- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6a6766fb3f..08d3488ef2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -503,7 +503,10 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadModelUrl.clear(); mModelPhysicsFee.clear(); - gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, + lod_sources_map_t lod_sources; + fillLODSourceStatistics(lod_sources); + + gMeshRepo.uploadModel(mModelPreview->mUploadData, lod_sources, mModelPreview->mPreviewScale, childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, mUploadModelUrl, mDestinationFolderId, false, @@ -1317,8 +1320,84 @@ void LLFloaterModelPreview::createSmoothComboBox(LLComboBox* combo_box, float mi std::string label = (++ilabel == SMOOTH_VALUES_NUMBER) ? "10 (max)" : llformat("%.1d", ilabel); combo_box->add(label, value, ADD_BOTTOM, true); } +} + +std::string get_source_file_extr(const std::string& filename) +{ + if (std::string::npos != filename.rfind(".gltf") + || std::string::npos != filename.rfind(".glb")) + { + return "gltf"; + } + else if (std::string::npos != filename.rfind(".dae")) + { + return "dae"; + } + else if (std::string::npos != filename.rfind(".slm")) + { + return "slm"; + } + else + { + return "unknown file"; + } +} +void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_sources_map_t& lod_sources) const +{ + lod_sources.clear(); + // This doesn't nessesarily reflect the actual source of meshes, just user choices, + // some meshes could have been matched from different lods, but should be good + // enough for statistics. + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + const std::string &lod_string = lod_name[lod]; + if (mLODMode[lod] == LLModelPreview::USE_LOD_ABOVE) + { + lod_sources[lod_string] = "lod above"; + } + else if (mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_AUTO + || mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_PRECISE + || mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_SLOPPY) + { + lod_sources[lod_string] = "generated"; + } + else if (mLODMode[lod] == LLModelPreview::LOD_FROM_FILE) + { + const std::string& file = mModelPreview->mLODFile[lod]; + lod_sources[lod_string] = get_source_file_extr(file); + } + else + { + lod_sources[lod_string] = "unknown source"; + } + } + if (mModelPreview->mLODFile[LLModel::LOD_PHYSICS].empty()) + { + if (mModelPreview->mPhysicsSearchLOD >= 0 && mModelPreview->mPhysicsSearchLOD <= 3) + { + lod_sources["physics"] = lod_name[mModelPreview->mPhysicsSearchLOD]; + } + else + { + lod_sources["physics"] = "none"; + } + } + else + { + const std::string& file = mModelPreview->mLODFile[LLModel::LOD_PHYSICS]; + if (std::string::npos == file.rfind("cube.dae")) + { + // There is a chance it will misfire if someone tries to upload a cube.dae mesh, + // but should be negligible enough. + lod_sources["physics"] = get_source_file_extr(file); + } + else + { + lod_sources["physics"] = "bounding box"; + } + } } //----------------------------------------------------------------------------- @@ -1656,7 +1735,10 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions, lock_scale_if_joint_position); } - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + lod_sources_map_t lod_sources; + mp->fillLODSourceStatistics(lod_sources); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, lod_sources, mp->mModelPreview->mPreviewScale, mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, mp->mUploadModelUrl, mp->mDestinationFolderId, diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 7b652a3613..982f36c46e 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -223,6 +223,9 @@ private: void createSmoothComboBox(LLComboBox* combo_box, float min, float max); + typedef std::map lod_sources_map_t; + void fillLODSourceStatistics(lod_sources_map_t& lod_sources) const; + LLUUID mDestinationFolderId; LLButton* mUploadBtn; LLButton* mCalculateBtn; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 07d68fc3ec..fd3360b234 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2569,7 +2569,8 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_ return MESH_OK; } -LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, +LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, const LLMeshUploadThread::lod_sources_map_t& sources_list, + LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, const std::string & upload_url, LLUUID destination_folder_id, bool do_upload, LLHandle fee_observer, @@ -2584,6 +2585,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObserverHandle(upload_observer) { mInstanceList = data; + mLodSources = sources_list; mUploadTextures = upload_textures; mUploadSkin = upload_skin; mUploadJoints = upload_joints; @@ -2721,6 +2723,12 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector& res["mesh_list"] = LLSD::emptyArray(); res["texture_list"] = LLSD::emptyArray(); res["instance_list"] = LLSD::emptyArray(); + LLSD& lod_sources = res["source_format"]; + lod_sources["high"] = 0; + for (auto &source : mLodSources) + { + lod_sources[source.first] = source.second; + } S32 mesh_num = 0; S32 texture_num = 0; @@ -5026,12 +5034,13 @@ bool LLMeshRepoThread::hasHeader(const LLUUID& mesh_id) const return iter != mMeshHeader.end(); } -void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, +void LLMeshRepository::uploadModel(std::vector& data, const std::map &lod_sources, + LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, std::string upload_url, const LLUUID& destination_folder_id, bool do_upload, LLHandle fee_observer, LLHandle upload_observer) { - LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, + LLMeshUploadThread* thread = new LLMeshUploadThread(data, lod_sources, scale, upload_textures, upload_skin, upload_joints, lock_scale_if_joint_position, upload_url, destination_folder_id, do_upload, fee_observer, upload_observer); mUploadWaitList.push_back(thread); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 2b772f7803..ab17b921d6 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -691,6 +691,8 @@ public: }; typedef std::map, instance_list, LLUploadModelInstanceLess> instance_map; instance_map mInstance; + typedef std::map lod_sources_map_t; + lod_sources_map_t mLodSources; LLMutex* mMutex; S32 mPendingUploads; @@ -707,7 +709,8 @@ public: std::string mWholeModelUploadURL; LLUUID mDestinationFolderId; - LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures, + LLMeshUploadThread(instance_list& data, const lod_sources_map_t& sources_list, + LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, const std::string & upload_url, const LLUUID destination_folder_id = LLUUID::null, @@ -869,7 +872,8 @@ public: bool meshUploadEnabled(); bool meshRezEnabled(); - void uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, + void uploadModel(std::vector& data, const std::map &lod_sources, + LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, std::string upload_url, const LLUUID& destination_folder_id = LLUUID::null, -- cgit v1.3 From 548727ab00558976dc2574710d20bd35a9eedf0b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 15 Aug 2025 17:35:45 +0300 Subject: #4537 Some links were missing favorite options --- indra/newview/llinventorybridge.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 331754d009..1e6c5cf04a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -7805,6 +7805,15 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Properties")); addDeleteContextMenuOptions(items, disabled_items); + + if (isFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (isAgentInventory()) + { + items.push_back(std::string("Add to Favorites")); + } } addLinkReplaceMenuOption(items, disabled_items); hide_context_entries(menu, items, disabled_items); @@ -8031,6 +8040,15 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Find Original")); addDeleteContextMenuOptions(items, disabled_items); + + if (isFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (isAgentInventory()) + { + items.push_back(std::string("Add to Favorites")); + } } hide_context_entries(menu, items, disabled_items); } -- cgit v1.3 From d5cc91e1f1b7ea71d0866d91d4a39ab826957635 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 15 Aug 2025 19:55:22 +0300 Subject: #4559 Crash at killCacheEntry --- indra/newview/llviewermessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 44831aea03..7d39cc6059 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3669,7 +3669,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) gObjectList.killObject(objectp); } - if(delete_object) + if(delete_object && regionp) { regionp->killCacheEntry(local_id); } -- cgit v1.3 From 99001eaa4ffdac78953a64797d9d8163b9d32791 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 15 Aug 2025 20:03:30 +0300 Subject: #4561 Crash at initializeURLHistory --- indra/llui/llflatlistview.cpp | 2 +- indra/newview/llfloaterwebcontent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 5be20bd314..dfe0a71b74 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -69,7 +69,7 @@ const LLRect& LLFlatListView::getItemsRect() const bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/) { if (!item) return false; - if (value.isUndefined()) return false; + if (value.isUndefined()) return false; // item stays an orphan?!!! //force uniqueness of items, easiest check but unreliable if (item->getParent() == mItemsPanel) return false; diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index e1b6df6072..3ff84ac9b7 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -130,7 +130,7 @@ void LLFloaterWebContent::initializeURLHistory() for(; iter_history != end_history; ++iter_history) { std::string url = (*iter_history).asString(); - if(! url.empty()) + if(! url.empty() && url_list) url_list->addSimpleElement(url); } } -- cgit v1.3 From 68d3d5cd739693dd0bf42c93c02673e2dd74accc Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Fri, 15 Aug 2025 19:57:55 -0700 Subject: Remove unused vstool, files (#4500) Clean up of some unused files: - vstool - No longer used - indra/edit-me-to-trigger-new-build.txt - Shouldn't be needed... - win_crash_logger/* - Empty directory --- .gitattributes | 3 - indra/edit-me-to-trigger-new-build.txt | 1 - indra/tools/vstool/DispatchUtility.cs | 271 ------------ indra/tools/vstool/README.txt | 9 - indra/tools/vstool/VSTool.csproj | 98 ----- indra/tools/vstool/VSTool.exe | Bin 24576 -> 0 bytes indra/tools/vstool/VSTool.sln | 19 - indra/tools/vstool/app.config | 3 - indra/tools/vstool/main.cs | 733 --------------------------------- indra/win_crash_logger/README.txt | 3 - 10 files changed, 1140 deletions(-) delete mode 100644 indra/edit-me-to-trigger-new-build.txt delete mode 100644 indra/tools/vstool/DispatchUtility.cs delete mode 100644 indra/tools/vstool/README.txt delete mode 100755 indra/tools/vstool/VSTool.csproj delete mode 100755 indra/tools/vstool/VSTool.exe delete mode 100755 indra/tools/vstool/VSTool.sln delete mode 100644 indra/tools/vstool/app.config delete mode 100755 indra/tools/vstool/main.cs delete mode 100644 indra/win_crash_logger/README.txt diff --git a/.gitattributes b/.gitattributes index 30cc9de8f1..5c7f5b73b0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,5 @@ * text eol=lf -# VSTool (normalization disabled) -indra/tools/vstool/* -text - # Images *.bmp binary *.BMP binary diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt deleted file mode 100644 index 8b13789179..0000000000 --- a/indra/edit-me-to-trigger-new-build.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/indra/tools/vstool/DispatchUtility.cs b/indra/tools/vstool/DispatchUtility.cs deleted file mode 100644 index 6056ac55a1..0000000000 --- a/indra/tools/vstool/DispatchUtility.cs +++ /dev/null @@ -1,271 +0,0 @@ -#region Using Directives - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Reflection; -using System.Security.Permissions; - -#endregion - -namespace TestDispatchUtility -{ - /// - /// Provides helper methods for working with COM IDispatch objects that have a registered type library. - /// - public static class DispatchUtility - { - #region Private Constants - - private const int S_OK = 0; //From WinError.h - private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800 - - #endregion - - #region Public Methods - - /// - /// Gets whether the specified object implements IDispatch. - /// - /// An object to check. - /// True if the object implements IDispatch. False otherwise. - public static bool ImplementsIDispatch(object obj) - { - bool result = obj is IDispatchInfo; - return result; - } - - /// - /// Gets a Type that can be used with reflection. - /// - /// An object that implements IDispatch. - /// Whether an exception should be thrown if a Type can't be obtained. - /// A .NET Type that can be used with reflection. - /// If doesn't implement IDispatch. - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - public static Type GetType(object obj, bool throwIfNotFound) - { - RequireReference(obj, "obj"); - Type result = GetType((IDispatchInfo)obj, throwIfNotFound); - return result; - } - - /// - /// Tries to get the DISPID for the requested member name. - /// - /// An object that implements IDispatch. - /// The name of a member to lookup. - /// If the method returns true, this holds the DISPID on output. - /// If the method returns false, this value should be ignored. - /// True if the member was found and resolved to a DISPID. False otherwise. - /// If doesn't implement IDispatch. - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - public static bool TryGetDispId(object obj, string name, out int dispId) - { - RequireReference(obj, "obj"); - bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId); - return result; - } - - /// - /// Invokes a member by DISPID. - /// - /// An object that implements IDispatch. - /// The DISPID of a member. This can be obtained using - /// . - /// The arguments to pass to the member. - /// The member's return value. - /// - /// This can invoke a method or a property get accessor. - /// - public static object Invoke(object obj, int dispId, object[] args) - { - string memberName = "[DispId=" + dispId + "]"; - object result = Invoke(obj, memberName, args); - return result; - } - - /// - /// Invokes a member by name. - /// - /// An object. - /// The name of the member to invoke. - /// The arguments to pass to the member. - /// The member's return value. - /// - /// This can invoke a method or a property get accessor. - /// - public static object Invoke(object obj, string memberName, object[] args) - { - RequireReference(obj, "obj"); - Type type = obj.GetType(); - object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, - null, obj, args, null); - return result; - } - - #endregion - - #region Private Methods - - /// - /// Requires that the value is non-null. - /// - /// The type of the value. - /// The value to check. - /// The name of the value. - private static void RequireReference(T value, string name) where T : class - { - if (value == null) - { - throw new ArgumentNullException(name); - } - } - - /// - /// Gets a Type that can be used with reflection. - /// - /// An object that implements IDispatch. - /// Whether an exception should be thrown if a Type can't be obtained. - /// A .NET Type that can be used with reflection. - private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound) - { - RequireReference(dispatch, "dispatch"); - - Type result = null; - int typeInfoCount; - int hr = dispatch.GetTypeInfoCount(out typeInfoCount); - if (hr == S_OK && typeInfoCount > 0) - { - // Type info isn't usually culture-aware for IDispatch, so we might as well pass - // the default locale instead of looking up the current thread's LCID each time - // (via CultureInfo.CurrentCulture.LCID). - dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result); - } - - if (result == null && throwIfNotFound) - { - // If the GetTypeInfoCount called failed, throw an exception for that. - Marshal.ThrowExceptionForHR(hr); - - // Otherwise, throw the same exception that Type.GetType would throw. - throw new TypeLoadException(); - } - - return result; - } - - /// - /// Tries to get the DISPID for the requested member name. - /// - /// An object that implements IDispatch. - /// The name of a member to lookup. - /// If the method returns true, this holds the DISPID on output. - /// If the method returns false, this value should be ignored. - /// True if the member was found and resolved to a DISPID. False otherwise. - private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId) - { - RequireReference(dispatch, "dispatch"); - RequireReference(name, "name"); - - bool result = false; - - // Members names aren't usually culture-aware for IDispatch, so we might as well - // pass the default locale instead of looking up the current thread's LCID each time - // (via CultureInfo.CurrentCulture.LCID). - Guid iidNull = Guid.Empty; - int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId); - - const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h - const int DISPID_UNKNOWN = -1; //From OAIdl.idl - if (hr == S_OK) - { - result = true; - } - else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN) - { - // This is the only supported "error" case because it means IDispatch - // is saying it doesn't know the member we asked about. - result = false; - } - else - { - // The other documented result codes are all errors. - Marshal.ThrowExceptionForHR(hr); - } - - return result; - } - - #endregion - - #region Private Interfaces - - /// - /// A partial declaration of IDispatch used to lookup Type information and DISPIDs. - /// - /// - /// This interface only declares the first three methods of IDispatch. It omits the - /// fourth method (Invoke) because there are already plenty of ways to do dynamic - /// invocation in .NET. But the first three methods provide dynamic type metadata - /// discovery, which .NET doesn't provide normally if you have a System.__ComObject - /// RCW instead of a strongly-typed RCW. - /// - /// Note: The original declaration of IDispatch is in OAIdl.idl. - /// - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("00020400-0000-0000-C000-000000000046")] - private interface IDispatchInfo - { - /// - /// Gets the number of Types that the object provides (0 or 1). - /// - /// Returns 0 or 1 for the number of Types provided by . - /// - /// http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85) - /// - [PreserveSig] - int GetTypeInfoCount(out int typeInfoCount); - - /// - /// Gets the Type information for an object if returned 1. - /// - /// Must be 0. - /// Typically, LOCALE_SYSTEM_DEFAULT (2048). - /// Returns the object's Type information. - /// - /// http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85) - /// - void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, - MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo); - - /// - /// Gets the DISPID of the specified member name. - /// - /// Must be IID_NULL. Pass a copy of Guid.Empty. - /// The name of the member to look up. - /// Must be 1. - /// Typically, LOCALE_SYSTEM_DEFAULT (2048). - /// If a member with the requested - /// is found, this returns its DISPID and the method's return value is 0. - /// If the method returns a non-zero value, then this parameter's output value is - /// undefined. - /// Zero for success. Non-zero for failure. - /// - /// http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85) - /// - [PreserveSig] - int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId); - - // NOTE: The real IDispatch also has an Invoke method next, but we don't need it. - // We can invoke methods using .NET's Type.InvokeMember method with the special - // [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo - // and invoke methods on that through reflection. - // Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx - } - - #endregion - } -} diff --git a/indra/tools/vstool/README.txt b/indra/tools/vstool/README.txt deleted file mode 100644 index e419180031..0000000000 --- a/indra/tools/vstool/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -VSTool is a command line utility to manipulate VisualStudio settings. - -The windows cmake project configuration uses VSTool.exe - -A handy upgrade: - figure out how to make cmake build this csharp app - - or write the app using script (jscript?!?) so it doesn't need to be built. - - diff --git a/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj deleted file mode 100755 index 7f431e85c7..0000000000 --- a/indra/tools/vstool/VSTool.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {96943E2D-1373-4617-A117-D0F997A94919} - Debug - AnyCPU - - - - - VSTool - - - JScript - Grid - IE50 - false - Exe - VSTool - Always - VSTool.VSToolMain - - - - - v2.0 - 2.0 - - - .\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - - - false - false - false - false - 4 - full - prompt - - - .\ - false - 285212672 - false - - - TRACE - - - false - 4096 - false - - - true - false - false - false - 4 - none - prompt - - - - System - - - System.Data - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe deleted file mode 100755 index 751540413a..0000000000 Binary files a/indra/tools/vstool/VSTool.exe and /dev/null differ diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln deleted file mode 100755 index 21e3d75971..0000000000 --- a/indra/tools/vstool/VSTool.sln +++ /dev/null @@ -1,19 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/indra/tools/vstool/app.config b/indra/tools/vstool/app.config deleted file mode 100644 index 8494f728ff..0000000000 --- a/indra/tools/vstool/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs deleted file mode 100755 index 1d6b2f14d1..0000000000 --- a/indra/tools/vstool/main.cs +++ /dev/null @@ -1,733 +0,0 @@ -// Code about getting running instances visual studio -// was borrowed from -// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx - - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using Microsoft.CSharp; - -namespace VSTool -{ - // The MessageFilter class comes from: - // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx - // It allows vstool to get timing error messages from - // visualstudio and handle them. - public class MessageFilter : IOleMessageFilter - { - // - // Class containing the IOleMessageFilter - // thread error-handling functions. - - // Start the filter. - public static void Register() - { - IOleMessageFilter newFilter = new MessageFilter(); - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(newFilter, out oldFilter); - } - - // Done with the filter, close it. - public static void Revoke() - { - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(null, out oldFilter); - } - - // - // IOleMessageFilter functions. - // Handle incoming thread requests. - int IOleMessageFilter.HandleInComingCall(int dwCallType, - System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr - lpInterfaceInfo) - { - //Return the flag SERVERCALL_ISHANDLED. - return 0; - } - - // Thread call was rejected, so try again. - int IOleMessageFilter.RetryRejectedCall(System.IntPtr - hTaskCallee, int dwTickCount, int dwRejectType) - { - if (dwRejectType == 2) - // flag = SERVERCALL_RETRYLATER. - { - // Retry the thread call immediately if return >=0 & - // <100. - return 99; - } - // Too busy; cancel call. - return -1; - } - - int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, - int dwTickCount, int dwPendingType) - { - //Return the flag PENDINGMSG_WAITDEFPROCESS. - return 2; - } - - // Implement the IOleMessageFilter interface. - [DllImport("Ole32.dll")] - private static extern int - CoRegisterMessageFilter(IOleMessageFilter newFilter, out - IOleMessageFilter oldFilter); - } - - [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - interface IOleMessageFilter - { - [PreserveSig] - int HandleInComingCall( - int dwCallType, - IntPtr hTaskCaller, - int dwTickCount, - IntPtr lpInterfaceInfo); - - [PreserveSig] - int RetryRejectedCall( - IntPtr hTaskCallee, - int dwTickCount, - int dwRejectType); - - [PreserveSig] - int MessagePending( - IntPtr hTaskCallee, - int dwTickCount, - int dwPendingType); - } - - class ViaCOM - { - public static object GetProperty(object from_obj, string prop_name) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.GetProperty, null, - from_obj, - null); - } - catch (Exception e) - { - Console.WriteLine("Error getting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object SetProperty(object from_obj, string prop_name, object new_value) - { - try - { - object[] args = { new_value }; - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.SetProperty, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error setting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object CallMethod(object from_obj, string method_name, params object[] args) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - method_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.InvokeMethod, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error calling method \"{0}\"", method_name); - Console.WriteLine(e.Message); - throw e; - } - } - }; - - /// - /// The main entry point class for VSTool. - /// - class VSToolMain - { - #region Interop imports - [DllImport("ole32.dll")] - public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); - - [DllImport("ole32.dll")] - public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); - #endregion - - static System.Boolean ignore_case = true; - - static string solution_name = null; - static bool use_new_vs = false; - static Hashtable projectDict = new Hashtable(); - static string startup_project = null; - static string config = null; - - static object dte = null; - static object solution = null; - - /// - /// The main entry point for the application. - /// - [STAThread] - static int Main(string[] args) - { - int retVal = 0; - bool need_save = false; - - try - { - parse_command_line(args); - - Console.WriteLine("Editing solution: {0}", solution_name); - - bool found_open_solution = GetDTEAndSolution(); - - if (dte == null || solution == null) - { - retVal = 1; - } - else - { - MessageFilter.Register(); - - // Walk through all of the projects in the solution - // and list the type of each project. - foreach (DictionaryEntry p in projectDict) - { - string project_name = (string)p.Key; - string working_dir = (string)p.Value; - if (SetProjectWorkingDir(solution, project_name, working_dir)) - { - need_save = true; - } - } - - if (config != null) - { - need_save = SetActiveConfig(config); - } - - if (startup_project != null) - { - need_save = SetStartupProject(startup_project); - } - - if (need_save) - { - if (found_open_solution == false) - { - ViaCOM.CallMethod(solution, "Close", null); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - retVal = 1; - } - finally - { - if (solution != null) - { - Marshal.ReleaseComObject(solution); - solution = null; - } - - if (dte != null) - { - Marshal.ReleaseComObject(dte); - dte = null; - } - - MessageFilter.Revoke(); - } - return retVal; - } - - public static bool parse_command_line(string[] args) - { - string options_desc = - "--solution : MSVC solution name. (required)\n" + - "--use_new_vs : Ignore running versions of visual studio.\n" + - "--workingdir : Set working dir of a VC project.\n" + - "--config : Set the active config for the solution.\n" + - "--startup : Set the startup project for the solution.\n"; - - try - { - // Command line param parsing loop. - int i = 0; - for (; i < args.Length; ++i) - { - if ("--solution" == args[i]) - { - if (solution_name != null) - { - throw new ApplicationException("Found second --solution option"); - } - solution_name = args[++i]; - } - else if ("--use_new_vs" == args[i]) - { - use_new_vs = true; - } - - else if ("--workingdir" == args[i]) - { - string project_name = args[++i]; - string working_dir = args[++i]; - projectDict.Add(project_name, working_dir); - } - else if ("--config" == args[i]) - { - if (config != null) - { - throw new ApplicationException("Found second --config option"); - } - config = args[++i]; - } - else if ("--startup" == args[i]) - { - if (startup_project != null) - { - throw new ApplicationException("Found second --startup option"); - } - startup_project = args[++i]; - } - else - { - throw new ApplicationException("Found unrecognized token on command line: " + args[i]); - } - } - - if (solution_name == null) - { - throw new ApplicationException("The --solution option is required."); - } - } - catch(ApplicationException e) - { - - Console.WriteLine("Oops! " + e.Message); - Console.Write("Command line:"); - foreach (string arg in args) - { - Console.Write(" " + arg); - } - Console.Write("\n\n"); - Console.WriteLine("VSTool command line usage"); - Console.Write(options_desc); - throw e; - } - return true; - } - - public static bool GetDTEAndSolution() - { - bool found_open_solution = true; - - Console.WriteLine("Looking for existing VisualStudio instance..."); - - // Get an instance of the currently running Visual Studio .NET IDE. - // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1"); - string full_solution_name = System.IO.Path.GetFullPath(solution_name); - if (false == use_new_vs) - { - dte = GetIDEInstance(full_solution_name); - } - - if (dte == null) - { - try - { - Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance..."); - Console.WriteLine(" Reading .sln file version..."); - string version = GetSolutionVersion(full_solution_name); - - Console.WriteLine(" Using version: {0}...", version); - string progid = GetVSProgID(version); - - Type objType = Type.GetTypeFromProgID(progid); - dte = System.Activator.CreateInstance(objType); - Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name); - - solution = ViaCOM.GetProperty(dte, "Solution"); - object[] openArgs = { full_solution_name }; - ViaCOM.CallMethod(solution, "Open", openArgs); - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Quitting do to error opening: {0}", full_solution_name); - solution = null; - dte = null; - return found_open_solution; - } - found_open_solution = false; - } - - if (solution == null) - { - solution = ViaCOM.GetProperty(dte, "Solution"); - } - - return found_open_solution; - } - - /// - /// Get the DTE object for the instance of Visual Studio IDE that has - /// the specified solution open. - /// - /// The absolute filename of the solution - /// Corresponding DTE object or null if no such IDE is running - public static object GetIDEInstance( string solutionFile ) - { - Hashtable runningInstances = GetIDEInstances( true ); - IDictionaryEnumerator enumerator = runningInstances.GetEnumerator(); - - while ( enumerator.MoveNext() ) - { - try - { - object ide = enumerator.Value; - if (ide != null) - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case)) - { - return ide; - } - } - } - catch{} - } - - return null; - } - - /// - /// Get a table of the currently running instances of the Visual Studio .NET IDE. - /// - /// Only return instances that have opened a solution - /// A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object - public static Hashtable GetIDEInstances( bool openSolutionsOnly ) - { - Hashtable runningIDEInstances = new Hashtable(); - Hashtable runningObjects = GetRunningObjectTable(); - - IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); - while ( rotEnumerator.MoveNext() ) - { - string candidateName = (string) rotEnumerator.Key; - if (!candidateName.StartsWith("!VisualStudio.DTE")) - continue; - - object ide = rotEnumerator.Value; - if (ide == null) - continue; - - if (openSolutionsOnly) - { - try - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName"); - if (solutionFile != String.Empty) - { - runningIDEInstances[ candidateName ] = ide; - } - } - catch {} - } - else - { - runningIDEInstances[ candidateName ] = ide; - } - } - return runningIDEInstances; - } - - /// - /// Get a snapshot of the running object table (ROT). - /// - /// A hashtable mapping the name of the object in the ROT to the corresponding object - [STAThread] - public static Hashtable GetRunningObjectTable() - { - Hashtable result = new Hashtable(); - - int numFetched = 0; - IRunningObjectTable runningObjectTable; - IEnumMoniker monikerEnumerator; - IMoniker[] monikers = new IMoniker[1]; - - GetRunningObjectTable(0, out runningObjectTable); - runningObjectTable.EnumRunning(out monikerEnumerator); - monikerEnumerator.Reset(); - - while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0) - { - IBindCtx ctx; - CreateBindCtx(0, out ctx); - - string runningObjectName; - monikers[0].GetDisplayName(ctx, null, out runningObjectName); - - object runningObjectVal; - runningObjectTable.GetObject( monikers[0], out runningObjectVal); - - result[ runningObjectName ] = runningObjectVal; - } - - return result; - } - - public static string GetSolutionVersion(string solutionFullFileName) - { - string version; - System.IO.StreamReader solutionStreamReader = null; - string firstLine; - string format; - - try - { - solutionStreamReader = new System.IO.StreamReader(solutionFullFileName); - do - { - firstLine = solutionStreamReader.ReadLine(); - } - while (firstLine == ""); - - format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim(); - - switch(format) - { - case "7.00": - version = "VC70"; - break; - - case "8.00": - version = "VC71"; - break; - - case "9.00": - version = "VC80"; - break; - - case "10.00": - version = "VC90"; - break; - - case "11.00": - version = "VC100"; - break; - - case "12.00": - version = "VC150"; - break; - - default: - throw new ApplicationException("Unknown .sln version: " + format); - } - } - finally - { - if(solutionStreamReader != null) - { - solutionStreamReader.Close(); - } - } - - return version; - } - - public static string GetVSProgID(string version) - { - string progid = null; - switch(version) - { - case "VC70": - progid = "VisualStudio.DTE.7"; - break; - - case "VC71": - progid = "VisualStudio.DTE.7.1"; - break; - - case "VC80": - progid = "VisualStudio.DTE.8.0"; - break; - - case "VC90": - progid = "VisualStudio.DTE.9.0"; - break; - - case "VC100": - progid = "VisualStudio.DTE.10.0"; - break; - - case "VC120": - progid = "VisualStudio.DTE.12.0"; - break; - - case "VC150": - progid = "VisualStudio.DTE.15.0"; - break; - - default: - throw new ApplicationException("Can't handle VS version: " + version); - } - - return progid; - } - - public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir) - { - bool made_change = false; - Console.WriteLine("Looking for project {0}...", project_name); - try - { - object prjs = ViaCOM.GetProperty(sol, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for(int i = 1; i <= (int)count; ++i) - { - object[] prjItemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs); - string name = (string)ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare(name, project_name, ignore_case)) - { - Console.WriteLine("Found project: {0}", project_name); - Console.WriteLine("Setting working directory"); - - string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName"); - Console.WriteLine(full_project_name); - - // *NOTE:Mani Thanks to incompatibilities between different versions of the - // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to - // the VCProjectEngine types from a different version than the one built - // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built - // in VS 8.0. To avoid this problem, we can use the com object interfaces directly, - // without the type casting. Its tedious code, but it seems to work. - - // oCfgs should be assigned to a 'Project.Configurations' collection. - object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations"); - - // oCount will be assigned to the number of configs present in oCfgs. - object oCount = ViaCOM.GetProperty(oCfgs, "Count"); - - for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex) - { - object[] itemArgs = {(object)cfgIndex}; - object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs); - object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings"); - ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir); - } - - break; - } - } - made_change = true; - } - catch( Exception e ) - { - Console.WriteLine(e.Message); - Console.WriteLine("Failed to set working dir for project, {0}.", project_name); - } - - return made_change; - } - - public static bool SetStartupProject(string startup_project) - { - bool result = false; - try - { - // You need the 'unique name of the project to set StartupProjects. - // find the project by generic name. - Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project); - object prjs = ViaCOM.GetProperty(solution, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for (int i = 1; i <= (int)count; ++i) - { - object[] itemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs); - object prjName = ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare((string)prjName, startup_project, ignore_case)) - { - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName")); - Console.WriteLine(" Success!"); - result = true; - break; - } - } - - if (result == false) - { - Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project); - } - } - catch (Exception e) - { - Console.WriteLine(" Failed to set the startup project!"); - Console.WriteLine(e.Message); - } - return result; - } - - public static bool SetActiveConfig(string config) - { - bool result = false; - try - { - Console.WriteLine("Trying to set active config to \"{0}\"", config); - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations"); - object[] itemArgs = { (object)config }; - object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs); - ViaCOM.CallMethod(solCfg, "Activate", null); - Console.WriteLine(" Success!"); - result = true; - } - catch (Exception e) - { - Console.WriteLine(" Failed to set \"{0}\" as the active config.", config); - Console.WriteLine(e.Message); - } - return result; - } - } -} diff --git a/indra/win_crash_logger/README.txt b/indra/win_crash_logger/README.txt deleted file mode 100644 index 6932a8d9c3..0000000000 --- a/indra/win_crash_logger/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This component is no longer used in Linden Lab builds. -Change requests to support continued use by open source -builds are welcome. -- cgit v1.3 From 89b8490dedb3f8c41c6027da6af0be4552d81a23 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 16 Aug 2025 09:27:10 +0300 Subject: #4544 Fix extension check being case sensitive --- indra/newview/llfloatermodelpreview.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 08d3488ef2..96a03ce2a6 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1322,18 +1322,19 @@ void LLFloaterModelPreview::createSmoothComboBox(LLComboBox* combo_box, float mi } } -std::string get_source_file_extr(const std::string& filename) +std::string get_source_file_format(const std::string& filename) { - if (std::string::npos != filename.rfind(".gltf") - || std::string::npos != filename.rfind(".glb")) + const std::string extension = gDirUtilp->getExtension(filename); + if (extension == "gltf" + || extension == "glb") { return "gltf"; } - else if (std::string::npos != filename.rfind(".dae")) + else if (extension == "dae") { return "dae"; } - else if (std::string::npos != filename.rfind(".slm")) + else if (extension == "slm") { return "slm"; } @@ -1366,7 +1367,7 @@ void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_s else if (mLODMode[lod] == LLModelPreview::LOD_FROM_FILE) { const std::string& file = mModelPreview->mLODFile[lod]; - lod_sources[lod_string] = get_source_file_extr(file); + lod_sources[lod_string] = get_source_file_format(file); } else { @@ -1391,7 +1392,7 @@ void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_s { // There is a chance it will misfire if someone tries to upload a cube.dae mesh, // but should be negligible enough. - lod_sources["physics"] = get_source_file_extr(file); + lod_sources["physics"] = get_source_file_format(file); } else { -- cgit v1.3 From e7c506ba455f32eb8532f5e07bf83419126b5212 Mon Sep 17 00:00:00 2001 From: fmartian Date: Sun, 17 Aug 2025 02:34:50 +0200 Subject: Fix regex strings for Python 3.12+ Python 3.12 and newer does complain about single backslash in strings and is probably going to treat it as an error in some future version. Make the string constant a raw string. --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index cf5e748513..6991e0c8f2 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -273,13 +273,13 @@ class ViewerManifest(LLManifest): # All lines up to and including the first blank line are the file header; skip them lines.reverse() # so that pop will pull from first to last line - while not re.match("\s*$", lines.pop()) : + while not re.match(r"\s*$", lines.pop()) : pass # do nothing # A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names names = [] for line in lines : - if re.match("\S", line) : + if re.match(r"\S", line) : names.append(line.rstrip()) # It's not fair to always put the same people at the head of the list random.shuffle(names) -- cgit v1.3 From a9a2e7c633bbe289b553762741adfe9e4ad94928 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 18 Aug 2025 16:21:01 +0300 Subject: #4557 fix lags in outfit search with many outfits --- indra/newview/lloutfitslist.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index cb2a6191fa..4e594af432 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -254,7 +254,11 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) // for reliability just fetch it whole, linked items included LLInventoryModelBackgroundFetch::instance().fetchFolderAndLinks(cat_id, [cat_id, list] { - if (list) list->updateList(cat_id); + if (list) + { + list->updateList(cat_id); + list->setForceRefresh(true); + } }); } else @@ -264,6 +268,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) // Refresh the list of outfit items after fetch(). // Further list updates will be triggered by the category observer. list->updateList(cat_id); + list->setForceRefresh(true); } // If filter is currently applied we store the initial tab state. @@ -590,7 +595,7 @@ void LLOutfitsList::onFilterSubStringChanged(const std::string& new_string, cons LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (list) { - list->setFilterSubString(new_string, true); + list->setFilterSubString(new_string, tab->getDisplayChildren()); } if (old_string.empty()) -- cgit v1.3 From 181273f92990e5e37ca8f15c1d7d80d784b1ad77 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 3 Aug 2024 15:42:06 +0200 Subject: Change another case of a regex sequence needing to be a raw string --- scripts/packages-formatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/packages-formatter.py b/scripts/packages-formatter.py index 4449111e46..5d31702e76 100755 --- a/scripts/packages-formatter.py +++ b/scripts/packages-formatter.py @@ -42,7 +42,7 @@ _autobuild_env=os.environ.copy() # Coerce stdout encoding to utf-8 as cygwin's will be detected as cp1252 otherwise. _autobuild_env["PYTHONIOENCODING"] = "utf-8" -pkg_line=re.compile('^([\w-]+):\s+(.*)$') +pkg_line=re.compile(r'^([\w-]+):\s+(.*)$') def autobuild(*args): """ -- cgit v1.3 From 89c373c20b6032bab819e99cc8ace7b7e6b92360 Mon Sep 17 00:00:00 2001 From: fmartian Date: Mon, 18 Aug 2025 21:16:54 +0200 Subject: Add new LastModified option to HttpRequest handling (#4563) * Add LastModified: option to the HttpOptions and handle it properly in HttpOpRequest::prepareRequest() * grid_name could be empty if an invalid grid was passed in. --- indra/llcorehttp/_httpoprequest.cpp | 13 +++++++++++++ indra/llcorehttp/httpoptions.cpp | 6 ++++++ indra/llcorehttp/httpoptions.h | 8 ++++++++ indra/newview/llviewernetwork.cpp | 4 ++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 6186e7a308..081a4d9bac 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -538,6 +538,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) long sslHostV(0L); long dnsCacheTimeout(-1L); long nobody(0L); + curl_off_t lastModified(0L); if (mReqOptions) { @@ -546,6 +547,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L; dnsCacheTimeout = mReqOptions->getDNSCacheTimeout(); nobody = mReqOptions->getHeadersOnly() ? 1L : 0L; + lastModified = (curl_off_t)mReqOptions->getLastModified(); } check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); @@ -554,6 +556,17 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) check_curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody); + if (lastModified) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); +#if (LIBCURL_VERSION_NUM >= 0x073B00) + // requires curl 7.59.0 + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE_LARGE, lastModified); +#else + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE, (long)lastModified); +#endif + } + // The Linksys WRT54G V5 router has an issue with frequent // DNS lookups from LAN machines. If they happen too often, // like for every HTTP request, the router gets annoyed after diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index d85f6039b1..5abd28e211 100644 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -47,6 +47,7 @@ HttpOptions::HttpOptions() : mVerifyPeer(sDefaultVerifyPeer), mVerifyHost(false), mDNSCacheTimeout(-1L), + mLastModified(0), mNoBody(false) {} @@ -129,6 +130,11 @@ void HttpOptions::setHeadersOnly(bool nobody) } } +void HttpOptions::setLastModified(time_t lastModified) +{ + mLastModified = lastModified; +} + void HttpOptions::setDefaultSSLVerifyPeer(bool verify) { sDefaultVerifyPeer = verify; diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 56a28013cb..fdb277c66e 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -178,6 +178,13 @@ public: return mNoBody; } + // Default: 0 + void setLastModified(time_t lastModified); + time_t getLastModified() const + { + return mLastModified; + } + /// Sets default behavior for verifying that the name in the /// security certificate matches the name of the host contacted. /// Defaults false if not set, but should be set according to @@ -199,6 +206,7 @@ protected: bool mVerifyHost; int mDNSCacheTimeout; bool mNoBody; + time_t mLastModified; static bool sDefaultVerifyPeer; }; // end class HttpOptions diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 16ddc2f89c..f11fa09ce9 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -450,7 +450,7 @@ std::string LLGridManager::getGridLabel(const std::string& grid) { std::string grid_label; std::string grid_name = getGrid(grid); - if (!grid.empty()) + if (!grid_name.empty()) { grid_label = mGridList[grid_name][GRID_LABEL_VALUE].asString(); } @@ -466,7 +466,7 @@ std::string LLGridManager::getGridId(const std::string& grid) { std::string grid_id; std::string grid_name = getGrid(grid); - if (!grid.empty()) + if (!grid_name.empty()) { grid_id = mGridList[grid_name][GRID_ID_VALUE].asString(); } -- cgit v1.3 From b96c7ec6e6e2e4f2bfd11469155bec4827ac9517 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 18 Aug 2025 22:15:51 +0300 Subject: #4518 Dupplicates can appear in favorites if parent and child gets added back to back --- indra/newview/llinventorypanel.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index b540e9c5bb..b2dd47548c 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -2298,6 +2298,7 @@ public: void removeItemID(const LLUUID& id) override; bool isInRootContent(const LLUUID& id, LLFolderViewItem* view_item) override; + bool hasPredecessorsInRootContent(const LLInventoryObject* model_item) const; protected: LLInventoryFavoritesItemsPanel(const Params&); @@ -2344,6 +2345,24 @@ bool LLInventoryFavoritesItemsPanel::isInRootContent(const LLUUID& id, LLFolderV return found != mRootContentIDs.end(); } +bool LLInventoryFavoritesItemsPanel::hasPredecessorsInRootContent(const LLInventoryObject* obj) const +{ + LLUUID parent_id = obj->getParentUUID(); + while (parent_id.notNull()) + { + if (mRootContentIDs.contains(parent_id)) + { + return true; + } + LLViewerInventoryCategory* cat = mInventory->getCategory(parent_id); + if (cat) + { + parent_id = cat->getParentUUID(); + } + } + return false; +} + void LLInventoryFavoritesItemsPanel::findAndInitRootContent(const LLUUID& id) { F64 curent_time = LLTimer::getTotalSeconds(); @@ -2495,7 +2514,8 @@ void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, con } LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); - if (!folder_view_item) + if (!folder_view_item + && !hasPredecessorsInRootContent(model_item)) { const LLUUID& parent_id = cat->getParentUUID(); mRootContentIDs.emplace(cat->getUUID()); @@ -2507,7 +2527,9 @@ void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, con else { // New favorite item - if (model_item->getIsFavorite() && typedViewsFilter(id, model_item)) + if (model_item->getIsFavorite() + && typedViewsFilter(id, model_item) + && !hasPredecessorsInRootContent(model_item)) { const LLUUID& parent_id = model_item->getParentUUID(); mRootContentIDs.emplace(id); -- cgit v1.3 From 434f9e927135d961b51b2175960a27be3908f7c3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 18 Aug 2025 21:36:45 +0300 Subject: #4544 Make model dump go into logs not into work folder, viewer isn't supposed to write there. --- indra/newview/llfloatermodelpreview.cpp | 16 ++++++++++------ indra/newview/llfloatermodelpreview.h | 1 + indra/newview/llmeshrepository.cpp | 2 ++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 96a03ce2a6..f76f39222b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1090,9 +1090,7 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) } else if (which_mode == cube_mode) { - std::string path = gDirUtilp->getAppRODataDir(); - gDirUtilp->append(path, "cube.dae"); - sInstance->loadModel(LLModel::LOD_PHYSICS, path); + sInstance->loadModel(LLModel::LOD_PHYSICS, getBoundingBoxCubePath()); } LLModelPreview *model_preview = sInstance->mModelPreview; @@ -1344,6 +1342,13 @@ std::string get_source_file_format(const std::string& filename) } } +std::string LLFloaterModelPreview::getBoundingBoxCubePath() +{ + std::string path = gDirUtilp->getAppRODataDir(); + gDirUtilp->append(path, "cube.dae"); + return path; +} + void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_sources_map_t& lod_sources) const { lod_sources.clear(); @@ -1388,10 +1393,9 @@ void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_s else { const std::string& file = mModelPreview->mLODFile[LLModel::LOD_PHYSICS]; - if (std::string::npos == file.rfind("cube.dae")) + const std::string cube = getBoundingBoxCubePath(); + if (cube != file) // check for "cube.dae" { - // There is a chance it will misfire if someone tries to upload a cube.dae mesh, - // but should be negligible enough. lod_sources["physics"] = get_source_file_format(file); } else diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 982f36c46e..20e5b2666a 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -223,6 +223,7 @@ private: void createSmoothComboBox(LLComboBox* combo_box, float min, float max); + static std::string getBoundingBoxCubePath(); typedef std::map lod_sources_map_t; void fillLODSourceStatistics(lod_sources_map_t& lod_sources) const; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index fd3360b234..9e8ed3bb43 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2685,6 +2685,8 @@ void dump_llsd_to_file(const LLSD& content, std::string filename) { if (gSavedSettings.getBOOL("MeshUploadLogXML")) { + filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + filename); llofstream of(filename.c_str()); LLSDSerialize::toPrettyXML(content,of); } -- cgit v1.3 From 77514ebddd68ca47bc3751f0a6e55a83deec79a9 Mon Sep 17 00:00:00 2001 From: Rye Date: Mon, 18 Aug 2025 21:26:20 -0400 Subject: Fix macOS deprecation warnings --- indra/llprimitive/lldaeloader.cpp | 2 +- indra/llwindow/llopenglview-objc.h | 13 ------ indra/llwindow/llopenglview-objc.mm | 82 ++++++++++----------------------- indra/llwindow/llwindowmacosx-objc.mm | 3 +- indra/newview/llappdelegate-objc.mm | 2 +- indra/newview/llappviewermacosx-objc.h | 3 -- indra/newview/llappviewermacosx-objc.mm | 39 ---------------- indra/newview/llfilepicker_mac.mm | 6 +-- indra/newview/llfloateremojipicker.cpp | 4 +- indra/newview/llfloateruipreview.cpp | 3 +- 10 files changed, 36 insertions(+), 121 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 0759447902..4c028e7128 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1314,7 +1314,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do { //Build a joint for the resolver to work with char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str() ); + snprintf(str, sizeof(str), "./%s",(*jointIt).first.c_str() ); //LL_WARNS()<<"Joint "<< str < + extern BOOL gHiDPISupport; #pragma mark local functions @@ -105,20 +107,6 @@ attributedStringInfo getSegments(NSAttributedString *str) return screen; } - -- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint -{ - float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x)); - float normalizedY = aPoint.y - self.frame.origin.y; - - return NSMakePoint(normalizedX, normalizedY); -} - -- (NSPoint)flipPoint:(NSPoint)aPoint -{ - return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y); -} - @end @implementation LLOpenGLView @@ -244,7 +232,7 @@ attributedStringInfo getSegments(NSAttributedString *str) - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync { - [self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]]; + [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeURL]]; [self initWithFrame:frame]; // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6. @@ -295,13 +283,13 @@ attributedStringInfo getSegments(NSAttributedString *str) if (vsync) { GLint value = 1; - [glContext setValues:&value forParameter:NSOpenGLCPSwapInterval]; + [glContext setValues:&value forParameter:NSOpenGLContextParameterSwapInterval]; } else { // supress this error after move to Xcode 7: // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull] // Tried using ObjC 'nonnull' keyword as per SO article but didn't build GLint swapInterval=0; - [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; + [glContext setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval]; } mOldResize = false; @@ -355,13 +343,13 @@ attributedStringInfo getSegments(NSAttributedString *str) mMousePos[1] = mPoint.y; // Apparently people still use this? - if ([theEvent modifierFlags] & NSCommandKeyMask && - !([theEvent modifierFlags] & NSControlKeyMask) && - !([theEvent modifierFlags] & NSShiftKeyMask) && - !([theEvent modifierFlags] & NSAlternateKeyMask) && - !([theEvent modifierFlags] & NSAlphaShiftKeyMask) && - !([theEvent modifierFlags] & NSFunctionKeyMask) && - !([theEvent modifierFlags] & NSHelpKeyMask)) + if ([theEvent modifierFlags] & NSEventModifierFlagCommand && + !([theEvent modifierFlags] & NSEventModifierFlagControl) && + !([theEvent modifierFlags] & NSEventModifierFlagShift) && + !([theEvent modifierFlags] & NSEventModifierFlagOption) && + !([theEvent modifierFlags] & NSEventModifierFlagCapsLock) && + !([theEvent modifierFlags] & NSEventModifierFlagFunction) && + !([theEvent modifierFlags] & NSEventModifierFlagHelp)) { callRightMouseDown(mMousePos, [theEvent modifierFlags]); mSimulatedRightClick = true; @@ -511,7 +499,7 @@ attributedStringInfo getSegments(NSAttributedString *str) if (acceptsText && !mMarkedTextAllowed && - !(mModifiers & (NSControlKeyMask | NSCommandKeyMask)) && // commands don't invoke InputWindow + !(mModifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) && // commands don't invoke InputWindow ![(LLAppDelegate*)[NSApp delegate] romanScript] && ch > ' ' && ch != NSDeleteCharacter && @@ -534,14 +522,14 @@ attributedStringInfo getSegments(NSAttributedString *str) NSInteger mask = 0; switch([theEvent keyCode]) { - case 56: - mask = NSShiftKeyMask; + case kVK_Shift: + mask = NSEventModifierFlagShift; break; - case 58: - mask = NSAlternateKeyMask; + case kVK_Option: + mask = NSEventModifierFlagOption; break; - case 59: - mask = NSControlKeyMask; + case kVK_Control: + mask = NSEventModifierFlagControl; break; default: return; @@ -582,7 +570,7 @@ attributedStringInfo getSegments(NSAttributedString *str) pboard = [sender draggingPasteboard]; - if ([[pboard types] containsObject:NSURLPboardType]) + if ([[pboard types] containsObject:NSPasteboardTypeURL]) { if (sourceDragMask & NSDragOperationLink) { NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0]; @@ -657,7 +645,7 @@ attributedStringInfo getSegments(NSAttributedString *str) }; int string_length = [aString length]; - unichar text[string_length]; + unichar* text = (unichar*)malloc(sizeof(unichar) * string_length); attributedStringInfo segments; // I used 'respondsToSelector:@selector(string)' // to judge aString is an attributed string or not. @@ -675,6 +663,7 @@ attributedStringInfo getSegments(NSAttributedString *str) segments.seg_standouts.push_back(true); } setMarkedText(text, selected, replacement, string_length, segments); + free(text); if (string_length > 0) { mHasMarkedText = TRUE; @@ -783,9 +772,9 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) insertNewline:(id)sender { - if (!(mModifiers & NSCommandKeyMask) && - !(mModifiers & NSShiftKeyMask) && - !(mModifiers & NSAlternateKeyMask)) + if (!(mModifiers & NSEventModifierFlagCommand) && + !(mModifiers & NSEventModifierFlagShift) && + !(mModifiers & NSEventModifierFlagOption)) { callUnicodeCallback(13, 0); } else { @@ -904,27 +893,6 @@ attributedStringInfo getSegments(NSAttributedString *str) return self; } -- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view -{ - NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation]; - if(currentScreen) - { - NSPoint windowPoint = [view convertPoint:point toView:nil]; - NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint]; - NSPoint flippedScreenPoint = [currentScreen flipPoint:screenPoint]; - flippedScreenPoint.y += [currentScreen frame].origin.y; - - return flippedScreenPoint; - } - - return NSZeroPoint; -} - -- (NSPoint)flipPoint:(NSPoint)aPoint -{ - return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y); -} - - (BOOL) becomeFirstResponder { callFocus(); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 2e75d309ea..41b1e3195c 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -213,7 +213,8 @@ OSErr setImageCursor(CursorRef ref) NSWindowRef createNSWindow(int x, int y, int width, int height) { LLNSWindow *window = [[LLNSWindow alloc]initWithContentRect:NSMakeRect(x, y, width, height) - styleMask:NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask backing:NSBackingStoreBuffered defer:NO]; + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered defer:NO]; [window makeKeyAndOrderFront:nil]; [window setAcceptsMouseMovedEvents:TRUE]; [window setRestorable:FALSE]; // Viewer manages state from own settings diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index d4b05dde72..b8fd3dc189 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -372,7 +372,7 @@ struct AttachmentInfo - (void)sendEvent:(NSEvent *)event { [super sendEvent:event]; - if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) + if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) { [[self keyWindow] sendEvent:event]; } diff --git a/indra/newview/llappviewermacosx-objc.h b/indra/newview/llappviewermacosx-objc.h index d0ae0a7fc2..3fbf4202f1 100644 --- a/indra/newview/llappviewermacosx-objc.h +++ b/indra/newview/llappviewermacosx-objc.h @@ -30,9 +30,6 @@ #include #include -//Why? Because BOOL -void launchApplication(const std::string* app_name, const std::vector* args); - void force_ns_sxeption(); #endif // LL_LLAPPVIEWERMACOSX_OBJC_H diff --git a/indra/newview/llappviewermacosx-objc.mm b/indra/newview/llappviewermacosx-objc.mm index 9b6bfe621b..2ea3f2f171 100644 --- a/indra/newview/llappviewermacosx-objc.mm +++ b/indra/newview/llappviewermacosx-objc.mm @@ -33,45 +33,6 @@ #include "llappviewermacosx-objc.h" -void launchApplication(const std::string* app_name, const std::vector* args) -{ - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (app_name->empty()) return; - - NSMutableString* app_name_ns = [NSMutableString stringWithString:[[NSBundle mainBundle] resourcePath]]; //Path to resource dir - [app_name_ns appendFormat:@"/%@", [NSString stringWithCString:app_name->c_str() - encoding:[NSString defaultCStringEncoding]]]; - - NSMutableArray *args_ns = nil; - args_ns = [[NSMutableArray alloc] init]; - - for (int i=0; i < args->size(); ++i) - { - NSLog(@"Adding string %s", (*args)[i].c_str()); - [args_ns addObject: - [NSString stringWithCString:(*args)[i].c_str() - encoding:[NSString defaultCStringEncoding]]]; - } - - NSTask *task = [[NSTask alloc] init]; - NSBundle *bundle = [NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:app_name_ns]]; - [task setLaunchPath:[bundle executablePath]]; - [task setArguments:args_ns]; - [task launch]; - -// NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; -// NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:app_name_ns]]; -// -// NSError *error = nil; -// [workspace launchApplicationAtURL:url options:0 configuration:[NSDictionary dictionaryWithObject:args_ns forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; - //TODO Handle error - - [pool release]; - return; -} - void force_ns_sxeption() { NSException *exception = [NSException exceptionWithName:@"Forced NSException" reason:nullptr userInfo:nullptr]; diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index b21bc724fb..978069457c 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -86,7 +86,7 @@ std::unique_ptr> doLoadDialog(const std::vector doSaveDialog(const std::string* file, [panel setNameFieldStringValue: fileName]; [panel setDirectoryURL: url]; if([panel runModal] == - NSFileHandlingPanelOKButton) + NSModalResponseOK) { NSURL* url = [panel URL]; NSString* p = [url path]; @@ -211,7 +211,7 @@ void doSaveDialogModeless(const std::string* file, [panel beginWithCompletionHandler:^(NSModalResponse result) { - if (result == NSOKButton) + if (result == NSModalResponseOK) { NSURL* url = [panel URL]; NSString* p = [url path]; diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index 7e13503103..c5f4a2f0cf 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -1284,7 +1284,7 @@ void LLFloaterEmojiPicker::saveState() if (!recentlyUsed.empty()) recentlyUsed += ","; char buffer[32]; - sprintf(buffer, "%u", (U32)emoji); + snprintf(buffer, sizeof(buffer), "%u", (U32)emoji); recentlyUsed += buffer; if (!--maxCount) break; @@ -1301,7 +1301,7 @@ void LLFloaterEmojiPicker::saveState() if (!frequentlyUsed.empty()) frequentlyUsed += ","; char buffer[32]; - sprintf(buffer, "%u:%u", (U32)it.first, (U32)it.second); + snprintf(buffer, sizeof(buffer), "%u:%u", (U32)it.first, (U32)it.second); frequentlyUsed += buffer; if (!--maxCount) break; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 990a299c50..abffba8ffa 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -1042,7 +1042,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector& filen { CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) int max_file_length = 256; // (max file name length is 255 in OSX) - char executable_buf[max_file_length]; + char* executable_buf = (char*)malloc(sizeof(char) * max_file_length); if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* { executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path @@ -1052,6 +1052,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector& filen std::string warning = "Unable to get CString from CFString for executable path"; popupAndPrintWarning(warning); } + free(executable_buf); } else { -- cgit v1.3 From 07daeb4632d34a469b459347bd46800ebb05bc54 Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Tue, 19 Aug 2025 12:22:36 -0700 Subject: Revert "Remove the first login screen (#4451)" (#4578) * Revert "Remove the first login screen (#4451)" This reverts commit b82f52acbb00a9dd3e5426e8a6510a0ef6f41289. * Revert "#4451 Remove missed first login image" This reverts commit 8eb2429a16b7dee570a28578f3d75f2a423f20af. --- indra/newview/llpanellogin.cpp | 103 +++++--- indra/newview/llpanellogin.h | 1 + indra/newview/skins/default/textures/textures.xml | 1 + .../default/textures/windows/first_login_image.jpg | Bin 0 -> 104529 bytes .../skins/default/xui/de/panel_login_first.xml | 39 +++ .../skins/default/xui/en/panel_login_first.xml | 262 +++++++++++++++++++++ .../skins/default/xui/es/panel_login_first.xml | 39 +++ .../skins/default/xui/fr/panel_login_first.xml | 39 +++ .../skins/default/xui/it/panel_login_first.xml | 39 +++ .../skins/default/xui/ja/panel_login_first.xml | 54 +++++ .../skins/default/xui/pl/panel_login_first.xml | 30 +++ .../skins/default/xui/pt/panel_login_first.xml | 39 +++ .../skins/default/xui/ru/panel_login_first.xml | 39 +++ .../skins/default/xui/tr/panel_login_first.xml | 39 +++ .../skins/default/xui/zh/panel_login_first.xml | 39 +++ indra/newview/viewer_manifest.py | 1 + 16 files changed, 728 insertions(+), 36 deletions(-) create mode 100644 indra/newview/skins/default/textures/windows/first_login_image.jpg create mode 100644 indra/newview/skins/default/xui/de/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/en/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/es/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/fr/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/it/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/ja/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/pl/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/pt/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/ru/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/tr/panel_login_first.xml create mode 100644 indra/newview/skins/default/xui/zh/panel_login_first.xml diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 59aa375457..ed80c8b732 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -184,6 +184,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), + mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -202,7 +203,14 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - buildFromFile("panel_login.xml"); + if (mFirstLoginThisInstall) + { + buildFromFile( "panel_login_first.xml"); + } + else + { + buildFromFile( "panel_login.xml"); + } reshape(rect.getWidth(), rect.getHeight()); @@ -216,36 +224,38 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("sign_up_text")); std::string current_grid = LLGridManager::getInstance()->getGrid(); + if (!mFirstLoginThisInstall) + { + LLComboBox* favorites_combo = getChild("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - LLComboBox* favorites_combo = getChild("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - - LLComboBox* server_choice_combo = getChild("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + LLComboBox* server_choice_combo = getChild("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); - std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) - { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) + std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) { - LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; - server_choice_combo->add(grid_choice->second, grid_choice->first); + if (!grid_choice->first.empty() && current_grid != grid_choice->first) + { + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); + } } - } - server_choice_combo->sortByName(); + server_choice_combo->sortByName(); - LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); + } LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -321,6 +331,15 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, void LLPanelLogin::addFavoritesToStartLocation() { + if (mFirstLoginThisInstall) + { + // first login panel has no favorites, just update name length and buttons + std::string user_defined_name = getChild("username_combo")->getSimple(); + mUsernameLength = static_cast(user_defined_name.length()); + updateLoginButtons(); + return; + } + // Clear the combo. LLComboBox* combo = getChild("start_location_combo"); if (!combo) return; @@ -540,9 +559,16 @@ void LLPanelLogin::resetFields() // function is used to reset list in case of changes by external sources return; } - - LLPointer cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - sInstance->populateUserList(cred); + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; + } + else + { + LLPointer cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred); + } } // static @@ -560,6 +586,7 @@ void LLPanelLogin::setFields(LLPointer credential) if(identifier.has("type") && (std::string)identifier["type"] == "agent") { + // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; @@ -1054,7 +1081,8 @@ void LLPanelLogin::onRememberUserCheck(void*) LLComboBox* user_combo(sInstance->getChild("username_combo")); bool remember = remember_name->getValue().asBoolean(); - if (user_combo->getCurrentIndex() != -1 + if (!sInstance->mFirstLoginThisInstall + && user_combo->getCurrentIndex() != -1 && !remember) { remember = true; @@ -1169,14 +1197,17 @@ void LLPanelLogin::updateLoginButtons() login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); - LLComboBox* user_combo = getChild("username_combo"); - LLCheckBoxCtrl* remember_name = getChild("remember_name"); - if (user_combo->getCurrentIndex() != -1) + if (!mFirstLoginThisInstall) { - remember_name->setValue(true); - LLCheckBoxCtrl* remember_pass = getChild("remember_password"); - remember_pass->setEnabled(true); - } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user + LLComboBox* user_combo = getChild("username_combo"); + LLCheckBoxCtrl* remember_name = getChild("remember_name"); + if (user_combo->getCurrentIndex() != -1) + { + remember_name->setValue(true); + LLCheckBoxCtrl* remember_pass = getChild("remember_password"); + remember_pass->setEnabled(true); + } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user + } } void LLPanelLogin::populateUserList(LLPointer credential) diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 1259bf26d6..a1bf25fb05 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -119,6 +119,7 @@ private: static LLPanelLogin* sInstance; static bool sCapslockDidNotification; + bool mFirstLoginThisInstall; static bool sCredentialSet; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b18d151ab7..d650e7e791 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -657,6 +657,7 @@ with the same filename but different name + diff --git a/indra/newview/skins/default/textures/windows/first_login_image.jpg b/indra/newview/skins/default/textures/windows/first_login_image.jpg new file mode 100644 index 0000000000..30f31341ed Binary files /dev/null and b/indra/newview/skins/default/textures/windows/first_login_image.jpg differ diff --git a/indra/newview/skins/default/xui/de/panel_login_first.xml b/indra/newview/skins/default/xui/de/panel_login_first.xml new file mode 100644 index 0000000000..038001157e --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_login_first.xml @@ -0,0 +1,39 @@ + + + + http://secondlife.com/account/request.php?lang=de + + + https://join.secondlife.com/ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_search.xml b/indra/newview/skins/default/xui/en/floater_search.xml index 76a486e211..43c4aa1b9d 100644 --- a/indra/newview/skins/default/xui/en/floater_search.xml +++ b/indra/newview/skins/default/xui/en/floater_search.xml @@ -1,26 +1,202 @@ - + legacy_header_height="18" + can_minimize="true" + can_close="true" + can_resize="true" + height="775" + layout="topleft" + min_height="500" + min_width="600" + name="Search" + save_rect="true" + single_instance="true" + save_visibility="true" + title="SEARCH" + tab_stop="true" + width="780"> + + + + + + + + + + + + + + + + + + + + -- cgit v1.3 From 694bf1e25aca5cca1b46b86f85404152d29f766b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 30 Sep 2025 21:37:49 +0300 Subject: #4762 Better cacheOptimize's issue handling --- indra/llmath/llvolume.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 7c60253618..b3cb278d59 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5713,6 +5713,8 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { try { + // providing mIndices should help avoid unused vertices + // but those should have been filtered out on upload vert_count = static_cast(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count)); } catch (std::bad_alloc&) @@ -5722,10 +5724,16 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) } } - if (vert_count < 65535 && vert_count != 0) + // Probably should be using meshopt_remapVertexBuffer instead of remaping manually + if (vert_count < 65535 && vert_count > 0) { //copy results back into volume resizeVertices(vert_count); + if (mNumVertices == 0) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL; + } if (!data.w.empty()) { @@ -5738,13 +5746,27 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { U32 src_idx = i; U32 dst_idx = remap[i]; - if (dst_idx >= (U32)mNumVertices) + if (dst_idx == U32_MAX) + { + // Unused indices? Probably need to resize mIndices + dst_idx = mNumVertices - 1; + llassert(false); + LL_DEBUGS_ONCE("LLVOLUME") << "U32_MAX destination index, substituting" << LL_ENDL; + } + else if (dst_idx >= (U32)mNumVertices) { dst_idx = mNumVertices - 1; // Shouldn't happen, figure out what gets returned in remap and why. llassert(false); LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL; } + if (src_idx >= (U32)data.p.size()) + { + // data.p.size() is supposed to be equal to mNumIndices + src_idx = (U32)(data.p.size() - 1); + llassert(false); + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid source index, substituting" << LL_ENDL; + } mIndices[i] = dst_idx; mPositions[dst_idx].load3(data.p[src_idx].mV); @@ -5778,7 +5800,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) } else { - if (vert_count == 0) + if (vert_count <= 0) { LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL; } -- cgit v1.3 From ee6a9e7ed10f775bce312a0b8911ea8721342250 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 30 Sep 2025 22:44:40 +0300 Subject: #4758 Extra logging to track discard 6 Plus clamped some values and preventing decode from starting --- indra/llrender/llimagegl.cpp | 3 ++- indra/newview/lltexturefetch.cpp | 21 +++++++++++++++++---- indra/newview/llviewertexture.cpp | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 52738ec626..94115a06fd 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1544,7 +1544,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S if (discard_level < 0) { llassert(mCurrentDiscardLevel >= 0); - discard_level = mCurrentDiscardLevel; + discard_level = llmin(mCurrentDiscardLevel, MAX_DISCARD_LEVEL); } // Actual image width/height = raw image width/height * 2^discard_level @@ -1644,6 +1644,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_ discard_level = mCurrentDiscardLevel; } discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); + discard_level = llmin(discard_level, MAX_DISCARD_LEVEL); if (main_thread // <--- always force creation of new_texname when not on main thread ... && !defer_copy // <--- ... or defer copy is set diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 8b991f3f34..f7cb0ee7ed 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1703,10 +1703,10 @@ bool LLTextureFetchWorker::doWork(S32 param) mHttpReplyOffset = 0; mLoadedDiscard = mRequestedDiscard; - if (mLoadedDiscard < 0) + if (mLoadedDiscard < 0 || (mLoadedDiscard > MAX_DISCARD_LEVEL && mFormattedImage->getCodec() == IMG_CODEC_J2C)) { LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard - << ", should be >=0" << LL_ENDL; + << ", should be >=0 and <=" << MAX_DISCARD_LEVEL << LL_ENDL; } setState(DECODE_IMAGE); if (mWriteToCacheState != NOT_WRITE) @@ -1768,14 +1768,27 @@ bool LLTextureFetchWorker::doWork(S32 param) LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: mLoadedDiscard < 0" << LL_ENDL; return true; } + + llassert_always(mFormattedImage.notNull()); + S32 discard = mHaveAllData && mFormattedImage->getCodec() != IMG_CODEC_J2C ? 0 : mLoadedDiscard; + if (discard > MAX_DISCARD_LEVEL) // only warn for j2c + { + // We encode j2c with fixed amount of discard levels, + // Trying to decode beyound that will fail. + LL_WARNS(LOG_TXT) << "Decode entered with invalid discard. ID = " << mID << LL_ENDL; + + //abort, don't decode + setState(DONE); + LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: mLoadedDiscard > MAX_DISCARD_LEVEL" << LL_ENDL; + return true; + } + mDecodeTimer.reset(); mRawImage = NULL; mAuxImage = NULL; - llassert_always(mFormattedImage.notNull()); // if we have the entire image data (and the image is not J2C), decode the full res image // DO NOT decode a higher res j2c than was requested. This is a waste of time and memory. - S32 discard = mHaveAllData && mFormattedImage->getCodec() != IMG_CODEC_J2C ? 0 : mLoadedDiscard; mDecoded = false; setState(DECODE_IMAGE_UPDATE); LL_DEBUGS(LOG_TXT) << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3142c9950b..6135e18840 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2153,7 +2153,7 @@ bool LLViewerFetchedTexture::updateFetch() } const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); - if (override_tex_discard_level != 0) + if (override_tex_discard_level != 0 && override_tex_discard_level <= MAX_DISCARD_LEVEL) { desired_discard = override_tex_discard_level; } -- cgit v1.3 From 503affdc9799311e6adeaf0271e470c46f8ceda8 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 1 Oct 2025 17:54:46 +0300 Subject: #vp484 Crash in LLFolderViewFolder::setOpen --- indra/llui/llfolderviewitem.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 9ca77dbe46..0f9fd35868 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -2106,10 +2106,14 @@ void LLFolderViewFolder::setOpen(bool openitem) { // navigateToFolder can destroy this view // delay it in case setOpen was called from click or key processing - doOnIdleOneTime([this]() - { - getViewModelItem()->navigateToFolder(); - }); + LLPointer view_model_item = mViewModelItem; + doOnIdleOneTime([view_model_item]() + { + if (view_model_item.notNull()) + { + view_model_item.get()->navigateToFolder(); + } + }); } else { -- cgit v1.3 From 69312e248e65a03fca67dd38b00a84164461269e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Wed, 1 Oct 2025 18:41:01 +0300 Subject: #4768 Crash at retransmitUnackedPackets For some reason there are no logs for these crashes, but lack of connection data indicates that viewer was disconnected prior to crash. --- indra/newview/llappviewer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 442a37e977..eadc5e7e63 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5553,7 +5553,10 @@ void LLAppViewer::idleNetwork() add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); // Retransmit unacknowledged packets. - gXferManager->retransmitUnackedPackets(); + if (gXferManager) + { + gXferManager->retransmitUnackedPackets(); + } gAssetStorage->checkForTimeouts(); gViewerThrottle.setBufferLoadRate(gMessageSystem->getBufferLoadRate()); gViewerThrottle.updateDynamicThrottle(); -- cgit v1.3 From f05fe9c195d589da6726be32ce89ba7a42124e71 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:28:51 +0300 Subject: #4770 Crashes on ~LLCoprocedureManager() Situation is not clear, so hoping that explicit cleanup will reveal something. --- indra/llmessage/llcoproceduremanager.cpp | 33 +++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 563dd9459c..5c7b1c4235 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -138,7 +138,22 @@ LLCoprocedureManager::LLCoprocedureManager() LLCoprocedureManager::~LLCoprocedureManager() { - close(); + try + { + close(); + } + catch (const boost::fibers::fiber_error&) + { + LL_WARNS() << "Fiber error during ~LLCoprocedureManager()" << LL_ENDL; + } + catch (const std::exception& e) + { + // Shutting down, just log it + LL_WARNS() << "Exception during ~LLCoprocedureManager(): " << e.what() << LL_ENDL; + } + mPropertyQueryFn.clear(); + mPropertyDefineFn.clear(); + mPoolMap.clear(); } void LLCoprocedureManager::initializePool(const std::string &poolName, size_t queue_size) @@ -365,6 +380,22 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size, s LLCoprocedurePool::~LLCoprocedurePool() { + try + { + close(); // should have been closed already, but shouldn't hurt + mStatusListener.disconnect(); + mPendingCoprocs.reset(); + mCoroMapping.clear(); + } + catch (const boost::fibers::fiber_error&) + { + LL_WARNS() << "Fiber error during ~LLCoprocedurePool() " << mPoolName << LL_ENDL; + } + catch (const std::exception& e) + { + // Shutting down, just log it + LL_WARNS() << "Exception " << e.what() << " during ~LLCoprocedurePool() in " << mPoolName << LL_ENDL; + } } //------------------------------------------------------------------------- -- cgit v1.3 From 45528d33280a2ea8ce03211e8e60d9ef991d07ea Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:33:53 +0300 Subject: #4773 Crash on sub_image_lines Just caught it and discard_level is somehow 7, which seems like it resulted in src going out of bounds, which crashed glTexSubImage2D --- indra/llrender/llimagegl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 94115a06fd..97ea6f67bd 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1097,6 +1097,8 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w // full width texture, do 32 lines at a time for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size) { + // If this keeps crashing, pass down data_size, looks like it is using + // imageraw->getData(); for data, but goes way over allocated size limit glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src); src += line_width * batch_size; } @@ -1106,6 +1108,8 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w // partial width or strange height for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1) { + // If this keeps crashing, pass down data_size, looks like it is using + // imageraw->getData(); for data, but goes way over allocated size limit glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); src += line_width; } @@ -1544,8 +1548,9 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S if (discard_level < 0) { llassert(mCurrentDiscardLevel >= 0); - discard_level = llmin(mCurrentDiscardLevel, MAX_DISCARD_LEVEL); + discard_level = mCurrentDiscardLevel; } + discard_level = llmin(discard_level, MAX_DISCARD_LEVEL); // Actual image width/height = raw image width/height * 2^discard_level S32 raw_w = imageraw->getWidth() ; -- cgit v1.3 From 589498fece769446310c085e9feb08ccd8400c2c Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Wed, 1 Oct 2025 17:50:28 -0700 Subject: Reenable havok llphysicsextensions on Darwin x86_64 with llphysicsextensions_stub used for aarch64 --- autobuild.xml | 40 ++++------------------------------- build.sh | 1 - indra/cmake/LLPhysicsExtensions.cmake | 9 +++++++- indra/newview/CMakeLists.txt | 9 ++++++++ 4 files changed, 21 insertions(+), 38 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index c9355c73c0..280078b4c2 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1432,53 +1432,21 @@ platforms - darwin64 - - archive - - creds - github - hash - 7facda95e2f00c260513f3d4db42588fa8ba703c - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289774 - - name - darwin64 - - linux64 - - archive - - creds - github - hash - 01d08f13c7bc8d1b95b0330fa6833b7d8274e4d0 - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289775 - - name - linux64 - - windows64 + common archive creds github hash - 6d00345c7d3471bc5f7c1218e014dd0f1a2c069b + 1949ae355a70a4cbe2f0969de636680a0b5d7b15 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289778 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/299453833 name - windows64 + common license diff --git a/build.sh b/build.sh index 36e332cf42..325386e7e9 100755 --- a/build.sh +++ b/build.sh @@ -158,7 +158,6 @@ pre_build() if [[ "$arch" == "Darwin" ]] then - HAVOK=OFF SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") fi diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake index 80d243d9f8..6112621b5a 100644 --- a/indra/cmake/LLPhysicsExtensions.cmake +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -22,7 +22,14 @@ if (HAVOK) include(Havok) use_prebuilt_binary(llphysicsextensions_source) set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/src) - target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions) + if(DARWIN) + set(LLPHYSICSEXTENSIONS_STUB_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub) + # can't set these library dependencies per-arch here, need to do it using XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=*] in newview/CMakeLists.txt + #target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions) + #target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensionsstub) + else() + target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions) + endif() elseif (HAVOK_TPV) use_prebuilt_binary(llphysicsextensions_tpv) target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions_tpv) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c727d5ae57..72baac73ae 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -59,6 +59,10 @@ if (NOT HAVOK_TPV) # which means we need to duct tape this togther ... add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) + if (NOT "${LLPHYSICSEXTENSIONS_STUB_DIR}" EQUAL "") + # for darwin universal builds we need both real llphysicsextensions and the stub for aarch64 fallback + add_subdirectory(${LLPHYSICSEXTENSIONS_STUB_DIR} llphysicsextensionsstub) + endif() # Another hack that works with newer cmake versions: cmake_policy( SET CMP0079 NEW) @@ -1952,6 +1956,11 @@ elseif (DARWIN) RESOURCE SecondLife.xib #LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip" + # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL" + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensions" + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensionsstub/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsstub" ) else (WINDOWS) # Linux -- cgit v1.3 From b8cf54d909263e14622d9669b192c9ad14dc7173 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Wed, 1 Oct 2025 18:17:16 -0700 Subject: Fix configurations like windows where LLPHYSICSEXTENSIONS_STUB_DIR is unset --- indra/newview/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 72baac73ae..1444eeaba3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -59,7 +59,7 @@ if (NOT HAVOK_TPV) # which means we need to duct tape this togther ... add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) - if (NOT "${LLPHYSICSEXTENSIONS_STUB_DIR}" EQUAL "") + if (NOT "${LLPHYSICSEXTENSIONS_STUB_DIR}" STREQUAL "") # for darwin universal builds we need both real llphysicsextensions and the stub for aarch64 fallback add_subdirectory(${LLPHYSICSEXTENSIONS_STUB_DIR} llphysicsextensionsstub) endif() -- cgit v1.3 From fc41f57a06065957bc377d7a1716c5c04b8fec70 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Thu, 2 Oct 2025 11:26:48 -0700 Subject: Attempt to fix build error --- indra/newview/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1444eeaba3..9e566096fc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -61,6 +61,7 @@ if (NOT HAVOK_TPV) add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) if (NOT "${LLPHYSICSEXTENSIONS_STUB_DIR}" STREQUAL "") # for darwin universal builds we need both real llphysicsextensions and the stub for aarch64 fallback + # this will only be set when HAVOK is ON, otherwise the normal stub fallback will be in effect add_subdirectory(${LLPHYSICSEXTENSIONS_STUB_DIR} llphysicsextensionsstub) endif() @@ -73,6 +74,9 @@ if (NOT HAVOK_TPV) target_link_libraries(llphysicsextensions llrender ) if (DARWIN) target_compile_options( llphysicsextensions PRIVATE -Wno-unused-local-typedef) + + # TODO - move this into llphysicsextensions/CMakeLists.txt once I've proved it works + set_target_properties(llphysicsextensions PROPERTIES OSX_ARCHITECTURES "x86_64") endif (DARWIN) endif() endif (NOT HAVOK_TPV) -- cgit v1.3 From 4b5d1c660c1994c67e1d171f5c35e777ece5cf7c Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Thu, 2 Oct 2025 12:42:02 -0700 Subject: Add workflow_dispatch trigger to build workflow (#4774) Allow builds to be manually triggered --- .github/workflows/build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1d6a23dc4d..5a5628ede2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,6 +1,7 @@ name: Build on: + workflow_dispatch: pull_request: push: branches: ["main", "release/*", "project/*"] -- cgit v1.3 From 99d8f22c99e54ba4c22a2b5834bba2c0de549fca Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Thu, 2 Oct 2025 22:24:59 +0300 Subject: #4757 Model uploader warning when physics library is missing --- indra/newview/llviewermenufile.cpp | 18 +++++++++++++++++- indra/newview/skins/default/xui/en/notifications.xml | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 3695478061..801ff3c212 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -912,7 +912,23 @@ class LLFileUploadModel : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLFloaterModelPreview::showModelPreview(); + if (LLConvexDecomposition::isFunctional()) + { + LLFloaterModelPreview::showModelPreview(); + } + else + { + if (gGLManager.mIsApple) + { + LLNotificationsUtil::add("ModelUploaderMissingPhysicsApple"); + } + else + { + // TPV? + LLNotificationsUtil::add("ModelUploaderMissingPhysics"); + LLFloaterModelPreview::showModelPreview(); + } + } return true; } }; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 7fc96af55d..536008c85c 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2237,6 +2237,25 @@ Couldn't open uploaded sound file for reading: fail + +Model upload is not yet available on Apple Silicon, but will be supported in an upcoming release. + +Workaround: Right-click the Second Life app in Finder, select +"Get Info", then check "Open using Rosetta" + fail + + + +Physics library is not present, some of the model uploader's functionality might not work or might not work correctly. + fail + + Date: Thu, 2 Oct 2025 13:35:54 -0700 Subject: new llphysicsextensions_source package that sets OSX_ARCHITECTURES properly and should hopefully package llphysicsextensions_tpv successfully --- autobuild.xml | 4 ++-- indra/newview/CMakeLists.txt | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 280078b4c2..56831346c1 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1439,11 +1439,11 @@ creds github hash - 1949ae355a70a4cbe2f0969de636680a0b5d7b15 + fff82c79edb900c547c40dca9a0e3ebac5a8c7da hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/299453833 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/299858950 name common diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 9e566096fc..0d50aeca82 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -74,9 +74,6 @@ if (NOT HAVOK_TPV) target_link_libraries(llphysicsextensions llrender ) if (DARWIN) target_compile_options( llphysicsextensions PRIVATE -Wno-unused-local-typedef) - - # TODO - move this into llphysicsextensions/CMakeLists.txt once I've proved it works - set_target_properties(llphysicsextensions PROPERTIES OSX_ARCHITECTURES "x86_64") endif (DARWIN) endif() endif (NOT HAVOK_TPV) -- cgit v1.3 From e30bc61d9a63ed29985bd6e07405f0051bfceaf6 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Thu, 2 Oct 2025 14:51:14 -0700 Subject: Restore creation of secondlife-bin.MAP file on Darwin x86_64 for production of llphysicsextensions_tpv --- indra/newview/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0d50aeca82..eb40067930 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1955,12 +1955,12 @@ elseif (DARWIN) set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES RESOURCE SecondLife.xib - #LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip" # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL" XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" - XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensions" + # only generate the .MAP file for llphysicsextensions_tpv on x86_64 + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensions -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensionsstub/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsstub" ) else (WINDOWS) -- cgit v1.3 From 9a413357ad5bc5f5492ece90b2c9cc9dbe6087c8 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 2 Oct 2025 06:18:22 -0400 Subject: Fix infinite growth of mLoadingPhysicsShapes in mesh repository --- indra/newview/llmeshrepository.cpp | 45 +++++++++++++++++++++++++++++--------- indra/newview/llmeshrepository.h | 5 ++++- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8d5f94cdbb..1f6a046919 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -256,6 +256,7 @@ // mDecompositionRequests mMutex rw.repo.mMutex, ro.repo.none [5] // mPhysicsShapeRequests mMutex rw.repo.mMutex, ro.repo.none [5] // mDecompositionQ mMutex rw.repo.mLoadedMutex, rw.main.mLoadedMutex [5] (was: [0]) +// mPhysicsQ mMutex rw.repo.mLoadedMutex, rw.main.mLoadedMutex [5] (was: [0]) // mHeaderReqQ mMutex ro.repo.none [5], rw.repo.mMutex, rw.any.mMutex // mLODReqQ mMutex ro.repo.none [5], rw.repo.mMutex, rw.any.mMutex // mUnavailableQ mMutex rw.repo.none [0], ro.main.none [5], rw.main.mLoadedMutex @@ -982,6 +983,12 @@ LLMeshRepoThread::~LLMeshRepoThread() mDecompositionQ.pop_front(); } + while (!mPhysicsQ.empty()) + { + delete mPhysicsQ.front(); + mPhysicsQ.pop_front(); + } + delete mHttpRequest; mHttpRequest = nullptr; delete mMutex; @@ -2565,7 +2572,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_ { LLMutexLock lock(mLoadedMutex); - mDecompositionQ.push_back(d); + mPhysicsQ.push_back(d); } return MESH_OK; } @@ -3441,13 +3448,14 @@ void LLMeshRepoThread::notifyLoadedMeshes() } } - if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty()) + if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || !mDecompositionQ.empty() || !mPhysicsQ.empty()) { if (mLoadedMutex->trylock()) { std::deque> skin_info_q; std::deque skin_info_unavail_q; std::list decomp_q; + std::list physics_q; if (! mSkinInfoQ.empty()) { @@ -3464,6 +3472,11 @@ void LLMeshRepoThread::notifyLoadedMeshes() decomp_q.swap(mDecompositionQ); } + if (!mPhysicsQ.empty()) + { + physics_q.swap(mPhysicsQ); + } + mLoadedMutex->unlock(); // Process the elements free of the lock @@ -3480,9 +3493,15 @@ void LLMeshRepoThread::notifyLoadedMeshes() while (! decomp_q.empty()) { - gMeshRepo.notifyDecompositionReceived(decomp_q.front()); + gMeshRepo.notifyDecompositionReceived(decomp_q.front(), false); decomp_q.pop_front(); } + + while (!physics_q.empty()) + { + gMeshRepo.notifyDecompositionReceived(physics_q.front(), true); + physics_q.pop_front(); + } } } @@ -4724,13 +4743,13 @@ void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id) } } -void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp) +void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp, bool physics_mesh) { - decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID); + LLUUID decomp_id = decomp->mMeshID; // Copy to avoid invalidation in below deletion + decomposition_map::iterator iter = mDecompositionMap.find(decomp_id); if (iter == mDecompositionMap.end()) { //just insert decomp into map - mDecompositionMap[decomp->mMeshID] = decomp; - mLoadingDecompositions.erase(decomp->mMeshID); + mDecompositionMap[decomp_id] = decomp; sCacheBytesDecomps += decomp->sizeBytes(); } else @@ -4738,10 +4757,17 @@ void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decom sCacheBytesDecomps -= iter->second->sizeBytes(); iter->second->merge(decomp); sCacheBytesDecomps += iter->second->sizeBytes(); - - mLoadingDecompositions.erase(decomp->mMeshID); delete decomp; } + + if (physics_mesh) + { + mLoadingPhysicsShapes.erase(decomp_id); + } + else + { + mLoadingDecompositions.erase(decomp_id); + } } void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume, S32 lod) @@ -4888,7 +4914,6 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) std::unordered_set::iterator iter = mLoadingPhysicsShapes.find(mesh_id); if (iter == mLoadingPhysicsShapes.end()) { //no request pending for this skin info - // *FIXME: Nothing ever deletes entries, can't be right mLoadingPhysicsShapes.insert(mesh_id); mPendingPhysicsShapeRequests.push(mesh_id); } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index ab17b921d6..cf05807164 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -521,6 +521,9 @@ public: // list of completed Decomposition info requests std::list mDecompositionQ; + // list of completed Physics Mesh info requests + std::list mPhysicsQ; + //queue of requested headers std::queue mHeaderReqQ; @@ -855,7 +858,7 @@ public: void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 request_lod, S32 volume_lod); void notifySkinInfoReceived(LLMeshSkinInfo* info); void notifySkinInfoUnavailable(const LLUUID& info); - void notifyDecompositionReceived(LLModel::Decomposition* info); + void notifyDecompositionReceived(LLModel::Decomposition* info, bool physics_mesh); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); static S32 getActualMeshLOD(LLMeshHeader& header, S32 lod); -- cgit v1.3 From b277cc6a8fd2a48ed3ba6498734d9fae209d181e Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 18 Sep 2025 13:38:54 -0400 Subject: Initial VHACD based llconvexdecomposition --- autobuild.xml | 68 +-- indra/CMakeLists.txt | 3 + indra/cmake/CMakeLists.txt | 1 + indra/cmake/LLPhysicsExtensions.cmake | 8 +- indra/cmake/VHACD.cmake | 9 + indra/llconvexdecomposition/CMakeLists.txt | 39 ++ .../llconvexdecomposition.cpp | 83 ++++ .../llconvexdecomposition/llconvexdecomposition.h | 231 ++++++++++ .../llconvexdecompositionvhacd.cpp | 492 +++++++++++++++++++++ .../llconvexdecompositionvhacd.h | 339 ++++++++++++++ indra/llprimitive/CMakeLists.txt | 6 + indra/llprimitive/llmodel.cpp | 4 +- indra/llprimitive/llmodel.h | 3 +- indra/newview/CMakeLists.txt | 8 +- indra/newview/llfloatermodelpreview.cpp | 12 +- indra/newview/llmodelpreview.cpp | 14 +- indra/newview/llviewerobjectlist.cpp | 4 +- .../skins/default/xui/en/floater_model_preview.xml | 149 ++++++- 18 files changed, 1418 insertions(+), 55 deletions(-) create mode 100644 indra/cmake/VHACD.cmake create mode 100644 indra/llconvexdecomposition/CMakeLists.txt create mode 100644 indra/llconvexdecomposition/llconvexdecomposition.cpp create mode 100644 indra/llconvexdecomposition/llconvexdecomposition.h create mode 100644 indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp create mode 100644 indra/llconvexdecomposition/llconvexdecompositionvhacd.h diff --git a/autobuild.xml b/autobuild.xml index c9355c73c0..8a022cd304 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1496,41 +1496,19 @@ platforms - darwin64 - - archive - - hash - f290b000b31f9e36f2489946cbc99f5e - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/59995/563653/llphysicsextensions_stub-1.0.542456-darwin64-542456.tar.bz2 - - name - darwin64 - - linux64 - - archive - - hash - 711f4ec769e4b5f59ba25ee43c11bcbc - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4724/14846/llphysicsextensions_stub-1.0.504712-linux64-504712.tar.bz2 - - name - linux64 - - windows64 + common archive hash - 2e5f1f7046a49d8b0bc295aa878116bc + bc41438b10ac6474cf5560465a3662a64f9e65a81342e4c33f18f6694581c7ee28c9ee6f091c36e80a0b1e10c68205be71eb5f8e40fef115d2c744fc2bbfcb43 + hash_algorithm + blake2b url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2 + https://github.com/AlchemyViewer/llphysicsextensions_stub/releases/download/v1.0-cb4900e/llphysicsextensions_stub-1.0-common-17836965684.tar.zst name - windows64 + common license @@ -1540,7 +1518,7 @@ copyright Copyright (c) 2010, Linden Research, Inc. version - 1.0.542456 + 1.0 name llphysicsextensions_stub @@ -2966,6 +2944,38 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors description Discord Social SDK + vhacd + + platforms + + common + + archive + + hash + 140d8fc952a10edb5f2d72ab405336019ef32cadfa64f0cfce76c9de4bc6268cbc87cc8cd89d3417fb78b531d441701afc8d016bafe4bd275df2707f7daf1387 + hash_algorithm + blake2b + url + https://github.com/AlchemyViewer/3p-vhacd/releases/download/v4.1.0-r2/vhacd-4.1.0-r2-common-18166921729.tar.zst + + name + common + + + license + BSD + license_file + LICENSES/vhacd.txt + copyright + Copyright (c) 2011, Khaled Mamou + version + 4.1.0-r2 + name + vhacd + description + Voxelized Hierarchical Approximate Convex Decomposition + package_description diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 6504002dd9..246bd7bfa0 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -61,6 +61,9 @@ add_subdirectory(cmake) add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) add_subdirectory(${LIBS_OPEN_PREFIX}llappearance) add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter) +if (NOT HAVOK AND NOT HAVOK_TPV) + add_subdirectory(${LIBS_OPEN_PREFIX}llconvexdecomposition) +endif () add_subdirectory(${LIBS_OPEN_PREFIX}llcommon) add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp) add_subdirectory(${LIBS_OPEN_PREFIX}llimage) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 4608f68f50..2ba282bdb7 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -62,6 +62,7 @@ set(cmake_SOURCE_FILES UI.cmake UnixInstall.cmake Variables.cmake + VHACD.cmake ViewerMiscLibs.cmake VisualLeakDetector.cmake LibVLCPlugin.cmake diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake index 80d243d9f8..bb6cb703d2 100644 --- a/indra/cmake/LLPhysicsExtensions.cmake +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -23,9 +23,15 @@ if (HAVOK) use_prebuilt_binary(llphysicsextensions_source) set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/src) target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions) + target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 ) elseif (HAVOK_TPV) use_prebuilt_binary(llphysicsextensions_tpv) - target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions_tpv) + if(WINDOWS) + target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/llphysicsextensions_tpv.lib) + else() + target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/libllphysicsextensions_tpv.a) + endif() + target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 ) else (HAVOK) use_prebuilt_binary(llphysicsextensions_stub) set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub) diff --git a/indra/cmake/VHACD.cmake b/indra/cmake/VHACD.cmake new file mode 100644 index 0000000000..9f37f32b2d --- /dev/null +++ b/indra/cmake/VHACD.cmake @@ -0,0 +1,9 @@ +# -*- cmake -*- +include(Prebuilt) + +add_library(ll::vhacd INTERFACE IMPORTED) + +use_system_binary(vhacd) +use_prebuilt_binary(vhacd) + +target_include_directories(ll::vhacd SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/vhacd/) diff --git a/indra/llconvexdecomposition/CMakeLists.txt b/indra/llconvexdecomposition/CMakeLists.txt new file mode 100644 index 0000000000..7dae884db8 --- /dev/null +++ b/indra/llconvexdecomposition/CMakeLists.txt @@ -0,0 +1,39 @@ +# -*- cmake -*- + +project(llconvexdecomposition) + +include(00-Common) +include(LLCommon) +include(LLMath) +include(VHACD) + +set(llconvexdecomposition_SOURCE_FILES + llconvexdecomposition.cpp + llconvexdecompositionvhacd.cpp + ) + +set(llconvexdecomposition_HEADER_FILES + CMakeLists.txt + llconvexdecomposition.h + llconvexdecompositionvhacd.h + ) + +set_source_files_properties(${llconvexdecomposition_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llconvexdecomposition_SOURCE_FILES ${llconvexdecomposition_HEADER_FILES}) + +add_library (llconvexdecomposition ${llconvexdecomposition_SOURCE_FILES}) +target_include_directories(llconvexdecomposition INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(llconvexdecomposition + llcommon + llmath + ll::vhacd) + +if(WINDOWS) + target_compile_options(llconvexdecomposition PRIVATE /bigobj) +endif() + +# Add tests + diff --git a/indra/llconvexdecomposition/llconvexdecomposition.cpp b/indra/llconvexdecomposition/llconvexdecomposition.cpp new file mode 100644 index 0000000000..7b9d775c53 --- /dev/null +++ b/indra/llconvexdecomposition/llconvexdecomposition.cpp @@ -0,0 +1,83 @@ +/** +* @file llconvexdecomposition.cpp +* @author falcon@lindenlab.com +* @brief Inner implementation of LLConvexDecomposition interface +* +* $LicenseInfo:firstyear=2011&license=lgpl$ +* 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$ +*/ + +#include "linden_common.h" + +#include "llconvexdecompositionvhacd.h" +#include "llconvexdecomposition.h" + +bool LLConvexDecomposition::s_isInitialized = false; + +// static +bool LLConvexDecomposition::isFunctional() +{ + return LLConvexDecompositionVHACD::isFunctional(); +} + +// static +LLConvexDecomposition* LLConvexDecomposition::getInstance() +{ + if ( !s_isInitialized ) + { + return nullptr; + } + else + { + return LLConvexDecompositionVHACD::getInstance(); + } +} + +// static +LLCDResult LLConvexDecomposition::initSystem() +{ + LLCDResult result = LLConvexDecompositionVHACD::initSystem(); + if ( result == LLCD_OK ) + { + s_isInitialized = true; + } + return result; +} + +// static +LLCDResult LLConvexDecomposition::initThread() +{ + return LLConvexDecompositionVHACD::initThread(); +} + +// static +LLCDResult LLConvexDecomposition::quitThread() +{ + return LLConvexDecompositionVHACD::quitThread(); +} + +// static +LLCDResult LLConvexDecomposition::quitSystem() +{ + return LLConvexDecompositionVHACD::quitSystem(); +} + + diff --git a/indra/llconvexdecomposition/llconvexdecomposition.h b/indra/llconvexdecomposition/llconvexdecomposition.h new file mode 100644 index 0000000000..8008bc6e12 --- /dev/null +++ b/indra/llconvexdecomposition/llconvexdecomposition.h @@ -0,0 +1,231 @@ +/** + * @file llconvexdecomposition.cpp + * @brief LLConvexDecomposition interface definition + * + * $LicenseInfo:firstyear=2011&license=lgpl$ + * 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$ + */ + +#ifndef LL_CONVEX_DECOMPOSITION +#define LL_CONVEX_DECOMPOSITION + +typedef int bool32; + +#if defined(_WIN32) || defined(_WIN64) +#define LLCD_CALL __cdecl +#else +#define LLCD_CALL +#endif + +struct LLCDParam +{ + enum LLCDParamType + { + LLCD_INVALID = 0, + LLCD_INTEGER, + LLCD_FLOAT, + LLCD_BOOLEAN, + LLCD_ENUM + }; + + struct LLCDEnumItem + { + const char* mName; + int mValue; + }; + + union LLCDValue + { + float mFloat; + int mIntOrEnumValue; + bool32 mBool; + }; + + union LLCDParamDetails + { + struct { + LLCDValue mLow; + LLCDValue mHigh; + LLCDValue mDelta; + } mRange; + + struct { + int mNumEnums; + LLCDEnumItem* mEnumsArray; + } mEnumValues; + }; + + const char* mName; + const char* mDescription; + LLCDParamType mType; + LLCDParamDetails mDetails; + LLCDValue mDefault; + int mStage; + + // WARNING: Only the LLConvexDecomposition implementation + // should change this value + int mReserved; +}; + +struct LLCDStageData +{ + const char* mName; + const char* mDescription; + bool32 mSupportsCallback; +}; + +struct LLCDMeshData +{ + enum IndexType + { + INT_16, + INT_32 + }; + + const float* mVertexBase; + int mVertexStrideBytes; + int mNumVertices; + const void* mIndexBase; + IndexType mIndexType; + int mIndexStrideBytes; + int mNumTriangles; +}; + +struct LLCDHull +{ + const float* mVertexBase; + int mVertexStrideBytes; + int mNumVertices; +}; + +enum LLCDResult +{ + LLCD_OK = 0, + LLCD_UNKOWN_ERROR, + LLCD_NULL_PTR, + LLCD_INVALID_STAGE, + LLCD_UNKNOWN_PARAM, + LLCD_BAD_VALUE, + LLCD_REQUEST_OUT_OF_RANGE, + LLCD_INVALID_MESH_DATA, + LLCD_INVALID_HULL_DATA, + LLCD_STAGE_NOT_READY, + LLCD_INVALID_THREAD, + LLCD_NOT_IMPLEMENTED +}; + +// This callback will receive a string describing the current subtask being performed +// as well as a pair of numbers indicating progress. (The values should not be interpreted +// as a completion percentage as 'current' may be greater than 'final'.) +// If the callback returns zero, the decomposition will be terminated +typedef int (LLCD_CALL *llcdCallbackFunc)(const char* description, int current_progress, int final_progress); + +class LLConvexDecomposition +{ +public: + // Obtain a pointer to the actual implementation + static LLConvexDecomposition* getInstance(); + + /// @returns false if this is the stub + static bool isFunctional(); + + static LLCDResult initSystem(); + static LLCDResult initThread(); + static LLCDResult quitThread(); + static LLCDResult quitSystem(); + + // Generate a decomposition object handle + virtual void genDecomposition(int& decomp) = 0; + // Delete decomposition object handle + virtual void deleteDecomposition(int decomp) = 0; + // Bind given decomposition handle + // Commands operate on currently bound decomposition + virtual void bindDecomposition(int decomp) = 0; + + // Sets *paramsOut to the address of the LLCDParam array and returns + // the number of parameters + virtual int getParameters(const LLCDParam** paramsOut) = 0; + + + // Sets *stagesOut to the address of the LLCDStageData array and returns + // the number of stages + virtual int getStages(const LLCDStageData** stagesOut) = 0; + + + // Set a parameter by name. Pass enum values as integers. + virtual LLCDResult setParam(const char* name, float val) = 0; + virtual LLCDResult setParam(const char* name, int val) = 0; + virtual LLCDResult setParam(const char* name, bool val) = 0; + + + // Set incoming mesh data. Data is copied to local buffers and will + // persist until the next setMeshData call + virtual LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ) = 0; + + + // Register a callback to be called periodically during the specified stage + // See the typedef above for more information + virtual LLCDResult registerCallback( int stage, llcdCallbackFunc callback ) = 0; + + + // Execute the specified decomposition stage + virtual LLCDResult executeStage(int stage) = 0; + virtual LLCDResult buildSingleHull() = 0 ; + + + // Gets the number of hulls generated by the specified decompositions stage + virtual int getNumHullsFromStage(int stage) = 0; + + + // Populates hullOut to reference the internal copy of the requested hull + // The data will persist only until the next executeStage call for that stage. + virtual LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ) = 0; + + virtual LLCDResult getSingleHull( LLCDHull* hullOut ) = 0 ; + + + // TODO: Implement lock of some kind to disallow this call if data not yet ready + // Populates the meshDataOut to reference the utility's copy of the mesh geometry + // for the hull and stage specified. + // You must copy this data if you want to continue using it after the next executeStage + // call + virtual LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut) = 0; + + + // Creates a mesh from hullIn and temporarily stores it internally in the utility. + // The mesh data persists only until the next call to getMeshFromHull + virtual LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) = 0; + + // Takes meshIn, generates a single convex hull from it, converts that to a mesh + // stored internally, and populates meshOut to reference the internally stored data. + // The data is persistent only until the next call to generateSingleHullMeshFromMesh + virtual LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut) = 0; + + // + /// Debug + virtual void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) = 0; + +private: + static bool s_isInitialized; +}; + +#endif //LL_CONVEX_DECOMPOSITION + diff --git a/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp b/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp new file mode 100644 index 0000000000..78876f9f36 --- /dev/null +++ b/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp @@ -0,0 +1,492 @@ +/** +* @file llconvexdecompositionvhacd.cpp +* @author rye@alchemyviewer.org +* @brief A VHACD based implementation of LLConvexDecomposition +* +* $LicenseInfo:firstyear=2025&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2025, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "llmath.h" +#include "v3math.h" + +#include +#include + +#define ENABLE_VHACD_IMPLEMENTATION 1 +#include "VHACD.h" + +#include "llconvexdecompositionvhacd.h" + +constexpr S32 MAX_HULLS = 256; +constexpr S32 MAX_VERTICES_PER_HULL = 256; + +bool LLConvexDecompositionVHACD::isFunctional() +{ + return true; +} + +LLConvexDecomposition* LLConvexDecompositionVHACD::getInstance() +{ + return LLSimpleton::getInstance(); +} + +LLCDResult LLConvexDecompositionVHACD::initSystem() +{ + createInstance(); + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::initThread() +{ + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::quitThread() +{ + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::quitSystem() +{ + deleteSingleton(); + return LLCD_OK; +} + +LLConvexDecompositionVHACD::LLConvexDecompositionVHACD() +{ + //Create our vhacd instance and setup default parameters + mVHACD = VHACD::CreateVHACD(); + + mVHACDParameters.m_callback = &mVHACDCallback; + mVHACDParameters.m_logger = &mVHACDLogger; + + mDecompStages[0].mName = "Analyze"; + mDecompStages[0].mDescription = nullptr; + + LLCDParam param; + param.mName = "Fill Mode"; + param.mDescription = nullptr; + param.mType = LLCDParam::LLCD_ENUM; + param.mDetails.mEnumValues.mNumEnums = 3; + + static LLCDParam::LLCDEnumItem fill_enums[3]; + fill_enums[(size_t)VHACD::FillMode::FLOOD_FILL].mName = "Flood"; + fill_enums[(size_t)VHACD::FillMode::FLOOD_FILL].mValue = (int)VHACD::FillMode::FLOOD_FILL; + fill_enums[(size_t)VHACD::FillMode::SURFACE_ONLY].mName = "Surface Only"; + fill_enums[(size_t)VHACD::FillMode::SURFACE_ONLY].mValue = (int)VHACD::FillMode::SURFACE_ONLY; + fill_enums[(size_t)VHACD::FillMode::RAYCAST_FILL].mName = "Raycast"; + fill_enums[(size_t)VHACD::FillMode::RAYCAST_FILL].mValue = (int)VHACD::FillMode::RAYCAST_FILL; + + param.mDetails.mEnumValues.mEnumsArray = fill_enums; + param.mDefault.mIntOrEnumValue = (int)VHACD::FillMode::FLOOD_FILL; + param.mStage = 0; + param.mReserved = -1; + mDecompParams.push_back(param); + + enum EVoxelQualityLevels + { + E_LOW_QUALITY = 0, + E_NORMAL_QUALITY, + E_HIGH_QUALITY, + E_VERY_HIGH_QUALITY, + E_ULTRA_QUALITY, + E_MAX_QUALITY, + E_NUM_QUALITY_LEVELS + }; + + param.mName = "Voxel Resolution"; + param.mDescription = nullptr; + param.mType = LLCDParam::LLCD_ENUM; + param.mDetails.mEnumValues.mNumEnums = E_NUM_QUALITY_LEVELS; + + static LLCDParam::LLCDEnumItem voxel_quality_enums[E_NUM_QUALITY_LEVELS]; + voxel_quality_enums[E_LOW_QUALITY].mName = "Low"; + voxel_quality_enums[E_LOW_QUALITY].mValue = 200000; + voxel_quality_enums[E_NORMAL_QUALITY].mName = "Normal"; + voxel_quality_enums[E_NORMAL_QUALITY].mValue = 400000; + voxel_quality_enums[E_HIGH_QUALITY].mName = "High"; + voxel_quality_enums[E_HIGH_QUALITY].mValue = 800000; + voxel_quality_enums[E_VERY_HIGH_QUALITY].mName = "Very High"; + voxel_quality_enums[E_VERY_HIGH_QUALITY].mValue = 1200000; + voxel_quality_enums[E_ULTRA_QUALITY].mName = "Ultra"; + voxel_quality_enums[E_ULTRA_QUALITY].mValue = 1600000; + voxel_quality_enums[E_MAX_QUALITY].mName = "Maximum"; + voxel_quality_enums[E_MAX_QUALITY].mValue = 2000000; + + param.mDetails.mEnumValues.mEnumsArray = voxel_quality_enums; + param.mDefault.mIntOrEnumValue = 400000; + param.mStage = 0; + param.mReserved = -1; + mDecompParams.push_back(param); + + param.mName = "Num Hulls"; + param.mDescription = nullptr; + param.mType = LLCDParam::LLCD_FLOAT; + param.mDetails.mRange.mLow.mFloat = 1.f; + param.mDetails.mRange.mHigh.mFloat = MAX_HULLS; + param.mDetails.mRange.mDelta.mFloat = 1.f; + param.mDefault.mFloat = 8.f; + param.mStage = 0; + param.mReserved = -1; + mDecompParams.push_back(param); + + param.mName = "Num Vertices"; + param.mDescription = nullptr; + param.mType = LLCDParam::LLCD_FLOAT; + param.mDetails.mRange.mLow.mFloat = 3.f; + param.mDetails.mRange.mHigh.mFloat = MAX_VERTICES_PER_HULL; + param.mDetails.mRange.mDelta.mFloat = 1.f; + param.mDefault.mFloat = 32.f; + param.mStage = 0; + param.mReserved = -1; + mDecompParams.push_back(param); + + param.mName = "Error Tolerance"; + param.mDescription = nullptr; + param.mType = LLCDParam::LLCD_FLOAT; + param.mDetails.mRange.mLow.mFloat = 0.0001f; + param.mDetails.mRange.mHigh.mFloat = 99.f; + param.mDetails.mRange.mDelta.mFloat = 0.001f; + param.mDefault.mFloat = 1.f; + param.mStage = 0; + param.mReserved = -1; + mDecompParams.push_back(param); + + for (const LLCDParam& param : mDecompParams) + { + const char* const name = param.mName; + + switch (param.mType) + { + case LLCDParam::LLCD_FLOAT: + { + setParam(name, param.mDefault.mFloat); + break; + } + case LLCDParam::LLCD_ENUM: + case LLCDParam::LLCD_INTEGER: + { + setParam(name, param.mDefault.mIntOrEnumValue); + break; + } + case LLCDParam::LLCD_BOOLEAN: + { + setParam(name, (param.mDefault.mBool != 0)); + break; + } + case LLCDParam::LLCD_INVALID: + default: + { + break; + } + } + } +} + +LLConvexDecompositionVHACD::~LLConvexDecompositionVHACD() +{ + mBoundDecomp = nullptr; + mDecompData.clear(); + + mVHACD->Release(); +} + +void LLConvexDecompositionVHACD::genDecomposition(int& decomp) +{ + int new_decomp_id = static_cast(mDecompData.size()) + 1; + mDecompData[new_decomp_id] = LLDecompData(); + decomp = new_decomp_id; +} + +void LLConvexDecompositionVHACD::deleteDecomposition(int decomp) +{ + auto iter = mDecompData.find(decomp); + if (iter != mDecompData.end()) + { + if (mBoundDecomp == &iter->second) + { + mBoundDecomp = nullptr; + } + mDecompData.erase(iter); + } +} + +void LLConvexDecompositionVHACD::bindDecomposition(int decomp) +{ + auto iter = mDecompData.find(decomp); + if (iter != mDecompData.end()) + { + mBoundDecomp = &iter->second; + } + else + { + LL_WARNS() << "Failed to bind unknown decomposition: " << decomp << LL_ENDL; + mBoundDecomp = nullptr; + } +} + +LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, float val) +{ + if (name == std::string("Num Hulls")) + { + mVHACDParameters.m_maxConvexHulls = llclamp(ll_round(val), 1, MAX_HULLS); + } + else if (name == std::string("Num Vertices")) + { + mVHACDParameters.m_maxNumVerticesPerCH = llclamp(ll_round(val), 3, MAX_VERTICES_PER_HULL); + } + else if (name == std::string("Error Tolerance")) + { + mVHACDParameters.m_minimumVolumePercentErrorAllowed = val; + } + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, bool val) +{ + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val) +{ + if (name == std::string("Fill Mode")) + { + mVHACDParameters.m_fillMode = (VHACD::FillMode)val; + } + else if (name == std::string("Voxel Resolution")) + { + mVHACDParameters.m_resolution = val; + } + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::setMeshData( const LLCDMeshData* data, bool vertex_based ) +{ + if (!mBoundDecomp) + { + return LLCD_NULL_PTR; + } + + return mBoundDecomp->mSourceMesh.from(data, vertex_based); +} + +LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackFunc callback ) +{ + if (stage == 0) + { + mVHACDCallback.setCallbackFunc(callback); + return LLCD_OK; + } + else + { + return LLCD_INVALID_STAGE; + } +} + +LLCDResult LLConvexDecompositionVHACD::executeStage(int stage) +{ + if (!mBoundDecomp) + { + return LLCD_NULL_PTR; + } + + if (stage != 0) + { + return LLCD_INVALID_STAGE; + } + + mBoundDecomp->mDecomposedHulls.clear(); + + const auto& decomp_mesh = mBoundDecomp->mSourceMesh; + if (!mVHACD->Compute((const double* const)decomp_mesh.mVertices.data(), static_cast(decomp_mesh.mVertices.size()), (const uint32_t* const)decomp_mesh.mIndices.data(), static_cast(decomp_mesh.mIndices.size()), mVHACDParameters)) + { + return LLCD_INVALID_HULL_DATA; + } + + uint32_t num_nulls = mVHACD->GetNConvexHulls(); + if (num_nulls == 0) + { + return LLCD_INVALID_HULL_DATA; + } + + for (uint32_t i = 0; num_nulls > i; ++i) + { + VHACD::IVHACD::ConvexHull ch; + if (!mVHACD->GetConvexHull(i, ch)) + continue; + + LLConvexMesh out_mesh; + out_mesh.setVertices(ch.m_points); + out_mesh.setIndices(ch.m_triangles); + + mBoundDecomp->mDecomposedHulls.push_back(std::move(out_mesh)); + } + + mVHACD->Clean(); + + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::buildSingleHull() +{ + LL_INFOS() << "Building single hull mesh" << LL_ENDL; + if (!mBoundDecomp || mBoundDecomp->mSourceMesh.mVertices.empty()) + { + return LLCD_NULL_PTR; + } + + mBoundDecomp->mSingleHullMesh.clear(); + + VHACD::QuickHull quickhull; + uint32_t num_tris = quickhull.ComputeConvexHull(mBoundDecomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL); + if (num_tris > 0) + { + mBoundDecomp->mSingleHullMesh.setVertices(quickhull.GetVertices()); + mBoundDecomp->mSingleHullMesh.setIndices(quickhull.GetIndices()); + + return LLCD_OK; + } + + return LLCD_INVALID_MESH_DATA; +} + +int LLConvexDecompositionVHACD::getNumHullsFromStage(int stage) +{ + if (!mBoundDecomp || stage != 0) + { + return 0; + } + + return narrow(mBoundDecomp->mDecomposedHulls.size()); +} + +LLCDResult LLConvexDecompositionVHACD::getSingleHull( LLCDHull* hullOut ) +{ + memset( hullOut, 0, sizeof(LLCDHull) ); + + if (!mBoundDecomp) + { + return LLCD_NULL_PTR; + } + + if (mBoundDecomp->mSingleHullMesh.vertices.empty()) + { + return LLCD_INVALID_HULL_DATA; + } + + mBoundDecomp->mSingleHullMesh.to(hullOut); + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LLCDHull* hullOut ) +{ + memset( hullOut, 0, sizeof(LLCDHull) ); + + if (!mBoundDecomp) + { + return LLCD_NULL_PTR; + } + + if (stage != 0) + { + return LLCD_INVALID_STAGE; + } + + if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull) + { + return LLCD_REQUEST_OUT_OF_RANGE; + } + + mBoundDecomp->mDecomposedHulls[hull].to(hullOut); + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut ) +{ + memset( meshDataOut, 0, sizeof(LLCDMeshData)); + if (!mBoundDecomp) + { + return LLCD_NULL_PTR; + } + + if (stage != 0) + { + return LLCD_INVALID_STAGE; + } + + if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull) + { + return LLCD_REQUEST_OUT_OF_RANGE; + } + + mBoundDecomp->mDecomposedHulls[hull].to(meshDataOut); + return LLCD_OK; +} + +LLCDResult LLConvexDecompositionVHACD::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) +{ + memset(meshOut, 0, sizeof(LLCDMeshData)); + + LLVHACDMesh inMesh(hullIn); + + VHACD::QuickHull quickhull; + uint32_t num_tris = quickhull.ComputeConvexHull(inMesh.mVertices, MAX_VERTICES_PER_HULL); + if (num_tris > 0) + { + mMeshFromHullData.setVertices(quickhull.GetVertices()); + mMeshFromHullData.setIndices(quickhull.GetIndices()); + + mMeshFromHullData.to(meshOut); + return LLCD_OK; + } + + return LLCD_INVALID_HULL_DATA; +} + +LLCDResult LLConvexDecompositionVHACD::generateSingleHullMeshFromMesh(LLCDMeshData* meshIn, LLCDMeshData* meshOut) +{ + memset( meshOut, 0, sizeof(LLCDMeshData) ); + + LLVHACDMesh inMesh(meshIn, true); + + VHACD::QuickHull quickhull; + uint32_t num_tris = quickhull.ComputeConvexHull(inMesh.mVertices, MAX_VERTICES_PER_HULL); + if (num_tris > 0) + { + mSingleHullMeshFromMeshData.setVertices(quickhull.GetVertices()); + mSingleHullMeshFromMeshData.setIndices(quickhull.GetIndices()); + + mSingleHullMeshFromMeshData.to(meshOut); + return LLCD_OK; + } + + return LLCD_INVALID_MESH_DATA; +} + +void LLConvexDecompositionVHACD::loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) +{ + static LLCDMeshData meshData; + memset( &meshData, 0, sizeof(LLCDMeshData) ); + *meshDataOut = &meshData; +} diff --git a/indra/llconvexdecomposition/llconvexdecompositionvhacd.h b/indra/llconvexdecomposition/llconvexdecompositionvhacd.h new file mode 100644 index 0000000000..675356629c --- /dev/null +++ b/indra/llconvexdecomposition/llconvexdecompositionvhacd.h @@ -0,0 +1,339 @@ +/** +* @file llconvexdecompositionvhacd.h +* @author rye@alchemyviewer.org +* @brief A VHACD based implementation of LLConvexDecomposition +* +* $LicenseInfo:firstyear=2025&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2025, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_CONVEX_DECOMP_UTIL_VHACD_H +#define LL_CONVEX_DECOMP_UTIL_VHACD_H + +#include "llconvexdecomposition.h" +#include "llsingleton.h" +#include "llmath.h" + +#include + +#include "VHACD.h" + +class LLDecompDataVHACD; + +class LLConvexDecompositionVHACD : public LLSimpleton, public LLConvexDecomposition +{ + class VHACDCallback : public VHACD::IVHACD::IUserCallback + { + public: + void Update(const double overallProgress, const double stageProgress, const char* const stage, const char* operation) override + { + std::string out_msg = llformat("Stage: %s Operation: %s", stage, operation); + if (mCurrentStage != stage && mCurrentOperation != operation) + { + mCurrentStage = stage; + mCurrentOperation = operation; + LL_INFOS("VHACD") << out_msg << LL_ENDL; + } + + if(mCallbackFunc) + { + mCallbackFunc(out_msg.c_str(), ll_round(static_cast(stageProgress)), ll_round(static_cast(overallProgress))); + } + } + + void setCallbackFunc(llcdCallbackFunc func) + { + mCallbackFunc = func; + } + + private: + std::string mCurrentStage; + std::string mCurrentOperation; + llcdCallbackFunc mCallbackFunc = nullptr; + }; + + class VHACDLogger : public VHACD::IVHACD::IUserLogger + { + void Log(const char* const msg) override + { + LL_INFOS("VHACD") << msg << LL_ENDL; + } + }; + +public: + + LLConvexDecompositionVHACD(); + virtual ~LLConvexDecompositionVHACD(); + + static bool isFunctional(); + static LLConvexDecomposition* getInstance(); + static LLCDResult initSystem(); + static LLCDResult initThread(); + static LLCDResult quitThread(); + static LLCDResult quitSystem(); + + void genDecomposition(int& decomp); + void deleteDecomposition(int decomp); + void bindDecomposition(int decomp); + + // Sets *paramsOut to the address of the LLCDParam array and returns + // the length of the array + int getParameters(const LLCDParam** paramsOut) + { + *paramsOut = mDecompParams.data(); + return narrow(mDecompParams.size()); + } + + int getStages(const LLCDStageData** stagesOut) + { + *stagesOut = mDecompStages.data(); + return narrow(mDecompStages.size()); + } + + // Set a parameter by name. Returns false if out of bounds or unsupported parameter + LLCDResult setParam(const char* name, float val); + LLCDResult setParam(const char* name, int val); + LLCDResult setParam(const char* name, bool val); + LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ); + LLCDResult registerCallback(int stage, llcdCallbackFunc callback ); + + LLCDResult executeStage(int stage); + LLCDResult buildSingleHull(); + + int getNumHullsFromStage(int stage); + + LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ); + LLCDResult getSingleHull( LLCDHull* hullOut ) ; + + // TODO: Implement lock of some kind to disallow this call if data not yet ready + LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut); + LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ); + + // For visualizing convex hull shapes in the viewer physics shape display + LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut); + + /// Debug + void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut); + +private: + std::vector mDecompParams; + std::array mDecompStages; + + struct LLVHACDMesh + { + using vertex_type = VHACD::Vertex; + using index_type = VHACD::Triangle; + using vertex_array_type = std::vector; + using index_array_type = std::vector; + + LLVHACDMesh() = default; + LLVHACDMesh(const LLCDHull* hullIn) + { + if (hullIn) + { + from(hullIn); + } + }; + + LLVHACDMesh(const LLCDMeshData* meshIn, bool vertex_based) + { + if (meshIn) + { + from(meshIn, vertex_based); + } + }; + + void clear() + { + mVertices.clear(); + mIndices.clear(); + } + + void setVertices(const float* data, int num_vertices, int vertex_stride_bytes) + { + vertex_array_type vertices; + vertices.reserve(num_vertices); + + const int stride = vertex_stride_bytes / sizeof(float); + for (int i = 0; i < num_vertices; ++i) + { + vertices.emplace_back(data[i * stride + 0], + data[i * stride + 1], + data[i * stride + 2]); + } + + mVertices = std::move(vertices); + } + + void setIndices(const void* data, int num_indices, int index_stride_bytes, LLCDMeshData::IndexType type) + { + index_array_type indices; + indices.reserve(num_indices); + + if (type == LLCDMeshData::INT_16) + { + const U16* index_data = static_cast(data); + const int stride = index_stride_bytes / sizeof(U16); + for (int i = 0; i < num_indices; ++i) + { + indices.emplace_back(index_data[i * stride + 0], + index_data[i * stride + 1], + index_data[i * stride + 2]); + } + } + else + { + const U32* index_data = static_cast(data); + const int stride = index_stride_bytes / sizeof(U32); + for (int i = 0; i < num_indices; ++i) + { + indices.emplace_back(index_data[i * stride + 0], + index_data[i * stride + 1], + index_data[i * stride + 2]); + } + } + + mIndices = std::move(indices); + } + + LLCDResult from(const LLCDHull* hullIn) + { + clear(); + + if (!hullIn || !hullIn->mVertexBase || (hullIn->mNumVertices < 3) || (hullIn->mVertexStrideBytes != 12 && hullIn->mVertexStrideBytes != 16)) + { + return LLCD_INVALID_HULL_DATA; + } + + setVertices(hullIn->mVertexBase, hullIn->mNumVertices, hullIn->mVertexStrideBytes); + + return LLCD_OK; + } + + LLCDResult from(const LLCDMeshData* meshIn, bool vertex_based) + { + clear(); + + if (!meshIn || !meshIn->mVertexBase || (meshIn->mNumVertices < 3) || (meshIn->mVertexStrideBytes != 12 && meshIn->mVertexStrideBytes != 16)) + { + return LLCD_INVALID_MESH_DATA; + } + + if (!vertex_based && ((meshIn->mNumTriangles < 1) || !meshIn->mIndexBase)) + { + return LLCD_INVALID_MESH_DATA; + } + + setVertices(meshIn->mVertexBase, meshIn->mNumVertices, meshIn->mVertexStrideBytes); + if(!vertex_based) + { + setIndices(meshIn->mIndexBase, meshIn->mNumTriangles, meshIn->mIndexStrideBytes, meshIn->mIndexType); + } + + return LLCD_OK; + } + + vertex_array_type mVertices; + index_array_type mIndices; + }; + + struct LLConvexMesh + { + using vertex_type = glm::vec3; + using index_type = glm::u32vec3; + using vertex_array_type = std::vector; + using index_array_type = std::vector; + + LLConvexMesh() = default; + + void clear() + { + vertices.clear(); + indices.clear(); + } + + void setVertices(const std::vector& in_vertices) + { + vertices.clear(); + vertices.reserve(in_vertices.size()); + + for (const auto& vertex : in_vertices) + { + vertices.emplace_back(narrow(vertex.mX), narrow(vertex.mY), narrow(vertex.mZ)); + } + } + + void setIndices(const std::vector& in_indices) + { + indices.clear(); + indices.reserve(in_indices.size()); + + for (const auto& triangle : in_indices) + { + indices.emplace_back(narrow(triangle.mI0), narrow(triangle.mI1), narrow(triangle.mI2)); + } + } + + void to(LLCDHull* meshOut) const + { + meshOut->mVertexBase = (float*)vertices.data(); + meshOut->mVertexStrideBytes = sizeof(vertex_type); + meshOut->mNumVertices = (int)vertices.size(); + } + + void to(LLCDMeshData* meshOut) const + { + meshOut->mVertexBase = (float*)vertices.data(); + meshOut->mVertexStrideBytes = sizeof(vertex_type); + meshOut->mNumVertices = (int)vertices.size(); + + meshOut->mIndexType = LLCDMeshData::INT_32; + meshOut->mIndexBase = indices.data(); + meshOut->mIndexStrideBytes = sizeof(index_type); + meshOut->mNumTriangles = (int)indices.size(); + } + + vertex_array_type vertices; + index_array_type indices; + }; + + struct LLDecompData + { + LLVHACDMesh mSourceMesh; + LLConvexMesh mSingleHullMesh; + + std::vector mDecomposedHulls; + }; + + std::unordered_map mDecompData; + + LLDecompData* mBoundDecomp = nullptr; + + VHACD::IVHACD* mVHACD = nullptr; + VHACDCallback mVHACDCallback; + VHACDLogger mVHACDLogger; + VHACD::IVHACD::Parameters mVHACDParameters; + + LLConvexMesh mMeshFromHullData; + LLConvexMesh mSingleHullMeshFromMeshData; +}; + +#endif //LL_CONVEX_DECOMP_UTIL_VHACD_H diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index e13f0bbd96..9e90314a51 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -70,6 +70,12 @@ target_link_libraries(llprimitive ll::glm ) +if (TARGET llconvexdecomposition) + target_link_libraries(llprimitive + llconvexdecomposition + ) +endif () + #add unit tests if (LL_TESTS) INCLUDE(LLAddBuildTest) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 00ef79ce7f..8055bffd32 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1296,10 +1296,10 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) } void LLModel::setConvexHullDecomposition( - const LLModel::convex_hull_decomposition& decomp) + const LLModel::convex_hull_decomposition& decomp, const std::vector& decomp_mesh) { mPhysics.mHull = decomp; - mPhysics.mMesh.clear(); + mPhysics.mMesh = decomp_mesh; updateHullCenters(); } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 6501b3dc50..ac88af18f0 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -305,7 +305,8 @@ public: S32 mDecompID; void setConvexHullDecomposition( - const convex_hull_decomposition& decomp); + const convex_hull_decomposition& decomp, + const std::vector& decomp_mesh); void updateHullCenters(); LLVector3 mCenterOfHullCenters; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c727d5ae57..0f7670a57a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1709,10 +1709,6 @@ if (WINDOWS) list(APPEND viewer_SOURCE_FILES ${viewer_INSTALLER_FILES}) endif (WINDOWS) -if (HAVOK OR HAVOK_TPV) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_HAVOK") -endif (HAVOK OR HAVOK_TPV) - if( DEFINED LLSTARTUP_COMPILE_FLAGS ) # progress view disables/enables icons based on available packages set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") @@ -2029,6 +2025,10 @@ if( TARGET ll::nvapi ) target_link_libraries(${VIEWER_BINARY_NAME} ll::nvapi ) endif() +if ( TARGET llconvexdecomposition ) + target_link_libraries(${VIEWER_BINARY_NAME} llconvexdecomposition ) +endif () + set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to artwork files.") diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f76f39222b..ef29be8200 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1035,8 +1035,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) gMeshRepo.mDecompThread->submitRequest(request); } } - - if (stage == "Decompose") + if (stage == "Analyze") + { + sInstance->setStatusMessage(sInstance->getString("decomposing")); + sInstance->childSetVisible("Analyze", false); + sInstance->childSetVisible("analyze_cancel", true); + } + else if (stage == "Decompose") { sInstance->setStatusMessage(sInstance->getString("decomposing")); sInstance->childSetVisible("Decompose", false); @@ -1137,6 +1142,7 @@ void LLFloaterModelPreview::initDecompControls() childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); + childSetCommitCallback("analyze_cancel", onPhysicsStageCancel, NULL); childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); @@ -2018,7 +2024,7 @@ void LLFloaterModelPreview::DecompRequest::completed() { //called from the main thread if (mContinue) { - mModel->setConvexHullDecomposition(mHull); + mModel->setConvexHullDecomposition(mHull, mHullMesh); if (sInstance) { diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index e0649e1d88..d71f368232 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2626,7 +2626,16 @@ void LLModelPreview::updateStatusMessages() //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild("physics analysis"); +#if LL_HAVOK + LLPanel* panel = fmp->getChild("physics simplification"); + panel->setVisible(true); + + panel = fmp->getChild("physics analysis havok"); + panel->setVisible(true); +#else + LLPanel* panel = fmp->getChild("physics analysis vhacd"); + panel->setVisible(true); +#endif LLView* child = panel->getFirstChild(); while (child) { @@ -2650,6 +2659,8 @@ void LLModelPreview::updateStatusMessages() fmp->childSetVisible("simplify_cancel", false); fmp->childSetVisible("Decompose", true); fmp->childSetVisible("decompose_cancel", false); + fmp->childSetVisible("Analyze", true); + fmp->childSetVisible("analyze_cancel", false); if (phys_hulls > 0) { @@ -2659,6 +2670,7 @@ void LLModelPreview::updateStatusMessages() if (phys_tris || phys_hulls > 0) { fmp->childEnable("Decompose"); + fmp->childEnable("Analyze"); } } else diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index d72d428c08..fb9e5fd0a9 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1070,7 +1070,7 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url) if (diff.empty()) { - LL_INFOS() << "No outstanding object IDs to request. Pending count: " << mPendingObjectCost.size() << LL_ENDL; + LL_DEBUGS() << "No outstanding object IDs to request. Pending count: " << mPendingObjectCost.size() << LL_ENDL; return; } @@ -1205,7 +1205,7 @@ void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url) if (idList.size() < 1) { - LL_INFOS() << "No outstanding object physics flags to request." << LL_ENDL; + LL_DEBUGS() << "No outstanding object physics flags to request." << LL_ENDL; return; } diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index f11d687840..39e9de0980 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -40,7 +40,7 @@ Simplifying... TBD One or more textures in this model were scaled to be within the allowed limits. - + Skinning disabled due to too many joints: [JOINTS], maximum: [MAX] Rigged to unrecognized joint name [NAME] @@ -807,7 +807,7 @@ help_topic="upload_model_physics" label="Physics" name="physics_panel"> - + --> - + - + + + Step 2: Convert to hulls (optional) + + + Fill Mode: + + + Resolution: + + + Hulls per Mesh: + + + Vertices per hull: + + + Error tolerance: + + + + + + +