From c820bb2929a37fb222ce0d7368d699e81f5edc00 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sat, 31 Aug 2024 01:33:27 +0200 Subject: Minimal code needed to add RLVa with an on/off toggle --- indra/newview/CMakeLists.txt | 7 ++++ indra/newview/app_settings/settings.xml | 11 ++++++ indra/newview/llappviewer.cpp | 8 ++++ indra/newview/llstartup.cpp | 3 ++ indra/newview/rlvactions.cpp | 15 ++++++++ indra/newview/rlvactions.h | 19 ++++++++++ indra/newview/rlvcommon.cpp | 40 ++++++++++++++++++++ indra/newview/rlvcommon.h | 16 ++++++++ indra/newview/rlvdefines.h | 51 ++++++++++++++++++++++++++ indra/newview/rlvhandler.cpp | 40 ++++++++++++++++++++ indra/newview/rlvhandler.h | 25 +++++++++++++ indra/newview/skins/default/xui/en/strings.xml | 1 + 12 files changed, 236 insertions(+) create mode 100644 indra/newview/rlvactions.cpp create mode 100644 indra/newview/rlvactions.h create mode 100644 indra/newview/rlvcommon.cpp create mode 100644 indra/newview/rlvcommon.h create mode 100644 indra/newview/rlvdefines.h create mode 100644 indra/newview/rlvhandler.cpp create mode 100644 indra/newview/rlvhandler.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7a9f3a46b5..70a9f09e1f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -726,6 +726,9 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp pipeline.cpp + rlvactions.cpp + rlvcommon.cpp + rlvhandler.cpp ) set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING @@ -1386,6 +1389,10 @@ set(viewer_HEADER_FILES llxmlrpctransaction.h noise.h pipeline.h + rlvdefines.h + rlvactions.h + rlvcommon.h + rlvhandler.h roles_constants.h VertexCache.h VorbisFramework.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ec06582d90..48e0878383 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9843,6 +9843,17 @@ Value https://feedback.secondlife.com/ + RestrainedLove + + Comment + Toggles RLVa features (requires restart) + Persist + 1 + Type + Boolean + Value + 1 + RevokePermsOnStopAnimation Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index afa701c5f2..6a2498c57a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -250,6 +250,10 @@ using namespace LL; #include "llcoproceduremanager.h" #include "llviewereventrecorder.h" +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhandler.h" + // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either // this app, or another 'component' of the viewer. App globals should be @@ -1710,6 +1714,9 @@ bool LLAppViewer::cleanup() //ditch LLVOAvatarSelf instance gAgentAvatarp = NULL; + // Sanity check to catch cases where someone forgot to do an RlvActions::isRlvEnabled() check + LL_ERRS_IF(!RlvHandler::isEnabled() && RlvHandler::instanceExists()) << "RLV handler instance exists even though RLVa is disabled" << LL_ENDL; + LLNotifications::instance().clear(); // workaround for DEV-35406 crash on shutdown @@ -3333,6 +3340,7 @@ LLSD LLAppViewer::getViewerInfo() const } #endif + info["RLV_VERSION"] = RlvActions::isRlvEnabled() ? RlvStrings::getVersionAbout() : "(disabled)"; info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index b32b80331a..3b027df460 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -205,6 +205,7 @@ #include "threadpool.h" #include "llperfstats.h" +#include "rlvhandler.h" #if LL_WINDOWS #include "lldxhardware.h" @@ -876,6 +877,8 @@ bool idle_startup() return false; } + RlvHandler::setEnabled(gSavedSettings.get(Rlv::Settings::Main)); + // reset the values that could have come in from a slurl // DEV-42215: Make sure they're not empty -- gUserCredential // might already have been set from gSavedSettings, and it's too bad diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp new file mode 100644 index 0000000000..1988c99ecf --- /dev/null +++ b/indra/newview/rlvactions.cpp @@ -0,0 +1,15 @@ +#include "llviewerprecompiledheaders.h" + +#include "rlvactions.h" +#include "rlvhandler.h" + +// ============================================================================ +// Helper functions +// + +bool RlvActions::isRlvEnabled() +{ + return RlvHandler::isEnabled(); +} + +// ============================================================================ diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h new file mode 100644 index 0000000000..ac4fc73339 --- /dev/null +++ b/indra/newview/rlvactions.h @@ -0,0 +1,19 @@ +#pragma once + +// ============================================================================ +// RlvActions - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible +// + +class RlvActions +{ + // ================ + // Helper functions + // ================ +public: + /* + * Convenience function to check if RLVa is enabled without having to include rlvhandler.h + */ + static bool isRlvEnabled(); +}; + +// ============================================================================ diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp new file mode 100644 index 0000000000..f641d56a85 --- /dev/null +++ b/indra/newview/rlvcommon.cpp @@ -0,0 +1,40 @@ +#include "llviewerprecompiledheaders.h" +#include "llversioninfo.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +using namespace Rlv; + +// ============================================================================ +// RlvStrings +// + +std::string RlvStrings::getVersion(bool wants_legacy) +{ + return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)", + !wants_legacy ? "RestrainedLove" : "RestrainedLife", + SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, + ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch); +} + +std::string RlvStrings::getVersionAbout() +{ + return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", + SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, + ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, LLVersionInfo::instance().getBuild()); +} + +std::string RlvStrings::getVersionNum() +{ + return llformat("%d%02d%02d%02d", + SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, SpecVersion::Build); +} + +std::string RlvStrings::getVersionImplNum() +{ + return llformat("%d%02d%02d%02d", + ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, ImplVersion::ImplId); +} + +// ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h new file mode 100644 index 0000000000..288d48e373 --- /dev/null +++ b/indra/newview/rlvcommon.h @@ -0,0 +1,16 @@ +#pragma once + +// ============================================================================ +// RlvStrings +// + +class RlvStrings +{ +public: + static std::string getVersion(bool wants_legacy); + static std::string getVersionAbout(); + static std::string getVersionImplNum(); + static std::string getVersionNum(); +}; + +// ============================================================================ diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h new file mode 100644 index 0000000000..dc1e58f47c --- /dev/null +++ b/indra/newview/rlvdefines.h @@ -0,0 +1,51 @@ +#pragma once + +// ============================================================================ +// Defines +// + +namespace Rlv +{ + // Version of the specification we report + struct SpecVersion { + static constexpr S32 Major = 4; + static constexpr S32 Minor = 0; + static constexpr S32 Patch = 0; + static constexpr S32 Build = 0; + }; + + // RLVa implementation version + struct ImplVersion { + static constexpr S32 Major = 3; + static constexpr S32 Minor = 0; + static constexpr S32 Patch = 0; + static constexpr S32 ImplId = 2; /* Official viewer */ + }; +} + +// Defining these makes it easier if we ever need to change our tag +#define RLV_WARNS LL_WARNS("RLV") +#define RLV_INFOS LL_INFOS("RLV") +#define RLV_DEBUGS LL_DEBUGS("RLV") +#define RLV_ENDL LL_ENDL + +// ============================================================================ +// Settings +// + +namespace Rlv +{ + namespace Settings + { + constexpr char Main[] = "RestrainedLove"; + constexpr char Debug[] = "RestrainedLoveDebug"; + + constexpr char DebugHideUnsetDup[] = "RLVaDebugHideUnsetDuplicate"; + constexpr char EnableIMQuery[] = "RLVaEnableIMQuery"; + constexpr char EnableTempAttach[] = "RLVaEnableTemporaryAttachments"; + constexpr char TopLevelMenu[] = "RLVaTopLevelMenu"; + }; + +}; + +// ============================================================================ diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp new file mode 100644 index 0000000000..3315ed1999 --- /dev/null +++ b/indra/newview/rlvhandler.cpp @@ -0,0 +1,40 @@ +#include "llviewerprecompiledheaders.h" +#include "llappviewer.h" +#include "llstartup.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" +#include "rlvhandler.h" + +using namespace Rlv; + +// ============================================================================ +// Static variable initialization +// + +bool RlvHandler::mIsEnabled = false; + +// ============================================================================ +// Initialization helper functions +// + +bool RlvHandler::canEnable() +{ + return LLStartUp::getStartupState() <= STATE_LOGIN_CLEANUP; +} + +bool RlvHandler::setEnabled(bool enable) +{ + if (mIsEnabled == enable) + return enable; + + if (enable && canEnable()) + { + RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersionAbout() << RLV_ENDL; + mIsEnabled = true; + } + + return mIsEnabled; +} + +// ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h new file mode 100644 index 0000000000..0d4cbe98fb --- /dev/null +++ b/indra/newview/rlvhandler.h @@ -0,0 +1,25 @@ +#pragma once + +#include "llsingleton.h" + +#include "rlvdefines.h" + +// ============================================================================ +// RlvHandler class +// + +class RlvHandler : public LLSingleton +{ + LLSINGLETON_EMPTY_CTOR(RlvHandler); + +public: + // Initialization (deliberately static so they can safely be called in tight loops) + static bool canEnable(); + static bool isEnabled() { return mIsEnabled; } + static bool setEnabled(bool enable); + +private: + static bool mIsEnabled; +}; + +// ============================================================================ diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 2d04b3e0fe..a270bc473d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -60,6 +60,7 @@ Disk cache: [DISK_CACHE_INFO] HiDPI display mode: [HIDPI] +RestrainedLove API: [RLV_VERSION] J2C Decoder Version: [J2C_VERSION] Audio Driver Version: [AUDIO_DRIVER_VERSION] [LIBCEF_VERSION] -- cgit v1.2.3 From b82e9b73d35e41ed51063905dd31ccced9e97266 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 1 Sep 2024 01:21:00 +0200 Subject: Add owner say chat hook --- indra/newview/CMakeLists.txt | 2 + indra/newview/app_settings/settings.xml | 44 ++++++++ indra/newview/llviewermessage.cpp | 28 ++++- indra/newview/rlvdefines.h | 62 +++++++++++ indra/newview/rlvhandler.cpp | 44 +++++++- indra/newview/rlvhandler.h | 11 ++ indra/newview/rlvhelper.cpp | 136 +++++++++++++++++++++++++ indra/newview/rlvhelper.h | 24 +++++ indra/newview/skins/default/xui/en/strings.xml | 22 ++++ 9 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 indra/newview/rlvhelper.cpp create mode 100644 indra/newview/rlvhelper.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 70a9f09e1f..a7bbadfd86 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -728,6 +728,7 @@ set(viewer_SOURCE_FILES pipeline.cpp rlvactions.cpp rlvcommon.cpp + rlvhelper.cpp rlvhandler.cpp ) @@ -1392,6 +1393,7 @@ set(viewer_HEADER_FILES rlvdefines.h rlvactions.h rlvcommon.h + rlvhelper.h rlvhandler.h roles_constants.h VertexCache.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 48e0878383..be88ad6e2f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9852,6 +9852,50 @@ Type Boolean Value + 0 + + RestrainedLoveDebug + + Comment + Toggles RLVa debug mode (displays the commands when in debug mode) + Persist + 1 + Type + Boolean + Value + 0 + + RLVaBlockedExperiences + + Comment + List of experiences blocked from interacting with RLVa + Persist + 1 + Type + String + Value + bfe25fb4-222c-11e5-85a2-fa4c4ccaa202 + + RLVaDebugHideUnsetDuplicate + + Comment + Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE + Persist + 1 + Type + Boolean + Value + 0 + + RLVaEnableTemporaryAttachments + + Comment + Allows temporary attachments (regardless of origin) to issue RLV commands + Persist + 1 + Type + Boolean + Value 1 RevokePermsOnStopAnimation diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 872a9a1581..4ed16c19a6 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -118,6 +118,8 @@ #include "llpanelplaceprofile.h" #include "llviewerregion.h" #include "llfloaterregionrestarting.h" +#include "rlvactions.h" +#include "rlvhandler.h" #include "llnotificationmanager.h" // #include "llexperiencecache.h" @@ -2382,15 +2384,16 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } bool is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); + bool show_script_chat_particles = chat.mSourceType == CHAT_SOURCE_OBJECT + && chat.mChatType != CHAT_TYPE_DEBUG_MSG + && gSavedSettings.getBOOL("EffectScriptChatParticles"); chatter = gObjectList.findObject(from_id); if (chatter) { chat.mPosAgent = chatter->getPositionAgent(); // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) + if (show_script_chat_particles && (!RlvActions::isRlvEnabled() || CHAT_TYPE_OWNER != chat.mChatType) ) { LLPointer psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); psc->setSourceObject(chatter); @@ -2470,8 +2473,25 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) case CHAT_TYPE_WHISPER: chat.mText = LLTrans::getString("whisper") + " "; break; - case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: + if (RlvActions::isRlvEnabled()) + { + if (RlvHandler::instance().handleSimulatorChat(mesg, chat, chatter)) + { + break; + } + else if (show_script_chat_particles) + { + LLPointer psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); + psc->setSourceObject(chatter); + psc->setColor(color); + //We set the particles to be owned by the object's owner, + //just in case they should be muted by the mute list + psc->setOwnerUUID(owner_id); + LLViewerPartSim::getInstance()->addPartSource(psc); + } + } + case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_NORMAL: case CHAT_TYPE_DIRECT: break; diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index dc1e58f47c..6ba2afbc69 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -29,6 +29,68 @@ namespace Rlv #define RLV_DEBUGS LL_DEBUGS("RLV") #define RLV_ENDL LL_ENDL +#define RLV_RELEASE +#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + // Make sure we halt execution on errors + #define RLV_ERRS LL_ERRS("RLV") + // Keep our asserts separate from LL's + #define RLV_ASSERT(f) if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; } + #define RLV_ASSERT_DBG(f) RLV_ASSERT(f) +#else + // We don't want to check assertions in release builds + #ifndef RLV_RELEASE + #define RLV_ASSERT(f) RLV_VERIFY(f) + #define RLV_ASSERT_DBG(f) + #else + #define RLV_ASSERT(f) + #define RLV_ASSERT_DBG(f) + #endif // RLV_RELEASE +#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + +namespace Rlv +{ + namespace Constants + { + constexpr char CmdPrefix = '@'; + } +} + +// ============================================================================ +// Enumeration declarations +// + +namespace Rlv +{ + enum class ECmdRet{ + Unknown = 0x0000, // Unknown error (should only be used internally) + Retained, // Command was retained + Success = 0x0100, // Command executed successfully + SuccessUnset, // Command executed successfully (RLV_TYPE_REMOVE for an unrestricted behaviour) + SuccessDuplicate, // Command executed successfully (RLV_TYPE_ADD for an already restricted behaviour) + SuccessDeprecated, // Command executed successfully but has been marked as deprecated + SuccessDelayed, // Command parsed valid but will execute at a later time + Failed = 0x0200, // Command failed (general failure) + FailedSyntax, // Command failed (syntax error) + FailedOption, // Command failed (invalid option) + FailedParam, // Command failed (invalid param) + FailedLock, // Command failed (command is locked by another object) + FailedDisabled, // Command failed (command disabled by user) + FailedUnknown, // Command failed (unknown command) + FailedNoSharedRoot, // Command failed (missing #RLV) + FailedDeprecated, // Command failed (deprecated and no longer supported) + FailedNoBehaviour, // Command failed (force modifier on an object with no active restrictions) + FailedUnheldBehaviour, // Command failed (local modifier on an object that doesn't hold the base behaviour) + FailedBlocked, // Command failed (object is blocked) + FailedThrottled, // Command failed (throttled) + FailedNoProcessor // Command doesn't have a template processor define (legacy code) + }; + + constexpr bool isReturnCodeSuccess(ECmdRet eRet) + { + return (static_cast(eRet) & static_cast(ECmdRet::Success)) == static_cast(ECmdRet::Success); + } +} + // ============================================================================ // Settings // diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 3315ed1999..bf78a0a38a 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1,10 +1,12 @@ #include "llviewerprecompiledheaders.h" #include "llappviewer.h" #include "llstartup.h" +#include "llviewercontrol.h" +#include "llviewerobject.h" -#include "rlvdefines.h" #include "rlvcommon.h" #include "rlvhandler.h" +#include "rlvhelper.h" using namespace Rlv; @@ -14,6 +16,46 @@ using namespace Rlv; bool RlvHandler::mIsEnabled = false; +// ============================================================================ +// Command processing functions +// + +bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj) +{ + static LLCachedControl enable_temp_attach(gSavedSettings, Settings::EnableTempAttach); + static LLCachedControl show_debug_output(gSavedSettings, Settings::Debug); + static LLCachedControl hide_unset_dupes(gSavedSettings, Settings::DebugHideUnsetDup); + + if ( message.length() <= 3 || Rlv::Constants::CmdPrefix != message[0] || CHAT_TYPE_OWNER != chat.mChatType || + (chatObj && chatObj->isTempAttachment() && !enable_temp_attach()) ) + { + return false; + } + + message.erase(0, 1); + LLStringUtil::toLower(message); + CommandDbgOut cmdDbgOut(message); + + boost_tokenizer tokens(message, boost::char_separator(",", "", boost::drop_empty_tokens)); + for (const std::string& strCmd : tokens) + { + ECmdRet eRet = (ECmdRet)processCommand(chat.mFromID, strCmd, true); + if ( show_debug_output() && + (!hide_unset_dupes() || (ECmdRet::SuccessUnset != eRet && ECmdRet::SuccessDuplicate != eRet)) ) + { + cmdDbgOut.add(strCmd, eRet); + } + } + + message = cmdDbgOut.get(); + return true; +} + +ECmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCmd, bool fromObj) +{ + return ECmdRet::FailedNoProcessor; +} + // ============================================================================ // Initialization helper functions // diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index 0d4cbe98fb..8cf054e98e 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -1,9 +1,12 @@ #pragma once +#include "llchat.h" #include "llsingleton.h" #include "rlvdefines.h" +class LLViewerObject; + // ============================================================================ // RlvHandler class // @@ -13,6 +16,14 @@ class RlvHandler : public LLSingleton LLSINGLETON_EMPTY_CTOR(RlvHandler); public: + /* + * Helper functions + */ +public: + // Command processing helper functions + bool handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj); + Rlv::ECmdRet processCommand(const LLUUID& idObj, const std::string& stCmd, bool fromObj); + // Initialization (deliberately static so they can safely be called in tight loops) static bool canEnable(); static bool isEnabled() { return mIsEnabled; } diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp new file mode 100644 index 0000000000..ade2b83dd7 --- /dev/null +++ b/indra/newview/rlvhelper.cpp @@ -0,0 +1,136 @@ +#include "llviewerprecompiledheaders.h" + +#include "lltrans.h" + +#include "rlvhelper.h" + +using namespace Rlv; + +// ========================================================================= +// Various helper classes/timers/functors +// + +namespace Rlv +{ + // =========================================================================== + // CommandDbgOut + // + + void CommandDbgOut::add(std::string strCmd, ECmdRet eRet) + { + ECmdRet resultBucket; + + // Successful and retained commands are added as-is + if (isReturnCodeSuccess(eRet)) + resultBucket = ECmdRet::Success; + else if (ECmdRet::Retained == eRet) + resultBucket = ECmdRet::Retained; + else + { + // Failed commands get the failure reason appended to help troubleshooting + resultBucket = ECmdRet::Failed; + strCmd.append(llformat(" (%s)", getReturnCodeString(eRet).c_str())); + } + + std::string& strResult = mCommandResults[resultBucket]; + if (!strResult.empty()) + strResult.append(", "); + strResult.append(strCmd); + } + + std::string CommandDbgOut::get() const { + std::ostringstream result; + + if (1 == mCommandResults.size()) + { + auto it = mCommandResults.begin(); + result << " " << getDebugVerbFromReturnCode(it->first) << ": @" << it->second;; + } + else if (mCommandResults.size() > 1) + { + auto appendResult = [&](ECmdRet eRet, const std::string& name) + { + auto it = mCommandResults.find(eRet); + if (it == mCommandResults.end()) return; + result << "\n - " << LLTrans::getString(name) << ": @" << it->second; + }; + result << ": @" << mOrigCmd; + appendResult(ECmdRet::Success, "RlvDebugExecuted"); + appendResult(ECmdRet::Failed, "RlvDebugFailed"); + appendResult(ECmdRet::Retained, "RlvDebugRetained"); + } + + return result.str(); + } + + std::string CommandDbgOut::getDebugVerbFromReturnCode(ECmdRet eRet) + { + switch (eRet) + { + case ECmdRet::Success: + return LLTrans::getString("RlvDebugExecuted"); + case ECmdRet::Failed: + return LLTrans::getString("RlvDebugFailed"); + case ECmdRet::Retained: + return LLTrans::getString("RlvDebugRetained"); + default: + RLV_ASSERT(false); + return LLStringUtil::null; + } + } + + std::string CommandDbgOut::getReturnCodeString(ECmdRet eRet) + { + switch (eRet) + { + case ECmdRet::SuccessUnset: + return LLTrans::getString("RlvReturnCodeUnset"); + case ECmdRet::SuccessDuplicate: + return LLTrans::getString("RlvReturnCodeDuplicate"); + case ECmdRet::SuccessDelayed: + return LLTrans::getString("RlvReturnCodeDelayed"); + case ECmdRet::SuccessDeprecated: + return LLTrans::getString("RlvReturnCodeDeprecated"); + case ECmdRet::FailedSyntax: + return LLTrans::getString("RlvReturnCodeSyntax"); + case ECmdRet::FailedOption: + return LLTrans::getString("RlvReturnCodeOption"); + case ECmdRet::FailedParam: + return LLTrans::getString("RlvReturnCodeParam"); + case ECmdRet::FailedLock: + return LLTrans::getString("RlvReturnCodeLock"); + case ECmdRet::FailedDisabled: + return LLTrans::getString("RlvReturnCodeDisabled"); + case ECmdRet::FailedUnknown: + return LLTrans::getString("RlvReturnCodeUnknown"); + case ECmdRet::FailedNoSharedRoot: + return LLTrans::getString("RlvReturnCodeNoSharedRoot"); + case ECmdRet::FailedDeprecated: + return LLTrans::getString("RlvReturnCodeDeprecatedAndDisabled"); + case ECmdRet::FailedNoBehaviour: + return LLTrans::getString("RlvReturnCodeNoBehaviour"); + case ECmdRet::FailedUnheldBehaviour: + return LLTrans::getString("RlvReturnCodeUnheldBehaviour"); + case ECmdRet::FailedBlocked: + return LLTrans::getString("RlvReturnCodeBlocked"); + case ECmdRet::FailedThrottled: + return LLTrans::getString("RlvReturnCodeThrottled"); + case ECmdRet::FailedNoProcessor: + return LLTrans::getString("RlvReturnCodeNoProcessor"); + // The following are identified by the chat verb + case ECmdRet::Retained: + case ECmdRet::Success: + case ECmdRet::Failed: + return LLStringUtil::null; + // The following shouldn't occur + case ECmdRet::Unknown: + default: + RLV_ASSERT(false); + return LLStringUtil::null; + } + } + + // =========================================================================== +} + +// ============================================================================ diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h new file mode 100644 index 0000000000..89bdc709d5 --- /dev/null +++ b/indra/newview/rlvhelper.h @@ -0,0 +1,24 @@ +#pragma once + +#include "rlvdefines.h" + +// ============================================================================ +// Various helper classes/timers/functors +// + +namespace Rlv +{ + struct CommandDbgOut + { + CommandDbgOut(const std::string& orig_cmd) : mOrigCmd(orig_cmd) {} + void add(std::string strCmd, ECmdRet eRet); + std::string get() const; + static std::string getDebugVerbFromReturnCode(ECmdRet eRet); + static std::string getReturnCodeString(ECmdRet eRet); + private: + std::string mOrigCmd; + std::map mCommandResults; + }; +} + +// ============================================================================ diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index a270bc473d..39a663298a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4376,4 +4376,26 @@ and report the problem. [https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Knowledge Base] + + executed + failed + retained + unset + duplicate + delayed + deprecated + thingy error + invalid option + invalid param + locked command + disabled command + unknown command + missing #RLV + deprecated and disabled + no active behaviours + base behaviour not held + blocked object + throttled + no command processor found + -- cgit v1.2.3 From 7402fe6412e98e4b295ee3e04874f379c752f7a0 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Mon, 2 Sep 2024 01:39:17 +0200 Subject: Add basic scaffolding to support reply commands and handle @versionXXX as an illustration --- indra/newview/app_settings/settings.xml | 11 ++ indra/newview/llappviewer.cpp | 2 +- indra/newview/rlvcommon.cpp | 37 ++++- indra/newview/rlvcommon.h | 49 ++++-- indra/newview/rlvdefines.h | 142 +++++++++++------ indra/newview/rlvhandler.cpp | 93 ++++++++++- indra/newview/rlvhandler.h | 8 +- indra/newview/rlvhelper.cpp | 231 ++++++++++++++++++++++++++++ indra/newview/rlvhelper.h | 265 ++++++++++++++++++++++++++++++-- 9 files changed, 757 insertions(+), 81 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index be88ad6e2f..ab577200f5 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9897,6 +9897,17 @@ Boolean Value 1 + + RLVaExperimentalCommands + + Comment + Enables the experimental command set + Persist + 1 + Type + Boolean + Value + 1 RevokePermsOnStopAnimation diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6a2498c57a..6a2f24a103 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3340,7 +3340,7 @@ LLSD LLAppViewer::getViewerInfo() const } #endif - info["RLV_VERSION"] = RlvActions::isRlvEnabled() ? RlvStrings::getVersionAbout() : "(disabled)"; + info["RLV_VERSION"] = RlvActions::isRlvEnabled() ? Rlv::Strings::getVersionAbout() : "(disabled)"; info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION))); // Settings diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index f641d56a85..898df3af42 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -1,5 +1,10 @@ #include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llchat.h" +#include "lldbstrings.h" #include "llversioninfo.h" +#include "llviewerstats.h" +#include "message.h" #include "rlvdefines.h" #include "rlvcommon.h" @@ -10,7 +15,7 @@ using namespace Rlv; // RlvStrings // -std::string RlvStrings::getVersion(bool wants_legacy) +std::string Strings::getVersion(bool wants_legacy) { return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)", !wants_legacy ? "RestrainedLove" : "RestrainedLife", @@ -18,23 +23,47 @@ std::string RlvStrings::getVersion(bool wants_legacy) ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch); } -std::string RlvStrings::getVersionAbout() +std::string Strings::getVersionAbout() { return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, LLVersionInfo::instance().getBuild()); } -std::string RlvStrings::getVersionNum() +std::string Strings::getVersionNum() { return llformat("%d%02d%02d%02d", SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, SpecVersion::Build); } -std::string RlvStrings::getVersionImplNum() +std::string Strings::getVersionImplNum() { return llformat("%d%02d%02d%02d", ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, ImplVersion::ImplId); } // ============================================================================ +// RlvUtil +// + +bool Util::sendChatReply(S32 nChannel, const std::string& strUTF8Text) +{ + if (!isValidReplyChannel(nChannel)) + return false; + + // Copy/paste from send_chat_from_viewer() + gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ChatData); + gMessageSystem->addStringFast(_PREHASH_Message, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN)); + gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); + gMessageSystem->addS32("Channel", nChannel); + gAgent.sendReliableMessage(); + add(LLStatViewer::CHAT_COUNT, 1); + + return true; +} + +// ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index 288d48e373..79ac6e1704 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -1,16 +1,41 @@ #pragma once -// ============================================================================ -// RlvStrings -// - -class RlvStrings +namespace Rlv { -public: - static std::string getVersion(bool wants_legacy); - static std::string getVersionAbout(); - static std::string getVersionImplNum(); - static std::string getVersionNum(); -}; + // ============================================================================ + // RlvStrings + // + + class Strings + { + public: + static std::string getVersion(bool wants_legacy); + static std::string getVersionAbout(); + static std::string getVersionImplNum(); + static std::string getVersionNum(); + }; + + // ============================================================================ + // RlvUtil + // + + namespace Util + { + bool isValidReplyChannel(S32 nChannel, bool isLoopback = false); + bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); + bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); + }; + + inline bool Util::isValidReplyChannel(S32 nChannel, bool isLoopback) + { + return (nChannel > (!isLoopback ? 0 : -1)) && (CHAT_CHANNEL_DEBUG != nChannel); + } + + inline bool Util::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text) + { + S32 nChannel; + return LLStringUtil::convertToS32(strChannel, nChannel) ? sendChatReply(nChannel, strUTF8Text) : false; + } -// ============================================================================ + // ============================================================================ +} diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 6ba2afbc69..0459b59483 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -4,32 +4,14 @@ // Defines // -namespace Rlv -{ - // Version of the specification we report - struct SpecVersion { - static constexpr S32 Major = 4; - static constexpr S32 Minor = 0; - static constexpr S32 Patch = 0; - static constexpr S32 Build = 0; - }; - - // RLVa implementation version - struct ImplVersion { - static constexpr S32 Major = 3; - static constexpr S32 Minor = 0; - static constexpr S32 Patch = 0; - static constexpr S32 ImplId = 2; /* Official viewer */ - }; -} - // Defining these makes it easier if we ever need to change our tag #define RLV_WARNS LL_WARNS("RLV") #define RLV_INFOS LL_INFOS("RLV") #define RLV_DEBUGS LL_DEBUGS("RLV") #define RLV_ENDL LL_ENDL +#define RLV_VERIFY(f) (f) -#define RLV_RELEASE +#define RLV_DEBUG #if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG // Make sure we halt execution on errors #define RLV_ERRS LL_ERRS("RLV") @@ -37,18 +19,36 @@ namespace Rlv #define RLV_ASSERT(f) if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; } #define RLV_ASSERT_DBG(f) RLV_ASSERT(f) #else + // Don't halt execution on errors in release + #define RLV_ERRS LL_WARNS("RLV") // We don't want to check assertions in release builds - #ifndef RLV_RELEASE + #ifdef RLV_DEBUG #define RLV_ASSERT(f) RLV_VERIFY(f) #define RLV_ASSERT_DBG(f) #else #define RLV_ASSERT(f) #define RLV_ASSERT_DBG(f) - #endif // RLV_RELEASE + #endif // RLV_DEBUG #endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG namespace Rlv { + // Version of the specification we report + namespace SpecVersion { + constexpr S32 Major = 4; + constexpr S32 Minor = 0; + constexpr S32 Patch = 0; + constexpr S32 Build = 0; + }; + + // RLVa implementation version + namespace ImplVersion { + constexpr S32 Major = 3; + constexpr S32 Minor = 0; + constexpr S32 Patch = 0; + constexpr S32 ImplId = 13; + }; + namespace Constants { constexpr char CmdPrefix = '@'; @@ -61,33 +61,84 @@ namespace Rlv namespace Rlv { - enum class ECmdRet{ - Unknown = 0x0000, // Unknown error (should only be used internally) - Retained, // Command was retained - Success = 0x0100, // Command executed successfully - SuccessUnset, // Command executed successfully (RLV_TYPE_REMOVE for an unrestricted behaviour) - SuccessDuplicate, // Command executed successfully (RLV_TYPE_ADD for an already restricted behaviour) - SuccessDeprecated, // Command executed successfully but has been marked as deprecated - SuccessDelayed, // Command parsed valid but will execute at a later time - Failed = 0x0200, // Command failed (general failure) - FailedSyntax, // Command failed (syntax error) - FailedOption, // Command failed (invalid option) - FailedParam, // Command failed (invalid param) - FailedLock, // Command failed (command is locked by another object) - FailedDisabled, // Command failed (command disabled by user) - FailedUnknown, // Command failed (unknown command) - FailedNoSharedRoot, // Command failed (missing #RLV) - FailedDeprecated, // Command failed (deprecated and no longer supported) - FailedNoBehaviour, // Command failed (force modifier on an object with no active restrictions) - FailedUnheldBehaviour, // Command failed (local modifier on an object that doesn't hold the base behaviour) - FailedBlocked, // Command failed (object is blocked) - FailedThrottled, // Command failed (throttled) - FailedNoProcessor // Command doesn't have a template processor define (legacy code) + enum class EBehaviour { + Version = 0, + VersionNew, + VersionNum, + + Count, + Unknown, }; + enum class EBehaviourOptionType + { + None, // Behaviour takes no parameters + Exception, // Behaviour requires an exception as a parameter + NoneOrException, // Behaviour takes either no parameters or an exception + }; + + enum class EParamType { + Unknown = 0x00, + Add = 0x01, // == "n"|"add" + Remove = 0x02, // == "y"|"rem" + Force = 0x04, // == "force" + Reply = 0x08, // == + Clear = 0x10, + AddRem = Add | Remove + }; + + enum class ECmdRet { + Unknown = 0x0000, // Unknown error (should only be used internally) + Retained, // Command was retained + Success = 0x0100, // Command executed successfully + SuccessUnset, // Command executed successfully (RLV_TYPE_REMOVE for an unrestricted behaviour) + SuccessDuplicate, // Command executed successfully (RLV_TYPE_ADD for an already restricted behaviour) + SuccessDeprecated, // Command executed successfully but has been marked as deprecated + SuccessDelayed, // Command parsed valid but will execute at a later time + Failed = 0x0200, // Command failed (general failure) + FailedSyntax, // Command failed (syntax error) + FailedOption, // Command failed (invalid option) + FailedParam, // Command failed (invalid param) + FailedLock, // Command failed (command is locked by another object) + FailedDisabled, // Command failed (command disabled by user) + FailedUnknown, // Command failed (unknown command) + FailedNoSharedRoot, // Command failed (missing #RLV) + FailedDeprecated, // Command failed (deprecated and no longer supported) + FailedNoBehaviour, // Command failed (force modifier on an object with no active restrictions) + FailedUnheldBehaviour, // Command failed (local modifier on an object that doesn't hold the base behaviour) + FailedBlocked, // Command failed (object is blocked) + FailedThrottled, // Command failed (throttled) + FailedNoProcessor // Command doesn't have a template processor define (legacy code) + }; + + enum class EExceptionCheck + { + Permissive, // Exception can be set by any object + Strict, // Exception must be set by all objects holding the restriction + Default, // Permissive or strict will be determined by currently enforced restrictions + }; + + // Replace&remove in c++23 + template + constexpr std::enable_if_t && !std::is_convertible_v, std::underlying_type_t> to_underlying(E e) noexcept + { + return static_cast>(e); + } + + template + constexpr std::enable_if_t && !std::is_convertible_v, bool> has_flag(E value, E flag) noexcept + { + return (to_underlying(value) & to_underlying(flag)) != 0; + } + constexpr bool isReturnCodeSuccess(ECmdRet eRet) { - return (static_cast(eRet) & static_cast(ECmdRet::Success)) == static_cast(ECmdRet::Success); + return (to_underlying(eRet) & to_underlying(ECmdRet::Success)) == to_underlying(ECmdRet::Success); + } + + constexpr bool isReturnCodeFailed(ECmdRet eRet) + { + return (to_underlying(eRet) & to_underlying(ECmdRet::Failed)) == to_underlying(ECmdRet::Failed); } } @@ -103,6 +154,7 @@ namespace Rlv constexpr char Debug[] = "RestrainedLoveDebug"; constexpr char DebugHideUnsetDup[] = "RLVaDebugHideUnsetDuplicate"; + constexpr char EnableExperimentalCommands[] = "RLVaExperimentalCommands"; constexpr char EnableIMQuery[] = "RLVaEnableIMQuery"; constexpr char EnableTempAttach[] = "RLVaEnableTemporaryAttachments"; constexpr char TopLevelMenu[] = "RLVaTopLevelMenu"; diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index bf78a0a38a..3d7f73937f 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1,4 +1,5 @@ #include "llviewerprecompiledheaders.h" +#include "llagent.h" #include "llappviewer.h" #include "llstartup.h" #include "llviewercontrol.h" @@ -22,11 +23,12 @@ bool RlvHandler::mIsEnabled = false; bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj) { + // *TODO: There's an edge case for temporary attachments when going from enabled -> disabled with restrictions already in place static LLCachedControl enable_temp_attach(gSavedSettings, Settings::EnableTempAttach); static LLCachedControl show_debug_output(gSavedSettings, Settings::Debug); static LLCachedControl hide_unset_dupes(gSavedSettings, Settings::DebugHideUnsetDup); - if ( message.length() <= 3 || Rlv::Constants::CmdPrefix != message[0] || CHAT_TYPE_OWNER != chat.mChatType || + if ( message.length() <= 3 || Constants::CmdPrefix != message[0] || CHAT_TYPE_OWNER != chat.mChatType || (chatObj && chatObj->isTempAttachment() && !enable_temp_attach()) ) { return false; @@ -39,7 +41,7 @@ bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, c boost_tokenizer tokens(message, boost::char_separator(",", "", boost::drop_empty_tokens)); for (const std::string& strCmd : tokens) { - ECmdRet eRet = (ECmdRet)processCommand(chat.mFromID, strCmd, true); + ECmdRet eRet = processCommand(chat.mFromID, strCmd, true); if ( show_debug_output() && (!hide_unset_dupes() || (ECmdRet::SuccessUnset != eRet && ECmdRet::SuccessDuplicate != eRet)) ) { @@ -53,7 +55,44 @@ bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, c ECmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCmd, bool fromObj) { - return ECmdRet::FailedNoProcessor; + const RlvCommand rlvCmd(idObj, strCmd); + return processCommand(std::ref(rlvCmd), fromObj); +} + +ECmdRet RlvHandler::processCommand(std::reference_wrapper rlvCmd, bool fromObj) +{ + { + const RlvCommand& rlvCmdTmp = rlvCmd; // Reference to the temporary with limited variable scope since we don't want it to leak below + + RLV_DEBUGS << "[" << rlvCmdTmp.getObjectID() << "]: " << rlvCmdTmp.asString() << RLV_ENDL; + if (!rlvCmdTmp.isValid()) + { + RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL; + return ECmdRet::FailedSyntax; + } + if (rlvCmdTmp.isBlocked()) + { + RLV_DEBUGS << "\t-> blocked command" << RLV_ENDL; + return ECmdRet::FailedDisabled; + } + } + + ECmdRet eRet = ECmdRet::Unknown; + switch (rlvCmd.get().getParamType()) + { + case EParamType::Reply: + eRet = rlvCmd.get().processCommand(); + break; + case EParamType::Unknown: + default: + eRet = ECmdRet::FailedParam; + break; + } + RLV_ASSERT(ECmdRet::Unknown != eRet); + + RLV_DEBUGS << "\t--> command " << (isReturnCodeSuccess(eRet) ? "succeeded" : "failed") << RLV_ENDL; + + return eRet; } // ============================================================================ @@ -72,7 +111,7 @@ bool RlvHandler::setEnabled(bool enable) if (enable && canEnable()) { - RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersionAbout() << RLV_ENDL; + RLV_INFOS << "Enabling Restrained Love API support - " << Strings::getVersionAbout() << RLV_ENDL; mIsEnabled = true; } @@ -80,3 +119,49 @@ bool RlvHandler::setEnabled(bool enable) } // ============================================================================ +// Command handlers (RLV_TYPE_REPLY) +// + +ECmdRet CommandHandlerBaseImpl::processCommand(const RlvCommand& rlvCmd, ReplyHandlerFunc* pHandler) +{ + // Sanity check - should specify a - valid - reply channel + S32 nChannel; + if (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel) || !Util::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) + return ECmdRet::FailedParam; + + std::string strReply; + ECmdRet eRet = (*pHandler)(rlvCmd, strReply); + + // If we made it this far then: + // - the command was handled successfully so we send off the response + // - the command failed but we still send off an - empty - response to keep the issuing script from blocking + if (nChannel != 0) + { + Util::sendChatReply(nChannel, strReply); + } + + return eRet; +} + +// Handles: @version= and @versionnew= +template<> template<> +ECmdRet VersionReplyHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + strReply = Strings::getVersion(EBehaviour::Version == rlvCmd.getBehaviourType()); + return ECmdRet::Success; +} + +// Handles: @versionnum[:impl]= +template<> template<> +ECmdRet ReplyHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (!rlvCmd.hasOption()) + strReply = Strings::getVersionNum(); + else if ("impl" == rlvCmd.getOption()) + strReply = Strings::getVersionImplNum(); + else + return ECmdRet::FailedOption; + return ECmdRet::Success; +} + +// ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index 8cf054e98e..a5e91548ef 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -3,7 +3,7 @@ #include "llchat.h" #include "llsingleton.h" -#include "rlvdefines.h" +#include "rlvhelper.h" class LLViewerObject; @@ -15,15 +15,17 @@ class RlvHandler : public LLSingleton { LLSINGLETON_EMPTY_CTOR(RlvHandler); -public: /* - * Helper functions + * Command processing */ public: // Command processing helper functions bool handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj); Rlv::ECmdRet processCommand(const LLUUID& idObj, const std::string& stCmd, bool fromObj); +protected: + Rlv::ECmdRet processCommand(std::reference_wrapper rlvCmdRef, bool fromObj); +public: // Initialization (deliberately static so they can safely be called in tight loops) static bool canEnable(); static bool isEnabled() { return mIsEnabled; } diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index ade2b83dd7..c3f9e6f756 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -1,11 +1,242 @@ #include "llviewerprecompiledheaders.h" #include "lltrans.h" +#include "llviewercontrol.h" #include "rlvhelper.h" +#include + using namespace Rlv; +// ============================================================================ +// BehaviourDictionary +// + +BehaviourDictionary::BehaviourDictionary() +{ + // + // Restrictions + // + + // + // Reply-only + // + addEntry(new ReplyProcessor("version")); + addEntry(new ReplyProcessor("versionnew")); + addEntry(new ReplyProcessor("versionnum")); + + // Populate mString2InfoMap (the tuple should be unique) + for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList) + { + RLV_VERIFY(mString2InfoMap.insert(std::make_pair(std::make_pair(bhvr_info_p->getBehaviour(), static_cast(bhvr_info_p->getParamTypeMask())), bhvr_info_p)).second); + } + + // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour) + for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList) + { + if ((bhvr_info_p->getParamTypeMask() & to_underlying(EParamType::AddRem)) && !bhvr_info_p->isSynonym()) + { +#ifdef RLV_DEBUG + for (const auto& itBhvr : boost::make_iterator_range(mBhvr2InfoMap.lower_bound(bhvr_info_p->getBehaviourType()), mBhvr2InfoMap.upper_bound(bhvr_info_p->getBehaviourType()))) + { + RLV_ASSERT((itBhvr.first != bhvr_info_p->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != bhvr_info_p->getBehaviourFlags())); + } +#endif // RLV_DEBUG + mBhvr2InfoMap.insert(std::pair(bhvr_info_p->getBehaviourType(), bhvr_info_p)); + } + } +} + +BehaviourDictionary::~BehaviourDictionary() +{ + for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList) + { + delete bhvr_info_p; + } + mBhvrInfoList.clear(); +} + +void BehaviourDictionary::addEntry(const BehaviourInfo* entry_p) +{ + // Filter experimental commands (if disabled) + static LLCachedControl sEnableExperimental(gSavedSettings, Settings::EnableExperimentalCommands); + if (!entry_p || (!sEnableExperimental && entry_p->isExperimental())) + { + return; + } + + // Sanity check for duplicate entries +#ifndef LL_RELEASE_FOR_DOWNLOAD + std::for_each(mBhvrInfoList.begin(), mBhvrInfoList.end(), + [&entry_p](const BehaviourInfo* bhvr_info_p) { + RLV_ASSERT_DBG((bhvr_info_p->getBehaviour() != entry_p->getBehaviour()) || ((bhvr_info_p->getParamTypeMask() & entry_p->getParamTypeMask()) == 0)); + }); +#endif // LL_RELEASE_FOR_DOWNLOAD + + mBhvrInfoList.push_back(entry_p); +} + +const BehaviourInfo* BehaviourDictionary::getBehaviourInfo(EBehaviour eBhvr, EParamType eParamType) const +{ + const BehaviourInfo* bhvr_info_p = nullptr; + for (auto itBhvrLower = mBhvr2InfoMap.lower_bound(eBhvr), itBhvrUpper = mBhvr2InfoMap.upper_bound(eBhvr); + std::find_if(itBhvrLower, itBhvrUpper, [eParamType](const auto& bhvrEntry) { return bhvrEntry.second->getParamTypeMask() == to_underlying(eParamType); }) != itBhvrUpper; + ++itBhvrLower) + { + if (bhvr_info_p) + return nullptr; + bhvr_info_p = itBhvrLower->second; + } + return bhvr_info_p; +} + +const BehaviourInfo* BehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p) const +{ + size_t idxBhvrLastPart = strBhvr.find_last_of('_'); + std::string strBhvrLastPart((std::string::npos != idxBhvrLastPart) && (idxBhvrLastPart < strBhvr.size()) ? strBhvr.substr(idxBhvrLastPart + 1) : LLStringUtil::null); + + bool isStrict = (strBhvrLastPart.compare("sec") == 0); + if (is_strict_p) + *is_strict_p = isStrict; + + auto itBhvr = mString2InfoMap.find(std::make_pair((!isStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (has_flag(eParamType, EParamType::AddRem)) ? EParamType::AddRem : eParamType)); + if ((mString2InfoMap.end() == itBhvr) && (!isStrict) && (!strBhvrLastPart.empty()) && (EParamType::Force == eParamType)) + { + // No match found but it could still be a local scope modifier + auto itBhvrMod = mString2InfoMap.find(std::make_pair(strBhvr.substr(0, idxBhvrLastPart), EParamType::AddRem)); + } + + return ((itBhvr != mString2InfoMap.end()) && ((!isStrict) || (itBhvr->second->hasStrict()))) ? itBhvr->second : nullptr; +} + +EBehaviour BehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, EParamType eParamType, bool* pisStrict) const +{ + const BehaviourInfo* bhvr_info_p = getBehaviourInfo(strBhvr, eParamType, pisStrict); + // Filter out locally scoped modifier commands since they don't actually have a unique behaviour value of their own + return bhvr_info_p->getBehaviourType(); +} + +bool BehaviourDictionary::getCommands(const std::string& strMatch, EParamType eParamType, std::list& cmdList) const +{ + cmdList.clear(); + for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList) + { + if ((bhvr_info_p->getParamTypeMask() & to_underlying(eParamType)) || (EParamType::Unknown == eParamType)) + { + std::string strCmd = bhvr_info_p->getBehaviour(); + if ((std::string::npos != strCmd.find(strMatch)) || (strMatch.empty())) + cmdList.push_back(strCmd); + if ((bhvr_info_p->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty()))) + cmdList.push_back(strCmd); + } + } + return !cmdList.empty(); +} + +bool BehaviourDictionary::getHasStrict(EBehaviour eBhvr) const +{ + for (const auto& itBhvr : boost::make_iterator_range(mBhvr2InfoMap.lower_bound(eBhvr), mBhvr2InfoMap.upper_bound(eBhvr))) + { + // Only restrictions can be strict + if (to_underlying(EParamType::AddRem) != itBhvr.second->getParamTypeMask()) + continue; + return itBhvr.second->hasStrict(); + } + RLV_ASSERT(false); + return false; +} + +void BehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, EParamType eParamType, BehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable) +{ + auto itBhvr = mString2InfoMap.find(std::make_pair(strBhvr, (has_flag(eParamType, EParamType::AddRem)) ? EParamType::AddRem : eParamType)); + if (mString2InfoMap.end() != itBhvr) + { + const_cast(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable); + } +} + +// ============================================================================ +// RlvCommmand +// + +RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCmd) + : mObjId(idObj) +{ + if (parseCommand(strCmd, mBehaviour, mOption, mParam)) + { + if ("n" == mParam || "add" == mParam) + mParamType = EParamType::Add; + else if ("y" == mParam || "rem" == mParam) + mParamType = EParamType::Remove; + else if ("clear" == mBehaviour) // clear is the odd one out so just make it its own type + mParamType = EParamType::Clear; + else if ("force" == mParam) + mParamType = EParamType::Force; + else if (S32 nTemp; LLStringUtil::convertToS32(mParam, nTemp)) // Assume it's a reply command if we can convert to an S32 + mParamType = EParamType::Reply; + } + + mIsValid = mParamType != EParamType::Unknown; + if (!mIsValid) + { + mOption.clear(); + mParam.clear(); + return; + } + + mBhvrInfo = BehaviourDictionary::instance().getBehaviourInfo(mBehaviour, mParamType, &mIsStrict); +} + +RlvCommand::RlvCommand(const RlvCommand& rlvCmd, EParamType eParamType) + : mIsValid(rlvCmd.mIsValid), mObjId(rlvCmd.mObjId), mBehaviour(rlvCmd.mBehaviour), mBhvrInfo(rlvCmd.mBhvrInfo) + , mParamType( (EParamType::Unknown == eParamType) ? rlvCmd.mParamType : eParamType) + , mIsStrict(rlvCmd.mIsStrict), mOption(rlvCmd.mOption), mParam(rlvCmd.mParam), mIsRefCounted(rlvCmd.mIsRefCounted) +{ +} + +bool RlvCommand::parseCommand(const std::string& strCmd, std::string& strBhvr, std::string& strOption, std::string& strParam) +{ + // Format: [: + RLVaTopLevelMenu + + Comment + Show the RLVa specific menu as a top level menu + Persist + 1 + Type + Boolean + Value + 1 RevokePermsOnStopAnimation diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index c1bf31ff9a..b9d80fff8e 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -76,6 +76,7 @@ #include "llslurl.h" #include "llstartup.h" #include "llperfstats.h" +#include "rlvcommon.h" // Third party library includes #include @@ -933,6 +934,8 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "TerrainPaintBitDepth", handleSetShaderChanged); setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged); + + setting_setup_signal_listener(gSavedSettings, Rlv::Settings::TopLevelMenu, Rlv::Util::menuToggleVisible); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 97d5781566..b8a4cc89fd 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -147,6 +147,7 @@ #include "llviewershadermgr.h" #include "gltfscenemanager.h" #include "gltf/asset.h" +#include "rlvcommon.h" using namespace LLAvatarAppearanceDefines; @@ -6375,6 +6376,8 @@ void show_debug_menus() gMenuBarView->setItemVisible("Advanced", debug); // gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + Rlv::Util::menuToggleVisible(); + gMenuBarView->setItemVisible("Debug", qamode); gMenuBarView->setItemEnabled("Debug", qamode); diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index eda2cdedc8..abb54b5b39 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -1,15 +1,18 @@ #include "llviewerprecompiledheaders.h" + #include "llagent.h" #include "llchat.h" #include "lldbstrings.h" #include "llversioninfo.h" +#include "llviewermenu.h" #include "llviewerstats.h" #include "message.h" +#include -#include "rlvdefines.h" #include "rlvcommon.h" -#include +#include "llviewercontrol.h" +#include "rlvhandler.h" using namespace Rlv; @@ -48,6 +51,32 @@ std::string Strings::getVersionImplNum() // RlvUtil // +void Util::menuToggleVisible() +{ + bool isTopLevel = gSavedSettings.getBOOL(Settings::TopLevelMenu); + bool isRlvEnabled = RlvHandler::isEnabled(); + + LLMenuGL* menuRLVaMain = gMenuBarView->findChildMenuByName("RLVa Main", false); + LLMenuGL* menuAdvanced = gMenuBarView->findChildMenuByName("Advanced", false); + LLMenuGL* menuRLVaEmbed= menuAdvanced->findChildMenuByName("RLVa Embedded", false); + + gMenuBarView->setItemVisible("RLVa Main", isRlvEnabled && isTopLevel); + menuAdvanced->setItemVisible("RLVa Embedded", isRlvEnabled && !isTopLevel); + + if ( isRlvEnabled && menuRLVaMain && menuRLVaEmbed && + ( (isTopLevel && 1 == menuRLVaMain->getItemCount()) || (!isTopLevel && 1 == menuRLVaEmbed->getItemCount())) ) + { + LLMenuGL* menuFrom = isTopLevel ? menuRLVaEmbed : menuRLVaMain; + LLMenuGL* menuTo = isTopLevel ? menuRLVaMain : menuRLVaEmbed; + while (LLMenuItemGL* pItem = menuFrom->getItem(1)) + { + menuFrom->removeChild(pItem); + menuTo->addChild(pItem); + pItem->updateBranchParent(menuTo); + } + } +} + bool Util::parseStringList(const std::string& strInput, std::vector& optionList, std::string_view strSeparator) { if (!strInput.empty()) diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index bec3e23e11..d18abcf1ac 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -24,6 +24,7 @@ namespace Rlv namespace Util { bool isValidReplyChannel(S32 nChannel, bool isLoopback = false); + void menuToggleVisible(); bool parseStringList(const std::string& strInput, std::vector& optionList, std::string_view strSeparator = Constants::OptionSeparator); bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 40f3e51fca..d04bf87676 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1818,6 +1818,71 @@ function="World.EnvPreset" parameter="sl_about" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 3c49c33f1333be9508966bcb8e79adfbaec79e46 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Mon, 16 Sep 2024 15:41:09 +0200 Subject: Don't compose emojis on the RLVa console input --- indra/newview/skins/default/xui/en/floater_rlv_console.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml index 928d50cb41..708055d1b6 100644 --- a/indra/newview/skins/default/xui/en/floater_rlv_console.xml +++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml @@ -66,6 +66,7 @@ left="1" top="1" right="-1" + show_emoji_helper="false" wrap="true" /> -- cgit v1.2.3 From 6f4d7c2d6d363aee60d2f3d1fe4ed4a251aaa11b Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 17 Sep 2024 19:12:55 +0200 Subject: Add proper file headers --- indra/newview/rlvactions.cpp | 27 +++++++++++++++++++++++++++ indra/newview/rlvactions.h | 27 +++++++++++++++++++++++++++ indra/newview/rlvcommon.cpp | 27 +++++++++++++++++++++++++++ indra/newview/rlvcommon.h | 27 +++++++++++++++++++++++++++ indra/newview/rlvdefines.h | 27 +++++++++++++++++++++++++++ indra/newview/rlvfloaters.cpp | 27 +++++++++++++++++++++++++++ indra/newview/rlvfloaters.h | 27 +++++++++++++++++++++++++++ indra/newview/rlvhandler.cpp | 27 +++++++++++++++++++++++++++ indra/newview/rlvhandler.h | 27 +++++++++++++++++++++++++++ indra/newview/rlvhelper.cpp | 27 +++++++++++++++++++++++++++ indra/newview/rlvhelper.h | 27 +++++++++++++++++++++++++++ 11 files changed, 297 insertions(+) (limited to 'indra') diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp index 1988c99ecf..110beeafc0 100644 --- a/indra/newview/rlvactions.cpp +++ b/indra/newview/rlvactions.cpp @@ -1,3 +1,30 @@ +/** + * @file rlvactions.cpp + * @author Kitty Barnett + * @brief RLVa public facing helper class to easily make RLV checks + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #include "llviewerprecompiledheaders.h" #include "rlvactions.h" diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h index ac4fc73339..cb0df95e37 100644 --- a/indra/newview/rlvactions.h +++ b/indra/newview/rlvactions.h @@ -1,3 +1,30 @@ +/** + * @file rlvactions.h + * @author Kitty Barnett + * @brief RLVa public facing helper class to easily make RLV checks + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once // ============================================================================ diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index abb54b5b39..4140659715 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -1,3 +1,30 @@ +/** + * @file rlvcommon.h + * @author Kitty Barnett + * @brief RLVa helper functions and constants used throughout the viewer + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #include "llviewerprecompiledheaders.h" #include "llagent.h" diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index d18abcf1ac..6f1bbbbdc6 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -1,3 +1,30 @@ +/** + * @file rlvcommon.h + * @author Kitty Barnett + * @brief RLVa helper functions and constants used throughout the viewer + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once #include "rlvdefines.h" diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 88dffa1127..15baf1ba49 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -1,3 +1,30 @@ +/** + * @file rlvdefines.h + * @author Kitty Barnett + * @brief RLVa common defines, constants and enums + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once // ============================================================================ diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp index 8d107b2540..8a074fd14d 100644 --- a/indra/newview/rlvfloaters.cpp +++ b/indra/newview/rlvfloaters.cpp @@ -1,3 +1,30 @@ +/** + * @file rlvfloaters.cpp + * @author Kitty Barnett + * @brief RLVa floaters class implementations + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #include "llviewerprecompiledheaders.h" #include "llagentdata.h" diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h index a599bb051a..1d560f32d4 100644 --- a/indra/newview/rlvfloaters.h +++ b/indra/newview/rlvfloaters.h @@ -1,3 +1,30 @@ +/** + * @file rlvfloaters.h + * @author Kitty Barnett + * @brief RLVa floaters class implementations + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once #include "llfloater.h" diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 0a0da0e25d..bf086c1b4b 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1,3 +1,30 @@ +/** + * @file rlvhandler.cpp + * @author Kitty Barnett + * @brief RLVa helper classes for internal use only + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #include "llviewerprecompiledheaders.h" #include "llagent.h" #include "llstartup.h" diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index 7fa4da767a..38612485b1 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -1,3 +1,30 @@ +/** + * @file rlvhandler.h + * @author Kitty Barnett + * @brief Primary command process and orchestration class + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once #include "llchat.h" diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index ecb76a1db3..a82de4b9b8 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -1,3 +1,30 @@ +/** + * @file rlvhelper.cpp + * @author Kitty Barnett + * @brief RLVa helper classes for internal use only + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #include "llviewerprecompiledheaders.h" #include "lltrans.h" diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 644cd0ee22..7f0435f791 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -1,3 +1,30 @@ +/** + * @file rlvhelper.h + * @author Kitty Barnett + * @brief RLVa helper classes for internal use only + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + #pragma once #include "rlvdefines.h" -- cgit v1.2.3 From fca4227e59d3375e824e0265a08d6b7ed7715632 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 17 Sep 2024 23:07:29 +0200 Subject: Fix tab vs whitespace line --- indra/newview/llviewermenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index dbd3478637..bbf2dfad13 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6248,7 +6248,7 @@ void show_debug_menus() gMenuBarView->setItemVisible("Advanced", debug); // gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden - Rlv::Util::menuToggleVisible(); + Rlv::Util::menuToggleVisible(); gMenuBarView->setItemVisible("Debug", qamode); gMenuBarView->setItemEnabled("Debug", qamode); -- cgit v1.2.3 From e03ad4913fd9dc12d9efcdd3854885a1622277ef Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 17 Sep 2024 23:44:22 +0200 Subject: Mac build fixes: Reapply the template fix in rlvhelper.h + point to LLFloaterReg in the global namespace --- indra/newview/rlvfloaters.h | 3 ++- indra/newview/rlvhelper.h | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'indra') diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h index 1d560f32d4..8acfa43f28 100644 --- a/indra/newview/rlvfloaters.h +++ b/indra/newview/rlvfloaters.h @@ -32,6 +32,7 @@ #include "rlvdefines.h" class LLChatEntry; +class LLFloaterReg; class LLLayoutPanel; class LLTextEditor; class RlvCommand; @@ -45,7 +46,7 @@ namespace Rlv class FloaterConsole : public LLFloater { - friend class LLFloaterReg; + friend class ::LLFloaterReg; FloaterConsole(const LLSD& sdKey) : LLFloater(sdKey) {} public: diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 7f0435f791..f241332594 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -152,14 +152,20 @@ namespace Rlv // // CommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors) // + #if LL_WINDOWS + #define RLV_TEMPL_FIX(x) template + #else + #define RLV_TEMPL_FIX(x) template + #endif // LL_WINDOWS + template struct CommandHandler { - template::type> static ECmdRet onCommand(const RlvCommand&, bool&); - template::type> static void onCommandToggle(EBehaviour, bool); - template::type> static ECmdRet onCommand(const RlvCommand&); - template::type> static ECmdRet onCommand(const RlvCommand&, std::string&); + RLV_TEMPL_FIX(typename = typename std::enable_if::type) static ECmdRet onCommand(const RlvCommand&, bool&); + RLV_TEMPL_FIX(typename = typename std::enable_if::type) static void onCommandToggle(EBehaviour, bool); + RLV_TEMPL_FIX(typename = typename std::enable_if::type) static ECmdRet onCommand(const RlvCommand&); + RLV_TEMPL_FIX(typename = typename std::enable_if::type) static ECmdRet onCommand(const RlvCommand&, std::string&); }; // Aliases to improve readability in definitions @@ -179,11 +185,11 @@ namespace Rlv { public: // Default constructor used by behaviour specializations - template::type> + RLV_TEMPL_FIX(typename = typename std::enable_if::type) CommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {} // Constructor used when we don't want to specialize on behaviour (see BehaviourGenericProcessor) - template::type> + RLV_TEMPL_FIX(typename = typename std::enable_if::type) CommandProcessor(const std::string& strBhvr, EBehaviour eBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {} ECmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); } -- cgit v1.2.3 From dc64ac19fd74694a6e9ecf0cb68e3f83257c93b9 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 28 Sep 2024 00:36:12 +0200 Subject: Replace None and Success. Those are X11 defines and thus lead to compile errors when compiling a Linux viewer. --- indra/newview/rlvdefines.h | 6 +++--- indra/newview/rlvhandler.cpp | 6 +++--- indra/newview/rlvhelper.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'indra') diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 15baf1ba49..e3472ed4a8 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -102,7 +102,7 @@ namespace Rlv enum class EBehaviourOptionType { - None, // Behaviour takes no parameters + EmptyOrException, // Behaviour takes no parameters Exception, // Behaviour requires an exception as a parameter NoneOrException, // Behaviour takes either no parameters or an exception }; @@ -120,7 +120,7 @@ namespace Rlv enum class ECmdRet { Unknown = 0x0000, // Unknown error (should only be used internally) Retained, // Command was retained - Success = 0x0100, // Command executed successfully + Succeeded = 0x0100, // Command executed successfully SuccessUnset, // Command executed successfully (RLV_TYPE_REMOVE for an unrestricted behaviour) SuccessDuplicate, // Command executed successfully (RLV_TYPE_ADD for an already restricted behaviour) SuccessDeprecated, // Command executed successfully but has been marked as deprecated @@ -163,7 +163,7 @@ namespace Rlv constexpr bool isReturnCodeSuccess(ECmdRet eRet) { - return (to_underlying(eRet) & to_underlying(ECmdRet::Success)) == to_underlying(ECmdRet::Success); + return (to_underlying(eRet) & to_underlying(ECmdRet::Succeeded)) == to_underlying(ECmdRet::Succeeded); } constexpr bool isReturnCodeFailed(ECmdRet eRet) diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index bf086c1b4b..6c4b439105 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -198,7 +198,7 @@ ECmdRet ReplyHandler::onCommand(const RlvCommand& rlvCmd std::list cmdList; if (BehaviourDictionary::instance().getCommands(!optionList.empty() ? optionList[0] : LLStringUtil::null, eType, cmdList)) strReply = boost::algorithm::join(cmdList, optionList.size() >= 3 ? optionList[2] : Constants::OptionSeparator); - return ECmdRet::Success; + return ECmdRet::Succeeded; } // Handles: @version= and @versionnew= @@ -206,7 +206,7 @@ template<> template<> ECmdRet VersionReplyHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) { strReply = Strings::getVersion(EBehaviour::Version == rlvCmd.getBehaviourType()); - return ECmdRet::Success; + return ECmdRet::Succeeded; } // Handles: @versionnum[:impl]= @@ -219,7 +219,7 @@ ECmdRet ReplyHandler::onCommand(const RlvCommand& rlvCmd strReply = Strings::getVersionImplNum(); else return ECmdRet::FailedOption; - return ECmdRet::Success; + return ECmdRet::Succeeded; } // ============================================================================ diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index a82de4b9b8..988fc9ca8b 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -283,7 +283,7 @@ namespace Rlv else if (mForConsole) return; // Only show console feedback on successful commands when there's an informational notice - std::string& strResult = mCommandResults[isReturnCodeSuccess(eRet) ? ECmdRet::Success : (ECmdRet::Retained == eRet ? ECmdRet::Retained : ECmdRet::Failed)]; + std::string& strResult = mCommandResults[isReturnCodeSuccess(eRet) ? ECmdRet::Succeeded : (ECmdRet::Retained == eRet ? ECmdRet::Retained : ECmdRet::Failed)]; if (!strResult.empty()) strResult.append(", "); strResult.append(strCmd); @@ -308,7 +308,7 @@ namespace Rlv }; if (!mForConsole) result << ": @" << mOrigCmd; - appendResult(ECmdRet::Success, !mForConsole ? "RlvDebugExecuted" : "RlvConsoleExecuted"); + appendResult(ECmdRet::Succeeded, !mForConsole ? "RlvDebugExecuted" : "RlvConsoleExecuted"); appendResult(ECmdRet::Failed, !mForConsole ? "RlvDebugFailed" : "RlvConsoleFailed"); appendResult(ECmdRet::Retained, !mForConsole ? "RlvDebugRetained" : "RlvConsoleRetained"); } @@ -320,7 +320,7 @@ namespace Rlv { switch (eRet) { - case ECmdRet::Success: + case ECmdRet::Succeeded: return LLTrans::getString("RlvDebugExecuted"); case ECmdRet::Failed: return LLTrans::getString("RlvDebugFailed"); @@ -372,7 +372,7 @@ namespace Rlv return LLTrans::getString("RlvReturnCodeNoProcessor"); // The following are identified by the chat verb case ECmdRet::Retained: - case ECmdRet::Success: + case ECmdRet::Succeeded: case ECmdRet::Failed: return LLStringUtil::null; // The following shouldn't occur -- cgit v1.2.3 From 689f723a5f314ffa0f54c0e50a51cbe464b36ccf Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Wed, 2 Oct 2024 00:34:09 +0200 Subject: Remove unneeded RLV_VERIFY + undefine accidental RLV_DEBUG define (should fix Linux build) --- indra/newview/rlvdefines.h | 1 - indra/newview/rlvhelper.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index e3472ed4a8..e39328fdd6 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -38,7 +38,6 @@ #define RLV_ENDL LL_ENDL #define RLV_VERIFY(f) (f) -#define RLV_DEBUG #if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG // Make sure we halt execution on errors #define RLV_ERRS LL_ERRS("RLV") diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 988fc9ca8b..7cb1473c8c 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -57,7 +57,7 @@ BehaviourDictionary::BehaviourDictionary() // Populate mString2InfoMap (the tuple should be unique) for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList) { - RLV_VERIFY(mString2InfoMap.insert(std::make_pair(std::make_pair(bhvr_info_p->getBehaviour(), static_cast(bhvr_info_p->getParamTypeMask())), bhvr_info_p)).second); + mString2InfoMap.insert(std::make_pair(std::make_pair(bhvr_info_p->getBehaviour(), static_cast(bhvr_info_p->getParamTypeMask())), bhvr_info_p)); } // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour) -- cgit v1.2.3 From 3904a15c63dbebca439ecf62f07234e1895dc93b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 2 Oct 2024 17:35:17 +0300 Subject: viewer#2705 Some sky parameters weren't updating --- indra/llinventory/llsettingssky.cpp | 8 ++++++++ indra/newview/llsettingsvo.cpp | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 3685915ffd..ce6244d038 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -1995,6 +1995,7 @@ F32 LLSettingsSky::getCloudShadow() const void LLSettingsSky::setCloudShadow(F32 val) { mCloudShadow = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2051,6 +2052,7 @@ F32 LLSettingsSky::getMaxY() const void LLSettingsSky::setMaxY(F32 val) { mMaxY = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2062,6 +2064,7 @@ LLQuaternion LLSettingsSky::getMoonRotation() const void LLSettingsSky::setMoonRotation(const LLQuaternion &val) { mMoonRotation = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2073,6 +2076,7 @@ F32 LLSettingsSky::getMoonScale() const void LLSettingsSky::setMoonScale(F32 val) { mMoonScale = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2095,6 +2099,7 @@ F32 LLSettingsSky::getMoonBrightness() const void LLSettingsSky::setMoonBrightness(F32 brightness_factor) { mMoonBrightness = brightness_factor; + setDirtyFlag(true); setLLSDDirty(); } @@ -2131,6 +2136,7 @@ LLColor3 LLSettingsSky::getSunlightColorClamped() const void LLSettingsSky::setSunlightColor(const LLColor3 &val) { mSunlightColor = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2142,6 +2148,7 @@ LLQuaternion LLSettingsSky::getSunRotation() const void LLSettingsSky::setSunRotation(const LLQuaternion &val) { mSunRotation = val; + setDirtyFlag(true); setLLSDDirty(); } @@ -2153,6 +2160,7 @@ F32 LLSettingsSky::getSunScale() const void LLSettingsSky::setSunScale(F32 val) { mSunScale = val; + setDirtyFlag(true); setLLSDDirty(); } diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 34b8535c84..fee0bbcda4 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -671,7 +671,8 @@ void LLSettingsVOSky::updateSettings() // After some A/B comparison of relesae vs EEP, tweak to allow strength to fall below 2 // at night, for better match. (mSceneLightStrength is a divisor, so lower value means brighter // local lights) - F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f); + LLCachedControl sdr(gSavedSettings, "RenderSunDynamicRange", 1.f); + F32 sun_dynamic_range = llmax(sdr(), 0.0001f); mSceneLightStrength = 2.0f * (0.75f + sun_dynamic_range * dp); gSky.setSunAndMoonDirectionsCFR(sun_direction, moon_direction); -- cgit v1.2.3 From 9d3c8475c62f1664b450e0056d60ef95acc52d97 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 3 Oct 2024 00:06:32 +0300 Subject: viewer#2709 Fix loose triangle #2 --- indra/llrender/llrender2dutils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index c3d5da0914..5b08c29d64 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -1693,10 +1693,10 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mTop* height_vec).mV); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft* width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop); gGL.vertex3fv((height_vec).mV); -- cgit v1.2.3 From 0e86bebcfc80259476654190880f9bfd5b35934e Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:46:33 -0700 Subject: #2650 Add UI controls for debug settings: RenderTonemapMix RenderTonemapType (#2787) Co-authored-by: Maxim Nikolenko --- .../en/floater_preferences_graphics_advanced.xml | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 1deb81175e..8bb15d1d3a 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -943,6 +943,57 @@ width="260"> + + + Tone Mapper: + + + + + + + + Date: Fri, 4 Oct 2024 14:16:04 -0700 Subject: cherry pick secondlife/viewer#912 BugSplat Crash 1412267: nvoglv64+0xadcd00 (#2785) * secondlife/viewer#912 BugSplat Crash 1412267: nvoglv64+0xadcd00 * fix cherry-pick merge breakage. * Fix signed/unsigned error --------- Co-authored-by: Alexander Gavriliuk --- indra/llprimitive/lldaeloader.cpp | 40 ++++----- indra/llprimitive/llmodel.cpp | 16 ++-- indra/llprimitive/llmodel.h | 2 +- indra/llprimitive/llmodelloader.cpp | 25 ++---- indra/llprimitive/llmodelloader.h | 41 +++++---- indra/newview/llmodelpreview.cpp | 164 +++++++++++++++++++----------------- 6 files changed, 140 insertions(+), 148 deletions(-) (limited to 'indra') diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index f286bff353..7fa4230237 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1115,19 +1115,17 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (skin) { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) + if (domGeometry* geom = daeSafeCast(skin->getSource().getElement())) { - domMesh* mesh = geom->getMesh(); - if (mesh) + if (domMesh* mesh = geom->getMesh()) { - std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin(); - while (i != mModelsMap[mesh].end()) + dae_model_map::const_iterator it = mModelsMap.find(mesh); + if (it != mModelsMap.end()) { - LLPointer mdl = *i; - LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin); - i++; + for (const LLPointer& model : it->second) + { + LLDAELoader::processDomModel(model, &dae, root, mesh, skin); + } } } } @@ -1297,6 +1295,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } } else + { //Has one or more skeletons for (std::vector::iterator skel_it = skeletons.begin(); skel_it != skeletons.end(); ++skel_it) @@ -1381,6 +1380,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } }//got skeleton? } + } domSkin::domJoints* joints = skin->getJoints(); @@ -1681,7 +1681,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do materials[model->mMaterialList[i]] = LLImportMaterial(); } mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + stretch_extents(model, transformation); } } @@ -2074,21 +2074,14 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da mTransform.condition(); } - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) + if (domInstance_geometry* instance_geo = daeSafeCast(element)) { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) + if (domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement())) { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) + if (domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID())))) { - - std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin(); - while (i != mModelsMap[mesh].end()) + for (LLModel* model : mModelsMap.find(mesh)->second) { - LLModel* model = *i; - LLMatrix4 transformation = mTransform; if (mTransform.determinant() < 0) @@ -2159,8 +2152,7 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da } mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - i++; + stretch_extents(model, transformation); } } } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 9908a155f2..4e3e49ec9f 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -91,19 +91,15 @@ std::string LLModel::getStatusString(U32 status) } -void LLModel::offsetMesh( const LLVector3& pivotPoint ) +void LLModel::offsetMesh(const LLVector3& pivotPoint) { - LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); + LLVector4a pivot(pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ]); - for (std::vector::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); ) + for (LLVolumeFace& face : mVolumeFaces) { - std::vector:: iterator currentFaceIt = faceIt++; - LLVolumeFace& face = *currentFaceIt; - LLVector4a *pos = (LLVector4a*) face.mPositions; - - for (S32 i=0; i LLModelLoader::sActiveLoaderList; -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform) +static void stretch_extents(const LLModel* model, const LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform) { LLVector4a box[] = { @@ -84,19 +84,19 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4 } } -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform) +void LLModelLoader::stretch_extents(const LLModel* model, const LLMatrix4& mat) { LLVector4a mina, maxa; LLMatrix4a mata; mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); + mina.load3(mExtents[0].mV); + maxa.load3(mExtents[1].mV); - stretch_extents(model, mata, mina, maxa, first_transform); + ::stretch_extents(model, mata, mina, maxa, mFirstTransform); - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); + mExtents[0].set(mina.getF32ptr()); + mExtents[1].set(maxa.getF32ptr()); } //----------------------------------------------------------------------------- @@ -291,14 +291,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) { if (idx >= model[lod].size()) { - if (model[lod].size()) - { - instance_list[i].mLOD[lod] = model[lod][0]; - } - else - { - instance_list[i].mLOD[lod] = NULL; - } + instance_list[i].mLOD[lod] = model[lod].front(); continue; } @@ -341,7 +334,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) { LLModelInstance& cur_instance = instance_list[i]; mScene[cur_instance.mTransform].push_back(cur_instance); - stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); + stretch_extents(cur_instance.mModel, cur_instance.mTransform); } setLoadState( DONE ); diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 83bd2f5bbd..530e61e2b8 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -34,13 +34,13 @@ class LLJoint; -typedef std::map JointTransformMap; -typedef std::map::iterator JointTransformMapIt; -typedef std::map JointMap; -typedef std::deque JointNameSet; +typedef std::map JointTransformMap; +typedef std::map::iterator JointTransformMapIt; +typedef std::map JointMap; +typedef std::deque JointNameSet; const S32 SLM_SUPPORTED_VERSION = 3; -const S32 NUM_LOD = 4; +const S32 NUM_LOD = 4; const U32 LEGACY_RIG_OK = 0; const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1; @@ -50,32 +50,32 @@ class LLModelLoader : public LLThread { public: - typedef std::map material_map; - typedef std::vector > model_list; - typedef std::vector model_instance_list; - typedef std::map scene; + typedef std::map material_map; + typedef std::vector> model_list; + typedef std::vector model_instance_list; + typedef std::map scene; // Callback with loaded model data and loaded LoD // - typedef boost::function load_callback_t; + typedef boost::function load_callback_t; // Function to provide joint lookup by name // (within preview avi skeleton, for example) // - typedef boost::function joint_lookup_func_t; + typedef boost::function joint_lookup_func_t; // Func to load and associate material with all it's textures, // returned value is the number of textures loaded // intentionally non-const so func can modify material to // store platform-specific data // - typedef boost::function texture_load_func_t; + typedef boost::function texture_load_func_t; // Callback to inform client of state changes // during loading process (errors will be reported // as state changes here as well) // - typedef boost::function state_callback_t; + typedef boost::function state_callback_t; typedef enum { @@ -136,7 +136,7 @@ public: JointNameSet& jointsFromNodes, JointMap& legalJointNamesMap, U32 maxJointsPerMesh); - virtual ~LLModelLoader() ; + virtual ~LLModelLoader(); virtual void setNoNormalize() { mNoNormalize = true; } virtual void setNoOptimize() { mNoOptimize = true; } @@ -156,13 +156,13 @@ public: bool loadFromSLM(const std::string& filename); void loadModelCallback(); - void loadTextures() ; //called in the main thread. + void loadTextures() ; // called in the main thread. void setLoadState(U32 state); + void stretch_extents(const LLModel* model, const LLMatrix4& mat); - - S32 mNumOfFetchingTextures ; //updated in the main thread - bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. + S32 mNumOfFetchingTextures ; // updated in the main thread + bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread. bool verifyCount( int expected, int result ); @@ -212,10 +212,7 @@ protected: LLSD mWarningsArray; // preview floater will pull logs from here static std::list sActiveLoaderList; - static bool isAlive(LLModelLoader* loader) ; + static bool isAlive(LLModelLoader* loader); }; -class LLMatrix4a; -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform); -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform); #endif // LL_LLMODELLOADER_H diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index ef09cfa55b..1e7da126b0 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -134,25 +134,17 @@ std::string getLodSuffix(S32 lod) void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) { - LLModelLoader::scene::iterator base_iter = scene.begin(); - bool found = false; - while (!found && (base_iter != scene.end())) + for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++) { - matOut = base_iter->first; - - LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); - while (!found && (base_instance_iter != base_iter->second.end())) + for (auto model_iter = scene_iter->second.begin(); model_iter != scene_iter->second.end(); model_iter++) { - LLModelInstance& base_instance = *base_instance_iter++; - LLModel* base_model = base_instance.mModel; - - if (base_model && (base_model->mLabel == name_to_match)) + if (model_iter->mModel && (model_iter->mModel->mLabel == name_to_match)) { - baseModelOut = base_model; + baseModelOut = model_iter->mModel; + matOut = scene_iter->first; return; } } - base_iter++; } } @@ -212,9 +204,12 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) LLModelPreview::~LLModelPreview() { + LLMutexLock lock(this); + if (mModelLoader) { mModelLoader->shutdown(); + mModelLoader = NULL; } if (mPreviewAvatar) @@ -262,7 +257,7 @@ void LLModelPreview::updateDimentionsAndOffsets() accounted.insert(instance.mModel); // update instance skin info for each lods pelvisZoffset - for (int j = 0; jfirst; @@ -322,9 +317,9 @@ void LLModelPreview::rebuildUploadData() mat *= scale_mat; - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) + for (auto model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { // for each instance with said transform applied - LLModelInstance instance = *model_iter++; + LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; @@ -910,7 +905,7 @@ void LLModelPreview::clearIncompatible(S32 lod) { mBaseModel = mModel[lod]; mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); replaced_base_model = true; } } @@ -1132,7 +1127,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) mBaseModel = mModel[loaded_lod]; mBaseScene = mScene[loaded_lod]; - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); } else { @@ -1248,7 +1243,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) { if (!mBaseModel.empty()) { - const std::string& model_name = mBaseModel[0]->getName(); + std::string model_name = mBaseModel.front()->getName(); LLLineEditor* description_form = mFMP->getChild("description_form"); if (description_form->getText().empty()) { @@ -1269,6 +1264,8 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) void LLModelPreview::resetPreviewTarget() { + LLMutexLock lock(this); + if (mModelLoader) { mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; @@ -1314,7 +1311,7 @@ void LLModelPreview::generateNormals() (*it)->generateNormals(angle_cutoff); } - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); } bool perform_copy = mModelFacesCopy[which_lod].empty(); @@ -2156,7 +2153,7 @@ void LLModelPreview::updateStatusMessages() S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { total_tris[i] = 0; total_verts[i] = 0; @@ -2460,12 +2457,16 @@ void LLModelPreview::updateStatusMessages() } } - if (mModelNoErrors && mModelLoader) + if (mModelNoErrors) { - if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + LLMutexLock lock(this); + if (mModelLoader) { - // Some textures are still loading, prevent upload until they are done - mModelNoErrors = false; + if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + { + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; + } } } @@ -2794,10 +2795,10 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { LLModelLoader::model_list* model = NULL; - if (lod < 0 || lod > 4) + if (lod < 0 || lod >= LLModel::NUM_LODS) { model = &mBaseModel; - lod = 5; + lod = LLModel::NUM_LODS; } else { @@ -3034,8 +3035,9 @@ void LLModelPreview::loadedCallback( S32 lod, void* opaque) { - LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); - if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) + LLModelPreview* pPreview = static_cast(opaque); + LLMutexLock lock(pPreview); + if (pPreview && pPreview->mModelLoader && !LLModelPreview::sIgnoreLoadedCallback) { // Load loader's warnings into floater's log tab const LLSD out = pPreview->mModelLoader->logOut(); @@ -3056,7 +3058,9 @@ void LLModelPreview::loadedCallback( } const LLVOAvatar* avatarp = pPreview->getPreviewAvatar(); - if (avatarp) { // set up ground plane for possible rendering + if (avatarp && avatarp->mRoot && avatarp->mDrawable) + { + // set up ground plane for possible rendering const LLVector3 root_pos = avatarp->mRoot->getPosition(); const LLVector4a* ext = avatarp->mDrawable->getSpatialExtents(); const LLVector4a min = ext[0], max = ext[1]; @@ -3200,12 +3204,12 @@ bool LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = false; - bool edges = mViewOption["show_edges"]; - bool joint_overrides = mViewOption["show_joint_overrides"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; + bool show_edges = mViewOption["show_edges"]; + bool show_joint_overrides = mViewOption["show_joint_overrides"]; + bool show_joint_positions = mViewOption["show_joint_positions"]; + bool show_skin_weight = mViewOption["show_skin_weight"]; + bool show_textures = mViewOption["show_textures"]; + bool show_physics = mViewOption["show_physics"]; S32 width = getWidth(); S32 height = getHeight(); @@ -3282,15 +3286,15 @@ bool LLModelPreview::render() fmp->childSetValue("upload_skin", true); mFirstSkinUpdate = false; upload_skin = true; - skin_weight = true; + show_skin_weight = true; mViewOption["show_skin_weight"] = true; } fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_overrides", skin_weight); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + fmp->setViewOptionEnabled("show_joint_overrides", show_skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", show_skin_weight); mFMP->childEnable("upload_skin"); - mFMP->childSetValue("show_skin_weight", skin_weight); + mFMP->childSetValue("show_skin_weight", show_skin_weight); } else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0) @@ -3313,11 +3317,12 @@ bool LLModelPreview::render() fmp->disableViewOption("show_joint_overrides"); fmp->disableViewOption("show_joint_positions"); - skin_weight = false; + show_skin_weight = false; mFMP->childSetValue("show_skin_weight", false); - fmp->setViewOptionEnabled("show_skin_weight", skin_weight); + fmp->setViewOptionEnabled("show_skin_weight", show_skin_weight); } } + //if (this) return TRUE; if (upload_skin && !has_skin_weights) { //can't upload skin weights if model has no skin weights @@ -3360,7 +3365,7 @@ bool LLModelPreview::render() mFMP->childSetEnabled("upload_joints", upload_skin); } - F32 explode = (F32)mFMP->childGetValue("physics_explode").asReal(); + F32 physics_explode = (F32)mFMP->childGetValue("physics_explode").asReal(); LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview @@ -3380,7 +3385,7 @@ bool LLModelPreview::render() F32 z_near = 0.001f; F32 z_far = mCameraDistance*10.0f + mPreviewScale.magVec() + mCameraOffset.magVec(); - if (skin_weight) + if (show_skin_weight) { target_pos = getPreviewAvatar()->getPositionAgent() + offset; z_near = 0.01f; @@ -3390,7 +3395,7 @@ bool LLModelPreview::render() refresh(); } - gObjectPreviewProgram.bind(skin_weight); + gObjectPreviewProgram.bind(show_skin_weight); gGL.loadIdentity(); gPipeline.enableLightsPreview(); @@ -3399,7 +3404,7 @@ bool LLModelPreview::render() LLQuaternion(mCameraYaw, LLVector3::z_axis); LLQuaternion av_rot = camera_rot; - F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; + F32 camera_distance = show_skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera LLVector3::z_axis, // up @@ -3415,9 +3420,9 @@ bool LLModelPreview::render() gGL.pushMatrix(); gGL.color4fv(PREVIEW_EDGE_COL.mV); - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + if (!mBaseModel.empty() && mVertexBuffer[LLModel::NUM_LODS].empty()) { - genBuffers(-1, skin_weight); + genBuffers(-1, show_skin_weight); //genBuffers(3); } @@ -3432,7 +3437,7 @@ bool LLModelPreview::render() if (!vb_vec.empty()) { const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != show_skin_weight; } else { @@ -3443,15 +3448,15 @@ bool LLModelPreview::render() if (regen) { - genBuffers(mPreviewLOD, skin_weight); + genBuffers(mPreviewLOD, show_skin_weight); } - if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + if (show_physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) { genBuffers(LLModel::LOD_PHYSICS, false); } - if (!skin_weight) + if (!show_skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { @@ -3473,11 +3478,7 @@ bool LLModelPreview::render() auto num_models = mVertexBuffer[mPreviewLOD][model].size(); for (size_t i = 0; i < num_models; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(); - - if (textures) + if (show_textures) { auto materialCnt = instance.mModel->mMaterialList.size(); if (i < materialCnt) @@ -3501,10 +3502,16 @@ bool LLModelPreview::render() gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); } + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + buffer->setBuffer(); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); - if (edges) + if (show_edges) { glLineWidth(PREVIEW_EDGE_WIDTH); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3517,7 +3524,7 @@ bool LLModelPreview::render() gGL.popMatrix(); } - if (physics) + if (show_physics) { glClear(GL_DEPTH_BUFFER_BIT); @@ -3583,12 +3590,12 @@ bool LLModelPreview::render() for (U32 i = 0; i < physics.mMesh.size(); ++i) { - if (explode > 0.f) + if (physics_explode > 0.f) { gGL.pushMatrix(); LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; - offset *= explode; + offset *= physics_explode; gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); } @@ -3603,7 +3610,7 @@ bool LLModelPreview::render() gGL.diffuseColor4ubv(hull_colors[i].mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions); - if (explode > 0.f) + if (physics_explode > 0.f) { gGL.popMatrix(); } @@ -3618,14 +3625,17 @@ bool LLModelPreview::render() if (render_mesh) { auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); - if (pass > 0){ + if (pass > 0) + { for (size_t i = 0; i < num_models; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV); + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; buffer->setBuffer(); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); @@ -3685,10 +3695,11 @@ bool LLModelPreview::render() auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); for (size_t v = 0; v < num_models; ++v) { + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; - buffer->setBuffer(); - LLStrider pos_strider; buffer->getVertexStrider(pos_strider, 0); LLVector4a* pos = (LLVector4a*)pos_strider.get(); @@ -3752,7 +3763,7 @@ bool LLModelPreview::render() U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); auto bind_count = skin->mAlternateBindMatrix.size(); - if (joint_overrides + if (show_joint_overrides && bind_count > 0 && joint_count == bind_count) { @@ -3795,16 +3806,15 @@ bool LLModelPreview::render() } } - for (U32 i = 0, e = static_cast(mVertexBuffer[mPreviewLOD][model].size()); i < e; ++i) + std::size_t size = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < size; ++i) { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - model->mSkinInfo.updateHash(); LLRenderPass::uploadMatrixPalette(mPreviewAvatar, &model->mSkinInfo); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (textures) + if (show_textures) { auto materialCnt = instance.mModel->mMaterialList.size(); if (i < materialCnt) @@ -3828,10 +3838,14 @@ bool LLModelPreview::render() gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); } + // Zero this variable for an obligatory buffer initialization + // See https://github.com/secondlife/viewer/issues/912 + LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; buffer->setBuffer(); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - if (edges) + if (show_edges) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); @@ -3846,7 +3860,7 @@ bool LLModelPreview::render() } } - if (joint_positions) + if (show_joint_positions) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; if (shader) -- cgit v1.2.3 From 85b7210fb9f849633b27a4b4631c42ae7dba78f2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 4 Oct 2024 21:11:56 +0300 Subject: viewer#2741 Sligtly better logging for a crash --- indra/llrender/llimagegl.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 67b4ada62f..abbf90bf59 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1323,12 +1323,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { //GL_ALPHA is deprecated, convert to RGBA if (pixels != nullptr) { - scratch.reset(new(std::nothrow) U32[width * height]); - if (!scratch) + try + { + scratch.reset(new U32[width * height]); + } + catch (std::bad_alloc) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; + << " bytes for a manual image W" << width << " H" << height + << " Pixformat: GL_ALPHA, pixtype: GL_UNSIGNED_BYTE" << LL_ENDL; } U32 pixel_count = (U32)(width * height); @@ -1350,12 +1354,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA if (pixels != nullptr) { - scratch.reset(new(std::nothrow) U32[width * height]); - if (!scratch) + try + { + scratch.reset(new U32[width * height]); + } + catch (std::bad_alloc) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; + << " bytes for a manual image W" << width << " H" << height + << " Pixformat: GL_LUMINANCE_ALPHA, pixtype: GL_UNSIGNED_BYTE" << LL_ENDL; } U32 pixel_count = (U32)(width * height); @@ -1380,12 +1388,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB if (pixels != nullptr) { - scratch.reset(new(std::nothrow) U32[width * height]); - if (!scratch) + try + { + scratch.reset(new U32[width * height]); + } + catch (std::bad_alloc) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; + << " bytes for a manual image W" << width << " H" << height + << " Pixformat: GL_LUMINANCE, pixtype: GL_UNSIGNED_BYTE" << LL_ENDL; } U32 pixel_count = (U32)(width * height); -- cgit v1.2.3 From b71343e827fe8b1e2dba6978b67bb3112944c674 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Sat, 5 Oct 2024 11:56:02 +0300 Subject: viewer#2443 voice dot indicator should be visible by default --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llvoicevisualizer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7c9cfb94fa..13ec35fa07 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13442,7 +13442,7 @@ Type Boolean Value - 0 + 1 WarningsAsChat diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp index 7691ac54f3..c5704982b8 100644 --- a/indra/newview/llvoicevisualizer.cpp +++ b/indra/newview/llvoicevisualizer.cpp @@ -337,7 +337,7 @@ void LLVoiceVisualizer::lipSyncOohAah( F32& ooh, F32& aah ) //--------------------------------------------------- void LLVoiceVisualizer::render() { - static LLCachedControl show_visualizer(gSavedSettings, "VoiceVisualizerEnabled", false); + static LLCachedControl show_visualizer(gSavedSettings, "VoiceVisualizerEnabled", true); if (!mVoiceEnabled || !show_visualizer) { return; -- cgit v1.2.3 From dbed987d07b7f81b836c8356e25063ba71266f21 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Thu, 10 Oct 2024 19:46:05 +0200 Subject: Implement the groundwork for wayland support. (#2803) During compile time try to detect libwayland-client-dev is installed, - If yes, compile a viewer which can run and start under wayland. libwayland-client is needed to detect if the viewer is hidden/minimized. - if no, disable wayland support and refuse to start the viewer under wayland (xwayland is okay). To not introduce a hard link dependency on libwayland-client.so the object will be loaded dynamically if needed. --- indra/cmake/UI.cmake | 9 + indra/llrender/llgl.cpp | 5 +- indra/llwindow/llwindowsdl.cpp | 524 +++++++++++++++++++++-------------------- indra/llwindow/llwindowsdl.h | 96 +++----- 4 files changed, 313 insertions(+), 321 deletions(-) (limited to 'indra') diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index ae039b4a47..a407f68db3 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -13,6 +13,15 @@ if (LINUX) return() endif() + include(FindPkgConfig) + pkg_check_modules(WAYLAND_CLIENT wayland-client) + + if( WAYLAND_CLIENT_FOUND ) + target_compile_definitions( ll::uilibraries INTERFACE LL_WAYLAND=1) + else() + message("pkgconfig could not find wayland client, compiling without full wayland support") + endif() + target_link_libraries( ll::uilibraries INTERFACE fltk Xrender diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 798b605f08..9209cdcb51 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1433,7 +1433,10 @@ void LLGLManager::initExtensions() mHasDebugOutput = mGLVersion >= 4.29f; #if LL_WINDOWS || LL_LINUX - mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + if( gGLHExts.mSysExts ) + mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + else + LL_WARNS() << "gGLHExts.mSysExts is not set.?" << LL_ENDL; #endif // Misc diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index ea95a5aa2e..f87a00c34b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -50,10 +50,10 @@ extern "C" { #if LL_LINUX // not necessarily available on random SDL platforms, so #if LL_LINUX // for execv(), waitpid(), fork() -# include -# include -# include -# include +#include +#include +#include +#include #endif // LL_LINUX extern bool gDebugWindowProc; @@ -64,52 +64,170 @@ const S32 MAX_NUM_RESOLUTIONS = 200; // LLWindowSDL // -#if LL_X11 -# include -#endif //LL_X11 +#include // TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar // set of reasons): Stash a pointer to the LLWindowSDL object here and // maintain in the constructor and destructor. This assumes that there will // be only one object of this class at any time. Currently this is true. -static LLWindowSDL *gWindowImplementation = NULL; - +static LLWindowSDL *gWindowImplementation = nullptr; void maybe_lock_display(void) { - if (gWindowImplementation && gWindowImplementation->Lock_Display) { + if (gWindowImplementation && gWindowImplementation->Lock_Display) gWindowImplementation->Lock_Display(); - } } - void maybe_unlock_display(void) { - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { + if (gWindowImplementation && gWindowImplementation->Unlock_Display) gWindowImplementation->Unlock_Display(); - } } -#if LL_X11 -// static Window LLWindowSDL::get_SDL_XWindowID(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } + if (gWindowImplementation) + return gWindowImplementation->mX11Data.mXWindowID; return None; } -//static Display* LLWindowSDL::get_SDL_Display(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; + if (gWindowImplementation) + return gWindowImplementation->mX11Data.mDisplay; + return nullptr; +} + +/* + * In wayland a window does not have a state of "minimized" or gets messages that it got minimized [1] + * There's two ways to approach this challenge: + * 1) Ignore it, this would mean even if minimized/not visible the viewer will always fun at full fps + * 2) Try to detect something like "minimized", the best way I found so far is to as for frame_done events. Those will + * only happen if parts of the viewer are visible. As such it is not the same a "minimized" but rather "this window + * is not fully hidden behind another window or minimized". That's (I guess) still better than nothing and running + * full tilt even if hidden. + * + * [1] As of 2024-09, maybe in the future we get nice things +*/ +#ifdef LL_WAYLAND +#include +#include + +bool LLWindowSDL::isWaylandWindowNotDrawing() const +{ + if( Wayland != mServerProtocol || mWaylandData.mLastFrameEvent == 0 ) + return false; + + auto currentTime = LLTimer::getTotalTime(); + if( (currentTime - mWaylandData.mLastFrameEvent) > 250000 ) + return true; + + return false; +} + +uint32_t (*ll_wl_proxy_get_version)(struct wl_proxy *proxy); +void (*ll_wl_proxy_destroy)(struct wl_proxy *proxy); +int (*ll_wl_proxy_add_listener)(struct wl_proxy *proxy, void (**implementation)(void), void *data); + +wl_interface *ll_wl_callback_interface; + +int ll_wl_callback_add_listener(struct wl_callback *wl_callback, + const struct wl_callback_listener *listener, void *data) +{ + return ll_wl_proxy_add_listener((struct wl_proxy *) wl_callback, + (void (**)(void)) listener, data); +} + +struct wl_proxy* (*ll_wl_proxy_marshal_flags)(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, ...); + + +bool loadWaylandClient() +{ + auto *pSO = dlopen( "libwayland-client.so", RTLD_NOW); + if( !pSO ) + return false; + + + ll_wl_callback_interface = (wl_interface*)dlsym(pSO, "wl_callback_interface"); + *(void**)&ll_wl_proxy_marshal_flags = dlsym(pSO, "wl_proxy_marshal_flags"); + *(void**)&ll_wl_proxy_get_version = dlsym(pSO, "wl_proxy_get_version"); + *(void**)&ll_wl_proxy_destroy = dlsym(pSO, "wl_proxy_destroy"); + *(void**)&ll_wl_proxy_add_listener = dlsym(pSO, "wl_proxy_add_listener"); + + return ll_wl_callback_interface != nullptr && ll_wl_proxy_marshal_flags != nullptr && + ll_wl_proxy_get_version != nullptr && ll_wl_proxy_destroy != nullptr && + ll_wl_proxy_add_listener != nullptr; +} + +struct wl_callback* ll_wl_surface_frame(struct wl_surface *wl_surface) +{ + auto version = ll_wl_proxy_get_version((struct wl_proxy *) wl_surface); + + auto callback = ll_wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, ll_wl_callback_interface, version, + 0, nullptr); + + return (struct wl_callback *) callback; +} + +void ll_wl_callback_destroy(struct wl_callback *wl_callback) +{ + ll_wl_proxy_destroy((struct wl_proxy *) wl_callback); +} + +void LLWindowSDL::waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_t time) +{ + static uint32_t frame_count {0}; + static F64SecondsImplicit lastInfo{0}; + + ++frame_count; + + ll_wl_callback_destroy(cb); + auto pThis = reinterpret_cast(data); + pThis->mWaylandData.mLastFrameEvent = LLTimer::getTotalTime(); + + auto now = LLTimer::getElapsedSeconds(); + if( lastInfo > 0) + { + auto diff = now.value() - lastInfo.value(); + constexpr double FPS_INFO_INTERVAL = 60.f * 5.f; + if( diff >= FPS_INFO_INTERVAL) + { + double fFPS = frame_count; + fFPS /= diff; + LL_INFOS() << "Wayland: FPS " << fFPS << " fps, " << frame_count << " #frames time " << (diff) << LL_ENDL; + frame_count = 0; + lastInfo = now; + } } - return NULL; + else + lastInfo = now; + + pThis->setupWaylandFrameCallback(); // ask for a new frame } -#endif // LL_X11 + +void LLWindowSDL::setupWaylandFrameCallback() +{ + static wl_callback_listener frame_listener { nullptr }; + frame_listener.done = &LLWindowSDL::waylandFrameDoneCB; + + auto cb = ll_wl_surface_frame(mWaylandData.mSurface); + ll_wl_callback_add_listener(cb, &frame_listener, this); +} +#else +bool LLWindowSDL::isWaylandWindowNotDrawing() +{ + return false; +} +void LLWindowSDL::setupWaylandFrameCallback() +{ + LL_WARNS() << "Viewer is running under Wayland, but was not compiled with full wayland support!" << LL_ENDL; +} +#endif LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, @@ -118,29 +236,12 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, bool enable_vsync, bool use_gl, bool ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) + Lock_Display(nullptr), + Unlock_Display(nullptr), mGamma(1.0f) { // Initialize the keyboard gKeyboard = new LLKeyboardSDL(); gKeyboard->setCallbacks(callbacks); - // Note that we can't set up key-repeat until after SDL has init'd video - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = {}; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - mHaveInputFocus = -1; - mIsMinimized = -1; - mFSAASamples = fsaa_samples; - -#if LL_X11 - mSDL_XWindowID = None; - mSDL_Display = nullptr; -#endif // LL_X11 // Assume 4:3 aspect ratio until we know better mOriginalAspectRatio = 1024.0 / 768.0; @@ -167,8 +268,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, mFlashing = false; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -197,7 +296,7 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; // If the requested width or height is 0, find the best default for the monitor. - if((width == 0) || (height == 0)) + if(width == 0 || height == 0) { // Scan through the list of modes, looking for one which has: // height between 700 and 800 @@ -205,16 +304,15 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) S32 resolutionCount = 0; LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); - if(resolutionList != NULL) + if(resolutionList != nullptr) { F32 closestAspect = 0; U32 closestHeight = 0; U32 closestWidth = 0; - int i; LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; - for(i=0; i < resolutionCount; i++) + for(S32 i=0; i < resolutionCount; i++) { F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; @@ -237,7 +335,7 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) } } - if((width == 0) || (height == 0)) + if(width == 0 || height == 0) { // Mode search failed for some reason. Use the old-school default. width = 1024; @@ -247,16 +345,10 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { - if (width == 0) - width = 1024; - if (height == 0) - width = 768; - LL_INFOS() << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << LL_ENDL; + LL_INFOS() << "createContext, fullscreen=" << fullscreen << " size=" << width << "x" << height << LL_ENDL; // captures don't survive contexts mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; if (width == 0) width = 1024; @@ -269,15 +361,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b mFullscreen = fullscreen; - int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - - if( mFullscreen ) - { - sdlflags |= SDL_WINDOW_FULLSCREEN; - tryFindFullscreenSize( width, height ); - } - - mSDLFlags = sdlflags; // Setup default backing colors GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; @@ -300,13 +383,19 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - // Create the window - mWindow = SDL_CreateWindow(mWindowTitle.c_str(), x, y, width, height, mSDLFlags); + int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + + if( mFullscreen ) + { + sdlflags |= SDL_WINDOW_FULLSCREEN; + tryFindFullscreenSize( width, height ); + } + + mWindow = SDL_CreateWindow( mWindowTitle.c_str(), x, y, width, height, sdlflags ); if (mWindow == nullptr) { LL_WARNS() << "Window creation failure. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("Window creation error", "Error", OSMB_OK); - return false; } // Create the context @@ -315,14 +404,12 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; setupFailure("GL Context creation error", "Error", OSMB_OK); - return false; } if (SDL_GL_MakeCurrent(mWindow, mContext) != 0) { LL_WARNS() << "Failed to make context current. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("GL Context failed to set current failure", "Error", OSMB_OK); - return false; } mSurface = SDL_GetWindowSurface(mWindow); @@ -345,7 +432,7 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b else { LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // No fullscreen support + mFullscreen = false; mFullscreenWidth = -1; mFullscreenHeight = -1; @@ -353,8 +440,7 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b mFullscreenRefresh = -1; std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); - OSMessageBox(error, "Error", OSMB_OK); - return false; + setupFailure( error, "Error", OSMB_OK ); } } else @@ -363,7 +449,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("Window creation error", "Error", OSMB_OK); - return false; } } @@ -397,7 +482,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b "will automatically adjust the screen each time it runs.", "Error", OSMB_OK); - return false; } LL_PROFILER_GPU_CONTEXT; @@ -411,10 +495,9 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { SDL_SetWindowIcon(mWindow, bmpsurface); SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; + bmpsurface = nullptr; } -#if LL_X11 /* Grab the window manager specific information */ SDL_SysWMinfo info; SDL_VERSION(&info.version); @@ -423,21 +506,41 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b /* Save the information for later use */ if ( info.subsystem == SDL_SYSWM_X11 ) { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.window; + mX11Data.mDisplay = info.info.x11.display; + mX11Data.mXWindowID = info.info.x11.window; + mServerProtocol = X11; + LL_INFOS() << "Running under X11" << LL_ENDL; + } + else if ( info.subsystem == SDL_SYSWM_WAYLAND ) + { +#ifdef LL_WAYLAND + if( !loadWaylandClient() ) + LL_ERRS() << "Failed to load wayland-client.so or grab required functions" << LL_ENDL; + + mWaylandData.mSurface = info.info.wl.surface; + mServerProtocol = Wayland; + setupWaylandFrameCallback(); + + // If set (XWayland) remove DISPLAY, this will prompt dullahan to also use Wayland + if( getenv("DISPLAY") ) + unsetenv("DISPLAY"); + + LL_INFOS() << "Running under Wayland" << LL_ENDL; + LL_WARNS() << "Be aware that with at least SDL2 the window will not receive minimizing events, thus minimized state can only be estimated." + "also setting the application icon via SDL_SetWindowIcon does not work." << LL_ENDL; +#else + setupFailure("Viewer is running under Wayland, but was not compiled with full wayland support!\nYou can compile the viewer with wayland prelimiary support using COMPILE_WAYLAND_SUPPORT", "Error", OSMB_OK); +#endif } else { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; + LL_WARNS() << "We're not running under X11 or Wayland? Wild." << LL_ENDL; } } else { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; + LL_WARNS() << "We're not running under any known WM. Wild." << LL_ENDL; } -#endif // LL_X11 SDL_StartTextInput(); //make sure multisampling is disabled by default @@ -523,12 +626,11 @@ void LLWindowSDL::destroyContext() LL_INFOS() << "shutdownGL begins" << LL_ENDL; gGLManager.shutdownGL(); -#if LL_X11 - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; -#endif // LL_X11 + mX11Data.mDisplay = nullptr; + mX11Data.mXWindowID = None; + Lock_Display = nullptr; + Unlock_Display = nullptr; + mServerProtocol = Unknown; LL_INFOS() << "Destroying SDL cursors" << LL_ENDL; quitCursors(); @@ -564,12 +666,9 @@ LLWindowSDL::~LLWindowSDL() { destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + delete []mSupportedResolutions; - gWindowImplementation = NULL; + gWindowImplementation = nullptr; } @@ -589,7 +688,6 @@ void LLWindowSDL::hide() } } -//virtual void LLWindowSDL::minimize() { if (mWindow) @@ -598,7 +696,6 @@ void LLWindowSDL::minimize() } } -//virtual void LLWindowSDL::restore() { if (mWindow) @@ -611,12 +708,6 @@ void LLWindowSDL::restore() // Usually called from LLWindowManager::destroyWindow() void LLWindowSDL::close() { - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } - // Make sure cursor is visible and we haven't mangled the clipping state. setMouseClipping(false); showCursor(); @@ -626,7 +717,7 @@ void LLWindowSDL::close() bool LLWindowSDL::isValid() { - return (mWindow != NULL); + return mWindow != nullptr; } bool LLWindowSDL::getVisible() const @@ -645,6 +736,9 @@ bool LLWindowSDL::getVisible() const bool LLWindowSDL::getMinimized() const { + if( isWaylandWindowNotDrawing() ) + return true; + bool result = false; if (mWindow) { @@ -698,10 +792,10 @@ bool LLWindowSDL::getSize(LLCoordScreen *size) const { size->mX = mSurface->w; size->mY = mSurface->h; - return (true); + return true; } - return (false); + return false; } bool LLWindowSDL::getSize(LLCoordWindow *size) const @@ -710,10 +804,10 @@ bool LLWindowSDL::getSize(LLCoordWindow *size) const { size->mX = mSurface->w; size->mY = mSurface->h; - return (true); + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) @@ -737,7 +831,6 @@ template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) if( nFlags & SDL_WINDOW_MAXIMIZED ) SDL_RestoreWindow( pWin ); - SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); SDL_Event event; event.type = SDL_WINDOWEVENT; @@ -803,7 +896,8 @@ bool LLWindowSDL::setGamma(const F32 gamma) Uint16 ramp[256]; mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; + if (mGamma == 0) + mGamma = 0.1f; mGamma = 1.f / mGamma; SDL_CalculateGammaRamp(mGamma, ramp); @@ -820,7 +914,8 @@ bool LLWindowSDL::isCursorHidden() // Constrains the mouse to the window. void LLWindowSDL::setMouseClipping(bool b) { - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); + if( mWindow ) + SDL_SetWindowGrab( mWindow, b?SDL_TRUE:SDL_FALSE ); } // virtual @@ -840,17 +935,11 @@ bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) LLCoordScreen screen_pos; if (!convertCoords(position, &screen_pos)) - { return false; - } - - //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; // do the actual forced cursor move. SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - return result; } @@ -868,7 +957,6 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) return convertCoords(screen_pos, position); } - F32 LLWindowSDL::getNativeAspectRatio() { // MBW -- there are a couple of bad assumptions here. One is that the display list won't include @@ -889,9 +977,7 @@ F32 LLWindowSDL::getNativeAspectRatio() // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. if (mOverrideAspectRatio > 0.f) - { return mOverrideAspectRatio; - } return mOriginalAspectRatio; } @@ -903,9 +989,7 @@ F32 LLWindowSDL::getPixelAspectRatio() { LLCoordScreen screen_size; if (getSize(&screen_size)) - { pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } } return pixel_aspect; @@ -916,61 +1000,34 @@ F32 LLWindowSDL::getPixelAspectRatio() // dialogs are still usable in fullscreen. void LLWindowSDL::beforeDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; if (SDLReallyCaptureInput(false)) // must ungrab input so popup works! { - if (mFullscreen) - { - // need to temporarily go non-fullscreen; bless SDL - // for providing a SDL_WM_ToggleFullScreen() - though - // it only works in X11 - if (running_x11 && mWindow) - { - SDL_SetWindowFullscreen( mWindow, 0 ); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } -#if LL_X11 - if (mSDL_Display) + if (mServerProtocol == X11 && mX11Data.mDisplay) { // Everything that we/SDL asked for should happen before we // potentially hand control over to GTK. maybe_lock_display(); - XSync(mSDL_Display, False); + XSync(mX11Data.mDisplay, False); maybe_unlock_display(); } -#endif // LL_X11 maybe_lock_display(); } void LLWindowSDL::afterDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; maybe_unlock_display(); - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_SetWindowFullscreen( mWindow, 0 ); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } void LLWindowSDL::flashIcon(F32 seconds) @@ -987,6 +1044,15 @@ void LLWindowSDL::flashIcon(F32 seconds) mFlashing = true; } +void LLWindowSDL::maybeStopFlashIcon() +{ + if (mFlashing && mFlashTimer.hasExpired()) + { + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); + } +} + bool LLWindowSDL::isClipboardTextAvailable() { return SDL_HasClipboardText() == SDL_TRUE; @@ -1054,9 +1120,7 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso { SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; if (SDL_GetDisplayMode( 0 , i, &mode) != 0) - { continue; - } int w = mode.w; int h = mode.h; @@ -1109,7 +1173,7 @@ bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) const // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) const @@ -1120,21 +1184,21 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) const // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) const { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) const { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) @@ -1142,55 +1206,17 @@ void LLWindowSDL::setupFailure(const std::string& text, const std::string& capti destroyContext(); OSMessageBox(text, caption, type); + + // This is so catastrophic > bail as fast as possible. Otherwise the viewer can be stuck in a perpetual state of startup pain + std::terminate(); } bool LLWindowSDL::SDLReallyCaptureInput(bool capture) { - // note: this used to be safe to call nestedly, but in the - // end that's not really a wise usage pattern, so don't. - - if (capture) - mReallyCapturedCount = 1; - else - mReallyCapturedCount = 0; - - bool wantGrab; - if (mReallyCapturedCount <= 0) // uncapture - { - wantGrab = false; - } else // capture - { - wantGrab = true; - } - - if (mReallyCapturedCount < 0) // yuck, imbalance. - { - mReallyCapturedCount = 0; - LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; - } - - bool newGrab = wantGrab; + if (!mFullscreen && mWindow ) /* only bother if we're windowed anyway */ + SDL_SetWindowGrab( mWindow, capture?SDL_TRUE:SDL_FALSE); - if (!mFullscreen) /* only bother if we're windowed anyway */ - { - int result; - if (wantGrab == true) - { - result = SDL_CaptureMouse(SDL_TRUE); - if (0 == result) - newGrab = true; - else - newGrab = false; - } - else - { - newGrab = false; - result = SDL_CaptureMouse(SDL_FALSE); - } - } - - // return boolean success for whether we ended up in the desired state - return capture == newGrab; + return capture; } U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) @@ -1237,7 +1263,6 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) void check_vm_bloat() { -#if LL_LINUX // watch our own VM and RSS sizes, warn if we bloated rapidly static const std::string STATS_FILE = "/proc/self/stat"; FILE *fp = fopen(STATS_FILE.c_str(), "r"); @@ -1252,7 +1277,7 @@ void check_vm_bloat() ssize_t res; size_t dummy; - char *ptr = NULL; + char *ptr = nullptr; for (int i=0; i<22; ++i) // parse past the values we don't want { res = getdelim(&ptr, &dummy, ' ', fp); @@ -1262,7 +1287,7 @@ void check_vm_bloat() goto finally; } free(ptr); - ptr = NULL; + ptr = nullptr; } // 23rd space-delimited entry is vsize res = getdelim(&ptr, &dummy, ' ', fp); @@ -1274,7 +1299,7 @@ void check_vm_bloat() } this_vm_size = atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; // 24th space-delimited entry is RSS res = getdelim(&ptr, &dummy, ' ', fp); llassert(ptr); @@ -1285,12 +1310,11 @@ void check_vm_bloat() } this_rss_size = getpagesize() * atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; - if (llabs(last_vm_size - this_vm_size) > - significant_vm_difference) + if (llabs(last_vm_size - this_vm_size) > significant_vm_difference) { if (this_vm_size > last_vm_size) { @@ -1302,8 +1326,7 @@ void check_vm_bloat() } } - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) + if (llabs(last_rss_size - this_rss_size) > significant_rss_difference) { if (this_rss_size > last_rss_size) { @@ -1319,21 +1342,16 @@ void check_vm_bloat() last_vm_size = this_vm_size; finally: - if (NULL != ptr) - { + if (ptr) free(ptr); - ptr = NULL; - } fclose(fp); } -#endif // LL_LINUX } // virtual void LLWindowSDL::processMiscNativeEvents() { -#if LL_GLIB // Pump until we've nothing left to do or passed 1/15th of a // second pumping for this frame. static LLTimer pump_timer; @@ -1343,18 +1361,15 @@ void LLWindowSDL::processMiscNativeEvents() { g_main_context_iteration(g_main_context_default(), false); } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); -#endif // hack - doesn't belong here - but this is just for debugging if (getenv("LL_DEBUG_BLOAT")) - { check_vm_bloat(); - } } void LLWindowSDL::gatherInput(bool app_has_focus) { - SDL_Event event; + SDL_Event event; // Handle all outstanding SDL events while (SDL_PollEvent(&event)) @@ -1388,7 +1403,7 @@ void LLWindowSDL::gatherInput(bool app_has_focus) { auto string = utf8str_to_utf16str( event.text.text ); mKeyModifiers = gKeyboard->currentMask( false ); - mInputType = "textinput"; + for( auto key: string ) { mKeyVirtualKey = key; @@ -1404,13 +1419,10 @@ void LLWindowSDL::gatherInput(bool app_has_focus) case SDL_KEYDOWN: mKeyVirtualKey = event.key.keysym.sym; mKeyModifiers = event.key.keysym.mod; - mInputType = "keydown"; // treat all possible Enter/Return keys the same if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) - { mKeyVirtualKey = SDLK_RETURN; - } gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); @@ -1433,13 +1445,10 @@ void LLWindowSDL::gatherInput(bool app_has_focus) case SDL_KEYUP: mKeyVirtualKey = event.key.keysym.sym; mKeyModifiers = event.key.keysym.mod; - mInputType = "keyup"; // treat all possible Enter/Return keys the same if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) - { mKeyVirtualKey = SDLK_RETURN; - } if (SDLCheckGrabbyKeys(mKeyVirtualKey, false) == 0) SDLReallyCaptureInput(false); // part of the fix for SL-13243 @@ -1461,7 +1470,7 @@ void LLWindowSDL::gatherInput(bool app_has_focus) else mCallbacks->handleMouseDown(this, openGlCoord, mask); } - else if (event.button.button == SDL_BUTTON_RIGHT) // right + else if (event.button.button == SDL_BUTTON_RIGHT) { mCallbacks->handleRightMouseDown(this, openGlCoord, mask); } @@ -1591,12 +1600,12 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty SDL_SwapLE32(0xFF00U), SDL_SwapLE32(0xFF0000U), SDL_SwapLE32(0xFF000000U)); - SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + SDL_FillRect(cursurface, nullptr, SDL_SwapLE32(0x00000000U)); // Blit the cursor pixel data onto a 32-bit RGBA surface so we // only have to cope with processing one type of pixel format. - if (0 == SDL_BlitSurface(bmpsurface, NULL, - cursurface, NULL)) + if (0 == SDL_BlitSurface(bmpsurface, nullptr, + cursurface, nullptr)) { // n.b. we already checked that width is a multiple of 8. const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; @@ -1670,12 +1679,10 @@ void LLWindowSDL::updateCursor() void LLWindowSDL::initCursors() { - int i; // Blank the cursor pointer array for those we may miss. - for (i=0; i LLWindowSDL::getDynamicFallbackFontList() // to use some of the fonts we want it to. const bool elide_unicode_coverage = true; std::vector rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; + FcFontSet *fs = nullptr; + FcPattern *sortpat = nullptr; LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; @@ -1983,7 +1990,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() // of languages that can be displayed, but ensures that their // preferred language is rendered from a single consistent font where // possible. - FL_Locale *locale = NULL; + FL_Locale *locale = nullptr; FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); if (success != 0) { @@ -2014,8 +2021,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() { // Sort the list of system fonts from most-to-least-desirable. FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); + fs = FcFontSort(nullptr, sortpat, elide_unicode_coverage, nullptr, &result); FcPatternDestroy(sortpat); } @@ -2028,10 +2034,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() for (int i=0; infont; ++i) { FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && filename) + if (FcResultMatch == FcPatternGetString(fs->fonts[i], FC_FILE, 0, &filename) && filename) { rtns.push_back(std::string((const char*)filename)); if (rtns.size() >= max_font_count_cutoff) @@ -2042,12 +2045,11 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() } LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector::iterator it = rtns.begin(); - it != rtns.end(); - ++it) + for (auto it = rtns.begin(); it != rtns.end(); ++it) { LL_DEBUGS() << " file: " << *it << LL_ENDL; } + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; rtns.push_back(final_fallback); diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index a85b7c11e7..974ba69b61 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -11,7 +11,6 @@ * 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. @@ -36,10 +35,8 @@ #include "SDL2/SDL.h" #include "SDL2/SDL_endian.h" -#if LL_X11 // get X11-specific headers for use in low-level stuff like copy-and-paste support #include "SDL2/SDL_syswm.h" -#endif // AssertMacros.h does bad things. #include "fix_macros.h" @@ -50,8 +47,8 @@ class LLWindowSDL : public LLWindow { public: void show() override; - void hide() override; + void restore() override; void close() override; @@ -62,11 +59,8 @@ public: bool getMaximized() const override; bool maximize() override; - void minimize() override; - void restore() override; - bool getPosition(LLCoordScreen *position) const override; bool getSize(LLCoordScreen *size) const override; @@ -87,49 +81,38 @@ public: bool getCursorPosition(LLCoordWindow *position) override; void showCursor() override; - void hideCursor() override; + bool isCursorHidden() override; void showCursorFromMouseMove() override; - void hideCursorUntilMouseMove() override; - bool isCursorHidden() override; - void updateCursor() override; void captureMouse() override; - void releaseMouse() override; void setMouseClipping(bool b) override; - void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; + void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; bool isClipboardTextAvailable() override; - bool pasteTextFromClipboard(LLWString &dst) override; - bool copyTextToClipboard(const LLWString &src) override; - bool isPrimaryTextAvailable() override; - bool pasteTextFromPrimary(LLWString &dst) override; - bool copyTextToPrimary(const LLWString &src) override; void flashIcon(F32 seconds) override; + void maybeStopFlashIcon(); F32 getGamma() const override; - bool setGamma(const F32 gamma) override; // Set the gamma + bool restoreGamma() override; // Restore original gamma table (before updating gamma) U32 getFSAASamples() const override; - void setFSAASamples(const U32 samples) override; - bool restoreGamma() override; // Restore original gamma table (before updating gamma) - void processMiscNativeEvents() override; void gatherInput(bool app_has_focus) override; @@ -162,7 +145,6 @@ public: void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } void beforeDialog() override; - void afterDialog() override; bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; @@ -179,31 +161,15 @@ public: static std::vector getDynamicFallbackFontList(); - // Not great that these are public, but they have to be accessible - // by non-class code and it's better than making them global. -#if LL_X11 - Window mSDL_XWindowID; - Display *mSDL_Display; -#endif - - void (*Lock_Display)(void); - - void (*Unlock_Display)(void); - -#if LL_X11 + void (*Lock_Display)(void) = nullptr; + void (*Unlock_Display)(void) = nullptr; static Window get_SDL_XWindowID(void); - static Display *get_SDL_Display(void); -#endif // LL_X11 - void *createSharedContext() override; - void makeContextCurrent(void *context) override; - void destroySharedContext(void *context) override; - void toggleVSync(bool enable_vsync) override; protected: @@ -219,7 +185,6 @@ protected: LLSD getNativeKeyData() const override; void initCursors(); - void quitCursors(); void moveWindow(const LLCoordScreen &position, const LLCoordScreen &size); @@ -239,7 +204,6 @@ protected: // create or re-create the GL context/window. Called from the constructor and switchContext(). bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); - void destroyContext(); void setupFailure(const std::string &text, const std::string &caption, U32 type); @@ -251,36 +215,50 @@ protected: // // Platform specific variables // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; + U32 mGrabbyKeyFlags = 0; - SDL_Window *mWindow; + SDL_Window *mWindow = nullptr; SDL_Surface *mSurface; SDL_GLContext mContext; SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; std::string mWindowTitle; - double mOriginalAspectRatio; - bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + double mOriginalAspectRatio = 1.0f; + bool mNeedsResize = false; // Constructor figured out the window is too big, it needs a resize. LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - F32 mGamma; - U32 mFSAASamples; + F32 mOverrideAspectRatio = 0.0f; + F32 mGamma = 0.0f; + U32 mFSAASamples = 0; - int mSDLFlags; - - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ + int mHaveInputFocus = -1; /* 0=no, 1=yes, else unknown */ friend class LLWindowManager; private: - bool mFlashing; + bool mFlashing = false; LLTimer mFlashTimer; - U32 mKeyVirtualKey; - U32 mKeyModifiers; - std::string mInputType; + U32 mKeyVirtualKey = 0; + U32 mKeyModifiers = KMOD_NONE; + + enum EServerProtocol{ X11, Wayland, Unknown }; + EServerProtocol mServerProtocol = Unknown; + struct { + Window mXWindowID = None; + Display *mDisplay = nullptr; + } mX11Data; + + // Wayland + struct { + wl_surface *mSurface = nullptr; + uint64_t mLastFrameEvent = 0; + } mWaylandData; + + bool isWaylandWindowNotDrawing() const; + + void setupWaylandFrameCallback(); + static void waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_t time); + // private: void tryFindFullscreenSize(int &aWidth, int &aHeight); -- cgit v1.2.3 From a60b8039f5007a760569d6c12b3b39899a345a5f Mon Sep 17 00:00:00 2001 From: AiraYumi Date: Fri, 11 Oct 2024 18:09:33 +0900 Subject: Remove FLTK (#2832) --- indra/cmake/UI.cmake | 3 +-- indra/newview/lldirpicker.cpp | 36 ------------------------------------ indra/newview/lldirpicker.h | 2 -- indra/newview/llfilepicker.h | 8 -------- 4 files changed, 1 insertion(+), 48 deletions(-) (limited to 'indra') diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index a407f68db3..23bd8018dd 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -7,7 +7,7 @@ add_library( ll::uilibraries INTERFACE IMPORTED ) if (LINUX) use_prebuilt_binary(fltk) - target_compile_definitions(ll::uilibraries INTERFACE LL_FLTK=1 LL_X11=1 ) + target_compile_definitions(ll::uilibraries INTERFACE LL_X11=1 ) if( USE_CONAN ) return() @@ -23,7 +23,6 @@ if (LINUX) endif() target_link_libraries( ll::uilibraries INTERFACE - fltk Xrender Xcursor Xfixes diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 51157fa430..17edca7ccb 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,11 +41,6 @@ # include "llfilepicker.h" #endif -#ifdef LL_FLTK - #include "FL/Fl.H" - #include "FL/Fl_Native_File_Chooser.H" -#endif - #if LL_WINDOWS #include #endif @@ -219,28 +214,20 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { -#ifndef LL_FLTK mFilePicker = new LLFilePicker(); -#endif reset(); } LLDirPicker::~LLDirPicker() { -#ifndef LL_FLTK delete mFilePicker; -#endif } void LLDirPicker::reset() { -#ifndef LL_FLTK if (mFilePicker) mFilePicker->reset(); -#else - mDir = ""; -#endif } bool LLDirPicker::getDir(std::string* filename, bool blocking) @@ -253,39 +240,16 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking) return false; } -#ifdef LL_FLTK - gViewerWindow->getWindow()->beforeDialog(); - Fl_Native_File_Chooser flDlg; - flDlg.title(LLTrans::getString("choose_the_directory").c_str()); - flDlg.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY ); - int res = flDlg.show(); - gViewerWindow->getWindow()->afterDialog(); - if( res == 0 ) - { - char const *pDir = flDlg.filename(0); - if( pDir ) - mDir = pDir; - } - else if( res == -1 ) - { - LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL; - } - return !mDir.empty(); -#endif return false; } std::string LLDirPicker::getDirName() { -#ifndef LL_FLTK if (mFilePicker) { return mFilePicker->getFirstFile(); } return ""; -#else - return mDir; -#endif } #else // not implemented diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 2ac3db7c2e..dc740caab2 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -77,10 +77,8 @@ private: #if LL_LINUX || LL_DARWIN // On Linux we just implement LLDirPicker on top of LLFilePicker -#ifndef LL_FLTK LLFilePicker *mFilePicker; #endif -#endif std::string* mFileName; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index e0bd32fe70..4d71a3b392 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -174,14 +174,6 @@ private: void *userdata); #endif -#if LL_FLTK - enum EType - { - eSaveFile, eOpenFile, eOpenMultiple - }; - bool openFileDialog( int32_t filter, bool blocking, EType aType ); -#endif - std::vector mFiles; S32 mCurrentFile; bool mLocked; -- cgit v1.2.3 From 4811e4263216a2f282cfe146e247578b50005e42 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Thu, 8 Aug 2024 11:04:35 -0700 Subject: (WIP) Local paintmap modification test --- indra/newview/llterrainpaintmap.cpp | 118 ++++++++++++++++++++- indra/newview/llterrainpaintmap.h | 38 +++++++ indra/newview/llviewermenu.cpp | 46 ++++++++ indra/newview/llvlcomposition.cpp | 8 ++ indra/newview/llvlcomposition.h | 6 ++ indra/newview/skins/default/xui/en/menu_viewer.xml | 7 ++ 6 files changed, 221 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 8ccde74c93..6979464cd3 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -38,18 +38,31 @@ #include "llsurface.h" #include "llsurfacepatch.h" #include "llviewercamera.h" +#include "llviewercontrol.h" #include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewertexture.h" -// static -bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +namespace +{ +#ifdef SHOW_ASSERT +void check_tex(const LLViewerTexture& tex) { llassert(tex.getComponents() == 3); llassert(tex.getWidth() > 0 && tex.getHeight() > 0); llassert(tex.getWidth() == tex.getHeight()); llassert(tex.getPrimaryFormat() == GL_RGB); llassert(tex.getGLTexture()); +} +#endif +} // namespace + +// static +bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif const LLSurface& surface = region.getLand(); const U32 patch_count = surface.getPatchesPerEdge(); @@ -283,3 +296,104 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& return success; } + +// TODO: Decide when to apply the paint queue - ideally once per frame per region +// Applies paints and then clears the paint queue +// *NOTE The paint queue is also cleared when setting the paintmap texture +void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue) +{ + if (queue.empty()) { return; } + +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + + gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); + + const std::vector& queue_list = queue.get(); + for (size_t i = 0; i < queue_list.size(); ++i) + { + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + queue.convertBitDepths(i, 8); + const LLTerrainPaint::ptr_t& paint = queue_list[i]; + + if (paint->mData.empty()) { continue; } + constexpr GLint level = 0; + if ((paint->mStartX >= tex.getWidth() - 1) || (paint->mStartY >= tex.getHeight() - 1)) { continue; } + constexpr GLint miplevel = 0; + const S32 x_offset = paint->mStartX; + const S32 y_offset = paint->mStartY; + const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset); + const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset); + const U8* pixels = paint->mData.data(); + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels); + stop_glerror(); + } + + // Generating mipmaps at the end... + glGenerateMipmap(GL_TEXTURE_2D); + stop_glerror(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + queue.clear(); +} + +bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) +{ + llassert(paint); + if (!paint) { return false; } + + // The paint struct should be pre-validated before this code is reached. + llassert(!paint->mData.empty()); + // The internal paint map image is currently 8 bits, so that's the maximum + // allowed bit depth. + llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8); + llassert(paint->mData.size() == (LLTerrainPaint::COMPONENTS * paint->mWidthX * paint->mWidthY)); + llassert(paint->mWidthX > 0); + llassert(paint->mWidthY > 0); +#ifdef SHOW_ASSERT + static LLCachedControl max_texture_width(gSavedSettings, "RenderMaxTextureResolution", 2048); +#endif + llassert(paint->mWidthX <= max_texture_width); + llassert(paint->mWidthY <= max_texture_width); + llassert(paint->mStartX < max_texture_width); + llassert(paint->mStartY < max_texture_width); + + mList.push_back(paint); + return true; +} + +bool LLTerrainPaintQueue::empty() const +{ + return mList.empty(); +} + +void LLTerrainPaintQueue::clear() +{ + mList.clear(); +} + +void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) +{ + llassert(target_bit_depth > 0 && target_bit_depth <= 8); + llassert(index < mList.size()); + + LLTerrainPaint::ptr_t& paint = mList[index]; + if (paint->mBitDepth == target_bit_depth) { return; } + + const F32 old_bit_max = F32((1 << paint->mBitDepth) - 1); + const F32 new_bit_max = F32((1 << target_bit_depth) - 1); + const F32 bit_conversion_factor = new_bit_max / old_bit_max; + + for (U8& color : paint->mData) + { + color = (U8)llround(F32(color) * bit_conversion_factor); + } + + paint->mBitDepth = target_bit_depth; +} diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h index 66827862c5..9189f12cbd 100644 --- a/indra/newview/llterrainpaintmap.h +++ b/indra/newview/llterrainpaintmap.h @@ -28,6 +28,7 @@ class LLViewerRegion; class LLViewerTexture; +class LLTerrainPaintQueue; class LLTerrainPaintMap { @@ -39,4 +40,41 @@ public: // to type TERRAIN_PAINT_TYPE_PBR_PAINTMAP. // Returns true if successful static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex); + + static void applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue); +}; + +// Enqueued paint operations, in texture coordinates. +// data is always RGB, with each U8 storing one color in the provided bit depth. +class LLTerrainPaint +{ +public: + using ptr_t = std::shared_ptr; + + U16 mStartX; + U16 mStartY; + U16 mWidthX; + U16 mWidthY; + U8 mBitDepth; + static const U8 COMPONENTS = 3; + std::vector mData; +}; + +class LLTerrainPaintQueue +{ +public: + bool enqueue(LLTerrainPaint::ptr_t& paint); + bool empty() const; + void clear(); + + const std::vector& get() const { return mList; } + + // Convert mBitDepth for the LLTerrainPaint in the queue at index + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + void convertBitDepths(size_t index, U8 target_bit_depth); + +private: + std::vector mList; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 10506e0e74..fa6e8870b3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -117,6 +117,7 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "lltoolselectland.h" +#include "llterrainpaintmap.h" #include "lltrans.h" #include "llviewerdisplay.h" //for gWindowResized #include "llviewergenericmessage.h" @@ -1448,6 +1449,50 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t } }; +class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerTexture* tex = gLocalTerrainMaterials.getPaintMap(); + if (!tex) + { + LL_WARNS() << "No local paint map available to edit" << LL_ENDL; + return false; + } + + LLTerrainPaintQueue& paint_queue = gLocalTerrainMaterials.getPaintQueue(); + + // Enqueue a paint + // Overrides an entire region patch with the material in the last slot + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for the paintmap (this could + // change in the future). + LLTerrainPaint::ptr_t paint = std::make_shared(); + const U16 width = U16(tex->getWidth() / 16); + paint->mStartX = width - 1; + paint->mStartY = width - 1; + paint->mWidthX = width; + paint->mWidthY = width; + constexpr U8 bit_depth = 5; + paint->mBitDepth = bit_depth; + constexpr U8 max_value = (1 << bit_depth) - 1; + const size_t pixel_count = width * width; + paint->mData.resize(LLTerrainPaint::COMPONENTS * pixel_count); + for (size_t pixel = 0; pixel < pixel_count; ++pixel) + { + paint->mData[(LLTerrainPaint::COMPONENTS*pixel) + LLTerrainPaint::COMPONENTS - 1] = max_value; + } + paint_queue.enqueue(paint); + + // Apply the paint queue ad-hoc right here for now. + // *TODO: Eventually the paint queue should be applied at a predictable + // time in the viewer frame loop. + LLTerrainPaintMap::applyPaintQueue(*tex, paint_queue); + + return true; + } +}; + class LLAdvancedTerrainDeleteLocalPaintMap : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9813,6 +9858,7 @@ void initialize_menus() // Develop > Terrain view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); view_listener_t::addMenu(new LLAdvancedTerrainCreateLocalPaintMap(), "Advanced.TerrainCreateLocalPaintMap"); + view_listener_t::addMenu(new LLAdvancedTerrainEditLocalPaintMap(), "Advanced.TerrainEditLocalPaintMap"); view_listener_t::addMenu(new LLAdvancedTerrainDeleteLocalPaintMap(), "Advanced.TerrainDeleteLocalPaintMap"); // Advanced > UI diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index 077e6e6cb1..d87658ba89 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -317,10 +317,18 @@ LLViewerTexture* LLTerrainMaterials::getPaintMap() return mPaintMap.get(); } +LLTerrainPaintQueue& LLTerrainMaterials::getPaintQueue() +{ + return mPaintQueue; +} + void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map) { llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP); + const bool changed = paint_map != mPaintMap; mPaintMap = paint_map; + // The paint map has changed, so edits are no longer valid + mPaintQueue.clear(); } // Boost the texture loading priority diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index f15f9bff6a..972a46d8db 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -27,10 +27,13 @@ #ifndef LL_LLVLCOMPOSITION_H #define LL_LLVLCOMPOSITION_H +#include + #include "llviewerlayer.h" #include "llviewershadermgr.h" #include "llviewertexture.h" #include "llpointer.h" +#include "llterrainpaintmap.h" #include "llimage.h" @@ -87,6 +90,8 @@ public: void setPaintType(U32 paint_type) { mPaintType = paint_type; } LLViewerTexture* getPaintMap(); void setPaintMap(LLViewerTexture* paint_map); + // Paint queue for current paint map + LLTerrainPaintQueue& getPaintQueue(); protected: void unboost(); @@ -105,6 +110,7 @@ protected: U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE; LLPointer mPaintMap; + LLTerrainPaintQueue mPaintQueue; }; // Local materials to override all regions diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index e1d33e5bc3..74ced74178 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3824,6 +3824,13 @@ function="World.EnvPreset" + + + Date: Fri, 9 Aug 2024 17:23:43 -0700 Subject: secondlife/viewer#1883: (WIP) Alpha paint queue --- indra/llrender/llglslshader.cpp | 22 ++ indra/llrender/llglslshader.h | 2 + indra/llrender/llshadermgr.cpp | 3 +- indra/llrender/llshadermgr.h | 1 + .../shaders/class1/interface/pbrTerrainBakeF.glsl | 2 +- .../shaders/class1/interface/terrainStampF.glsl | 44 +++ .../shaders/class1/interface/terrainStampV.glsl | 39 +++ indra/newview/lldrawpoolterrain.cpp | 8 +- indra/newview/llterrainpaintmap.cpp | 326 ++++++++++++++++++++- indra/newview/llterrainpaintmap.h | 28 +- indra/newview/llviewermenu.cpp | 33 ++- indra/newview/llviewershadermgr.cpp | 19 ++ indra/newview/llviewershadermgr.h | 1 + indra/newview/llvlcomposition.cpp | 8 +- indra/newview/llvlcomposition.h | 13 +- 15 files changed, 510 insertions(+), 39 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl create mode 100644 indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl (limited to 'indra') diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 6ba5463acd..bbbce1965e 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1138,6 +1138,28 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextu return uniform; } +// For LLImageGL-wrapped textures created via GL elsewhere with our API only. Use with caution. +S32 LLGLSLShader::bindTextureImageGL(S32 uniform, LLImageGL* texture, LLTexUnit::eTextureType mode) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + LL_WARNS_ONCE("Shader") << "Uniform index out of bounds. Size: " << (S32)mUniform.size() << " index: " << uniform << LL_ENDL; + llassert(false); + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->bind(texture); + } + + return uniform; +} + S32 LLGLSLShader::bindTexture(S32 uniform, LLRenderTarget* texture, bool depth, LLTexUnit::eTextureFilterOptions mode, U32 index) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 2d669c70a9..c24daaf686 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -264,6 +264,8 @@ public: // You can reuse the return value to unbind a texture when required. S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + // For LLImageGL-wrapped textures created via GL elsewhere with our API only. Use with caution. + S32 bindTextureImageGL(S32 uniform, LLImageGL* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR); S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0); S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 6097b09d96..796805e2a5 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1190,8 +1190,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("gltf_material_id"); // (GLTF) mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) + mReservedUniforms.push_back("terrain_stamp_scale"); - llassert(mReservedUniforms.size() == LLShaderMgr::TERRAIN_TEXTURE_TRANSFORMS +1); + llassert(mReservedUniforms.size() == LLShaderMgr::TERRAIN_STAMP_SCALE +1); mReservedUniforms.push_back("viewport"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 1bae0cd8a0..ff07ce454b 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -67,6 +67,7 @@ public: GLTF_MATERIAL_ID, // "gltf_material_id" (GLTF) TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF) + TERRAIN_STAMP_SCALE, // "terrain_stamp_scale" VIEWPORT, // "viewport" LIGHT_POSITION, // "light_position" diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl index cf20653a0f..a79a56d725 100644 --- a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl @@ -1,5 +1,5 @@ /** - * @file terrainBakeF.glsl + * @file pbrTerrainBakeF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl b/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl new file mode 100644 index 0000000000..e79e9010e6 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl @@ -0,0 +1,44 @@ +/** + * @file terrainStampF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +out vec4 frag_color; + +// Paint texture to stamp into the "paintmap" +uniform sampler2D diffuseMap; + +in vec2 vary_texcoord0; + +void main() +{ + vec4 col = texture(diffuseMap, vary_texcoord0); + if (col.a <= 0.0f) + { + discard; + } + + frag_color = max(col, vec4(0)); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl b/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl new file mode 100644 index 0000000000..294fa6be26 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl @@ -0,0 +1,39 @@ +/** + * @file terrainStampV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +uniform mat4 modelview_projection_matrix; +uniform vec2 terrain_stamp_scale; + +in vec3 position; + +out vec2 vary_texcoord0; + +void main() +{ + gl_Position = modelview_projection_matrix * vec4(position, 1.0); + // Positions without transforms are treated as UVs for the purpose of this shader. + vary_texcoord0.xy = terrain_stamp_scale * position.xy; +} + diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 5e676bc5b3..57def49539 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -296,7 +296,7 @@ void LLDrawPoolTerrain::renderFullShaderTextures() // GL_BLEND disabled by default drawLoop(); - // Disable multitexture + // Disable textures sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0); sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL1); @@ -557,7 +557,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool use_local_materials) // GL_BLEND disabled by default drawLoop(); - // Disable multitexture + // Disable textures if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE) { @@ -769,7 +769,7 @@ void LLDrawPoolTerrain::renderFull4TU() } LLVertexBuffer::unbind(); - // Disable multitexture + // Disable textures gGL.getTexUnit(3)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(3)->disable(); gGL.getTexUnit(3)->activate(); @@ -949,7 +949,7 @@ void LLDrawPoolTerrain::renderFull2TU() // Restore blend state gGL.setSceneBlendType(LLRender::BT_ALPHA); - // Disable multitexture + // Disable textures gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(1)->disable(); diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 6979464cd3..7dc09a4748 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -31,6 +31,8 @@ // library includes #include "llglslshader.h" #include "llrendertarget.h" +#include "llrender2dutils.h" +#include "llshadermgr.h" #include "llvertexbuffer.h" // newview includes @@ -89,8 +91,8 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& // Bind the debug shader and render terrain to tex // Use a scratch render target because its dimensions may exceed the standard bake target, and this is a one-off bake LLRenderTarget scratch_target; - const S32 dim = llmin(tex.getWidth(), tex.getHeight()); - scratch_target.allocate(dim, dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, LLTexUnit::eTextureMipGeneration::TMG_NONE); if (!scratch_target.isComplete()) { @@ -117,6 +119,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& const F32 region_half_width = region_width / 2.0f; const F32 region_camera_height = surface.getMaxZ() + DEFAULT_NEAR_PLANE; LLViewerCamera camera; + // TODO: Huh... I just realized this view vector is not completely vertical const LLVector3 region_center = LLVector3(region_half_width, region_half_width, 0.0) + region.getOriginAgent(); const LLVector3 camera_origin = LLVector3(0.0f, 0.0f, region_camera_height) + region_center; camera.lookAt(camera_origin, region_center, LLVector3::y_axis); @@ -250,6 +253,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& S32 alpha_ramp = shader.enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); LLPointer alpha_ramp_texture = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD_2D); + // TODO: Consider using LLGLSLShader::bindTexture gGL.getTexUnit(alpha_ramp)->bind(alpha_ramp_texture); gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -263,6 +267,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& const U32 vertex_offset = n * patch_index; llassert(index_offset + ni <= region_indices); llassert(vertex_offset + n <= region_vertices); + // TODO: Try a single big drawRange and see if that still works buf->drawRange(LLRender::TRIANGLES, vertex_offset, vertex_offset + n - 1, ni, index_offset); } } @@ -282,7 +287,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& gGL.flush(); LLVertexBuffer::unbind(); // Final step: Copy the output to the terrain paintmap - const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, dim, dim); + const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, tex.getWidth(), tex.getHeight()); if (!success) { LL_WARNS() << "Failed to copy framebuffer to paintmap" << LL_ENDL; @@ -297,10 +302,10 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& return success; } -// TODO: Decide when to apply the paint queue - ideally once per frame per region +// *TODO: Decide when to apply the paint queue - ideally once per frame per region // Applies paints and then clears the paint queue // *NOTE The paint queue is also cleared when setting the paintmap texture -void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue) +void LLTerrainPaintMap::applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue) { if (queue.empty()) { return; } @@ -310,6 +315,11 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); + // glTexSubImage2D replaces all pixels in the rectangular region. That + // makes it unsuitable for alpha. + llassert(queue.getComponents() == LLTerrainPaint::RGB); + constexpr GLenum pixformat = GL_RGB; + const std::vector& queue_list = queue.get(); for (size_t i = 0; i < queue_list.size(); ++i) { @@ -328,8 +338,10 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset); const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset); const U8* pixels = paint->mData.data(); - constexpr GLenum pixformat = GL_RGB; constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + // *TODO: Performance suggestion: Use the sub-image utility function + // that LLImageGL::setSubImage uses to split texture updates into + // lines, if that's faster. glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels); stop_glerror(); } @@ -343,7 +355,284 @@ void LLTerrainPaintMap::applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueu queue.clear(); } -bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) +namespace +{ + +// A general-purpose vertex buffer of a quad for stamping textures on the z=0 +// plane. +// *NOTE: Because we know the vertex XY coordinates go from 0 to 1 +// pre-transform, UVs can be calculated from the vertices +LLVertexBuffer& get_paint_triangle_buffer() +{ + static LLPointer buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); + static bool initialized = false; + if (!initialized) + { + // Two triangles forming a square from (0,0) to (1,1) + buf->allocateBuffer(/*vertices =*/ 4, /*indices =*/ 6); + LLStrider indices; + LLStrider vertices; + buf->getVertexStrider(vertices); + buf->getIndexStrider(indices); + // y + // 2....3 + // ^ . . + // | 0....1 + // | + // -------> x + // + // triangle 1: 0,1,2 + // triangle 2: 1,3,2 + (*(vertices++)).set(0.0f, 0.0f, 0.0f); + (*(vertices++)).set(1.0f, 0.0f, 0.0f); + (*(vertices++)).set(0.0f, 1.0f, 0.0f); + (*(vertices++)).set(1.0f, 1.0f, 0.0f); + *(indices++) = 0; + *(indices++) = 1; + *(indices++) = 2; + *(indices++) = 1; + *(indices++) = 3; + *(indices++) = 2; + buf->unmapBuffer(); + } + return *buf; +} + +}; + +// static +LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + llassert(queue_in.getComponents() == LLTerrainPaint::RGBA); + + // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead + // TODO: even if it means performing extra render operations to apply the paints, in rare cases where the paints can't all fit within an area that can be represented by the buffer + LLRenderTarget scratch_target; + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + LLTexUnit::eTextureMipGeneration::TMG_NONE); + if (!scratch_target.isComplete()) + { + llassert(false); + LL_WARNS() << "Failed to allocate render target" << LL_ENDL; + return false; + } + gGL.getTexUnit(0)->disable(); + stop_glerror(); + + scratch_target.bindTarget(); + glClearColor(0, 0, 0, 0); + scratch_target.clear(); + const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; + const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; + + LLVertexBuffer* buf = &get_paint_triangle_buffer(); + + // Update projection matrix and viewport + // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. + { + stop_glerror(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f); + stop_glerror(); + const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0); + glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight()); + } + + // View matrix + // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. + // Camera is centered in the middle of the framebuffer. + glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + { + LLViewerCamera camera; + const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); + const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f); + camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis); + camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); + GLfloat ogl_matrix[16]; + camera.getOpenGLTransform(ogl_matrix); + view *= glh::matrix4f(ogl_matrix); + } + + LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable scissor(GL_SCISSOR_TEST); + LLGLEnable cull_face(GL_CULL_FACE); + LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + LLGLSLShader& shader = gTerrainStampProgram; + shader.bind(); + + // First, apply the paint map as the background + { + glh::matrix4f model; + { + model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); + // We care about the whole paintmap, which is already a power of two. + // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0) + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB); + + // Incrementally apply each RGBA paint to the render target, then extract + // the result back into memory as an RGB paint. + // Put each result in queue_out. + const std::vector& queue_in_list = queue_in.get(); + for (size_t i = 0; i < queue_in_list.size(); ++i) + { + // It is currently the responsibility of the paint queue to convert + // incoming bits to the right bit depth for paint operations (this + // could change in the future). + queue_in.convertBitDepths(i, 8); + const LLTerrainPaint::ptr_t& paint_in = queue_in_list[i]; + + // Modelview matrix for the current paint + // View matrix is already computed. Just need the model matrix. + // Orthographic projection matrix is already updated + glh::matrix4f model; + { + model.set_scale(glh::vec3f(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); + model.set_translate(glh::vec3f(paint_in->mStartX, paint_in->mStartY, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + // Generate temporary stamp texture from paint contents. + // Our stamp image needs to be a power of two. + // Because the paint data may not cover a whole power-of-two region, + // allocate a bigger 2x2 image if needed, but set the image data later + // for a subset of the image. + // Pixel data outside this subset is left undefined. We will use + // TERRAIN_STAMP_SCALE in the stamp shader to define the subset of the + // image we care about. + const U32 width_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthX)))); + const U32 height_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthY)))); + LLPointer stamp_image; + { + // Create image object (dimensions not yet initialized in GL) + U32 stamp_tex_name; + LLImageGL::generateTextures(1, &stamp_tex_name); + const U32 components = paint_in->mComponents; + constexpr LLGLenum target = GL_TEXTURE_2D; + const LLGLenum internal_format = paint_in->mComponents == 4 ? GL_RGBA8 : GL_RGB8; + const LLGLenum format = paint_in->mComponents == 4 ? GL_RGBA : GL_RGB; + constexpr LLGLenum type = GL_UNSIGNED_BYTE; + stamp_image = new LLImageGL(stamp_tex_name, components, target, internal_format, format, type, LLTexUnit::TAM_WRAP); + // Nearest-neighbor filtering to reduce surprises + stamp_image->setFilteringOption(LLTexUnit::TFO_POINT); + + // Initialize the image dimensions in GL + constexpr U8* undefined_data_for_now = nullptr; + gGL.getTexUnit(0)->bind(stamp_image, false, true); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_rounded, height_rounded, 0, format, type, undefined_data_for_now); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + stamp_image->setSize(width_rounded, height_rounded, components); + stamp_image->setDiscardLevel(0); + + // Manually set a subset of the image in GL + const U8* data = paint_in->mData.data(); + const S32 data_width = paint_in->mWidthX; + const S32 data_height = paint_in->mWidthY; + constexpr S32 origin = 0; + // width = data_width; height = data_height. i.e.: Copy the full + // contents of data into the image. + stamp_image->setSubImage(data, data_width, data_height, origin, origin, /*width=*/data_width, /*height=*/data_height); + } + + // Apply ("stamp") the paint to the render target + { + shader.bindTextureImageGL(LLShaderMgr::DIFFUSE_MAP, stamp_image); + const F32 width_fraction = F32(paint_in->mWidthX) / F32(width_rounded); + const F32 height_fraction = F32(paint_in->mWidthY) / F32(height_rounded); + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, width_fraction, height_fraction); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + // Extract the result back into memory as an RGB paint + LLTerrainPaint::ptr_t paint_out = std::make_shared(); + { + paint_out->mStartX = paint_in->mStartX; + paint_out->mStartY = paint_in->mStartY; + paint_out->mWidthX = paint_in->mWidthX; + paint_out->mWidthY = paint_in->mWidthY; + paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mComponents = LLTerrainPaint::RGB; + paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); + constexpr GLint miplevel = 0; + const S32 x_offset = paint_out->mStartX; + const S32 y_offset = paint_out->mStartY; + const S32 width = llmin(paint_out->mWidthX, tex.getWidth() - x_offset); + const S32 height = llmin(paint_out->mWidthY, tex.getHeight() - y_offset); + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + llassert(paint_out->mData.size() <= std::numeric_limits::max()); + const GLsizei buf_size = (GLsizei)paint_out->mData.size(); + U8* pixels = paint_out->mData.data(); + glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels); + } + + // Enqueue the result to the new paint queue, with bit depths per color + // channel reduced from 8 to 5, and reduced from RGBA (paintmap + // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle + // update without alpha mask). This format is suitable for sending + // over the network. + // *TODO: At some point, queue_out will pass through a network + // round-trip which will reduce the bit depth, making the + // pre-conversion step not necessary. + queue_out.enqueue(paint_out); + queue_out.convertBitDepths(queue_out.size()-1, 5); + } + + queue_in.clear(); + + scratch_target.flush(); + + LLGLSLShader::unbind(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + return queue_out; +} + +LLTerrainPaintQueue::LLTerrainPaintQueue(U8 components) +: mComponents(components) +{ + llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); +} + +LLTerrainPaintQueue::LLTerrainPaintQueue(const LLTerrainPaintQueue& other) +{ + *this = other; + llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); +} + +LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(const LLTerrainPaintQueue& other) +{ + mComponents = other.mComponents; + mList = other.mList; + return *this; +} + +bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run) { llassert(paint); if (!paint) { return false; } @@ -353,7 +642,7 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) // The internal paint map image is currently 8 bits, so that's the maximum // allowed bit depth. llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8); - llassert(paint->mData.size() == (LLTerrainPaint::COMPONENTS * paint->mWidthX * paint->mWidthY)); + llassert(paint->mData.size() == (mComponents * paint->mWidthX * paint->mWidthY)); llassert(paint->mWidthX > 0); llassert(paint->mWidthY > 0); #ifdef SHOW_ASSERT @@ -364,10 +653,29 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint) llassert(paint->mStartX < max_texture_width); llassert(paint->mStartY < max_texture_width); - mList.push_back(paint); + if (!dry_run) { mList.push_back(paint); } return true; } +bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& paint_queue) +{ + constexpr bool dry_run = true; + for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) + { + if (!enqueue(paint), dry_run) { return false; } + } + for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) + { + enqueue(paint); + } + return true; +} + +size_t LLTerrainPaintQueue::size() const +{ + return mList.size(); +} + bool LLTerrainPaintQueue::empty() const { return mList.empty(); diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h index 9189f12cbd..b4d706b107 100644 --- a/indra/newview/llterrainpaintmap.h +++ b/indra/newview/llterrainpaintmap.h @@ -26,6 +26,8 @@ #pragma once +#include "llviewerprecompiledheaders.h" + class LLViewerRegion; class LLViewerTexture; class LLTerrainPaintQueue; @@ -41,14 +43,15 @@ public: // Returns true if successful static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex); - static void applyPaintQueue(LLViewerTexture& tex, LLTerrainPaintQueue& queue); + static void applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue); + static LLTerrainPaintQueue convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in); }; // Enqueued paint operations, in texture coordinates. -// data is always RGB, with each U8 storing one color in the provided bit depth. -class LLTerrainPaint +// mData is always RGB or RGBA (determined by mComponents), with each U8 +// storing one color with a max value of (1 >> mBitDepth) - 1 +struct LLTerrainPaint { -public: using ptr_t = std::shared_ptr; U16 mStartX; @@ -56,25 +59,38 @@ public: U16 mWidthX; U16 mWidthY; U8 mBitDepth; - static const U8 COMPONENTS = 3; + U8 mComponents; + const static U8 RGB = 3; + const static U8 RGBA = 4; std::vector mData; }; class LLTerrainPaintQueue { public: - bool enqueue(LLTerrainPaint::ptr_t& paint); + // components determines what type of LLTerrainPaint is allowed. Must be 3 (RGB) or 4 (RGBA) + LLTerrainPaintQueue(U8 components); + LLTerrainPaintQueue(const LLTerrainPaintQueue& other); + LLTerrainPaintQueue& operator=(const LLTerrainPaintQueue& other); + + bool enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run = false); + bool enqueue(LLTerrainPaintQueue& paint_queue); + size_t size() const; bool empty() const; void clear(); const std::vector& get() const { return mList; } + U8 getComponents() const { return mComponents; } // Convert mBitDepth for the LLTerrainPaint in the queue at index + // If mBitDepth is already equal to target_bit_depth, no conversion takes + // place. // It is currently the responsibility of the paint queue to convert // incoming bits to the right bit depth for the paintmap (this could // change in the future). void convertBitDepths(size_t index, U8 target_bit_depth); private: + U8 mComponents; std::vector mList; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index fa6e8870b3..c4bb5eaa2e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1435,6 +1435,7 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t const U32 max_resolution = gSavedSettings.getU32("RenderMaxTextureResolution"); dim = llclamp(dim, 16, max_resolution); dim = 1 << U32(std::ceil(std::log2(dim))); + // TODO: Could probably get away with not using image raw here, now that we aren't writing bits via the CPU (see load_exr for example) LLPointer image_raw = new LLImageRaw(dim,dim,3); LLPointer tex = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); const bool success = LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(*region, *tex); @@ -1460,7 +1461,7 @@ class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t return false; } - LLTerrainPaintQueue& paint_queue = gLocalTerrainMaterials.getPaintQueue(); + LLTerrainPaintQueue& paint_request_queue = gLocalTerrainMaterials.getPaintRequestQueue(); // Enqueue a paint // Overrides an entire region patch with the material in the last slot @@ -1477,17 +1478,31 @@ class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t paint->mBitDepth = bit_depth; constexpr U8 max_value = (1 << bit_depth) - 1; const size_t pixel_count = width * width; - paint->mData.resize(LLTerrainPaint::COMPONENTS * pixel_count); - for (size_t pixel = 0; pixel < pixel_count; ++pixel) + const U8 components = LLTerrainPaint::RGBA; + paint->mComponents = components; + paint->mData.resize(components * pixel_count); + for (size_t h = 0; h < paint->mWidthY; ++h) { - paint->mData[(LLTerrainPaint::COMPONENTS*pixel) + LLTerrainPaint::COMPONENTS - 1] = max_value; + for (size_t w = 0; w < paint->mWidthX; ++w) + { + const size_t pixel = (h * paint->mWidthX) + w; + // Solid blue color + paint->mData[(components*pixel) + components - 2] = max_value; // blue + // Alpha gradient from 0.0 to 1.0 along w + const U8 alpha = U8(F32(max_value) * F32(w+1) / F32(paint->mWidthX)); + paint->mData[(components*pixel) + components - 1] = alpha; // alpha + } } - paint_queue.enqueue(paint); + paint_request_queue.enqueue(paint); - // Apply the paint queue ad-hoc right here for now. - // *TODO: Eventually the paint queue should be applied at a predictable - // time in the viewer frame loop. - LLTerrainPaintMap::applyPaintQueue(*tex, paint_queue); + // Apply the paint queues ad-hoc right here for now. + // *TODO: Eventually the paint queue(s) should be applied at a + // predictable time in the viewer frame loop. + // TODO: In hindsight... maybe we *should* bind the paintmap to the render buffer. That makes a lot more sense, and we wouldn't have to reduce its resolution by settling for the bake buffer. If we do that, make a comment above convertPaintQueueRGBAToRGB that the texture is modified! + LLTerrainPaintQueue paint_send_queue = LLTerrainPaintMap::convertPaintQueueRGBAToRGB(*tex, paint_request_queue); + LLTerrainPaintQueue& paint_map_queue = gLocalTerrainMaterials.getPaintMapQueue(); + paint_map_queue.enqueue(paint_send_queue); + LLTerrainPaintMap::applyPaintQueueRGB(*tex, paint_map_queue); return true; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index a8fe221d98..8e7af28d41 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -100,6 +100,7 @@ LLGLSLShader gReflectionProbeDisplayProgram; LLGLSLShader gCopyProgram; LLGLSLShader gCopyDepthProgram; LLGLSLShader gPBRTerrainBakeProgram; +LLGLSLShader gTerrainStampProgram; //object shaders LLGLSLShader gObjectPreviewProgram; @@ -3170,6 +3171,24 @@ bool LLViewerShaderMgr::loadShadersInterface() } } + if (success) + { + LLGLSLShader* shader = &gTerrainStampProgram; + U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth"); + // LLTerrainPaintMap currently uses an RGB8 texture internally + bit_depth = llclamp(bit_depth, 1, 8); + shader->mName = llformat("Terrain Stamp Shader RGB%o", bit_depth); + + shader->mShaderFiles.clear(); + shader->mShaderFiles.push_back(make_pair("interface/terrainStampV.glsl", GL_VERTEX_SHADER)); + shader->mShaderFiles.push_back(make_pair("interface/terrainStampF.glsl", GL_FRAGMENT_SHADER)); + shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + const U32 value_range = (1 << bit_depth) - 1; + shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range)); + success = success && shader->createShader(); + llassert(success); + } + if (success) { gAlphaMaskProgram.mName = "Alpha Mask Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index b08796025a..e654967c46 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -175,6 +175,7 @@ extern LLGLSLShader gReflectionProbeDisplayProgram; extern LLGLSLShader gCopyProgram; extern LLGLSLShader gCopyDepthProgram; extern LLGLSLShader gPBRTerrainBakeProgram; +extern LLGLSLShader gTerrainStampProgram; //output tex0[tc0] - tex1[tc1] extern LLGLSLShader gTwoTextureCompareProgram; diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index d87658ba89..ca76d93cd7 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -317,18 +317,14 @@ LLViewerTexture* LLTerrainMaterials::getPaintMap() return mPaintMap.get(); } -LLTerrainPaintQueue& LLTerrainMaterials::getPaintQueue() -{ - return mPaintQueue; -} - void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map) { llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP); const bool changed = paint_map != mPaintMap; mPaintMap = paint_map; // The paint map has changed, so edits are no longer valid - mPaintQueue.clear(); + mPaintRequestQueue.clear(); + mPaintMapQueue.clear(); } // Boost the texture loading priority diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 972a46d8db..3f1124a8ac 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -90,8 +90,14 @@ public: void setPaintType(U32 paint_type) { mPaintType = paint_type; } LLViewerTexture* getPaintMap(); void setPaintMap(LLViewerTexture* paint_map); - // Paint queue for current paint map - LLTerrainPaintQueue& getPaintQueue(); + // Queue of client-triggered paint operations that need to be converted + // into a form that can be sent to the server. + // Paints in this queue are in RGBA format. + LLTerrainPaintQueue& getPaintRequestQueue() { return mPaintRequestQueue; } + // Paint queue for current paint map - this queue gets applied directly to + // the paint map. Paints within are assumed to have already been sent to + // the server. Paints in this queue are in RGB format. + LLTerrainPaintQueue& getPaintMapQueue() { return mPaintMapQueue; } protected: void unboost(); @@ -110,7 +116,8 @@ protected: U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE; LLPointer mPaintMap; - LLTerrainPaintQueue mPaintQueue; + LLTerrainPaintQueue mPaintRequestQueue{U8(4)}; + LLTerrainPaintQueue mPaintMapQueue{U8(3)}; }; // Local materials to override all regions -- cgit v1.2.3 From 642ace3c75d08cc55370374f5a091f0c8ff41a4c Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 16 Aug 2024 17:27:57 -0700 Subject: secondlife/viewer#1883: (WIP) (not yet working) Brush queue --- indra/newview/llterrainpaintmap.cpp | 349 ++++++++++++++++++++++++++++++++---- indra/newview/llterrainpaintmap.h | 90 ++++++++-- indra/newview/llviewermenu.cpp | 40 ++++- indra/newview/llvlcomposition.h | 5 + 4 files changed, 434 insertions(+), 50 deletions(-) (limited to 'indra') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 7dc09a4748..6a57605325 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -575,12 +575,16 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur paint_out->mWidthY = paint_in->mWidthY; paint_out->mBitDepth = 8; // Will be reduced to 5 bits later paint_out->mComponents = LLTerrainPaint::RGB; +#ifdef SHOW_ASSERT + paint_out->assert_confined_to(tex); +#endif + paint_out->confine_to(tex); paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); constexpr GLint miplevel = 0; const S32 x_offset = paint_out->mStartX; const S32 y_offset = paint_out->mStartY; - const S32 width = llmin(paint_out->mWidthX, tex.getWidth() - x_offset); - const S32 height = llmin(paint_out->mWidthY, tex.getHeight() - y_offset); + const S32 width = paint_out->mWidthX; + const S32 height = paint_out->mWidthY; constexpr GLenum pixformat = GL_RGB; constexpr GLenum pixtype = GL_UNSIGNED_BYTE; llassert(paint_out->mData.size() <= std::numeric_limits::max()); @@ -613,22 +617,294 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur return queue_out; } +// static +LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in) +{ +#ifdef SHOW_ASSERT + check_tex(tex); +#endif + + // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead + // TODO: even if it means performing extra render operations to apply the brushes, in rare cases where the paints can't all fit within an area that can be represented by the buffer + LLRenderTarget scratch_target; + const S32 max_dim = llmax(tex.getWidth(), tex.getHeight()); + scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, + LLTexUnit::eTextureMipGeneration::TMG_NONE); + if (!scratch_target.isComplete()) + { + llassert(false); + LL_WARNS() << "Failed to allocate render target" << LL_ENDL; + return false; + } + gGL.getTexUnit(0)->disable(); + stop_glerror(); + + scratch_target.bindTarget(); + glClearColor(0, 0, 0, 0); + scratch_target.clear(); + const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; + const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; + + LLVertexBuffer* buf = &get_paint_triangle_buffer(); + + // Update projection matrix and viewport + // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. + { + stop_glerror(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f); + stop_glerror(); + const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0); + glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight()); + } + + // View matrix + // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. + // Camera is centered in the middle of the framebuffer. + glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + { + LLViewerCamera camera; + const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); + const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f); + camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis); + camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); + GLfloat ogl_matrix[16]; + camera.getOpenGLTransform(ogl_matrix); + view *= glh::matrix4f(ogl_matrix); + } + + LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable scissor(GL_SCISSOR_TEST); + LLGLEnable cull_face(GL_CULL_FACE); + LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS); + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + LLGLSLShader& shader = gTerrainStampProgram; + shader.bind(); + + // First, apply the paint map as the background + { + glh::matrix4f model; + { + model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); + // We care about the whole paintmap, which is already a power of two. + // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0) + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB); + + // Incrementally apply each brush stroke to the render target, then extract + // the result back into memory as an RGB paint. + // Put each result in queue_out. + const std::vector& brush_list = queue_in.get(); + for (size_t i = 0; i < brush_list.size(); ++i) + { + const LLTerrainBrush::ptr_t& brush_in = brush_list[i]; + + // Modelview matrix for the current brush + // View matrix is already computed. Just need the model matrix. + // Orthographic projection matrix is already updated + // *NOTE: Brush path information is in region space. It will need to be + // converted to paintmap pixel space before it makes sense. + F32 brush_width_x; + F32 brush_width_y; + F32 brush_start_x; + F32 brush_start_y; + { + F32 min_x = brush_in->mPath[0].mV[VX]; + F32 max_x = min_x; + F32 min_y = brush_in->mPath[0].mV[VY]; + F32 max_y = min_y; + for (size_t i = 1; i < brush_in->mPath.size(); ++i) + { + const F32 x = brush_in->mPath[i].mV[VX]; + const F32 y = brush_in->mPath[i].mV[VY]; + min_x = llmin(min_x, x); + max_x = llmax(max_x, x); + min_y = llmin(min_y, y); + max_y = llmax(max_y, y); + } + brush_width_x = brush_in->mBrushSize + (max_x - min_x); + brush_width_y = brush_in->mBrushSize + (max_y - min_y); + brush_start_x = min_x - (brush_in->mBrushSize / 2.0f); + brush_start_y = min_y - (brush_in->mBrushSize / 2.0f); + // Convert brush path information to paintmap pixel space from region + // space. + brush_width_x *= tex.getWidth() / region.getWidth(); + brush_width_y *= tex.getHeight() / region.getWidth(); + brush_start_x *= tex.getWidth() / region.getWidth(); + brush_start_y *= tex.getHeight() / region.getWidth(); + } + glh::matrix4f model; + { + model.set_scale(glh::vec3f(brush_width_x, brush_width_y, 1.0f)); + model.set_translate(glh::vec3f(brush_start_x, brush_start_y, 0.0f)); + } + glh::matrix4f modelview = view * model; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(modelview.m); + + // Apply the "brush" to the render target + { + // TODO: Use different shader for this - currently this is using the stamp shader. The white image is just a placeholder for now + shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, LLViewerFetchedTexture::sWhiteImagep); + shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f); + buf->setBuffer(); + buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0); + } + + // Extract the result back into memory as an RGB paint + LLTerrainPaint::ptr_t paint_out = std::make_shared(); + { + paint_out->mStartX = U16(floor(brush_start_x)); + paint_out->mStartY = U16(floor(brush_start_y)); + const F32 dX = brush_start_x - F32(paint_out->mStartX); + const F32 dY = brush_start_y - F32(paint_out->mStartY); + paint_out->mWidthX = U16(ceil(brush_width_x + dX)); + paint_out->mWidthY = U16(ceil(brush_width_y + dY)); + paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mComponents = LLTerrainPaint::RGB; + // The brush strokes are expected to sometimes partially venture + // outside of the paintmap bounds. + paint_out->confine_to(tex); + paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY); + constexpr GLint miplevel = 0; + const S32 x_offset = paint_out->mStartX; + const S32 y_offset = paint_out->mStartY; + const S32 width = paint_out->mWidthX; + const S32 height = paint_out->mWidthY; + constexpr GLenum pixformat = GL_RGB; + constexpr GLenum pixtype = GL_UNSIGNED_BYTE; + llassert(paint_out->mData.size() <= std::numeric_limits::max()); + const GLsizei buf_size = (GLsizei)paint_out->mData.size(); + U8* pixels = paint_out->mData.data(); + glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels); + } + + // Enqueue the result to the new paint queue, with bit depths per color + // channel reduced from 8 to 5, and reduced from RGBA (paintmap + // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle + // update without alpha mask). This format is suitable for sending + // over the network. + // *TODO: At some point, queue_out will pass through a network + // round-trip which will reduce the bit depth, making the + // pre-conversion step not necessary. + queue_out.enqueue(paint_out); + queue_out.convertBitDepths(queue_out.size()-1, 5); + } + + queue_in.clear(); + + scratch_target.flush(); + + LLGLSLShader::unbind(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + return queue_out; +} + +template +LLTerrainQueue::LLTerrainQueue(LLTerrainQueue& other) +{ + *this = other; +} + +template +LLTerrainQueue& LLTerrainQueue::operator=(LLTerrainQueue& other) +{ + mList = other.mList; + return *this; +} + +template +bool LLTerrainQueue::enqueue(std::shared_ptr& t, bool dry_run) +{ + if (!dry_run) { mList.push_back(t); } + return true; +} + +template +bool LLTerrainQueue::enqueue(std::vector>& list) +{ + constexpr bool dry_run = true; + for (T::ptr_t& t : list) + { + if (!enqueue(t), dry_run) { return false; } + } + for (T::ptr_t& t : list) + { + enqueue(t); + } + return true; +} + +template +size_t LLTerrainQueue::size() const +{ + return mList.size(); +} + +template +bool LLTerrainQueue::empty() const +{ + return mList.empty(); +} + +template +void LLTerrainQueue::clear() +{ + mList.clear(); +} + +void LLTerrainPaint::assert_confined_to(const LLTexture& tex) const +{ + llassert(mStartX >= 0 && mStartX < tex.getWidth()); + llassert(mStartY >= 0 && mStartY < tex.getHeight()); + llassert(mWidthX <= tex.getWidth() - mStartX); + llassert(mWidthY <= tex.getHeight() - mStartY); +} + +void LLTerrainPaint::confine_to(const LLTexture& tex) +{ + mStartX = llmax(mStartX, 0); + mStartY = llmax(mStartY, 0); + mWidthX = llmin(mWidthX, tex.getWidth() - mStartX); + mWidthY = llmin(mWidthY, tex.getHeight() - mStartY); + assert_confined_to(tex); +} + LLTerrainPaintQueue::LLTerrainPaintQueue(U8 components) : mComponents(components) { llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); } -LLTerrainPaintQueue::LLTerrainPaintQueue(const LLTerrainPaintQueue& other) +LLTerrainPaintQueue::LLTerrainPaintQueue(LLTerrainPaintQueue& other) +: LLTerrainQueue(other) +, mComponents(other.mComponents) { - *this = other; llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA); } -LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(const LLTerrainPaintQueue& other) +LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(LLTerrainPaintQueue& other) { + LLTerrainQueue::operator=(other); mComponents = other.mComponents; - mList = other.mList; return *this; } @@ -653,37 +929,12 @@ bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run) llassert(paint->mStartX < max_texture_width); llassert(paint->mStartY < max_texture_width); - if (!dry_run) { mList.push_back(paint); } - return true; + return LLTerrainQueue::enqueue(paint, dry_run); } -bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& paint_queue) +bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& queue) { - constexpr bool dry_run = true; - for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) - { - if (!enqueue(paint), dry_run) { return false; } - } - for (LLTerrainPaint::ptr_t& paint : paint_queue.mList) - { - enqueue(paint); - } - return true; -} - -size_t LLTerrainPaintQueue::size() const -{ - return mList.size(); -} - -bool LLTerrainPaintQueue::empty() const -{ - return mList.empty(); -} - -void LLTerrainPaintQueue::clear() -{ - mList.clear(); + return LLTerrainQueue::enqueue(queue.mList); } void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) @@ -705,3 +956,33 @@ void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth) paint->mBitDepth = target_bit_depth; } + +LLTerrainBrushQueue::LLTerrainBrushQueue() +: LLTerrainQueue() +{ +} + +LLTerrainBrushQueue::LLTerrainBrushQueue(LLTerrainBrushQueue& other) +: LLTerrainQueue(other) +{ +} + +LLTerrainBrushQueue& LLTerrainBrushQueue::operator=(LLTerrainBrushQueue& other) +{ + LLTerrainQueue::operator=(other); + return *this; +} + +bool LLTerrainBrushQueue::enqueue(LLTerrainBrush::ptr_t& brush, bool dry_run) +{ + llassert(brush->mBrushSize > 0); + llassert(!brush->mPath.empty()); + llassert(brush->mPathOffset < brush->mPath.size()); + llassert(brush->mPathOffset < 2); // Harmless, but doesn't do anything useful, so might be a sign of implementation error + return LLTerrainQueue::enqueue(brush, dry_run); +} + +bool LLTerrainBrushQueue::enqueue(LLTerrainBrushQueue& queue) +{ + return LLTerrainQueue::enqueue(queue.mList); +} diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h index b4d706b107..cffdad80a2 100644 --- a/indra/newview/llterrainpaintmap.h +++ b/indra/newview/llterrainpaintmap.h @@ -28,10 +28,14 @@ #include "llviewerprecompiledheaders.h" +class LLTexture; class LLViewerRegion; class LLViewerTexture; class LLTerrainPaintQueue; +class LLTerrainBrushQueue; +// TODO: Terrain painting across regions. Assuming painting is confined to one +// region for now. class LLTerrainPaintMap { public: @@ -43,8 +47,34 @@ public: // Returns true if successful static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex); + // This operation clears the queue + // TODO: Decide if clearing the queue is needed - seems inconsistent static void applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue); + static LLTerrainPaintQueue convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in); + // TODO: Implement (it's similar to convertPaintQueueRGBAToRGB but different shader + need to calculate the dimensions + need a different vertex buffer for each brush stroke) + static LLTerrainPaintQueue convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in); +}; + +template +class LLTerrainQueue +{ +public: + LLTerrainQueue() = default; + LLTerrainQueue(LLTerrainQueue& other); + LLTerrainQueue& operator=(LLTerrainQueue& other); + + bool enqueue(std::shared_ptr& t, bool dry_run = false); + size_t size() const; + bool empty() const; + void clear(); + + const std::vector>& get() const { return mList; } + +protected: + bool enqueue(std::vector>& list); + + std::vector> mList; }; // Enqueued paint operations, in texture coordinates. @@ -63,23 +93,27 @@ struct LLTerrainPaint const static U8 RGB = 3; const static U8 RGBA = 4; std::vector mData; + + // Asserts that this paint's start/width fit within the bounds of the + // provided texture dimensions. + void assert_confined_to(const LLTexture& tex) const; + // Confines this paint's start/width so it fits within the bounds of the + // provided texture dimensions. + // Does not allocate mData. + void confine_to(const LLTexture& tex); }; -class LLTerrainPaintQueue +class LLTerrainPaintQueue : public LLTerrainQueue { public: + LLTerrainPaintQueue() = delete; // components determines what type of LLTerrainPaint is allowed. Must be 3 (RGB) or 4 (RGBA) LLTerrainPaintQueue(U8 components); - LLTerrainPaintQueue(const LLTerrainPaintQueue& other); - LLTerrainPaintQueue& operator=(const LLTerrainPaintQueue& other); + LLTerrainPaintQueue(LLTerrainPaintQueue& other); + LLTerrainPaintQueue& operator=(LLTerrainPaintQueue& other); bool enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run = false); - bool enqueue(LLTerrainPaintQueue& paint_queue); - size_t size() const; - bool empty() const; - void clear(); - - const std::vector& get() const { return mList; } + bool enqueue(LLTerrainPaintQueue& queue); U8 getComponents() const { return mComponents; } // Convert mBitDepth for the LLTerrainPaint in the queue at index @@ -92,5 +126,41 @@ public: private: U8 mComponents; - std::vector mList; +}; + +struct LLTerrainBrush +{ + using ptr_t = std::shared_ptr; + + // Width of the brush in region space. The brush is a square texture with + // alpha. + F32 mBrushSize; + // Brush path points in region space, excluding the vertical axis, which + // does not contribute to the paint map. + std::vector mPath; + // Offset of the brush path to actually start drawing at. An offset of 0 + // indicates that a brush stroke has just started (i.e. the user just + // pressed down the mouse button). An offset greater than 0 indicates the + // continuation of a brush stroke. Skipped entries in mPath are not drawn + // directly, but are used for stroke orientation and path interpolation. + // TODO: For the initial implementation, mPathOffset will be 0 and mPath + // will be of length of at most 1, leading to discontinuous paint paths. + // Then, mPathOffset may be 1 or 0, 1 indicating the continuation of a + // stroke with linear interpolation. It is unlikely that we will implement + // anything more sophisticated than that for now. + U8 mPathOffset; + // Indicates if this is the end of the brush stroke. Can occur if the mouse + // button is lifted, or if the mouse temporarily stops while held down. + bool mPathEnd; +}; + +class LLTerrainBrushQueue : public LLTerrainQueue +{ +public: + LLTerrainBrushQueue(); + LLTerrainBrushQueue(LLTerrainBrushQueue& other); + LLTerrainBrushQueue& operator=(LLTerrainBrushQueue& other); + + bool enqueue(LLTerrainBrush::ptr_t& brush, bool dry_run = false); + bool enqueue(LLTerrainBrushQueue& queue); }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c4bb5eaa2e..dd6b6d1ca1 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1461,17 +1461,38 @@ class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t return false; } + LLTerrainBrushQueue& brush_queue = gLocalTerrainMaterials.getBrushQueue(); LLTerrainPaintQueue& paint_request_queue = gLocalTerrainMaterials.getPaintRequestQueue(); + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS() << "No current region for calculating paint operations" << LL_ENDL; + return false; + } + // TODO: Create the brush + // Just a dab for now + LLTerrainBrush::ptr_t brush = std::make_shared(); + brush->mBrushSize = 16.0f; + brush->mPath.emplace_back(17.0f, 17.0f); + brush->mPathOffset = 0; + brush->mPathEnd = true; + brush_queue.enqueue(brush); + LLTerrainPaintQueue brush_as_paint_queue = LLTerrainPaintMap::convertBrushQueueToPaintRGB(*region, *tex, brush_queue); + //paint_send_queue.enqueue(brush_as_paint_queue); // TODO: What was this line for? (it might also be a leftover line from an unfinished edit) + + // TODO: Keep this around for later testing (i.e. when reducing framebuffer size and the offsets that requires) +#if 0 // Enqueue a paint - // Overrides an entire region patch with the material in the last slot + // Modifies a subsection of the region paintmap with the material in + // the last slot. // It is currently the responsibility of the paint queue to convert // incoming bits to the right bit depth for the paintmap (this could // change in the future). LLTerrainPaint::ptr_t paint = std::make_shared(); - const U16 width = U16(tex->getWidth() / 16); - paint->mStartX = width - 1; - paint->mStartY = width - 1; + const U16 width = 33; + paint->mStartX = 1; + paint->mStartY = 1; paint->mWidthX = width; paint->mWidthY = width; constexpr U8 bit_depth = 5; @@ -1488,12 +1509,19 @@ class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t const size_t pixel = (h * paint->mWidthX) + w; // Solid blue color paint->mData[(components*pixel) + components - 2] = max_value; // blue - // Alpha gradient from 0.0 to 1.0 along w - const U8 alpha = U8(F32(max_value) * F32(w+1) / F32(paint->mWidthX)); + //// Alpha grid: 1.0 if odd for either dimension, 0.0 otherwise + //const U8 alpha = U8(F32(max_value) * F32(bool(w % 2) || bool(h % 2))); + //paint->mData[(components*pixel) + components - 1] = alpha; // alpha + // Alpha "frame" + const bool edge = w == 0 || h == 0 || w == (paint->mWidthX - 1) || h == (paint->mWidthY - 1); + const bool near_edge_frill = ((w == 1 || w == (paint->mWidthX - 2)) && (h % 2 == 0)) || + ((h == 1 || h == (paint->mWidthY - 2)) && (w % 2 == 0)); + const U8 alpha = U8(F32(max_value) * F32(edge || near_edge_frill)); paint->mData[(components*pixel) + components - 1] = alpha; // alpha } } paint_request_queue.enqueue(paint); +#endif // Apply the paint queues ad-hoc right here for now. // *TODO: Eventually the paint queue(s) should be applied at a diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 3f1124a8ac..9a5d74adda 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -90,6 +90,10 @@ public: void setPaintType(U32 paint_type) { mPaintType = paint_type; } LLViewerTexture* getPaintMap(); void setPaintMap(LLViewerTexture* paint_map); + // Queue of client-triggered brush operations that need to be converted + // into a form that can be sent to the server. + // TODO: Consider getting rid of mPaintRequestQueue, as it's not really needed (brushes go directly to RGB queue) + LLTerrainBrushQueue& getBrushQueue() { return mBrushQueue; } // Queue of client-triggered paint operations that need to be converted // into a form that can be sent to the server. // Paints in this queue are in RGBA format. @@ -116,6 +120,7 @@ protected: U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE; LLPointer mPaintMap; + LLTerrainBrushQueue mBrushQueue; LLTerrainPaintQueue mPaintRequestQueue{U8(4)}; LLTerrainPaintQueue mPaintMapQueue{U8(3)}; }; -- cgit v1.2.3 From 81cc4fa7d61e838413b912a4ed2d957cc65bcb46 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 14:30:29 -0700 Subject: secondlife/viewer#1883: (WIP/Alpha/WOMM) Fix some compiler and runtime errors --- indra/newview/llterrainpaintmap.cpp | 52 ++++++++++++++++++------------------- indra/newview/llviewercontrol.cpp | 1 + indra/newview/llviewermenu.cpp | 8 ++++-- indra/newview/llviewershadermgr.cpp | 38 +++++++++++++++++---------- 4 files changed, 57 insertions(+), 42 deletions(-) (limited to 'indra') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 6a57605325..d36e4ea657 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -447,7 +447,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // View matrix // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. // Camera is centered in the middle of the framebuffer. - glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + glm::mat4 view(glm::make_mat4((GLfloat*) OGL_TO_CFR_ROTATION)); { LLViewerCamera camera; const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); @@ -456,7 +456,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); GLfloat ogl_matrix[16]; camera.getOpenGLTransform(ogl_matrix); - view *= glh::matrix4f(ogl_matrix); + view *= glm::make_mat4(ogl_matrix); } LLGLDisable stencil(GL_STENCIL_TEST); @@ -471,14 +471,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // First, apply the paint map as the background { - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); - model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); // We care about the whole paintmap, which is already a power of two. @@ -505,14 +505,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // Modelview matrix for the current paint // View matrix is already computed. Just need the model matrix. // Orthographic projection matrix is already updated - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); - model.set_translate(glh::vec3f(paint_in->mStartX, paint_in->mStartY, 0.0f)); + model = glm::scale(model, glm::vec3(paint_in->mWidthX, paint_in->mWidthY, 1.0f)); + model = glm::translate(model, glm::vec3(paint_in->mStartX, paint_in->mStartY, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); // Generate temporary stamp texture from paint contents. // Our stamp image needs to be a power of two. @@ -663,7 +663,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // View matrix // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer. // Camera is centered in the middle of the framebuffer. - glh::matrix4f view((GLfloat *) OGL_TO_CFR_ROTATION); + glm::mat4 view(glm::make_mat4((GLfloat*)OGL_TO_CFR_ROTATION)); { LLViewerCamera camera; const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f); @@ -672,7 +672,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); GLfloat ogl_matrix[16]; camera.getOpenGLTransform(ogl_matrix); - view *= glh::matrix4f(ogl_matrix); + view *= glm::make_mat4(ogl_matrix); } LLGLDisable stencil(GL_STENCIL_TEST); @@ -687,14 +687,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // First, apply the paint map as the background { - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); - model.set_translate(glh::vec3f(0.0f, 0.0f, 0.0f)); + model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f)); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex); // We care about the whole paintmap, which is already a power of two. @@ -748,14 +748,14 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe brush_start_x *= tex.getWidth() / region.getWidth(); brush_start_y *= tex.getHeight() / region.getWidth(); } - glh::matrix4f model; + glm::mat4 model; { - model.set_scale(glh::vec3f(brush_width_x, brush_width_y, 1.0f)); - model.set_translate(glh::vec3f(brush_start_x, brush_start_y, 0.0f)); + model = glm::scale(model, glm::vec3(brush_width_x, brush_width_y, 1.0f)); + model = glm::translate(model, glm::vec3(brush_start_x, brush_start_y, 0.0f)); } - glh::matrix4f modelview = view * model; + glm::mat4 modelview = view * model; gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(glm::value_ptr(modelview)); // Apply the "brush" to the render target { @@ -842,11 +842,11 @@ template bool LLTerrainQueue::enqueue(std::vector>& list) { constexpr bool dry_run = true; - for (T::ptr_t& t : list) + for (auto& t : list) { if (!enqueue(t), dry_run) { return false; } } - for (T::ptr_t& t : list) + for (auto& t : list) { enqueue(t); } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index f8a315d4d8..184c0e7d8b 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -911,6 +911,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged); setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged); { + setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleLocalTerrainChanged); const char* transform_suffixes[] = { "ScaleU", diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index dd6b6d1ca1..b39bf4fdbd 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1430,6 +1430,12 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t return false; } + // This calls gLocalTerrainMaterials.setPaintType + // It also ensures the terrain bake shader is compiled (handleSetShaderChanged), so call this first + // *TODO: Fix compile errors in shader so it can be used for all platforms. Then we can unhide the shader from behind this setting and remove the hook to handleSetShaderChanged. This advanced setting is intended to be used as a local setting for testing terrain, not a feature flag, but it is currently used like a feature flag as a temporary hack. + // *TODO: Ideally we would call setPaintType *after* the paint map is well-defined. The terrain draw pool should be able to handle an undefined paint map in the meantime. + gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true); + U16 dim = (U16)gSavedSettings.getU32("TerrainPaintResolution"); // Ensure a reasonable image size of power two const U32 max_resolution = gSavedSettings.getU32("RenderMaxTextureResolution"); @@ -1439,8 +1445,6 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t LLPointer image_raw = new LLImageRaw(dim,dim,3); LLPointer tex = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); const bool success = LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(*region, *tex); - // This calls gLocalTerrainMaterials.setPaintType - gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true); // If baking the paintmap failed, set the paintmap to nullptr. This // causes LLDrawPoolTerrain to use a blank paintmap instead. if (!success) { tex = nullptr; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 8e7af28d41..a6d397c039 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -3171,22 +3171,32 @@ bool LLViewerShaderMgr::loadShadersInterface() } } - if (success) + if (gSavedSettings.getBOOL("LocalTerrainPaintEnabled")) { - LLGLSLShader* shader = &gTerrainStampProgram; - U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth"); - // LLTerrainPaintMap currently uses an RGB8 texture internally - bit_depth = llclamp(bit_depth, 1, 8); - shader->mName = llformat("Terrain Stamp Shader RGB%o", bit_depth); + if (success) + { + LLGLSLShader* shader = &gTerrainStampProgram; + U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth"); + // LLTerrainPaintMap currently uses an RGB8 texture internally + bit_depth = llclamp(bit_depth, 1, 8); + shader->mName = llformat("Terrain Stamp Shader RGB%o", bit_depth); - shader->mShaderFiles.clear(); - shader->mShaderFiles.push_back(make_pair("interface/terrainStampV.glsl", GL_VERTEX_SHADER)); - shader->mShaderFiles.push_back(make_pair("interface/terrainStampF.glsl", GL_FRAGMENT_SHADER)); - shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - const U32 value_range = (1 << bit_depth) - 1; - shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range)); - success = success && shader->createShader(); - llassert(success); + shader->mShaderFiles.clear(); + shader->mShaderFiles.push_back(make_pair("interface/terrainStampV.glsl", GL_VERTEX_SHADER)); + shader->mShaderFiles.push_back(make_pair("interface/terrainStampF.glsl", GL_FRAGMENT_SHADER)); + shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + const U32 value_range = (1 << bit_depth) - 1; + shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range)); + success = success && shader->createShader(); + //llassert(success); + if (!success) + { + LL_WARNS() << "Failed to create shader '" << shader->mName << "', disabling!" << LL_ENDL; + gSavedSettings.setBOOL("RenderCanUseTerrainBakeShaders", false); + // continue as if this shader never happened + success = true; + } + } } if (success) -- cgit v1.2.3 From 303bf1977b802f5a091bec66b65dfb6c2f29b761 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 14:50:27 -0700 Subject: secondlife/viewer#1883: Fix terrain paintmap bit depth hardcoded in places and increase default bit depth to 8 --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llterrainpaintmap.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index babb8424dc..ebf1968007 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -15367,7 +15367,7 @@ Type U32 Value - 5 + 8 TerrainPaintResolution diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index d36e4ea657..ec40f299a4 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -573,7 +573,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur paint_out->mStartY = paint_in->mStartY; paint_out->mWidthX = paint_in->mWidthX; paint_out->mWidthY = paint_in->mWidthY; - paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later paint_out->mComponents = LLTerrainPaint::RGB; #ifdef SHOW_ASSERT paint_out->assert_confined_to(tex); @@ -602,7 +602,8 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // round-trip which will reduce the bit depth, making the // pre-conversion step not necessary. queue_out.enqueue(paint_out); - queue_out.convertBitDepths(queue_out.size()-1, 5); + LLCachedControl bit_depth(gSavedSettings, "TerrainPaintBitDepth"); + queue_out.convertBitDepths(queue_out.size()-1, bit_depth); } queue_in.clear(); @@ -775,7 +776,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe const F32 dY = brush_start_y - F32(paint_out->mStartY); paint_out->mWidthX = U16(ceil(brush_width_x + dX)); paint_out->mWidthY = U16(ceil(brush_width_y + dY)); - paint_out->mBitDepth = 8; // Will be reduced to 5 bits later + paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later paint_out->mComponents = LLTerrainPaint::RGB; // The brush strokes are expected to sometimes partially venture // outside of the paintmap bounds. @@ -803,7 +804,8 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe // round-trip which will reduce the bit depth, making the // pre-conversion step not necessary. queue_out.enqueue(paint_out); - queue_out.convertBitDepths(queue_out.size()-1, 5); + LLCachedControl bit_depth(gSavedSettings, "TerrainPaintBitDepth"); + queue_out.convertBitDepths(queue_out.size()-1, bit_depth); } queue_in.clear(); -- cgit v1.2.3 From d505eb4fce23e573c5155d1a9ba2857f549ca281 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 7 Oct 2024 15:57:50 -0700 Subject: secondlife/viewer#1883: Fix logic error caught by clang --- indra/newview/llterrainpaintmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index ec40f299a4..09caba8faa 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -846,7 +846,7 @@ bool LLTerrainQueue::enqueue(std::vector>& list) constexpr bool dry_run = true; for (auto& t : list) { - if (!enqueue(t), dry_run) { return false; } + if (!enqueue(t, dry_run)) { return false; } } for (auto& t : list) { -- cgit v1.2.3 From f88401c97a892ea4a6fce13ee15dad1bb976d992 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 11 Oct 2024 09:54:47 -0700 Subject: secondlife/viewer#1883: Review feedback --- indra/newview/llterrainpaintmap.cpp | 18 ++++++------------ indra/newview/llterrainpaintmap.h | 6 +++--- indra/newview/llvlcomposition.h | 2 -- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'indra') diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 09caba8faa..52376e3bf0 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -56,15 +56,15 @@ void check_tex(const LLViewerTexture& tex) llassert(tex.getPrimaryFormat() == GL_RGB); llassert(tex.getGLTexture()); } +#else +#define check_tex(tex) #endif } // namespace // static bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif const LLSurface& surface = region.getLand(); const U32 patch_count = surface.getPatchesPerEdge(); @@ -309,9 +309,7 @@ void LLTerrainPaintMap::applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQ { if (queue.empty()) { return; } -#ifdef SHOW_ASSERT check_tex(tex); -#endif gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true); @@ -362,7 +360,7 @@ namespace // plane. // *NOTE: Because we know the vertex XY coordinates go from 0 to 1 // pre-transform, UVs can be calculated from the vertices -LLVertexBuffer& get_paint_triangle_buffer() +LLVertexBuffer* get_paint_triangle_buffer() { static LLPointer buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); static bool initialized = false; @@ -395,7 +393,7 @@ LLVertexBuffer& get_paint_triangle_buffer() *(indices++) = 2; buf->unmapBuffer(); } - return *buf; + return buf.get(); } }; @@ -403,9 +401,7 @@ LLVertexBuffer& get_paint_triangle_buffer() // static LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif llassert(queue_in.getComponents() == LLTerrainPaint::RGBA); // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead @@ -429,7 +425,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; - LLVertexBuffer* buf = &get_paint_triangle_buffer(); + LLVertexBuffer* buf = get_paint_triangle_buffer(); // Update projection matrix and viewport // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. @@ -621,9 +617,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTextur // static LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in) { -#ifdef SHOW_ASSERT check_tex(tex); -#endif // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead // TODO: even if it means performing extra render operations to apply the brushes, in rare cases where the paints can't all fit within an area that can be represented by the buffer @@ -646,7 +640,7 @@ LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewe const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f; const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f; - LLVertexBuffer* buf = &get_paint_triangle_buffer(); + LLVertexBuffer* buf = get_paint_triangle_buffer(); // Update projection matrix and viewport // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later. diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h index cffdad80a2..6c321dc9c6 100644 --- a/indra/newview/llterrainpaintmap.h +++ b/indra/newview/llterrainpaintmap.h @@ -26,7 +26,7 @@ #pragma once -#include "llviewerprecompiledheaders.h" +#include class LLTexture; class LLViewerRegion; @@ -90,8 +90,8 @@ struct LLTerrainPaint U16 mWidthY; U8 mBitDepth; U8 mComponents; - const static U8 RGB = 3; - const static U8 RGBA = 4; + static constexpr U8 RGB = 3; + static constexpr U8 RGBA = 4; std::vector mData; // Asserts that this paint's start/width fit within the bounds of the diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 9a5d74adda..21fd484375 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -27,8 +27,6 @@ #ifndef LL_LLVLCOMPOSITION_H #define LL_LLVLCOMPOSITION_H -#include - #include "llviewerlayer.h" #include "llviewershadermgr.h" #include "llviewertexture.h" -- cgit v1.2.3 From 18797f911e6510044a444104531a28b1f1aa5f2d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 10 Oct 2024 23:42:05 +0300 Subject: viewer#2172 AM/PM selector --- indra/newview/app_settings/settings.xml | 4 +- indra/newview/llchathistory.cpp | 1 + indra/newview/llconversationlog.cpp | 20 ++++++--- indra/newview/llfloaterimsessiontab.cpp | 15 ++++++- indra/newview/llfloaterpreference.cpp | 11 +++++ indra/newview/llfloaterpreference.h | 2 + indra/newview/lllogchat.cpp | 48 +++++++++++----------- indra/newview/llpanelenvironment.cpp | 23 ++++++++--- indra/newview/llpanelteleporthistory.cpp | 15 ++++++- indra/newview/llsidepaneliteminfo.cpp | 3 +- indra/newview/llworldmap.cpp | 18 ++++++-- .../skins/default/xui/da/sidepanel_item_info.xml | 5 ++- .../skins/default/xui/de/sidepanel_item_info.xml | 3 ++ .../xui/en/floater_inventory_item_properties.xml | 6 ++- .../newview/skins/default/xui/en/notifications.xml | 2 +- .../default/xui/en/panel_preferences_general.xml | 31 ++++++++++++++ 16 files changed, 160 insertions(+), 47 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index babb8424dc..1d54b6bb7e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13066,9 +13066,9 @@ Use24HourClock Comment - 12 vs 24. At the moment only for region restart schedule floater + 12 vs 24. At the moment coverage is partial Persist - 0 + 1 Type Boolean Value diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 3e02820feb..bb5ee558ca 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -426,6 +426,7 @@ public: time_t current_time = time_corrected(); time_t message_time = (time_t)(current_time - LLFrameTimer::getElapsedSeconds() + mTime); + // Report abuse shouldn't use AM/PM, use 24-hour time time_string = "[" + LLTrans::getString("TimeMonth") + "]/[" + LLTrans::getString("TimeDay") + "]/[" + LLTrans::getString("TimeYear") + "] [" diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index ed563cbec9..ed16a4b135 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -118,11 +118,21 @@ const std::string LLConversation::createTimestamp(const U64Seconds& utc_time) LLSD substitution; substitution["datetime"] = (S32)utc_time.value(); - timeStr = "["+LLTrans::getString ("TimeMonth")+"]/[" - +LLTrans::getString ("TimeDay")+"]/[" - +LLTrans::getString ("TimeYear")+"] [" - +LLTrans::getString ("TimeHour")+"]:[" - +LLTrans::getString ("TimeMin")+"]"; + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + timeStr = "[" + LLTrans::getString("TimeMonth") + "]/[" + + LLTrans::getString("TimeDay") + "]/[" + + LLTrans::getString("TimeYear") + "] ["; + if (use_24h) + { + timeStr += LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "]"; + } + else + { + timeStr += LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "]"; + } LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 6a96dc0c69..0855a628fb 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -629,8 +629,19 @@ void LLFloaterIMSessionTab::deleteAllChildren() std::string LLFloaterIMSessionTab::appendTime() { - std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:" - "[" + LLTrans::getString("TimeMin") + "]"; + std::string timeStr; + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + timeStr = "[" + LLTrans::getString("TimeHour") + "]:" + "[" + LLTrans::getString("TimeMin") + "]"; + } + else + { + timeStr = "[" + LLTrans::getString("TimeHour12") + "]:" + "[" + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "]"; + } LLSD substitution; substitution["datetime"] = (S32)time_corrected(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 0c96c93d31..d7ac8f0552 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -473,6 +473,8 @@ bool LLFloaterPreference::postBuild() getChild("log_path_string")->setEnabled(false); // make it read-only but selectable getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + mTimeFormatCombobox = getChild("time_format_combobox"); + mTimeFormatCombobox->setCommitCallback(boost::bind(&LLFloaterPreference::onTimeFormatChange, this)); getChild("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); getChild("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions")); @@ -1108,6 +1110,13 @@ void LLFloaterPreference::onLanguageChange() } } +void LLFloaterPreference::onTimeFormatChange() +{ + std::string val = mTimeFormatCombobox->getValue(); + gSavedSettings.setBOOL("Use24HourClock", val == "1"); + onLanguageChange(); +} + void LLFloaterPreference::onNotificationsChange(const std::string& OptionName) { mNotificationOptions[OptionName] = getChild(OptionName)->getSelectedItemLabel(); @@ -1331,6 +1340,8 @@ void LLFloaterPreference::refresh() advanced->refresh(); } updateClickActionViews(); + + mTimeFormatCombobox->selectByValue(gSavedSettings.getBOOL("Use24HourClock") ? "1" : "0"); } void LLFloaterPreference::onCommitWindowedMode() diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index e06e758e3a..d5bd43e0ab 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -124,6 +124,7 @@ protected: void onClickClearCache(); // Clear viewer texture cache, file cache on next startup void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above void onLanguageChange(); + void onTimeFormatChange(); void onNotificationsChange(const std::string& OptionName); void onNameTagOpacityChange(const LLSD& newvalue); @@ -242,6 +243,7 @@ private: LLButton* mDeleteTranscriptsBtn = nullptr; LLButton* mEnablePopupBtn = nullptr; LLButton* mDisablePopupBtn = nullptr; + LLComboBox* mTimeFormatCombobox = nullptr; std::unique_ptr< ll::prefs::SearchData > mSearchData; bool mSearchDataDirty; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index bf49f33049..51f30dd86b 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -78,8 +78,8 @@ const static std::string MULTI_LINE_PREFIX(" "); * * Note: "You" was used as an avatar names in viewers of previous versions */ -const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$"); -const static boost::regex TIMESTAMP("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]|\\[\\d{1,2}:\\d{2}\\]).*"); +const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\s[AaPp][Mm]\\]\\s+|\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\s[AaPp][Mm]\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$"); +const static boost::regex TIMESTAMP("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}(\\s[AaPp][Mm])?\\]|\\[\\d{1,2}:\\d{2}(\\s[AaPp][Mm])?\\]).*"); /** * Regular expression suitable to match names like @@ -150,6 +150,10 @@ public: void checkAndCutOffDate(std::string& time_str) { + if (time_str.size() < 10) // not enough space for a date + { + return; + } // Cuts off the "%Y/%m/%d" from string for todays timestamps. // Assume that passed string has at least "%H:%M" time format. date log_date(not_a_date_time); @@ -166,20 +170,12 @@ public: if ( days_alive == zero_days ) { - // Yep, today's so strip "%Y/%m/%d" info - ptime stripped_time(not_a_date_time); - - mTimeStream.str(LLStringUtil::null); - mTimeStream << time_str; - mTimeStream >> stripped_time; - mTimeStream.clear(); - - time_str.clear(); - - mTimeStream.str(LLStringUtil::null); - mTimeStream << stripped_time; - mTimeStream >> time_str; - mTimeStream.clear(); + size_t pos = time_str.find_first_of(' '); + if (pos != std::string::npos) + { + time_str.erase(0, pos + 1); + LLStringUtil::trim(time_str); + } } LL_DEBUGS("LLChatLogParser") @@ -308,16 +304,22 @@ std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate) std::string timeStr; if (withdate) { - timeStr = "[" + LLTrans::getString ("TimeYear") + "]/[" - + LLTrans::getString ("TimeMonth") + "]/[" - + LLTrans::getString ("TimeDay") + "] [" - + LLTrans::getString ("TimeHour") + "]:[" - + LLTrans::getString ("TimeMin") + "]"; + timeStr = "[" + LLTrans::getString("TimeYear") + "]/[" + + LLTrans::getString("TimeMonth") + "]/[" + + LLTrans::getString("TimeDay") + "] "; + } + + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + timeStr += "[" + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "]"; } else { - timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" - + LLTrans::getString ("TimeMin")+"]"; + timeStr += "[" + LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "]"; } LLSD substitution; diff --git a/indra/newview/llpanelenvironment.cpp b/indra/newview/llpanelenvironment.cpp index be61c44b7c..d3df88b65e 100644 --- a/indra/newview/llpanelenvironment.cpp +++ b/indra/newview/llpanelenvironment.cpp @@ -48,6 +48,7 @@ #include "llappviewer.h" #include "llcallbacklist.h" +#include "llviewercontrol.h" #include "llviewerparcelmgr.h" #include "llinventorymodel.h" @@ -939,19 +940,29 @@ void LLPanelEnvironmentInfo::udpateApparentTimeOfDay() S32Hours hourofday(secondofday); S32Seconds secondofhour(secondofday - hourofday); S32Minutes minutesofhour(secondofhour); + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); bool am_pm(hourofday.value() >= 12); - if (hourofday.value() < 1) - hourofday = S32Hours(12); - if (hourofday.value() > 12) - hourofday -= S32Hours(12); + if (!use_24h) + { + if (hourofday.value() < 1) + hourofday = S32Hours(12); + if (hourofday.value() > 12) + hourofday -= S32Hours(12); + } std::string lblminute(((minutesofhour.value() < 10) ? "0" : "") + LLSD(minutesofhour.value()).asString()); - mLabelApparentTime->setTextArg("[HH]", LLSD(hourofday.value()).asString()); mLabelApparentTime->setTextArg("[MM]", lblminute); - mLabelApparentTime->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM")); + if (use_24h) + { + mLabelApparentTime->setTextArg("[AP]", std::string()); + } + else + { + mLabelApparentTime->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM")); + } mLabelApparentTime->setTextArg("[PRC]", LLSD((S32)(100 * perc)).asString()); } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index ebfdafdfe2..8097e0ac0b 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -42,6 +42,7 @@ #include "llnotificationsutil.h" #include "lltextbox.h" #include "lltoggleablemenu.h" +#include "llviewercontrol.h" #include "llviewermenu.h" #include "lllandmarkactions.h" #include "llclipboard.h" @@ -215,8 +216,18 @@ std::string LLTeleportHistoryFlatItem::getTimestamp() // Only show timestamp for today and yesterday if(time_diff < seconds_today + seconds_in_day) { - timestamp = "[" + LLTrans::getString("TimeHour12")+"]:[" - + LLTrans::getString("TimeMin")+"] ["+ LLTrans::getString("TimeAMPM")+"]"; + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + timestamp = "[" + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "]"; + } + else + { + timestamp = "[" + LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + LLTrans::getString("TimeAMPM") + "]"; + } + LLSD substitution; substitution["datetime"] = (S32) date.secondsSinceEpoch(); LLStringUtil::format(timestamp, substitution); diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index fccf745a74..68c5f3fb56 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -483,7 +483,8 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) } else { - std::string timeStr = getString("acquiredDate"); + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + std::string timeStr = use_24h ? getString("acquiredDate24") : getString("acquiredDateAMPM"); LLSD substitution; substitution["datetime"] = (S32) time_utc; LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 7962c28e6d..5951d6a93a 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -32,6 +32,7 @@ #include "message.h" #include "lltracker.h" #include "lluistring.h" +#include "llviewercontrol.h" #include "llviewertexturelist.h" #include "lltrans.h" #include "llgltexture.h" @@ -492,9 +493,20 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& case MAP_ITEM_MATURE_EVENT: case MAP_ITEM_ADULT_EVENT: { - std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:[" - +LLTrans::getString ("TimeMin")+"] [" - +LLTrans::getString ("TimeAMPM")+"]"; + std::string timeStr; + + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "]"; + } + else + { + std::string timeStr = "[" + LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "]"; + } LLSD substitution; substitution["datetime"] = (S32) extra; LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml index d52845160b..3e4f6946ca 100644 --- a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml @@ -12,9 +12,12 @@ Ejer kan: - + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] + (Beholdning) diff --git a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml index 168bb14248..6f0028d282 100644 --- a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml @@ -21,6 +21,9 @@ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] + (Inventar) 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 index 6c3214a76d..e6fa3c2172 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -25,9 +25,13 @@ Owner can: + name="acquiredDate24"> [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] + -Changing language will take effect after you restart [APP_NAME]. +Changing language or time format will take effect after you restart [APP_NAME]. + + Time Format: + + + + + Date: Fri, 11 Oct 2024 03:56:52 +0300 Subject: viewer#2172 Fix Unit Test --- indra/newview/tests/llworldmap_test.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra') diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index d5bf189d82..99c98f63ed 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -28,6 +28,7 @@ // Dependencies #include "linden_common.h" #include "llapr.h" +#include "llcontrol.h" // LLControlGroup #include "llsingleton.h" #include "lltrans.h" #include "lluistring.h" @@ -71,6 +72,8 @@ void LLUIString::updateResult() const { } void LLUIString::setArg(const std::string& , const std::string& ) { } void LLUIString::assign(const std::string& ) { } +LLControlGroup gSavedSettings("Global"); // saved at end of session + // End Stubbing // ------------------------------------------------------------------------------------------- @@ -131,6 +134,7 @@ namespace tut // Constructor and destructor of the test wrapper worldmap_test() { + gSavedSettings.declareBOOL("Use24HourClock", true, "", LLControlVariable::PERSIST_NO); mWorld = LLWorldMap::getInstance(); } ~worldmap_test() -- cgit v1.2.3 From bed3b57c52574ec593293c7397dd0da18e801fb4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Oct 2024 18:50:14 +0300 Subject: viewer#2172 AM/PM selector #2 --- indra/newview/llfloaterinspect.cpp | 3 ++- indra/newview/llfloaterland.cpp | 3 ++- indra/newview/llnotificationlistitem.cpp | 21 +++++++++++++++++---- indra/newview/llpanellandmarkinfo.cpp | 4 +++- indra/newview/llsidepaneliteminfo.cpp | 2 +- indra/newview/lltoastgroupnotifypanel.cpp | 19 +++++++++++++++---- .../skins/default/xui/da/sidepanel_item_info.xml | 2 +- .../skins/default/xui/de/sidepanel_item_info.xml | 2 +- .../skins/default/xui/en/floater_about_land.xml | 3 +++ .../skins/default/xui/en/floater_inspect.xml | 4 ++++ .../xui/en/floater_inventory_item_properties.xml | 2 +- .../skins/default/xui/en/panel_landmark_info.xml | 4 ++++ .../skins/default/xui/en/panel_place_profile.xml | 4 ++++ .../skins/default/xui/en/sidepanel_item_info.xml | 4 ++++ 14 files changed, 62 insertions(+), 15 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 0f1eb0cef0..5dea46843c 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -220,7 +220,8 @@ void LLFloaterInspect::refresh() } time_t timestamp = (time_t) (obj->mCreationDate/1000000); - std::string timeStr = getString("timeStamp"); + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + std::string timeStr = use_24h ? getString("timeStamp") : getString("timeStampAMPM"); LLSD substitution; substitution["datetime"] = (S32) timestamp; LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 52a3e78d04..5c5219bcdd 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -733,7 +733,8 @@ void LLPanelLandGeneral::refresh() // Display claim date time_t claim_date = parcel->getClaimDate(); - std::string claim_date_str = getString("time_stamp_template"); + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + std::string claim_date_str = use_24h ? getString("time_stamp_template") : getString("time_stamp_template_ampm"); LLSD substitution; substitution["datetime"] = (S32) claim_date; LLStringUtil::format (claim_date_str, substitution); diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index 5b8b28ebe6..9a33bcb1b9 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -38,6 +38,7 @@ #include "lluicolortable.h" #include "message.h" #include "llnotificationsutil.h" +#include "llviewercontrol.h" #include LLNotificationListItem::LLNotificationListItem(const Params& p) : LLPanel(p), @@ -133,10 +134,22 @@ std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_sta default: timeStr = "[" + LLTrans::getString("TimeMonth") + "]/[" +LLTrans::getString("TimeDay")+"]/[" - +LLTrans::getString("TimeYear")+"] [" - +LLTrans::getString("TimeHour")+"]:[" - +LLTrans::getString("TimeMin")+"] [" - +LLTrans::getString("TimeTimezone")+"]"; + +LLTrans::getString("TimeYear")+"] ["; + + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + timeStr += LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeTimezone") + "]"; + } + else + { + timeStr += LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "] [" + + LLTrans::getString("TimeTimezone") + "]"; + } break; } LLSD substitution; diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 41373cd7f5..7596c0eba8 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -41,6 +41,7 @@ #include "lllandmarkactions.h" #include "llparcel.h" #include "llslurl.h" +#include "llviewercontrol.h" #include "llviewerinventory.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -326,7 +327,8 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem) } else { - std::string timeStr = getString("acquired_date"); + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + std::string timeStr = use_24h ? getString("acquired_date") : getString("acquired_date_ampm"); LLSD substitution; substitution["datetime"] = (S32) time_utc; LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 68c5f3fb56..385e4314a9 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -484,7 +484,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) else { static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); - std::string timeStr = use_24h ? getString("acquiredDate24") : getString("acquiredDateAMPM"); + std::string timeStr = use_24h ? getString("acquiredDate") : getString("acquiredDateAMPM"); LLSD substitution; substitution["datetime"] = (S32) time_utc; LLStringUtil::format (timeStr, substitution); diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 3c3440d41a..95653dc19b 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -87,10 +87,21 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi std::string timeStr = "[" + LLTrans::getString("TimeWeek") + "], [" + LLTrans::getString("TimeMonth") + "]/[" + LLTrans::getString("TimeDay") + "]/[" - + LLTrans::getString("TimeYear") + "] [" - + LLTrans::getString("TimeHour") + "]:[" - + LLTrans::getString("TimeMin") + "] [" - + LLTrans::getString("TimeTimezone") + "]"; + + LLTrans::getString("TimeYear") + "] ["; + static bool use_24h = gSavedSettings.getBOOL("Use24HourClock"); + if (use_24h) + { + timeStr += LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeTimezone") + "]"; + } + else + { + timeStr += LLTrans::getString("TimeHour12") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeAMPM") + "] [" + + LLTrans::getString("TimeTimezone") + "]"; + } const LLDate timeStamp = notification->getDate(); LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate(); diff --git a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml index 3e4f6946ca..6a2acfedf7 100644 --- a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml @@ -12,7 +12,7 @@ Ejer kan: - + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] diff --git a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml index 6f0028d282..d5ff203e89 100644 --- a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml @@ -21,7 +21,7 @@ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] - + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 508aba6ae1..c5b42b6dae 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -125,6 +125,9 @@ name="no_selection_text"> No parcel selected. + + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] diff --git a/indra/newview/skins/default/xui/en/floater_inspect.xml b/indra/newview/skins/default/xui/en/floater_inspect.xml index 9403d58441..a083683c23 100644 --- a/indra/newview/skins/default/xui/en/floater_inspect.xml +++ b/indra/newview/skins/default/xui/en/floater_inspect.xml @@ -11,6 +11,10 @@ save_rect="true" title="INSPECT OBJECTS" width="400"> + + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] 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 index e6fa3c2172..cc7942abea 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -25,7 +25,7 @@ Owner can: + name="acquiredDate"> [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] Information about this location is unavailable due to access restrictions. Please check your permissions with the parcel owner. + + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml index 8f5292c531..bb877080b1 100644 --- a/indra/newview/skins/default/xui/en/panel_place_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml @@ -88,6 +88,10 @@ name="server_forbidden_text"> Information about this location is unavailable due to access restrictions. Please check your permissions with the parcel owner. + + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml index 1cb3eca2eb..40a88d4121 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml @@ -31,6 +31,10 @@ name="owner_can"> Owner can: + + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt] + [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt] -- cgit v1.2.3 From a6a3a1771b81e551e2d7fcd68e9df0cec092b27b Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 11 Oct 2024 06:35:10 -0700 Subject: Rework GHA matrix config to fix linux build --- indra/cmake/UI.cmake | 1 - indra/newview/rlvhelper.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index 23bd8018dd..595f394af4 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -6,7 +6,6 @@ include(GLIB) add_library( ll::uilibraries INTERFACE IMPORTED ) if (LINUX) - use_prebuilt_binary(fltk) target_compile_definitions(ll::uilibraries INTERFACE LL_X11=1 ) if( USE_CONAN ) diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 7cb1473c8c..1dac297bf1 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -95,12 +95,12 @@ void BehaviourDictionary::addEntry(const BehaviourInfo* entry_p) } // Sanity check for duplicate entries -#ifndef LL_RELEASE_FOR_DOWNLOAD +#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG std::for_each(mBhvrInfoList.begin(), mBhvrInfoList.end(), [&entry_p](const BehaviourInfo* bhvr_info_p) { RLV_ASSERT_DBG((bhvr_info_p->getBehaviour() != entry_p->getBehaviour()) || ((bhvr_info_p->getParamTypeMask() & entry_p->getParamTypeMask()) == 0)); }); -#endif // LL_RELEASE_FOR_DOWNLOAD +#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG mBhvrInfoList.push_back(entry_p); } -- cgit v1.2.3 From 90ff4b416d12814035492e519c08c36d925bbab5 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 11 Oct 2024 21:12:10 +0200 Subject: #2408 The long covenant with emojis (no double requesting) --- indra/newview/llfloaterregioninfo.cpp | 177 +++++++++++++++------------------- indra/newview/llfloaterregioninfo.h | 32 +++--- indra/newview/llviewerregion.cpp | 4 +- 3 files changed, 98 insertions(+), 115 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 165fb5ef88..df4acfac5e 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -148,40 +148,6 @@ public: static LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ); }; - -/* -void unpack_request_params( - LLMessageSystem* msg, - LLDispatcher::sparam_t& strings, - LLDispatcher::iparam_t& integers) -{ - char str_buf[MAX_STRING]; - S32 str_count = msg->getNumberOfBlocksFast(_PREHASH_StringData); - S32 i; - for (i = 0; i < str_count; ++i) - { - // we treat the SParam as binary data (since it might be an - // LLUUID in compressed form which may have embedded \0's,) - str_buf[0] = '\0'; - S32 data_size = msg->getSizeFast(_PREHASH_StringData, i, _PREHASH_SParam); - if (data_size >= 0) - { - msg->getBinaryDataFast(_PREHASH_StringData, _PREHASH_SParam, - str_buf, data_size, i, MAX_STRING - 1); - strings.push_back(std::string(str_buf, data_size)); - } - } - - U32 int_buf; - S32 int_count = msg->getNumberOfBlocksFast(_PREHASH_IntegerData); - for (i = 0; i < int_count; ++i) - { - msg->getU32("IntegerData", "IParam", int_buf, i); - integers.push_back(int_buf); - } -} -*/ - class LLPanelRegionEnvironment : public LLPanelEnvironmentInfo { public: @@ -326,8 +292,8 @@ void LLFloaterRegionInfo::onOpen(const LLSD& key) disableTabCtrls(); return; } - refreshFromRegion(gAgent.getRegion()); - requestRegionInfo(); + refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::BeforeRequestRegionInfo); + requestRegionInfo(true); if (!mGodLevelChangeSlot.connected()) { @@ -347,12 +313,14 @@ void LLFloaterRegionInfo::onRegionChanged() { if (getVisible()) //otherwise onOpen will do request { - requestRegionInfo(); + requestRegionInfo(false); } } -void LLFloaterRegionInfo::requestRegionInfo() +void LLFloaterRegionInfo::requestRegionInfo(bool is_opening) { + mIsRegionInfoRequestedFromOpening = is_opening; + LLTabContainer* tab = findChild("region_panels"); if (tab) { @@ -523,8 +491,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->getChild("agent_limit_spin")->setMaxValue((F32)hard_agent_limit); - LLPanelRegionGeneralInfo* panel_general = LLFloaterRegionInfo::getPanelGeneral(); - if (panel) + if (LLPanelRegionGeneralInfo* panel_general = LLFloaterRegionInfo::getPanelGeneral()) { panel_general->setObjBonusFactor(object_bonus_factor); } @@ -561,21 +528,25 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) { // Note: region info also causes LLRegionInfoModel::instance().update(msg); -> requestRegion(); -> changed message // we need to know env version here and in update(msg) to know when to request and when not to, when to filter 'changed' - floater->refreshFromRegion(gAgent.getRegion()); + ERefreshFromRegionPhase phase = floater->mIsRegionInfoRequestedFromOpening ? + ERefreshFromRegionPhase::AfterRequestRegionInfo : + ERefreshFromRegionPhase::NotFromFloaterOpening; + floater->refreshFromRegion(gAgent.getRegion(), phase); } // else will rerequest on onOpen either way } // static -void LLFloaterRegionInfo::sRefreshFromRegion(LLViewerRegion* region) +void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) { - if (region != gAgent.getRegion()) { return; } - - LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); - if (!floater) { return; } + if (region != gAgent.getRegion()) + return; - if (floater->getVisible() && region == gAgent.getRegion()) + if (LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info")) { - floater->refreshFromRegion(region); + if (floater->getVisible() && region == gAgent.getRegion()) + { + floater->refreshFromRegion(region, ERefreshFromRegionPhase::NotFromFloaterOpening); + } } } @@ -682,7 +653,7 @@ void LLFloaterRegionInfo::onTabSelected(const LLSD& param) active_panel->onOpen(LLSD()); } -void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) +void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { if (!region) { @@ -692,7 +663,7 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) // call refresh from region on all panels for (const auto& infoPanel : mInfoPanels) { - infoPanel->refreshFromRegion(region); + infoPanel->refreshFromRegion(region, phase); } mEnvironmentPanel->refreshFromRegion(region); } @@ -725,7 +696,7 @@ void LLFloaterRegionInfo::onGodLevelChange(U8 god_level) LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); if (floater && floater->getVisible()) { - refreshFromRegion(gAgent.getRegion()); + refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::NotFromFloaterOpening); } } @@ -795,7 +766,7 @@ void LLPanelRegionInfo::updateChild(LLUICtrl* child_ctr) } // virtual -bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region) +bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { if (region) mHost = region->getHost(); return true; @@ -823,12 +794,10 @@ void LLPanelRegionInfo::sendEstateOwnerMessage( } else { - strings_t::const_iterator it = strings.begin(); - strings_t::const_iterator end = strings.end(); - for(; it != end; ++it) + for (const std::string& string : strings) { msg->nextBlock("ParamList"); - msg->addString("Parameter", *it); + msg->addString("Parameter", string); } } msg->sendReliable(mHost); @@ -887,7 +856,7 @@ void LLPanelRegionInfo::onClickManageRestartSchedule() ///////////////////////////////////////////////////////////////////////////// // LLPanelRegionGeneralInfo // -bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) +bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); setCtrlsEnabled(allow_modify); @@ -904,7 +873,7 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) // Data gets filled in by processRegionInfo - return LLPanelRegionInfo::refreshFromRegion(region); + return LLPanelRegionInfo::refreshFromRegion(region, phase); } bool LLPanelRegionGeneralInfo::postBuild() @@ -1173,7 +1142,7 @@ bool LLPanelRegionDebugInfo::postBuild() } // virtual -bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) +bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); setCtrlsEnabled(allow_modify); @@ -1191,7 +1160,7 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) getChildView("cancel_restart_btn")->setEnabled(allow_modify); getChildView("region_debug_console_btn")->setEnabled(allow_modify); - return LLPanelRegionInfo::refreshFromRegion(region); + return LLPanelRegionInfo::refreshFromRegion(region, phase); } // virtual @@ -1233,7 +1202,7 @@ void LLPanelRegionDebugInfo::callbackAvatarID(const uuid_vec_t& ids, const std:: if (ids.empty() || names.empty()) return; mTargetAvatar = ids[0]; getChild("target_avatar_name")->setValue(LLSD(names[0].getCompleteName())); - refreshFromRegion( gAgent.getRegion() ); + refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::NotFromFloaterOpening); } // static @@ -1675,7 +1644,7 @@ void LLPanelRegionTerrainInfo::updateForMaterialType() } // virtual -bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) +bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { bool owner_or_god = gAgent.isGodlike() || (region && (region->getOwner() == gAgent.getID())); @@ -1819,7 +1788,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) getChildView("upload_raw_btn")->setEnabled(owner_or_god); getChildView("bake_terrain_btn")->setEnabled(owner_or_god); - return LLPanelRegionInfo::refreshFromRegion(region); + return LLPanelRegionInfo::refreshFromRegion(region, phase); } @@ -2289,25 +2258,27 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region) refresh(); } -bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region) +bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { updateControls(region); // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); - - // We want estate info. To make sure it works across region - // boundaries and multiple packets, we add a serial number to the - // integers and track against that on update. - strings_t strings; - //integers_t integers; - //LLFloaterRegionInfo::incrementSerial(); - LLFloaterRegionInfo::nextInvoice(); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); + bool rv = LLPanelRegionInfo::refreshFromRegion(region, phase); + if (phase != ERefreshFromRegionPhase::BeforeRequestRegionInfo) + { + // We want estate info. To make sure it works across region + // boundaries and multiple packets, we add a serial number to the + // integers and track against that on update. + strings_t strings; + //integers_t integers; + //LLFloaterRegionInfo::incrementSerial(); + LLFloaterRegionInfo::nextInvoice(); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); - sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); + } refresh(); @@ -2528,7 +2499,7 @@ LLPanelEstateCovenant::LLPanelEstateCovenant() } // virtual -bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) +bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { LLTextBox* region_name = getChild("region_name_text"); if (region_name) @@ -2574,13 +2545,17 @@ bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) getChild("reset_covenant")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate())); // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("EstateCovenantRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->sendReliable(region->getHost()); + bool rv = LLPanelRegionInfo::refreshFromRegion(region, phase); + + if (phase != ERefreshFromRegionPhase::AfterRequestRegionInfo) + { + gMessageSystem->newMessage("EstateCovenantRequest"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->sendReliable(region->getHost()); + } + return rv; } @@ -3128,7 +3103,7 @@ std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* regi return region->getCapability(cap); } -bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region) +bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); @@ -3151,10 +3126,13 @@ bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region) mTrusted->loading(); mTrusted->setReadonly(!allow_modify); - LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), - boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle(), _1)); + if (phase != ERefreshFromRegionPhase::AfterRequestRegionInfo) + { + LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), + boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle(), _1)); + } - return LLPanelRegionInfo::refreshFromRegion(region); + return LLPanelRegionInfo::refreshFromRegion(region, phase); } LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel) @@ -4181,35 +4159,32 @@ void LLPanelEstateAccess::copyListToClipboard(std::string list_name) { LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); if (!panel) return; - LLNameListCtrl* name_list = panel->getChild(list_name); - if (!name_list) return; + LLNameListCtrl* name_list = panel->getChild(list_name); std::vector list_vector = name_list->getAllData(); - if (list_vector.size() == 0) return; + if (list_vector.empty()) + return; LLSD::String list_to_copy; - for (std::vector::const_iterator iter = list_vector.begin(); - iter != list_vector.end(); - iter++) + for (LLScrollListItem* item : list_vector) { - LLScrollListItem *item = (*iter); if (item) { + if (!list_to_copy.empty()) + { + list_to_copy += "\n"; + } list_to_copy += item->getColumn(0)->getValue().asString(); } - if (std::next(iter) != list_vector.end()) - { - list_to_copy += "\n"; - } } LLClipboard::instance().copyToClipboard(utf8str_to_wstring(list_to_copy), 0, static_cast(list_to_copy.length())); } -bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region) +bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) { updateLists(); - return LLPanelRegionInfo::refreshFromRegion(region); + return LLPanelRegionInfo::refreshFromRegion(region, phase); } //========================================================================= diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 65c1291728..119f7c98f3 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -71,6 +71,13 @@ class LLPanelRegionEnvironment; class LLEventTimer; +enum class ERefreshFromRegionPhase +{ + NotFromFloaterOpening, + BeforeRequestRegionInfo, + AfterRequestRegionInfo +}; + class LLFloaterRegionInfo : public LLFloater { friend class LLFloaterReg; @@ -85,7 +92,7 @@ public: // get and process region info if necessary. static void processRegionInfo(LLMessageSystem* msg); - static void sRefreshFromRegion(LLViewerRegion* region); + static void refreshFromRegion(LLViewerRegion* region); static const LLUUID& getLastInvoice() { return sRequestInvoice; } static void nextInvoice() { sRequestInvoice.generate(); } @@ -104,7 +111,7 @@ public: void refresh() override; void onRegionChanged(); - void requestRegionInfo(); + void requestRegionInfo(bool is_opening); void enableTopButtons(); void disableTopButtons(); @@ -116,7 +123,7 @@ private: protected: void onTabSelected(const LLSD& param); void disableTabCtrls(); - void refreshFromRegion(LLViewerRegion* region); + void refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase); void onGodLevelChange(U8 god_level); // member data @@ -124,6 +131,7 @@ protected: typedef std::vector info_panels_t; info_panels_t mInfoPanels; LLPanelRegionEnvironment *mEnvironmentPanel; + bool mIsRegionInfoRequestedFromOpening { false }; //static S32 sRequestSerial; // serial # of last EstateOwnerRequest static LLUUID sRequestInvoice; @@ -144,7 +152,7 @@ public: void onChangeAnything(); static void onChangeText(LLLineEditor* caller, void* user_data); - virtual bool refreshFromRegion(LLViewerRegion* region); + virtual bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase); virtual bool estateUpdate(LLMessageSystem* msg) { return true; } bool postBuild() override; @@ -190,7 +198,7 @@ public: : LLPanelRegionInfo() {} ~LLPanelRegionGeneralInfo() {} - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; bool postBuild() override; @@ -222,7 +230,7 @@ public: bool postBuild() override; - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; protected: bool sendUpdate() override; @@ -254,8 +262,8 @@ public: bool postBuild() override; - bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator - void setEnvControls(bool available); // Whether environment settings are available for this region + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; // refresh local settings from region update from simulator + void setEnvControls(bool available); // Whether environment settings are available for this region bool validateTextureSizes(); bool validateMaterials(); @@ -327,7 +335,7 @@ public: static void updateEstateName(const std::string& name); static void updateEstateOwnerName(const std::string& name); - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; bool estateUpdate(LLMessageSystem* msg) override; bool postBuild() override; @@ -364,7 +372,7 @@ public: bool postBuild() override; void updateChild(LLUICtrl* child_ctrl) override; - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; bool estateUpdate(LLMessageSystem* msg) override; // LLView overrides @@ -430,7 +438,7 @@ public: static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id); static void infoCallback(LLHandle handle, const LLSD& content); - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; void sendPurchaseRequest()const; void processResponse( const LLSD& content ); @@ -470,7 +478,7 @@ public: void setPendingUpdate(bool pending) { mPendingUpdate = pending; } bool getPendingUpdate() { return mPendingUpdate; } - bool refreshFromRegion(LLViewerRegion* region) override; + bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; private: void onClickAddAllowedAgent(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 88e5d900cb..739821d2f5 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3155,7 +3155,7 @@ void LLViewerRegion::unpackRegionHandshake() std::string cap = getCapability("ModifyRegion"); // needed for queueQuery if (cap.empty()) { - LLFloaterRegionInfo::sRefreshFromRegion(this); + LLFloaterRegionInfo::refreshFromRegion(this); } else { @@ -3167,7 +3167,7 @@ void LLViewerRegion::unpackRegionHandshake() LLVLComposition* compp = region->getComposition(); if (!compp) { return; } compp->apply(composition_changes); - LLFloaterRegionInfo::sRefreshFromRegion(region); + LLFloaterRegionInfo::refreshFromRegion(region); }); } } -- cgit v1.2.3 From e8d33a8b5b06b70b6354672b6d426e82a8aed578 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Sat, 12 Oct 2024 01:49:27 +0300 Subject: Revert "Add toggles to avatar dropdown for hear sound or voice from avatar. (#2518, #2519)" This reverts commit 6af471482d6801530915c1c9ae4bdf788af52eae. --- indra/newview/llagent.cpp | 14 -------------- indra/newview/llagent.h | 7 ------- indra/newview/llviewermenu.cpp | 2 -- indra/newview/skins/default/xui/en/menu_viewer.xml | 19 ------------------- 4 files changed, 42 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index ca35608175..3d4f5e1054 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -355,20 +355,6 @@ bool LLAgent::isMicrophoneOn(const LLSD& sdname) return LLVoiceClient::getInstance()->getUserPTTState(); } -//static -void LLAgent::toggleHearMediaSoundFromAvatar() -{ - const S32 mediaSoundsEarLocation = gSavedSettings.getS32("MediaSoundsEarLocation"); - gSavedSettings.setS32("MediaSoundsEarLocation", !mediaSoundsEarLocation); -} - -//static -void LLAgent::toggleHearVoiceFromAvatar() -{ - const S32 voiceEarLocation = gSavedSettings.getS32("VoiceEarLocation"); - gSavedSettings.setS32("VoiceEarLocation", !voiceEarLocation); -} - // ************************************************************ // Enabled this definition to compile a 'hacked' viewer that // locally believes the end user has godlike powers. diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 448ee575f5..489131d974 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -376,13 +376,6 @@ public: private: bool mVoiceConnected; - //-------------------------------------------------------------------- - // Sound - //-------------------------------------------------------------------- -public: - static void toggleHearMediaSoundFromAvatar(); - static void toggleHearVoiceFromAvatar(); - //-------------------------------------------------------------------- // Chat //-------------------------------------------------------------------- diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 10506e0e74..120a3094cd 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9627,8 +9627,6 @@ void initialize_menus() registrar.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2), cb_info::UNTRUSTED_BLOCK); enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - registrar.add("Agent.ToggleHearMediaSoundFromAvatar", boost::bind(&LLAgent::toggleHearMediaSoundFromAvatar), cb_info::UNTRUSTED_BLOCK); - registrar.add("Agent.ToggleHearVoiceFromAvatar", boost::bind(&LLAgent::toggleHearVoiceFromAvatar), cb_info::UNTRUSTED_BLOCK); // File menu init_menu_file(); diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index e1d33e5bc3..1c645d8d70 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -561,25 +561,6 @@ parameter="conversation" /> - - - - - - - - - - Date: Sat, 12 Oct 2024 01:49:27 +0300 Subject: Revert "Add toggles to avatar dropdown for hear sound or voice from avatar. (#2518, #2519)" This reverts commit 6af471482d6801530915c1c9ae4bdf788af52eae. --- indra/newview/llagent.cpp | 14 -------------- indra/newview/llagent.h | 7 ------- indra/newview/llviewermenu.cpp | 2 -- indra/newview/skins/default/xui/en/menu_viewer.xml | 19 ------------------- 4 files changed, 42 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c8b0adbaf8..26c080bf89 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -355,20 +355,6 @@ bool LLAgent::isMicrophoneOn(const LLSD& sdname) return LLVoiceClient::getInstance()->getUserPTTState(); } -//static -void LLAgent::toggleHearMediaSoundFromAvatar() -{ - const S32 mediaSoundsEarLocation = gSavedSettings.getS32("MediaSoundsEarLocation"); - gSavedSettings.setS32("MediaSoundsEarLocation", !mediaSoundsEarLocation); -} - -//static -void LLAgent::toggleHearVoiceFromAvatar() -{ - const S32 voiceEarLocation = gSavedSettings.getS32("VoiceEarLocation"); - gSavedSettings.setS32("VoiceEarLocation", !voiceEarLocation); -} - // ************************************************************ // Enabled this definition to compile a 'hacked' viewer that // locally believes the end user has godlike powers. diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index afc34f747f..c1d3c6c14b 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -374,13 +374,6 @@ public: private: bool mVoiceConnected; - //-------------------------------------------------------------------- - // Sound - //-------------------------------------------------------------------- -public: - static void toggleHearMediaSoundFromAvatar(); - static void toggleHearVoiceFromAvatar(); - //-------------------------------------------------------------------- // Chat //-------------------------------------------------------------------- diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index df60130c9f..80c75ec919 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9579,8 +9579,6 @@ void initialize_menus() commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2)); enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2)); enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2)); - commit.add("Agent.ToggleHearMediaSoundFromAvatar", boost::bind(&LLAgent::toggleHearMediaSoundFromAvatar)); - commit.add("Agent.ToggleHearVoiceFromAvatar", boost::bind(&LLAgent::toggleHearVoiceFromAvatar)); // File menu init_menu_file(); diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index a03024487f..e0e9fdcc32 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -561,25 +561,6 @@ parameter="conversation" /> - - - - - - - - - - Date: Sun, 13 Oct 2024 08:09:51 +0200 Subject: Remove traces of FLTK (#2834) --- indra/llwindow/llwindowsdl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index f87a00c34b..9d736a9970 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1369,7 +1369,7 @@ void LLWindowSDL::processMiscNativeEvents() void LLWindowSDL::gatherInput(bool app_has_focus) { - SDL_Event event; + SDL_Event event; // Handle all outstanding SDL events while (SDL_PollEvent(&event)) -- cgit v1.2.3 From 2252f0fc932e9cd3533c72b96bdb032b7ef89da1 Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Sun, 13 Oct 2024 11:01:38 +0200 Subject: Fix time format copy&paste error (#2844) --- .../newview/skins/default/xui/en/floater_inventory_item_properties.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') 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 index cc7942abea..1aa216d6b4 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -30,7 +30,7 @@ - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local] Date: Fri, 11 Oct 2024 22:16:51 +0300 Subject: viewer#2819 Group member pagination toggle Group member pagination is not ready, disable it untill later --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llpanelgrouproles.cpp | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 13ec35fa07..b7d1575bb1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2469,6 +2469,17 @@ Value 1 + UseGroupMemberPagination + + Comment + Enable pagination of group memeber list 50 members at a time. + Persist + 1 + Type + Boolean + Value + 0 + DisplayTimecode Comment diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 4404efff98..e1f2d7588c 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1360,7 +1360,8 @@ void LLPanelGroupMembersSubTab::activate() { if (!gdatap || !gdatap->isMemberDataComplete()) { - const U32 page_size = 50; + static LLCachedControl enable_pagination(gSavedSettings, "UseGroupMemberPagination", false); + const U32 page_size = enable_pagination() ? 50 : 0; std::string sort_column_name = mMembersList->getSortColumnName(); bool sort_descending = !mMembersList->getSortAscending(); LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID, page_size, 0, sort_column_name, sort_descending); -- cgit v1.2.3 From 1983342a0578a32a2a5f148514e708d3be27d13f Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Mon, 14 Oct 2024 18:06:04 +0200 Subject: Use correct German date format for German localization (#2845) --- indra/newview/skins/default/xui/de/floater_about_land.xml | 3 ++- indra/newview/skins/default/xui/de/floater_inspect.xml | 5 ++++- indra/newview/skins/default/xui/de/panel_classified_info.xml | 2 +- indra/newview/skins/default/xui/de/panel_landmark_info.xml | 5 ++++- indra/newview/skins/default/xui/de/panel_place_profile.xml | 5 ++++- indra/newview/skins/default/xui/de/panel_profile_classified.xml | 2 +- indra/newview/skins/default/xui/de/panel_profile_secondlife.xml | 6 ++++++ indra/newview/skins/default/xui/de/panel_status_bar.xml | 2 +- indra/newview/skins/default/xui/de/sidepanel_item_info.xml | 8 ++++---- indra/newview/skins/default/xui/de/strings.xml | 8 ++++---- 10 files changed, 31 insertions(+), 15 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml index bb9ab26ef5..9c93ff38ad 100644 --- a/indra/newview/skins/default/xui/de/floater_about_land.xml +++ b/indra/newview/skins/default/xui/de/floater_about_land.xml @@ -25,7 +25,8 @@ (keiner) (Wird verkauft) Keine Parzelle ausgewählt. - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,slt] + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] Name: Beschreibung: Typ: diff --git a/indra/newview/skins/default/xui/de/floater_inspect.xml b/indra/newview/skins/default/xui/de/floater_inspect.xml index da97ceb2d8..a193e1123e 100644 --- a/indra/newview/skins/default/xui/de/floater_inspect.xml +++ b/indra/newview/skins/default/xui/de/floater_inspect.xml @@ -1,7 +1,10 @@ + + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,slt] + - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] diff --git a/indra/newview/skins/default/xui/de/panel_classified_info.xml b/indra/newview/skins/default/xui/de/panel_classified_info.xml index 007e9d69f0..1b8caf5f78 100644 --- a/indra/newview/skins/default/xui/de/panel_classified_info.xml +++ b/indra/newview/skins/default/xui/de/panel_classified_info.xml @@ -13,7 +13,7 @@ [TELEPORT] teleportieren, [MAP] Karte, [PROFILE] Profil - [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt] + [day,datetime,slt].[mthnum,datetime,slt].[year,datetime,slt] Aktiviert diff --git a/indra/newview/skins/default/xui/de/panel_landmark_info.xml b/indra/newview/skins/default/xui/de/panel_landmark_info.xml index 10cf34c170..8726d5e645 100644 --- a/indra/newview/skins/default/xui/de/panel_landmark_info.xml +++ b/indra/newview/skins/default/xui/de/panel_landmark_info.xml @@ -15,8 +15,11 @@ Die Informationen über diesen Standort sind zugriffsbeschränkt. Bitte wenden Sie sich bezüglich Ihrer Berechtigungen an den Eigentümer der Parzelle. + + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] + - [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]