diff --git a/autobuild.xml b/autobuild.xml index ac5174405d..bcb424112c 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -22,9 +22,9 @@ archive hash - aa31ee4c6315cb26bf6e2191b69598f5 + 1f887cbafc0fe2af1e85783de0f14102 url - http://3p.firestormviewer.org/jemalloc-5.1.0-linux64-190582149.tar.bz2 + http://3p.firestormviewer.org/jemalloc-5.2.1-linux64-210451204.tar.bz2 name linux64 @@ -964,11 +964,11 @@ archive hash - 87c4984c2bddcdaf6ca403a06f22ce4e + 4f9bf4566934e6e8611ef918186f20c5 hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.01.07-darwin-210010951.tar.bz2 + file:///opt/firestorm/fmodstudio-2.01.08-darwin-210441530.tar.bz2 name darwin @@ -978,11 +978,11 @@ archive hash - d33d848660ca7e4c2de789e325706d24 + c8024bad0445af488d355670ba13cc40 hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.01.07-linux64-203630250.tar.bz2 + file:///opt/firestorm/fmodstudio-2.01.08-linux64-210441517.tar.bz2 name linux64 @@ -992,11 +992,11 @@ archive hash - 9e9f303912776014519c18a0205250ee + c27de9c2f8c562551773a80399d6d037 hash_algorithm md5 url - file:///c:/cygwin/opt/firestorm/fmodstudio-2.01.07-windows-203561745.tar.bz2 + file:///c:/cygwin/opt/firestorm/fmodstudio-2.01.08-windows-210431451.tar.bz2 name windows @@ -1006,18 +1006,18 @@ archive hash - ae336fe814a6867f6449d0401ea7a9e4 + 29a66f79f7224cc17aa22d047853f7b0 hash_algorithm md5 url - file:///c:/cygwin/opt/firestorm/fmodstudio-2.01.07-windows64-203561747.tar.bz2 + file:///c:/cygwin/opt/firestorm/fmodstudio-2.01.08-windows64-210431454.tar.bz2 name windows64 version - 2.01.07 + 2.01.08 fontconfig diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 61feecc3ee..7b98ee3edf 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -401,11 +401,7 @@ inline bool operator!=(const LLVector3d& a, const LLVector3d& b) // [RLVa:KB] - RlvBehaviourModifierCompMin/Max inline bool operator<(const LLVector3d& lhs, const LLVector3d& rhs) { - return (lhs.mdV[0] < rhs.mdV[0] - || (lhs.mdV[0] == rhs.mdV[0] - && (lhs.mdV[1] < rhs.mdV[1] - || ((lhs.mdV[1] == rhs.mdV[1]) - && lhs.mdV[2] < rhs.mdV[2])))); + return std::tie(lhs.mdV[0], lhs.mdV[1], lhs.mdV[2]) < std::tie(rhs.mdV[0], rhs.mdV[1], rhs.mdV[2]); } // [/RLVa:KB] diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index b8835ba2e4..bee3d8140b 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -468,6 +468,13 @@ inline LLVector4 operator-(const LLVector4 &a) return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] ); } +// [RLVa:KB] - RlvBehaviourModifierCompMin/Max +inline bool operator<(const LLVector4& lhs, const LLVector4& rhs) +{ + return std::tie(lhs.mV[0], lhs.mV[1], lhs.mV[2], lhs.mV[3]) < std::tie(rhs.mV[0], rhs.mV[1], rhs.mV[2], rhs.mV[3]); +} +// [/RLVa:KB] + inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b) { LLVector4 vec = a - b; diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index a8e9a6bd64..795860e9f7 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -632,6 +632,13 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) // returns bool specifying if av_name was filled, false otherwise bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name) { + // Avoid null entries entering NameCache + // This is a catch-all, better to avoid at call site + if( agent_id.isNull() ) + { + return false; + } + // if (mRunning) { // ...only do immediate lookups when cache is running diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 1d4c10eab2..6c6f819415 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -156,9 +156,9 @@ void LLPluginProcessParent::shutdown() { EState state = (*it).second->mState; if (state != STATE_CLEANUP - || state != STATE_EXITING - || state != STATE_DONE - || state != STATE_ERROR) + && state != STATE_EXITING + && state != STATE_DONE + && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); } @@ -920,7 +920,8 @@ void LLPluginProcessParent::poll(F64 timeout) // } else { - LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << " (" << APR_TO_OS_ERROR(status) << ")" << LL_ENDL; + LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << " (" << APR_TO_OS_ERROR(status) << ") Rebuild PollSet" << LL_ENDL; + sPollsetNeedsRebuild = true; } // } diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 32ac6cc282..1deef703ff 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1355,6 +1355,14 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("sunAngle2"); mReservedUniforms.push_back("camPosLocal"); +// [RLVa:KB] - @setsphere + mReservedUniforms.push_back("rlvEffectMode"); + mReservedUniforms.push_back("rlvEffectParam1"); + mReservedUniforms.push_back("rlvEffectParam2"); + mReservedUniforms.push_back("rlvEffectParam3"); + mReservedUniforms.push_back("rlvEffectParam4"); + mReservedUniforms.push_back("rlvEffectParam5"); +// [/RLV:KB] mReservedUniforms.push_back("gWindDir"); mReservedUniforms.push_back("gSinWaveParams"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 3c6cb54f1c..518cba001f 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -210,6 +210,14 @@ public: WATER_SUN_ANGLE2, WL_CAMPOSLOCAL, +// [RLVa:KB] - @setsphere + RLV_EFFECT_MODE, + RLV_EFFECT_PARAM1, + RLV_EFFECT_PARAM2, + RLV_EFFECT_PARAM3, + RLV_EFFECT_PARAM4, + RLV_EFFECT_PARAM5, +// [/RLVa:KB] AVATAR_WIND, AVATAR_SINWAVE, diff --git a/indra/llui/fsregistrarutils.h b/indra/llui/fsregistrarutils.h index 0b8d55f247..3c5d26fa98 100644 --- a/indra/llui/fsregistrarutils.h +++ b/indra/llui/fsregistrarutils.h @@ -44,7 +44,12 @@ enum EFSRegistrarFunctionActionType FS_RGSTR_ACT_REQUEST_TELEPORT, FS_RGSTR_CHK_AVATAR_BLOCKED, FS_RGSTR_CHK_IS_SELF, - FS_RGSTR_CHK_IS_NOT_SELF + FS_RGSTR_CHK_IS_NOT_SELF, + FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA, + FS_RGSTR_CHK_HAVE_GROUP_DATA, + FS_RGSTR_CHK_CAN_LEAVE_GROUP, + FS_RGSTR_CHK_CAN_JOIN_GROUP, + FS_RGSTR_CHK_GROUP_NOT_ACTIVE }; class FSRegistrarUtils diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index fba3e98411..9cec673674 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -132,6 +132,7 @@ LLScrollListCtrl::Params::Params() search_column("search_column", 0), sort_column("sort_column", -1), sort_ascending("sort_ascending", true), + sort_lazily("sort_lazily", false), // FIRE-30732 deferred sort as a UI property persist_sort_order("persist_sort_order", false), // Persists sort order of scroll lists primary_sort_only("primary_sort_only", false), // Option to only sort by one column mouse_wheel_opaque("mouse_wheel_opaque", false), @@ -186,6 +187,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mTotalStaticColumnWidth(0), mTotalColumnPadding(0), mSorted(false), + mSortLazily(p.sort_lazily), // FIRE-30732 deferred sort configurability mDirty(false), mOriginalSelection(-1), mLastSelected(NULL), @@ -2112,6 +2114,20 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) enable_registrar.add("FS.EnableViewLog", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_ACT_VIEW_TRANSCRIPT)); // + // FIRE-30725 - Add more group functions to group URL context menu + std::string uuid_str = uuid.asString(); + + registrar.add("FS.JoinGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + uuid_str + "/groupjoin", true)); + registrar.add("FS.LeaveGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + uuid_str + "/groupleave", true)); + registrar.add("FS.ActivateGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + uuid_str + "/groupactivate", true)); + + enable_registrar.add("FS.WaitingForGroupData", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA)); + enable_registrar.add("FS.HaveGroupData", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_CHK_HAVE_GROUP_DATA)); + enable_registrar.add("FS.EnableJoinGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_CHK_CAN_JOIN_GROUP)); + enable_registrar.add("FS.EnableLeaveGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_CHK_CAN_LEAVE_GROUP)); + enable_registrar.add("FS.EnableActivateGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, uuid, FS_RGSTR_CHK_GROUP_NOT_ACTIVE)); + // + // create the context menu from the XUI file and display it std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; delete mPopupMenu; @@ -2957,7 +2973,9 @@ void LLScrollListCtrl::updateSort() const // if (hasSortOrder() && !isSorted()) // { static LLUICachedControl sortDeferFrameCount("FSSortDeferalFrames"); - if ( hasSortOrder() && !isSorted() && ( mLastUpdateFrame > 1 && ( LLFrameTimer::getFrameCount() - mLastUpdateFrame ) >= sortDeferFrameCount ) ) + if ( hasSortOrder() && !isSorted() && + ( !mSortLazily || // if deferred sorting is off OR the deferral period has been exceeded + ( mLastUpdateFrame > 1 && ( LLFrameTimer::getFrameCount() - mLastUpdateFrame ) >= sortDeferFrameCount ) ) ) // encoding two (unlikely) special values into mLastUpdateFrame 1 means we've sorted and 0 means we've nothing new to do. // 0 is set after sorting, 1 can be set by a parent for any post sorting action. { diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index b6cc6590ed..9f8c93b6ad 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -117,6 +117,7 @@ public: Optional search_column, sort_column; Optional sort_ascending; + Optional sort_lazily; // FIRE-30732 deferred sort as a UI property Optional persist_sort_order; // Persists sort order of scroll lists Optional primary_sort_only; // Option to only sort by one column @@ -559,6 +560,8 @@ private: // Option to only sort by one column bool mPrimarySortOnly; + // deferred sort as a UI property + bool mSortLazily; mutable bool mSorted; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index ab40ecc0c9..2eabf5eb54 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2144,6 +2144,18 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) enable_registrar.add("FS.EnableViewLog", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_ACT_VIEW_TRANSCRIPT)); // + // FIRE-30725 - Add more group functions to group URL context menu + registrar.add("FS.JoinGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupjoin", true)); + registrar.add("FS.LeaveGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupleave", true)); + registrar.add("FS.ActivateGroup", boost::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupactivate", true)); + + enable_registrar.add("FS.WaitingForGroupData", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA)); + enable_registrar.add("FS.HaveGroupData", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_CHK_HAVE_GROUP_DATA)); + enable_registrar.add("FS.EnableJoinGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_CHK_CAN_JOIN_GROUP)); + enable_registrar.add("FS.EnableLeaveGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_CHK_CAN_LEAVE_GROUP)); + enable_registrar.add("FS.EnableActivateGroup", boost::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, FS_RGSTR_CHK_GROUP_NOT_ACTIVE)); + // + // create and return the context menu from the XUI file LLContextMenu* menu = static_cast(mPopupMenuHandle.get()); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 57c8415eca..158521aa3c 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -60,7 +60,7 @@ namespace // LLWindowMacOSX // -BOOL LLWindowMacOSX::sUseMultGL = FALSE; +BOOL LLWindowMacOSX::sUseMultGL = TRUE; // Cross-platform bits: diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 7d26eee5af..70072af3af 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2006,7 +2006,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA ); - bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window"); + // avoid unfortunate sleep during trylock by static check + // bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window"); + static auto debug_logging_on = debugLoggingEnabled("Window"); + bool debug_window_proc = gDebugWindowProc || debug_logging_on; + // if (NULL != window_imp) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ea463d8a34..53e0e277dd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -806,6 +806,7 @@ set(viewer_SOURCE_FILES llviewerwearable.cpp llviewerwindow.cpp llviewerwindowlistener.cpp + llvisualeffect.cpp llvlcomposition.cpp llvlmanager.cpp llvoavatar.cpp @@ -851,14 +852,14 @@ set(viewer_SOURCE_FILES quickprefs.cpp rlvactions.cpp rlvenvironment.cpp - rlvhandler.cpp - rlvhelper.cpp rlvcommon.cpp - rlvlocks.cpp - rlvinventory.cpp + rlveffects.cpp rlvextensions.cpp rlvfloaters.cpp - rlvmodifiers.cpp + rlvhandler.cpp + rlvhelper.cpp + rlvinventory.cpp + rlvlocks.cpp rlvui.cpp sanitycheck.cpp streamtitledisplay.cpp @@ -1567,6 +1568,7 @@ set(viewer_HEADER_FILES llviewerwearable.h llviewerwindow.h llviewerwindowlistener.h + llvisualeffect.h llvlcomposition.h llvlmanager.h llvoavatar.h @@ -1609,15 +1611,16 @@ set(viewer_HEADER_FILES pieslice.h pipeline.h rlvactions.h - rlvenvironment.h - rlvdefines.h - rlvhandler.h - rlvhelper.h rlvcommon.h - rlvlocks.h - rlvinventory.h + rlvdefines.h + rlveffects.h + rlvenvironment.h rlvextensions.h rlvfloaters.h + rlvhandler.h + rlvhelper.h + rlvinventory.h + rlvlocks.h rlvmodifiers.h rlvui.h roles_constants.h diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp index 0f54723867..901a61bbf6 100644 --- a/indra/newview/aoengine.cpp +++ b/indra/newview/aoengine.cpp @@ -63,6 +63,7 @@ AOEngine::AOEngine() : { gSavedPerAccountSettings.getControl("UseAO")->getCommitSignal()->connect(boost::bind(&AOEngine::onToggleAOControl, this)); gSavedPerAccountSettings.getControl("UseAOStands")->getCommitSignal()->connect(boost::bind(&AOEngine::onToggleAOStandsControl, this)); + gSavedPerAccountSettings.getControl("PauseAO")->getCommitSignal()->connect(boost::bind(&AOEngine::onPauseAO, this)); mRegionChangeConnection = gAgent.addRegionChangedCallback(boost::bind(&AOEngine::onRegionChange, this)); } @@ -117,6 +118,15 @@ void AOEngine::onToggleAOStandsControl() enableStands(gSavedPerAccountSettings.getBOOL("UseAOStands")); } +void AOEngine::onPauseAO() +{ + // can't use mEnabled here as that gets switched over by enable() + if (gSavedPerAccountSettings.getBOOL("UseAO")) + { + enable(!gSavedPerAccountSettings.getBOOL("PauseAO")); + } +} + void AOEngine::clear(bool from_timer) { mOldSets.insert(mOldSets.end(), mSets.begin(), mSets.end()); diff --git a/indra/newview/aoengine.h b/indra/newview/aoengine.h index 2bfb85d10b..23b6dd9ba3 100644 --- a/indra/newview/aoengine.h +++ b/indra/newview/aoengine.h @@ -183,6 +183,8 @@ class AOEngine void onToggleAOControl(); void onToggleAOStandsControl(); + void onPauseAO(); + static void onNotecardLoadComplete(LLVFS* vfs, const LLUUID& assetUUID, LLAssetType::EType type, void* userdata, S32 status, LLExtStat extStatus); void parseNotecard(const char* buffer); diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 8b3e8996e5..52d58cea89 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -509,6 +509,8 @@ execute_parameters="fs_posestand" is_running_function="Floater.IsOpen" is_running_parameters="fs_posestand" + is_enabled_function="Agent.IsActionAllowed" + is_enabled_parameters="fs_when_not_sitting" /> - d6fee4de-09af-80b2-72c9-dd5eb509f18c + 3481ccd5-cc6c-65ca-c466-dc9df1bf3944 name PS_T_Pose - 63db3570-950d-089c-54c5-b406cb32635b + 0b4ee516-5dfd-ef4b-4ab6-300bb44cb045 name PS_Arms_Down_Legs_together - 46d5043d-6d86-c237-ab9c-c088d5608f37 + b23c52ef-0b15-11f2-852d-8fbd33417847 name PS_Arms_down_sitting - 767d488a-faa5-aeca-128f-af0b196967f1 + e14fee5f-3735-a236-2e26-94f92f366d81 name PS_Arms_downward_Legs_apart - c2a3ba2f-499f-6129-2c43-2085815b3c81 + 2029d88f-4efc-d72d-18d1-274caf9e9bc0 name PS_Arms_downward_Legs_together - 9e6fbfdb-d83e-a590-d59d-571c49002a7c + cff5559e-c915-0b5e-d587-f789b5cc299a name PS_Arms_forward_Legs_apart - 64d9b2e0-a124-b5fa-73f1-8703218f9aa8 + 23f3163c-183b-dac0-0cdd-7811bcc3b5f1 name PS_Arms_forward_Legs_together - a5b4ae9f-05d2-998f-5ca5-63ac5cfdf595 + b2f312aa-2c1e-27b8-50fe-a0fa4ff3df4e name PS_Arms_straight_Legs_apart - 16ca97b1-732d-8964-f044-1575d8bc2f98 + c17677b8-9fb2-8d6e-bbbe-219edce64ef4 name PS_Arms_straight_sitting - 284ff48c-5f45-8351-c459-020f0bc1cd77 + 2cfeed25-04f9-caff-f3d2-776cddea5771 name PS_Arms_upward_Legs_apart - 76e563a3-6a97-0487-f8dc-70a673fa58d8 + 6e83f685-2f53-278f-6758-b529327cce09 name PS_Arms_upward_Legs_together diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 38eed32b37..e01defca09 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -353,7 +353,7 @@ Type U32 Value - 2 + 5 FSGroupNotifyNoTransparency @@ -25629,5 +25629,16 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSStatusBarTimeFormat + + Comment + Which time format to use for the status bar clock, e.g. 12 Hours, 24 Hours, etc. The default "Language" restores the original behavior of changing the time display mode per language. + Persist + 1 + Type + String + Value + Language + diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index e35efe7f38..81ade2146d 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -744,6 +744,17 @@ Value 0 + PauseAO + + Comment + Pause the viewer side Animation Overrider + Persist + 0 + Type + Boolean + Value + 0 + UseAOStands Comment diff --git a/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl b/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl new file mode 100644 index 0000000000..8661ffe923 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl @@ -0,0 +1,167 @@ +/** + * + * Copyright (c) 2018-2020, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR + out vec4 frag_color; +#else + #define frag_color gl_FragColor +#endif + +VARYING vec2 vary_fragcoord; + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect depthMap; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +uniform int rlvEffectMode; // ESphereMode +uniform vec4 rlvEffectParam1; // Sphere origin (in local coordinates) +uniform vec4 rlvEffectParam2; // Min/max dist + min/max value +uniform bvec2 rlvEffectParam3; // Min/max dist extend +uniform vec4 rlvEffectParam4; // Sphere params (=color when using blend) +uniform vec2 rlvEffectParam5; // Blur direction (not used for blend) + +#define SPHERE_ORIGIN rlvEffectParam1.xyz +#define SPHERE_DISTMIN rlvEffectParam2.y +#define SPHERE_DISTMAX rlvEffectParam2.w +#define SPHERE_DISTEXTEND rlvEffectParam3 +#define SPHERE_VALUEMIN rlvEffectParam2.x +#define SPHERE_VALUEMAX rlvEffectParam2.z +#define SPHERE_PARAMS rlvEffectParam4 +#define BLUR_DIRECTION rlvEffectParam5.xy + +vec4 getPosition_d(vec2 pos_screen, float depth) +{ + vec2 sc = pos_screen.xy * 2.0; + sc /= screen_res; + sc -= vec2(1.0, 1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0 * depth - 1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec3 blur13(sampler2DRect source, vec2 tc, vec2 direction) +{ + vec4 color = vec4(0.0); + vec2 off1 = vec2(1.411764705882353) * direction; + vec2 off2 = vec2(3.2941176470588234) * direction; + vec2 off3 = vec2(5.176470588235294) * direction; + + color += texture2DRect(source, tc) * 0.1964825501511404; + + color += texture2DRect(source, tc + off1) * 0.2969069646728344; + color += texture2DRect(source, tc - off1) * 0.2969069646728344; + + color += texture2DRect(source, tc + off2) * 0.09447039785044732; + color += texture2DRect(source, tc - off2) * 0.09447039785044732; + + color += texture2DRect(source, tc + off3) * 0.010381362401148057; + color += texture2DRect(source, tc - off3) * 0.010381362401148057; + + return color.xyz; +} + +const float pi = 3.14159265; + +// http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html +vec3 blurVariable(sampler2DRect source, vec2 tc, float kernelSize, vec2 direction, float strength) { + float numBlurPixelsPerSide = float(kernelSize / 2); + + // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) + vec3 incrementalGaussian; + incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * strength); + incrementalGaussian.y = exp(-0.5 / (strength * strength)); + incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y; + + vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0); + float coefficientSum = 0.0; + + // Take the central sample first... + avgValue += texture2DRect(source, tc) * incrementalGaussian.x; + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + // Go through the remaining 8 vertical samples (4 on each side of the center) + for (float i = 1.0; i <= numBlurPixelsPerSide; i++) { + avgValue += texture2DRect(source, tc - i * direction) * incrementalGaussian.x; + avgValue += texture2DRect(source, tc + i * direction) * incrementalGaussian.x; + coefficientSum += 2.0 * incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + } + + return (avgValue / coefficientSum).rgb; +} + +vec3 chromaticAberration(sampler2DRect source, vec2 tc, vec2 redDrift, vec2 blueDrift, float strength) +{ + vec3 sourceColor = texture2DRect(source, tc).rgb; + + // Sample the color components + vec3 driftColor; + driftColor.r = texture2DRect(source, tc + redDrift).r; + driftColor.g = sourceColor.g; + driftColor.b = texture2DRect(source, tc + blueDrift).b; + + // Adjust the strength of the effect + return mix(sourceColor, driftColor, strength); +} + +void main() +{ + vec2 fragTC = vary_fragcoord.st; + float fragDepth = texture2DRect(depthMap, fragTC).x; + vec3 fragPosLocal = getPosition_d(fragTC, fragDepth).xyz; + float distance = length(fragPosLocal.xyz - SPHERE_ORIGIN); + + // Linear non-branching interpolation of the strength of the sphere effect (replaces if/elseif/else for x < min, min <= x <= max and x > max) + float effectStrength = SPHERE_VALUEMIN + mix(0, SPHERE_VALUEMAX - SPHERE_VALUEMIN, (distance - SPHERE_DISTMIN) / (SPHERE_DISTMAX - SPHERE_DISTMIN)); + effectStrength = mix(effectStrength, mix(0, SPHERE_VALUEMIN, SPHERE_DISTEXTEND.x), distance < SPHERE_DISTMIN); + effectStrength = mix(effectStrength, mix(0, SPHERE_VALUEMAX, SPHERE_DISTEXTEND.y), distance > SPHERE_DISTMAX); + + vec3 fragColor; + switch (rlvEffectMode) + { + case 0: // Blend + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + fragColor = mix(fragColor, SPHERE_PARAMS.rgb, effectStrength); + break; + case 1: // Blur (fixed) + fragColor = blur13(diffuseRect, fragTC, effectStrength * BLUR_DIRECTION); + break; + case 2: // Blur (variable) + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + fragColor = mix(fragColor, blurVariable(diffuseRect, fragTC, SPHERE_PARAMS.x, BLUR_DIRECTION, effectStrength), effectStrength > 0); + break; + case 3: // ChromaticAberration + fragColor = chromaticAberration(diffuseRect, fragTC, SPHERE_PARAMS.xy, SPHERE_PARAMS.zw, effectStrength); + break; + case 4: // Pixelate + { + effectStrength = sign(effectStrength); + float pixelWidth = max(1, round(SPHERE_PARAMS.x * effectStrength)); float pixelHeight = max(1, round(SPHERE_PARAMS.y * effectStrength)); + fragTC = vec2(pixelWidth * floor(fragTC.x / pixelWidth), pixelHeight * floor(fragTC.y / pixelHeight)); + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + } + break; + } + + frag_color.rgb = fragColor; + frag_color.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/rlvFMac.glsl b/indra/newview/app_settings/shaders/class1/deferred/rlvFMac.glsl new file mode 100644 index 0000000000..fce37c24be --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/rlvFMac.glsl @@ -0,0 +1,176 @@ +/** + * + * Copyright (c) 2018-2020, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR + out vec4 frag_color; +#else + #define frag_color gl_FragColor +#endif + +VARYING vec2 vary_fragcoord; + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect depthMap; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +uniform int rlvEffectMode; // ESphereMode +uniform vec4 rlvEffectParam1; // Sphere origin (in local coordinates) +uniform vec4 rlvEffectParam2; // Min/max dist + min/max value +uniform bvec2 rlvEffectParam3; // Min/max dist extend +uniform vec4 rlvEffectParam4; // Sphere params (=color when using blend) +uniform vec2 rlvEffectParam5; // Blur direction (not used for blend) + +#define SPHERE_ORIGIN rlvEffectParam1.xyz +#define SPHERE_DISTMIN rlvEffectParam2.y +#define SPHERE_DISTMAX rlvEffectParam2.w +#define SPHERE_DISTEXTEND rlvEffectParam3 +#define SPHERE_VALUEMIN rlvEffectParam2.x +#define SPHERE_VALUEMAX rlvEffectParam2.z +#define SPHERE_PARAMS rlvEffectParam4 +#define BLUR_DIRECTION rlvEffectParam5.xy + +vec4 getPosition_d(vec2 pos_screen, float depth) +{ + vec2 sc = pos_screen.xy * 2.0; + sc /= screen_res; + sc -= vec2(1.0, 1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0 * depth - 1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec3 blur13(sampler2DRect source, vec2 tc, vec2 direction) +{ + vec4 color = vec4(0.0); + vec2 off1 = vec2(1.411764705882353) * direction; + vec2 off2 = vec2(3.2941176470588234) * direction; + vec2 off3 = vec2(5.176470588235294) * direction; + + color += texture2DRect(source, tc) * 0.1964825501511404; + + color += texture2DRect(source, tc + off1) * 0.2969069646728344; + color += texture2DRect(source, tc - off1) * 0.2969069646728344; + + color += texture2DRect(source, tc + off2) * 0.09447039785044732; + color += texture2DRect(source, tc - off2) * 0.09447039785044732; + + color += texture2DRect(source, tc + off3) * 0.010381362401148057; + color += texture2DRect(source, tc - off3) * 0.010381362401148057; + + return color.xyz; +} + +const float pi = 3.14159265; + +// http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html +vec3 blurVariable(sampler2DRect source, vec2 tc, float kernelSize, vec2 direction, float strength) { + float numBlurPixelsPerSide = float(kernelSize / 2); + + // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889) + vec3 incrementalGaussian; + incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * strength); + incrementalGaussian.y = exp(-0.5 / (strength * strength)); + incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y; + + vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0); + float coefficientSum = 0.0; + + // Take the central sample first... + avgValue += texture2DRect(source, tc) * incrementalGaussian.x; + coefficientSum += incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + + // Go through the remaining 8 vertical samples (4 on each side of the center) + for (float i = 1.0; i <= numBlurPixelsPerSide; i++) { + avgValue += texture2DRect(source, tc - i * direction) * incrementalGaussian.x; + avgValue += texture2DRect(source, tc + i * direction) * incrementalGaussian.x; + coefficientSum += 2.0 * incrementalGaussian.x; + incrementalGaussian.xy *= incrementalGaussian.yz; + } + + return (avgValue / coefficientSum).rgb; +} + +vec3 chromaticAberration(sampler2DRect source, vec2 tc, vec2 redDrift, vec2 blueDrift, float strength) +{ + vec3 sourceColor = texture2DRect(source, tc).rgb; + + // Sample the color components + vec3 driftColor; + driftColor.r = texture2DRect(source, tc + redDrift).r; + driftColor.g = sourceColor.g; + driftColor.b = texture2DRect(source, tc + blueDrift).b; + + // Adjust the strength of the effect + return mix(sourceColor, driftColor, strength); +} + +void main() +{ + vec2 fragTC = vary_fragcoord.st; + float fragDepth = texture2DRect(depthMap, fragTC).x; + vec3 fragPosLocal = getPosition_d(fragTC, fragDepth).xyz; + float distance = length(fragPosLocal.xyz - SPHERE_ORIGIN); + + // Linear non-branching interpolation of the strength of the sphere effect (replaces if/elseif/else for x < min, min <= x <= max and x > max) + float effectStrength = SPHERE_VALUEMIN + mix(0.0, SPHERE_VALUEMAX - SPHERE_VALUEMIN, (distance - SPHERE_DISTMIN) / (SPHERE_DISTMAX - SPHERE_DISTMIN)); + if (distance < SPHERE_DISTMIN) + { + effectStrength = SPHERE_DISTEXTEND.x ? SPHERE_VALUEMIN : 0.0; + } + else if (distance > SPHERE_DISTMAX) + { + effectStrength = SPHERE_DISTEXTEND.y ? SPHERE_VALUEMAX : 0.0; + } + + vec3 fragColor; + if (rlvEffectMode == 0) // Blend + { + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + fragColor = mix(fragColor, SPHERE_PARAMS.rgb, effectStrength); + } + else if (rlvEffectMode == 1) // Blur (fixed) + { + fragColor = blur13(diffuseRect, fragTC, effectStrength * BLUR_DIRECTION); + } + else if (rlvEffectMode == 2) // Blur (variable) + { + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + if (effectStrength > 0) + { + fragColor = blurVariable(diffuseRect, fragTC, SPHERE_PARAMS.x, BLUR_DIRECTION, effectStrength); + } + } + else if (rlvEffectMode == 3) // ChromaticAberration + { + fragColor = chromaticAberration(diffuseRect, fragTC, SPHERE_PARAMS.xy, SPHERE_PARAMS.zw, effectStrength); + } + else if (rlvEffectMode == 4) // Pixelate + { + effectStrength = sign(effectStrength); + float pixelWidth = max(1, floor(SPHERE_PARAMS.x * effectStrength)); float pixelHeight = max(1, floor(SPHERE_PARAMS.y * effectStrength)); + fragTC = vec2(pixelWidth * floor(fragTC.x / pixelWidth), pixelHeight * floor(fragTC.y / pixelHeight)); + fragColor = texture2DRect(diffuseRect, fragTC).rgb; + } + + frag_color.rgb = fragColor; + frag_color.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/rlvV.glsl b/indra/newview/app_settings/shaders/class1/deferred/rlvV.glsl new file mode 100644 index 0000000000..19124b6101 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/rlvV.glsl @@ -0,0 +1,33 @@ +/** + * + * Copyright (c) 2018, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +ATTRIBUTE vec3 position; + +uniform vec2 screen_res; + +VARYING vec2 vary_fragcoord; +VARYING vec3 vary_position; + +void main() +{ + //transform vertex + vec4 pos = vec4(position.xyz, 1.0); + gl_Position = pos; + + + vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; + vary_position = (vec4(1, 0, 0, 1.0)).xyz; +} diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index c14b11162c..04098fad54 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -16,7 +16,7 @@ * may be used to endorse or promote products derived from this * software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS AS IS + * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MODULAR SYSTEMS OR CONTRIBUTORS @@ -673,13 +673,28 @@ bool cmd_line_chat(const std::string& revised_text, EChatType type, bool from_ge std::string status; if (i >> status) { + // send appropriate enable/disable messages to nearby chat - FIRE-24160 + bool aoWasEnabled = gSavedPerAccountSettings.getBOOL("UseAO"); + if (status == "on") { gSavedPerAccountSettings.setBOOL("UseAO", TRUE); + + // send appropriate enable/disable messages to nearby chat - FIRE-24160 + if (!aoWasEnabled) + { + report_to_nearby_chat(LLTrans::getString("FSAOEnabled")); + } } else if (status == "off") { gSavedPerAccountSettings.setBOOL("UseAO", FALSE); + + // send appropriate enable/disable messages to nearby chat - FIRE-24160 + if (aoWasEnabled) + { + report_to_nearby_chat(LLTrans::getString("FSAODisabled")); + } } else if (status == "sit") { diff --git a/indra/newview/fs_resources/EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt b/indra/newview/fs_resources/EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt index 1c161565a8..11e5ee0ce5 100644 --- a/indra/newview/fs_resources/EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt +++ b/indra/newview/fs_resources/EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt @@ -7,7 +7,7 @@ // // Bridge platform - string BRIDGE_VERSION = "2.25"; // This should match fslslbridge.cpp + string BRIDGE_VERSION = "2.27"; // This should match fslslbridge.cpp string gLatestURL; integer gViewerIsFirestorm; integer gTryHandshakeOnce = TRUE; @@ -85,8 +85,11 @@ { if (gAO_EnabledOC) { - aoListenOC(NULL_KEY, TRUE); - llWhisper(gAO_ChannelOC, "OpenCollar?"); + if (gAO_ChannelOC != PUBLIC_CHANNEL) + { + aoListenOC(NULL_KEY, TRUE); + llWhisper(gAO_ChannelOC, "OpenCollar?"); + } } else { @@ -456,7 +459,10 @@ default { gUseMoveLock = llList2Integer(commandList, 1); movelockMe(gUseMoveLock); - llOwnerSay(""); + if (llList2String(commandList, 2) != "noreport") + { + llOwnerSay(""); + } } else if (cmd == "llMoveToTarget") diff --git a/indra/newview/fscommon.cpp b/indra/newview/fscommon.cpp index a1bba035e0..b87fd79ef6 100644 --- a/indra/newview/fscommon.cpp +++ b/indra/newview/fscommon.cpp @@ -34,6 +34,8 @@ #include "llavataractions.h" #include "llavatarnamecache.h" #include "llfloaterperms.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" #include "llinventorymodel.h" #include "lllogchat.h" #include "llmutelist.h" @@ -316,6 +318,16 @@ bool FSCommon::isLinden(const LLUUID& av_id) last_name == LL_TESTER); } +// request group data from the server if it's not already cached +bool FSCommon::requestGroupData(const LLUUID& groupID) +{ + if (LLGroupMgr::getInstance()->getGroupData(groupID) == nullptr) + { + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(groupID); + return false; + } + return true; +} bool FSCommon::checkIsActionEnabled(const LLUUID& av_id, EFSRegistrarFunctionActionType action) { @@ -373,6 +385,52 @@ bool FSCommon::checkIsActionEnabled(const LLUUID& av_id, EFSRegistrarFunctionAct { return !isSelf; } + else if (action == FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA) + { + return !requestGroupData(av_id); + } + else if (action == FS_RGSTR_CHK_HAVE_GROUP_DATA) + { + return requestGroupData(av_id); + } + else if (action == FS_RGSTR_CHK_CAN_LEAVE_GROUP) + { + if (gAgent.getGroupID() == av_id && !RlvActions::canChangeActiveGroup()) + { + return false; + } + + return gAgent.isInGroup(av_id); + } + else if (action == FS_RGSTR_CHK_CAN_JOIN_GROUP) + { + if (!gAgent.canJoinGroups()) + { + return false; + } + + if (!RlvActions::canChangeActiveGroup()) + { + return false; + } + + LLGroupMgrGroupData* groupData = LLGroupMgr::getInstance()->getGroupData(av_id); + if (!groupData || !groupData->mOpenEnrollment) + { + return false; + } + + return !gAgent.isInGroup(av_id); + } + else if (action == FS_RGSTR_CHK_GROUP_NOT_ACTIVE) + { + if (!RlvActions::canChangeActiveGroup()) + { + return false; + } + + return (gAgent.isInGroup(av_id) && gAgent.getGroupID() != av_id); + } return false; } diff --git a/indra/newview/fscommon.h b/indra/newview/fscommon.h index be33ef6790..a7d8d350d6 100644 --- a/indra/newview/fscommon.h +++ b/indra/newview/fscommon.h @@ -78,6 +78,9 @@ namespace FSCommon */ extern S32 sObjectAddMsg; + // request group data from the server if it's not already cached + bool requestGroupData(const LLUUID& groupID); + bool checkIsActionEnabled(const LLUUID& av_id, EFSRegistrarFunctionActionType); LLSD populateGroupCount(); diff --git a/indra/newview/fsfloaterassetblacklist.cpp b/indra/newview/fsfloaterassetblacklist.cpp index 890c7a79de..00bb43988c 100644 --- a/indra/newview/fsfloaterassetblacklist.cpp +++ b/indra/newview/fsfloaterassetblacklist.cpp @@ -32,6 +32,8 @@ #include "fscommon.h" #include "fsscrolllistctrl.h" +#include "llagent.h" +#include "llaudioengine.h" #include "llfiltereditor.h" #include "llfloaterreg.h" #include "llviewercontrol.h" @@ -39,10 +41,11 @@ FSFloaterAssetBlacklist::FSFloaterAssetBlacklist(const LLSD& key) - : LLFloater(key), + : LLFloater(key), LLEventTimer(0.25f), mResultList(NULL), mFilterSubString(LLStringUtil::null), mFilterSubStringOrig(LLStringUtil::null), + mAudioSourceID(LLUUID::null), mBlacklistCallbackConnection() { } @@ -60,15 +63,24 @@ BOOL FSFloaterAssetBlacklist::postBuild() mResultList = getChild("result_list"); mResultList->setContextMenu(&FSFloaterAssetBlacklistMenu::gFSAssetBlacklistMenu); mResultList->setFilterColumn(0); + mResultList->setCommitCallback(boost::bind(&FSFloaterAssetBlacklist::onSelectionChanged, this)); + mResultList->setCommitOnSelectionChange(true); childSetAction("remove_btn", boost::bind(&FSFloaterAssetBlacklist::onRemoveBtn, this)); childSetAction("remove_temp_btn", boost::bind(&FSFloaterAssetBlacklist::onRemoveAllTemporaryBtn, this)); + childSetAction("play_btn", boost::bind(&FSFloaterAssetBlacklist::onPlayBtn, this)); + childSetAction("stop_btn", boost::bind(&FSFloaterAssetBlacklist::onStopBtn, this)); childSetAction("close_btn", boost::bind(&FSFloaterAssetBlacklist::onCloseBtn, this)); getChild("filter_input")->setCommitCallback(boost::bind(&FSFloaterAssetBlacklist::onFilterEdit, this, _2)); mBlacklistCallbackConnection = FSAssetBlacklist::getInstance()->setBlacklistChangedCallback(boost::bind(&FSFloaterAssetBlacklist::onBlacklistChanged, this, _1, _2)); + childSetEnabled("play_btn", false); + childSetEnabled("stop_btn", true); + childSetVisible("play_btn", true); + childSetVisible("stop_btn", false); + return TRUE; } @@ -82,13 +94,13 @@ std::string FSFloaterAssetBlacklist::getTypeString(S32 type) { switch (type) { - case 0: + case LLAssetType::AT_TEXTURE: return getString("asset_texture"); - case 1: + case LLAssetType::AT_SOUND: return getString("asset_sound"); - case 6: + case LLAssetType::AT_OBJECT: return getString("asset_object"); - case 45: + case LLAssetType::AT_PERSON: return getString("asset_resident"); default: return getString("asset_unknown"); @@ -144,6 +156,9 @@ void FSFloaterAssetBlacklist::addElementToList(const LLUUID& id, const LLSD& dat element["columns"][5]["column"] = "date_sort"; element["columns"][5]["type"] = "text"; element["columns"][5]["value"] = llformat("%u", (U64)date.secondsSinceEpoch()); + element["columns"][6]["column"] = "asset_type"; + element["columns"][6]["type"] = "integer"; + element["columns"][6]["value"] = data["asset_type"].asInteger(); mResultList->addElement(element, ADD_BOTTOM); } @@ -198,6 +213,57 @@ void FSFloaterAssetBlacklist::onRemoveAllTemporaryBtn() gObjectList.resetDerenderList(true); } +void FSFloaterAssetBlacklist::onSelectionChanged() +{ + bool enabled = false; + size_t num_selected = mResultList->getAllSelected().size(); + if (num_selected == 1) + { + const LLScrollListItem* item = mResultList->getFirstSelected(); + S32 name_column = mResultList->getColumn("asset_type")->mIndex; + + if (item && item->getColumn(name_column)->getValue().asInteger() == LLAssetType::AT_SOUND) + { + enabled = true; + } + } + + childSetEnabled("play_btn", enabled); +} + +void FSFloaterAssetBlacklist::onPlayBtn() +{ + const LLScrollListItem* item = mResultList->getFirstSelected(); + S32 name_column = mResultList->getColumn("asset_type")->mIndex; + + if (!item || item->getUUID().isNull() || item->getColumn(name_column)->getValue().asInteger() != LLAssetType::AT_SOUND) + { + return; + } + + onStopBtn(); + + mAudioSourceID = LLUUID::generateNewID(); + gAudiop->triggerSound(item->getUUID(), gAgentID, 1.0f, LLAudioEngine::AUDIO_TYPE_UI, LLVector3d::zero, LLUUID::null, mAudioSourceID); + + childSetVisible("stop_btn", true); + childSetVisible("play_btn", false); +} + +void FSFloaterAssetBlacklist::onStopBtn() +{ + if (mAudioSourceID.isNull()) + { + return; + } + + LLAudioSource* audio_source = gAudiop->findAudioSource(mAudioSourceID); + if (audio_source && !audio_source->isDone()) + { + audio_source->play(LLUUID::null); + } +} + void FSFloaterAssetBlacklist::onCloseBtn() { closeFloater(); @@ -220,6 +286,7 @@ void FSFloaterAssetBlacklist::onFilterEdit(const std::string& search_string) // Apply new filter. mResultList->setFilterString(mFilterSubStringOrig); + onSelectionChanged(); } BOOL FSFloaterAssetBlacklist::handleKeyHere(KEY key, MASK mask) @@ -233,6 +300,32 @@ BOOL FSFloaterAssetBlacklist::handleKeyHere(KEY key, MASK mask) return LLFloater::handleKeyHere(key, mask); } +BOOL FSFloaterAssetBlacklist::tick() +{ + if (mAudioSourceID.isNull()) + { + return FALSE; + } + + LLAudioSource* audio_source = gAudiop->findAudioSource(mAudioSourceID); + if (!audio_source || audio_source->isDone()) + { + childSetVisible("play_btn", true); + childSetVisible("stop_btn", false); + + mAudioSourceID.setNull(); + onSelectionChanged(); + } + + return FALSE; +} + +void FSFloaterAssetBlacklist::closeFloater(bool /* app_quitting */) +{ + onStopBtn(); + LLFloater::closeFloater(); +} + //--------------------------------------------------------------------------- // Context menu //--------------------------------------------------------------------------- diff --git a/indra/newview/fsfloaterassetblacklist.h b/indra/newview/fsfloaterassetblacklist.h index 83ffc020f7..a767db72c9 100644 --- a/indra/newview/fsfloaterassetblacklist.h +++ b/indra/newview/fsfloaterassetblacklist.h @@ -35,7 +35,7 @@ class FSScrollListCtrl; -class FSFloaterAssetBlacklist : public LLFloater +class FSFloaterAssetBlacklist : public LLFloater, public LLEventTimer { LOG_CLASS(FSFloaterAssetBlacklist); @@ -47,6 +47,8 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ bool hasAccelerators() const { return true; } + /*virtual*/ BOOL tick(); + /*virtual*/ void closeFloater(bool app_quitting = false); void addElementToList(const LLUUID& id, const LLSD& data); void removeElements(); @@ -54,13 +56,18 @@ public: protected: void onRemoveBtn(); void onRemoveAllTemporaryBtn(); + void onPlayBtn(); + void onStopBtn(); void onCloseBtn(); void onFilterEdit(const std::string& search_string); void onBlacklistChanged(const LLSD& data, FSAssetBlacklist::eBlacklistOperation op); + void onSelectionChanged(); void buildBlacklist(); std::string getTypeString(S32 type); + LLUUID mAudioSourceID; + private: FSScrollListCtrl* mResultList; diff --git a/indra/newview/fsfloaterim.cpp b/indra/newview/fsfloaterim.cpp index d63c509230..591d76f91e 100644 --- a/indra/newview/fsfloaterim.cpp +++ b/indra/newview/fsfloaterim.cpp @@ -37,6 +37,7 @@ #include "fsdata.h" #include "fsfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container #include "fsfloaternearbychat.h" +#include "fsnearbychathub.h" // FIRE-24133 - Redirect chat channel messages #include "fspanelimcontrolpanel.h" #include "llagent.h" #include "llappviewer.h" @@ -77,6 +78,8 @@ #include "rlvactions.h" #include "rlvhandler.h" +#include // FIRE-24133 - Redirect chat channel messages + const F32 ME_TYPING_TIMEOUT = 4.0f; const F32 OTHER_TYPING_TIMEOUT = 9.0f; const F32 NAME_REFRESH_TIMEOUT = 300.0f; @@ -381,7 +384,20 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type) // Truncate and convert to UTF8 for transport std::string utf8_text = wstring_to_utf8str(text); - + + // FIRE-24133 - Redirect chat channel messages + if (boost::regex_match(utf8_text.c_str(), boost::regex("/-{0,1}[0-9].*"))) + { + // message starts with a / and a valid channel number, so redirect it to a chat channel + FSNearbyChat::instance().sendChatFromViewer(text, CHAT_TYPE_NORMAL, false); + + // clean out the text box and typing indicator, which we wouldn't reach otherwise + mInputEditor->setText(LLStringUtil::null); + setTyping(false); + + return; + } + // Convert OOC and MU* style poses utf8_text = FSCommon::applyAutoCloseOoc(utf8_text); utf8_text = FSCommon::applyMuPose(utf8_text); diff --git a/indra/newview/fslslbridge.cpp b/indra/newview/fslslbridge.cpp index ad8c49cc4c..e8596296cb 100644 --- a/indra/newview/fslslbridge.cpp +++ b/indra/newview/fslslbridge.cpp @@ -55,7 +55,7 @@ static const std::string FS_BRIDGE_FOLDER = "#LSL Bridge"; static const std::string FS_BRIDGE_CONTAINER_FOLDER = "Landscaping"; static const U32 FS_BRIDGE_MAJOR_VERSION = 2; -static const U32 FS_BRIDGE_MINOR_VERSION = 25; +static const U32 FS_BRIDGE_MINOR_VERSION = 27; static const U32 FS_MAX_MINOR_VERSION = 99; static const std::string UPLOAD_SCRIPT_CURRENT = "EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt"; static const std::string FS_STATE_ATTRIBUTE = "state="; @@ -316,18 +316,32 @@ bool FSLSLBridge::lslToViewer(const std::string& message, const LLUUID& fromID, } if (tag == " do nothing when the FS AO is disabled + if (!gSavedPerAccountSettings.getBOOL("UseAO")) + { + return true; + } + status = true; size_t valuepos = message.find(FS_STATE_ATTRIBUTE); if (valuepos != std::string::npos) { + // send appropriate enable/disable messages to nearby chat - FIRE-24160 + // use BOOL to satisfy windows compiler + BOOL aoWasPaused = gSavedPerAccountSettings.getBOOL("PauseAO"); + BOOL aoStandsWasEnabled = gSavedPerAccountSettings.getBOOL("UseAOStands"); + // + if (message.substr(valuepos + FS_STATE_ATTRIBUTE.size(), 2) == "on") { - gSavedPerAccountSettings.setBOOL("UseAO", TRUE); + // Pause AO via bridge instead of switch AO on or off - FIRE-9305 + gSavedPerAccountSettings.setBOOL("PauseAO", FALSE); gSavedPerAccountSettings.setBOOL("UseAOStands", TRUE); } else if (message.substr(valuepos + FS_STATE_ATTRIBUTE.size(), 3) == "off") { - gSavedPerAccountSettings.setBOOL("UseAO", FALSE); + // Pause AO via bridge instead of switch AO on or off - FIRE-9305 + gSavedPerAccountSettings.setBOOL("PauseAO", TRUE); } else if (message.substr(valuepos + FS_STATE_ATTRIBUTE.size(), 7) == "standon") { @@ -341,6 +355,41 @@ bool FSLSLBridge::lslToViewer(const std::string& message, const LLUUID& fromID, { LL_WARNS("FSLSLBridge") << "AO control - Received unknown state" << LL_ENDL; } + + // send appropriate enable/disable messages to nearby chat - FIRE-24160 + std::string aoMessage; + + if (aoWasPaused != gSavedPerAccountSettings.getBOOL("PauseAO")) + { + if (aoWasPaused) + { + aoMessage = LLTrans::getString("FSAOResumedScript"); + } + else + { + aoMessage = LLTrans::getString("FSAOPausedScript"); + } + } + + if (aoStandsWasEnabled != gSavedPerAccountSettings.getBOOL("UseAOStands")) + { + if (aoStandsWasEnabled) + { + aoMessage = LLTrans::getString("FSAOStandsPausedScript"); + } + else + { + aoMessage = LLTrans::getString("FSAOStandsResumedScript"); + } + } + + if (!aoMessage.empty()) + { + LLSD args; + args["AO_MESSAGE"] = aoMessage; + LLNotificationsUtil::add("FSAOScriptedNotification", args); + } + // } } // FIRE-962 diff --git a/indra/newview/fspanellogin.cpp b/indra/newview/fspanellogin.cpp index 6699d6bed9..2f5d1449ec 100644 --- a/indra/newview/fspanellogin.cpp +++ b/indra/newview/fspanellogin.cpp @@ -1413,7 +1413,7 @@ void FSPanelLogin::updateServerCombo() server_choice_combo->addSeparator(ADD_TOP); LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(current_grid), current_grid, ADD_TOP); server_choice_combo->selectFirstItem(); diff --git a/indra/newview/fsslurlcommand.cpp b/indra/newview/fsslurlcommand.cpp index d0307b98d8..b53041d829 100644 --- a/indra/newview/fsslurlcommand.cpp +++ b/indra/newview/fsslurlcommand.cpp @@ -31,6 +31,7 @@ #include "llavataractions.h" #include "llcommandhandler.h" #include "llfloatersettingsdebug.h" +#include "llgroupactions.h" #include "lllogchat.h" #include "llnotificationsutil.h" @@ -135,6 +136,24 @@ public: return true; } + if (verb == "groupjoin") + { + LLGroupActions::join(LLUUID(target_id)); + return true; + } + + if (verb == "groupleave") + { + LLGroupActions::leave(LLUUID(target_id)); + return true; + } + + if (verb == "groupactivate") + { + LLGroupActions::activate(LLUUID(target_id)); + return true; + } + return false; } }; diff --git a/indra/newview/lfsimfeaturehandler.cpp b/indra/newview/lfsimfeaturehandler.cpp index ad7c60d2e4..03703c31b1 100644 --- a/indra/newview/lfsimfeaturehandler.cpp +++ b/indra/newview/lfsimfeaturehandler.cpp @@ -91,12 +91,12 @@ void LFSimFeatureHandler::setSupportedFeatures() region->getSimulatorFeatures(info); if (!LLGridManager::getInstance()->isInSecondLife() && info.has("OpenSimExtras")) // OpenSim specific sim features { - LL_INFOS() << "Setting OpenSimExtras..." << LL_ENDL; + LL_INFOS("SimFeatures") << "Setting OpenSimExtras..." << LL_ENDL; // For definition of OpenSimExtras please see // http://opensimulator.org/wiki/SimulatorFeatures_Extras const LLSD& extras(info["OpenSimExtras"]); - LL_DEBUGS() << "OpenSimExtras received: " << extras << LL_ENDL; + LL_DEBUGS("SimFeatures") << "OpenSimExtras received: " << extras << LL_ENDL; mSupportsExport = extras.has("ExportSupported") ? extras["ExportSupported"].asBoolean() : false; mMapServerURL = extras.has("map-server-url") ? extras["map-server-url"].asString() : gSavedSettings.getString("CurrentMapServerURL"); @@ -115,7 +115,7 @@ void LFSimFeatureHandler::setSupportedFeatures() // Note: we do not attempt to clear trailing port numbers or / or even directories. mHyperGridPrefix = mHyperGridPrefix.substr(pos+3,mHyperGridPrefix.size()-(pos+3)); } - LL_DEBUGS() << "Setting HyperGrid URL to \"GridURL\" [" << mHyperGridPrefix << "]" << LL_ENDL; + LL_DEBUGS("SimFeatures") << "Setting HyperGrid URL to \"GridURL\" [" << mHyperGridPrefix << "]" << LL_ENDL; } #ifdef OPENSIM else if (LLGridManager::instance().getGatekeeper() != std::string{}) @@ -124,14 +124,14 @@ void LFSimFeatureHandler::setSupportedFeatures() // worst case this is checking the login grid and will simply be the same as the fallback // If the GridURL is not available then we will try to use the Gatekeeper which is expected to be present. mHyperGridPrefix = LLGridManager::instance().getGatekeeper(); - LL_DEBUGS() << "Setting HyperGrid URL to \"Gatekeeper\" [" << mHyperGridPrefix << "]" << LL_ENDL; + LL_DEBUGS("SimFeatures") << "Setting HyperGrid URL to \"Gatekeeper\" [" << mHyperGridPrefix << "]" << LL_ENDL; } #endif else { // Just in case that fails we will default back to the current grid - mHyperGridPrefix = LLGridManager::instance().getGridId(); - LL_DEBUGS() << "Setting HyperGrid URL to fallback of current grid (target grid is misconfigured) [" << mHyperGridPrefix << "]" << LL_ENDL; + mHyperGridPrefix = LLGridManager::instance().getGrid(); + LL_DEBUGS("SimFeatures") << "Setting HyperGrid URL to fallback of current grid (target grid is misconfigured) [" << mHyperGridPrefix << "]" << LL_ENDL; } if (extras.has("SimulatorFPS") && extras.has("SimulatorFPSFactor") && diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f0df7e5977..2b3c6ff395 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -345,6 +345,14 @@ bool LLAgent::isActionAllowed(const LLSD& sdname) retval = false; } } + else if (param == "fs_when_not_sitting") + { + if (!gAgentAvatarp) + { + return false; + } + return !gAgentAvatarp->isSitting(); + } return retval; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4f3c458b48..a473bdfe02 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -679,7 +679,10 @@ static void settings_to_globals() static void settings_modify() { - LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); +// LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); +// [RLVa:KB] - @setsphere + LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred") || (gSavedSettings.getBOOL("WindLightUseAtmosShaders") && LLPipeline::sUseDepthTexture); +// [/RLVa:KB] LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index cc76b2e094..87bf2cb098 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -670,9 +670,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) U32 have_mask = params.mVertexBuffer->getTypeMask() & mask; if (have_mask != mask) { //FIXME! - LL_WARNS_ONCE() << "Missing required components, expected mask: " << mask - << " present: " << have_mask - << ". Skipping render batch." << LL_ENDL; + // Remove useless logging info from critical path (can be called many times per frame) + // TODO(Beq) Determine whether this can be intercepted earlier + // LL_WARNS_ONCE() << "Missing required components, expected mask: " << mask + // << " present: " << have_mask + // << ". Skipping render batch." << LL_ENDL; + // continue; } diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 77f0710d00..3136f96fe4 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -207,7 +207,7 @@ private: void LLFloaterIMNearbyChatScreenChannel::reshapePanel(LLFloaterIMNearbyChatToastPanel* panel) { S32 percentage = gSavedSettings.getS32("NearbyToastWidth"); - panel->reshape(gViewerWindow->getWindowWidthRaw() * percentage / 100, panel->getRect().getHeight(), TRUE); + panel->reshape(gViewerWindow->getWindowWidthScaled() * percentage / 100, panel->getRect().getHeight(), TRUE); } void LLFloaterIMNearbyChatScreenChannel::updateSize(LLRect old_world_rect, LLRect new_world_rect) diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 17321e0bf2..361f54c2f1 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -48,7 +48,9 @@ #include "llviewerobject.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" - +// [RLVa:KB] - @edit +#include "rlvactions.h" +// [/RLVa:KB] LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key) : LLFloater(key), @@ -105,6 +107,16 @@ void LLFloaterOpenObject::refresh() BOOL enabled = FALSE; LLSelectNode* node = mObjectSelection->getFirstRootNode(); +// [RLVa:KB] - @edit and @editobj + if ( (RlvActions::isRlvEnabled()) && (node) && (!RlvActions::canEdit(node->getObject())) ) + { + // If the floater was already open before getting edit restricted then a transient selection will allow manipulation + // of the object's inventory without it getting selected by LLSelectMgr::deselectIfTooFar(). + // Killing the selection would result in the user not realizing why their right-click breaks so close the floater instead. + closeFloater(); + return; + } +// [/RLVa:KB] if (node) { name = node->mName; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index f7ef007017..a239024ec7 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2275,7 +2275,7 @@ void LLFloaterPreference::refreshEnabledState() // [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a // "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n - ctrl_wind_light->setEnabled( (RlvActions::canChangeEnvironment()) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))); + ctrl_wind_light->setEnabled( ((RlvActions::canChangeEnvironment()) && (!RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE))) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))); // [/RLVa:KB] // ctrl_wind_light->setEnabled(TRUE); @@ -5972,7 +5972,10 @@ void LLPanelPreferenceOpensim::onClickRefreshGrid() std::string grid = mGridListControl->getSelectedValue(); getChild("grid_management_panel")->setEnabled(FALSE); LLGridManager::getInstance()->addGridListChangedCallback(boost::bind(&LLPanelPreferenceOpensim::refreshGridList, this, _1)); - LLGridManager::getInstance()->reFetchGrid(grid); + // FIRE-13223 grid info refresh does not update properly when applied to currently active grid + // LLGridManager::getInstance()->reFetchGrid(grid); + LLGridManager::getInstance()->reFetchGrid(grid, (grid == LLGridManager::getInstance()->getGrid()) ); + // } void LLPanelPreferenceOpensim::onClickRemoveGrid() diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index e786192df6..c1ac3e755d 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3177,6 +3177,14 @@ void LLIMMgr::addMessage( LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; } } + // FIRE-30424 - Incoming Group message sound plays for muted posters + else if(LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + // if this message was from a muted resident, there is no point in playing any sounds or + // doing anything else in this function, so return right here + return; + } + // else if(!do_not_disturb && PlayModeUISndNewIncomingIMSession == 2 && dialog == IM_NOTHING_SPECIAL) { make_ui_sound("UISndNewIncomingIMSession"); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c1f6c2f167..90c0c62079 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -258,7 +258,11 @@ std::string LLInvFVBridge::getSearchableCreatorName() const if(item) { LLAvatarName av_name; - if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name)) + // Avoid null id requests entering name cache + // if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name)) + const auto& creatorId {item->getCreatorUUID()}; + if ( creatorId.notNull() && LLAvatarNameCache::get(creatorId, &av_name) ) + // { std::string username = av_name.getUserName(); LLStringUtil::toUpper(username); @@ -7813,7 +7817,9 @@ void LLSettingsBridge::performAction(LLInventoryModel* model, std::string action if (!item) return; LLUUID asset_id = item->getAssetUUID(); - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id); + // FIRE-30701 - Allow crossfade time to apply when using EEP from inventory. + // LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id); + LLEnvironment::instance().setManualEnvironment(LLEnvironment::ENV_LOCAL, asset_id); LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); } else if ("apply_settings_parcel" == action) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 9f5a528219..02b97924d2 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -706,7 +706,10 @@ bool get_is_item_editable(const LLUUID& inv_item_id) case LLAssetType::AT_CLOTHING: return gAgentWearables.isWearableModifiable(inv_item_id); case LLAssetType::AT_OBJECT: - return true; +// [RLVa:KB] - @touch* + return (!RlvActions::isRlvEnabled()) || ((isAgentAvatarValid()) && (RlvActions::canEdit(gAgentAvatarp->getWornAttachment(inv_item_id)))); +// [/RLVa:KB] +// return true; default: return false;; } diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index b4236c406b..5a7ea32711 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -106,12 +106,14 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t mWaitList.insert(asset_uuid); return NULL; } - + // fIRE-14457 Fix CopySLURL fails / landmakrs not loading - based on snippet from Chorazin Allen + mRequestedList[asset_uuid] = gFrameTimeSeconds; gAssetStorage->getAssetData(asset_uuid, LLAssetType::AT_LANDMARK, LLLandmarkList::processGetAssetReply, NULL); - mRequestedList[asset_uuid] = gFrameTimeSeconds; + // fIRE-14457 Fix CopySLURL fails / landmakrs not loading - based on snippet from Chorazin Allen + // mRequestedList[asset_uuid] = gFrameTimeSeconds; } return NULL; } diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 4b231ca72b..3666ef7bc4 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -324,7 +324,10 @@ std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notifica from_id = notification->getPayload()["from_id"]; } LLAvatarName av_name; - if(LLAvatarNameCache::get(from_id, &av_name)) + // Avoid null UUID name cache requests + // if(LLAvatarNameCache::get(from_id, &av_name)) + if( from_id.notNull() && LLAvatarNameCache::get(from_id, &av_name) ) + // { res = av_name.getUserName(); } diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index ba831ab2ed..149d50c93a 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -37,6 +37,10 @@ #include "llscriptfloater.h" #include "llavatarname.h" #include "llavatarnamecache.h" +// [RLVa:KB] - @sendchat and @sendchannel/sendchannelexcept +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] using namespace LLNotificationsUI; @@ -112,6 +116,24 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification) if(notification->hasFormElements() && !notification->canShowToast()) { +// [RLVa:KB] - @sendchat and @sendchannel/sendchannelexcept + if (RlvActions::isRlvEnabled()) + { + const LLSD& sdPayload = notification->getPayload(); + if (sdPayload.has("chat_channel")) + { + const S32 nChannel = sdPayload["chat_channel"].asInteger(); + + // *TODO-RLVa: it's too late into the release cycle to block all script interactions so just take care of the nearby chat loophole for now + bool fBlock = (0 == nChannel) ? RlvActions::hasBehaviour(RLV_BHVR_SENDCHAT) : /*!RlvActions::canSendChannel(nChannel)*/false; + if (fBlock) + { + RlvUtil::notifyBlocked("blocked_scriptdialog"); + return false; + } + } + } +// [/RLVa:KB] LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID()); } else if (notification->canShowToast()) diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 4e37d8da59..799e0fb412 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -709,12 +709,42 @@ const std::string& LLTaskCategoryBridge::getDisplayName() const if (cat) { - // Make object root folder name localizable again + // FIRE-24142 - Show number of elements in object inventory //mDisplayName.assign(cat->getName()); if (cat->getParentUUID().isNull() && cat->getName() == "Contents") { - mDisplayName.assign(LLTrans::getString("Contents")); + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if (object) + { + LLInventoryObject::object_list_t contents; + + object->getInventoryContents(contents); + S32 numElements = contents.size(); + + std::string elementsString = "FSObjectInventoryNoElements"; + if (numElements == 1) + { + elementsString = "FSObjectInventoryOneElement"; + } + else + { + elementsString = "FSObjectInventoryElements"; + } + + LLSD args; + args["NUM_ELEMENTS"] = numElements; + mDisplayName.assign(llformat("%s (%s)", + LLTrans::getString("Contents").c_str(), + LLTrans::getString(elementsString, args).c_str())); + } + // fallback in case something goes wrong with finding the inventory object + else + { + // Make object root folder name localizable again + mDisplayName.assign(LLTrans::getString("Contents")); + } } + // else { mDisplayName.assign(cat->getName()); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 76cb8fcf99..bfb80a634b 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -173,11 +173,11 @@ protected: } // Enable/disable some menu items depending on the selection. + bool show_touch = !bp_selected && !clothes_selected && attachments_selected; + bool show_edit = bp_selected || clothes_selected || attachments_selected; // [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) bool rlv_blocked = (mUUIDs.size() == rlv_locked_count); // [/RLVa:KB] - bool show_touch = !bp_selected && !clothes_selected && attachments_selected; - bool show_edit = bp_selected || clothes_selected || attachments_selected; bool allow_detach = !bp_selected && !clothes_selected && attachments_selected; bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected; @@ -187,7 +187,7 @@ protected: menu->setItemEnabled("edit_item", 1 == mUUIDs.size() && get_is_item_editable(mUUIDs.front())); menu->setItemVisible("take_off", allow_take_off); menu->setItemVisible("detach", allow_detach); - menu->setItemVisible("edit_outfit_separator", show_touch | show_edit | allow_take_off || allow_detach); + menu->setItemVisible("edit_outfit_separator", show_touch || show_edit || allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); // [SL:KB] - Patch: Inventory-AttachmentEdit - Checked: 2010-09-04 (Catznip-2.2.0a) | Added: Catznip-2.1.2a menu->setItemVisible("take_off_or_detach", (!allow_detach) && (!allow_take_off) && (clothes_selected) && (attachments_selected)); diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index b162afddf0..808d218e8e 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -1006,9 +1006,13 @@ void LLPreviewTexture::onAspectRatioCommit(LLUICtrl* ctrl, void* userdata) void LLPreviewTexture::loadAsset() { - mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - mImageOldBoostLevel = mImage->getBoostLevel(); - mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + // mImageOldBoostLevel = mImage->getBoostLevel(); + // mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_PREVIEW, LLViewerTexture::LOD_TEXTURE); + mImageOldBoostLevel = LLGLTexture::BOOST_NONE; + // mImage->forceToSaveRawImage(0) ; // texture comment decoder mImage->setLoadedCallback(LLPreviewTexture::onTextureLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 134dfd5a73..0ce7258e59 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -519,9 +519,49 @@ BOOL LLStatusBar::postBuild() updateVolumeControlsVisibility(LLSD(FALSE)); } // + + // FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display + mClockFormatChoices["12 Hour"] = "[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt]"; + mClockFormatChoices["12 Hour Seconds"] = "[hour12, datetime, slt]:[min, datetime, slt]:[second, datetime, slt] [ampm, datetime, slt]"; + mClockFormatChoices["12 Hour TZ"] = "[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]"; + mClockFormatChoices["12 Hour TZ Seconds"] = "[hour12, datetime, slt]:[min, datetime, slt]:[second, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]"; + mClockFormatChoices["24 Hour"] = "[hour24, datetime, slt]:[min, datetime, slt]"; + mClockFormatChoices["24 Hour Seconds"] = "[hour24, datetime, slt]:[min, datetime, slt]:[second, datetime, slt]"; + mClockFormatChoices["24 Hour TZ"] = "[hour24, datetime, slt]:[min, datetime, slt] [timezone, datetime, slt]"; + mClockFormatChoices["24 Hour TZ Seconds"] = "[hour24, datetime, slt]:[min, datetime, slt]:[second, datetime, slt] [timezone, datetime, slt]"; + + // use the time format defined in the language's panel_status_bar.xml (default) + mClockFormatChoices["Language"] = getString("time"); + + mClockFormat = gSavedSettings.getString("FSStatusBarTimeFormat"); + // + return TRUE; } +// FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display +void LLStatusBar::updateClockDisplay() +{ + // Get current UTC time, adjusted for the user's clock + // being off. + time_t utc_time; + utc_time = time_corrected(); + + std::string timeStr = mClockFormatChoices[mClockFormat]; + LLSD substitution; + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + mTextTime->setText(timeStr); + + // Add seconds to clock + static const std::string tooltip_template = getString("timeTooltip"); + std::string dtStr = tooltip_template; + // + LLStringUtil::format (dtStr, substitution); + mTextTime->setToolTip (dtStr); +} +// + // Per-frame updates of visibility void LLStatusBar::refresh() { @@ -562,29 +602,25 @@ void LLStatusBar::refresh() { mClockUpdateTimer.reset(); - // Get current UTC time, adjusted for the user's clock - // being off. - time_t utc_time; - utc_time = time_corrected(); + // FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display + // // Get current UTC time, adjusted for the user's clock + // // being off. + // time_t utc_time; + // utc_time = time_corrected(); - // Add seconds to clock - //std::string timeStr = getString("time"); - static const std::string time_template = getString("time"); - std::string timeStr = time_template; - // - LLSD substitution; - substitution["datetime"] = (S32) utc_time; - LLStringUtil::format (timeStr, substitution); - mTextTime->setText(timeStr); + // std::string timeStr = getString("time"); + // LLSD substitution; + // substitution["datetime"] = (S32) utc_time; + // LLStringUtil::format (timeStr, substitution); + // mTextTime->setText(timeStr); - // set the tooltip to have the date - // Add seconds to clock - //std::string dtStr = getString("timeTooltip"); - static const std::string tooltip_template = getString("timeTooltip"); - std::string dtStr = tooltip_template; - // - LLStringUtil::format (dtStr, substitution); - mTextTime->setToolTip (dtStr); + // // set the tooltip to have the date + // std::string dtStr = getString("timeTooltip"); + // LLStringUtil::format (dtStr, substitution); + // mTextTime->setToolTip (dtStr); + + updateClockDisplay(); + // } // Pathfinding rebake functions @@ -1717,6 +1753,14 @@ void LLStatusBar::onPopupRolloverChanged(const LLSD& newvalue) } } +// FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display +void LLStatusBar::onTimeFormatChanged(const std::string& format) +{ + mClockFormat = format; + updateClockDisplay(); +} +// + // Implements secondlife:///app/balance/request to request a L$ balance // update via UDP message system. JC class LLBalanceHandler : public LLCommandHandler diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index a14a1f8370..81d427cfd4 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -157,6 +157,9 @@ public: void updateCurrencySymbols(); // + // FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display + void onTimeFormatChanged(const std::string& format); + private: void onClickBuyCurrency(); @@ -166,7 +169,8 @@ private: void onMouseEnterPresets(); void onMouseEnterVolume(); void onMouseEnterNearbyMedia(); - void onClickScreen(S32 x, S32 y); + // Does not exist 15-02-2021 + //void onClickScreen(S32 x, S32 y); static void onClickStreamToggle(void* data); // Media/Stream separation static void onClickMediaToggle(void* data); @@ -259,16 +263,11 @@ private: /** * Updates the visibility state of the parcel icons according to parcel properties */ - void updateParcelIconVisibility(); + // Does not exist 15-02-2021 + //void updateParcelIconVisibility(); void onBuyLandClicked(); - // Pathfinding support - void onRegionBoundaryCrossed(); - void onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus); - void createNavMeshStatusListenerForCurrentRegion(); - // Pathfinding support - // FIRE-19697: Add setting to disable graphics preset menu popup on mouse over void onPopupRolloverChanged(const LLSD& newvalue); @@ -395,6 +394,13 @@ private: void onMouseLeaveParcelInfo(); // +// FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display + std::map mClockFormatChoices; + std::string mClockFormat; + + void updateClockDisplay(); +// + std::string mCurrentLocationString; }; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index eebce59f9a..2f4b91a114 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -517,9 +517,21 @@ static bool handleRenderLocalLightsChanged(const LLSD& newvalue) return true; } +// [RLVa:KB] - @setsphere +static bool handleWindLightAtmosShadersChanged(const LLSD& newvalue) +{ + LLRenderTarget::sUseFBO = newvalue.asBoolean() && LLPipeline::sUseDepthTexture; + handleSetShaderChanged(LLSD()); + return true; +} +// [/RLVa:KB] + static bool handleRenderDeferredChanged(const LLSD& newvalue) { - LLRenderTarget::sUseFBO = newvalue.asBoolean(); +// LLRenderTarget::sUseFBO = newvalue.asBoolean(); +// [RLVa:KB] - @setsphere + LLRenderTarget::sUseFBO = newvalue.asBoolean() || (gSavedSettings.getBOOL("WindLightUseAtmosShaders") && LLPipeline::sUseDepthTexture); +// [/RLVa:KB] if (gPipeline.isInit()) { LLPipeline::refreshCachedSettings(); @@ -541,7 +553,10 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) // static bool handleRenderBumpChanged(const LLSD& newval) { - LLRenderTarget::sUseFBO = newval.asBoolean(); +// LLRenderTarget::sUseFBO = newval.asBoolean(); +// [RLVa:KB] - @setsphere + LLRenderTarget::sUseFBO = newval.asBoolean() || (gSavedSettings.getBOOL("WindLightUseAtmosShaders") && LLPipeline::sUseDepthTexture); +// [/RLVa:KB] if (gPipeline.isInit()) { gPipeline.updateRenderBump(); @@ -1033,6 +1048,17 @@ void handleSmallCameraFloaterChanged(const LLSD& newValue) } // +// FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display +void handleStatusbarTimeformatChanged(const LLSD& newValue) +{ + const std::string format = newValue.asString(); + if (gStatusBar) + { + gStatusBar->onTimeFormatChanged(format); + } +} +// + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() @@ -1060,7 +1086,10 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); - gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); +// gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); +// [RLVa:KB] - @setsphere + gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleWindLightAtmosShadersChanged, _2)); +// [/RLVa:KB] gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2)); gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2)); @@ -1280,6 +1309,9 @@ void settings_setup_listeners() // Optional small camera floater gSavedSettings.getControl("FSUseSmallCameraFloater")->getSignal()->connect(boost::bind(&handleSmallCameraFloaterChanged, _2)); + + // FIRE-20390, FIRE-4269 - Option for 12/24 hour clock and seconds display + gSavedSettings.getControl("FSStatusBarTimeFormat")->getSignal()->connect(boost::bind(&handleStatusbarTimeformatChanged, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index c4ad6774c5..e955166827 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -79,7 +79,8 @@ #include "llenvironment.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) -#include "rlvhandler.h" +#include "llvisualeffect.h" +#include "rlvactions.h" #include "rlvlocks.h" // [/RLVa:KB] #include "llpresetsmanager.h" @@ -1429,9 +1430,9 @@ void render_ui(F32 zoom_factor, int subfield) LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); render_hud_elements(); // [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) - if (gRlvHandler.isEnabled()) + if (RlvActions::hasBehaviour(RLV_BHVR_SETOVERLAY)) { - gRlvHandler.renderOverlay(); + LLVfxManager::instance().runEffect(EVisualEffect::RlvOverlay); } // [/RLVa:KB] render_hud_attachments(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 1b99238bcf..13c890c57a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1361,11 +1361,11 @@ class LLAdvancedToggleWireframe : public view_listener_t { bool handleEvent(const LLSD& userdata) { -// [RLVa:KB] - Checked: RLVa-2.0.0 - bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD(); - if ( (!gUseWireframe) && (fRlvBlockWireframe) ) +// [RLVa:KB] - @detach and @viewwireframe + const bool fRlvCanViewWireframe = RlvActions::canViewWireframe(); + if ( (!gUseWireframe) && (!fRlvCanViewWireframe) ) RlvUtil::notifyBlocked(RlvStringKeys::Blocked::Wireframe); - set_use_wireframe( (!gUseWireframe) && (!fRlvBlockWireframe) ); + set_use_wireframe( (!gUseWireframe) && (fRlvCanViewWireframe) ); return true; } }; @@ -3500,10 +3500,10 @@ bool enable_attachment_touch(const LLUUID& inv_item_id) if (isAgentAvatarValid()) { const LLViewerObject* attach_obj = gAgentAvatarp->getWornAttachment(gInventory.getLinkedItemID(inv_item_id)); - return (attach_obj) && (attach_obj->flagHandleTouch()) && ( (!RlvActions::isRlvEnabled()) || (RlvActions::canTouch(gAgentAvatarp->getWornAttachment(inv_item_id))) ); -// [RLVa:KB] - Checked: 2012-08-15 (RLVa-1.4.7) - //return (attach_obj) && (attach_obj->flagHandleTouch()); +// [RLVa:KB] - @touch* + return (attach_obj) && (attach_obj->flagHandleTouch()) && (!RlvActions::isRlvEnabled() || RlvActions::canTouch(attach_obj)); // [/RLVa:KB] +// return (attach_obj) && (attach_obj->flagHandleTouch()); } return false; } @@ -10492,8 +10492,8 @@ class LLViewHighlightTransparent : public view_listener_t bool handleEvent(const LLSD& userdata) { // LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; -// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - LLDrawPoolAlpha::sShowDebugAlpha = (!LLDrawPoolAlpha::sShowDebugAlpha) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)); +// [RLVa:KB] - @edit and @viewtransparent + LLDrawPoolAlpha::sShowDebugAlpha = (!LLDrawPoolAlpha::sShowDebugAlpha) && (RlvActions::canHighlightTransparent()); // [/RLVa:KB] return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index c42a5e5c06..39f25ae290 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -8179,6 +8179,20 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) } } +// [RLVa:KB] - @sendchat and @sendchannel/sendchannelexcept + if ( (RlvActions::isRlvEnabled()) && (0 <= button_idx) ) + { + const S32 nChannel = notification["payload"]["chat_channel"].asInteger(); + + // *TODO-RLVa: it's too late into the release cycle to block all script interactions so just take care of the nearby chat loophole for now + bool fBlock = (0 == nChannel) ? RlvActions::hasBehaviour(RLV_BHVR_SENDCHAT) : /*!RlvActions::canSendChannel(nChannel)*/false; + if (fBlock) + { + button_idx = -1; + } + } +// [/RLVa:KB] + if (0 <= button_idx) { LLMessageSystem* msg = gMessageSystem; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index cd60588896..dc040019f0 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -83,6 +83,7 @@ #include #include +#include // FIRE-30694 DeadObject Spamming cleanup #include "fsassetblacklist.h" #include "fsfloaterimport.h" #include "fscommon.h" @@ -1410,15 +1411,30 @@ void LLViewerObjectList::clearDebugText() void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { - bool new_dead_object = true; + // FIRE-30694 DeadObject Spam - handle new_dead_object properly and closer to source + // bool new_dead_object = true; if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { LL_INFOS() << "Object " << objectp->mID << " already on dead list!" << LL_ENDL; - new_dead_object = false; + // FIRE-30694 DeadObject Spam + // new_dead_object = false; } else { - mDeadObjects.insert(objectp->mID); + // FIRE-30694 DeadObject Spam + // mDeadObjects.insert(objectp->mID); + bool success; + std::tie( std::ignore, success ) = mDeadObjects.insert( objectp->mID ); + if( success ) + { + mNumDeadObjects++; + llassert( mNumDeadObjects == mDeadObjects.size() ); + } + else + { + LL_WARNS() << "Object " << objectp->mID << " failed to insert on dead list!" << LL_ENDL; + } + // } // Cleanup any references we have to this object @@ -1454,10 +1470,11 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // Also, not cleaned up removeDrawable(objectp->mDrawable); - if(new_dead_object) - { - mNumDeadObjects++; - } + // FIRE-30694 DeadObject Spam + // if(new_dead_object) + // { + // mNumDeadObjects++; + // } } static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); @@ -1589,12 +1606,17 @@ void LLViewerObjectList::killAllObjects() void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) { + // FIRE-30694 DeadObject Spam + llassert( mNumDeadObjects == mDeadObjects.size() ); + if (!mNumDeadObjects) { // No dead objects, don't need to scan object list. return; } + // FIRE-30694 DeadObject Spam + S32 num_divergent = 0; S32 num_removed = 0; LLViewerObject *objectp; @@ -1617,7 +1639,13 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) if (objectp->isDead()) { - mDeadObjects.erase(objectp->mID); // Use timer for cleaning up dead objects + // FIRE-30694 DeadObject Spam + // mDeadObjects.erase(objectp->mID); // Use timer for cleaning up dead objects + if(mDeadObjects.erase(objectp->mID)==0) + { + LL_WARNS() << "Attempt to delete object " << objectp->mID << " but object not in dead list" << LL_ENDL; + num_divergent++; // this is the number we are adrift in the count + } LLPointer::swap(*iter, *target); *target = NULL; ++target; @@ -1651,9 +1679,10 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) mObjects.erase(mObjects.begin()+(mObjects.size()-num_removed), mObjects.end()); mNumDeadObjects -= num_removed; - if (mNumDeadObjects != mDeadObjects.size()) + // TODO(Beq) If this still happens, we ought to realign at this point. Do a full sweep and reset. + if ( mNumDeadObjects != mDeadObjects.size() ) { - LL_WARNS() << "Num dead objects != dead object list size" << LL_ENDL; + LL_WARNS() << "Num dead objects (" << mNumDeadObjects << ") != dead object list size (" << mDeadObjects.size() << "), deadlist discrepancy (" << num_divergent << ")" << LL_ENDL; } // } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index b0f2beeabe..d84649f3f5 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -247,6 +247,9 @@ LLGLSLShader gDeferredFullbrightShinyProgram; LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; LLGLSLShader gDeferredSkinnedFullbrightProgram; LLGLSLShader gNormalMapGenProgram; +// [RLVa:KB] - @setsphere +LLGLSLShader gRlvSphereProgram; +// [/RLVa:KB] // Deferred materials shaders LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; @@ -342,6 +345,9 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredWLCloudProgram); mShaderList.push_back(&gDeferredWLMoonProgram); mShaderList.push_back(&gDeferredWLSunProgram); +// [RLVa:KB] - @setsphere + mShaderList.push_back(&gRlvSphereProgram); +// [/RLVa:KB] } LLViewerShaderMgr::~LLViewerShaderMgr() @@ -4114,6 +4120,9 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() gWLCloudProgram.unload(); gWLSunProgram.unload(); gWLMoonProgram.unload(); +// [RLVa:KB] - @setsphere + gRlvSphereProgram.unload(); +// [/RLVa:KB] return TRUE; } @@ -4147,6 +4156,22 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() success = gWLCloudProgram.createShader(NULL, NULL); } +// [RLVa:KB] - @setsphere + if (success) + { + gRlvSphereProgram.mName = "RLVa Sphere Post Processing Shader"; + gRlvSphereProgram.mShaderFiles.clear(); + gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvV.glsl", GL_VERTEX_SHADER_ARB)); +#ifndef LL_DARWIN + gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvF.glsl", GL_FRAGMENT_SHADER_ARB)); +#else + gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvFMac.glsl", GL_FRAGMENT_SHADER_ARB)); +#endif + gRlvSphereProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT]; + success = gRlvSphereProgram.createShader(NULL, NULL); + } +// [/RLV:KB] + if (success) { gWLSunProgram.mName = "Windlight Sun Program"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 5008873b62..955e8da0b1 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -334,6 +334,9 @@ extern LLGLSLShader gDeferredFullbrightShinyProgram; extern LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; extern LLGLSLShader gDeferredSkinnedFullbrightProgram; extern LLGLSLShader gNormalMapGenProgram; +// [RLVa:KB] - @setsphere +extern LLGLSLShader gRlvSphereProgram; +// [/RLVa:KB] // Deferred materials shaders extern LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index a06f906762..e048947762 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -640,7 +640,11 @@ void send_viewer_stats(bool include_preferences) LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; - if (debugLoggingEnabled("LogViewerStatsPacket")) + // avoid unfortunate sleep during trylock by static check + // if (debugLoggingEnabled("LogViewerStatsPacket")) + static auto debug_logging_on = debugLoggingEnabled("LogViewerStatsPacket"); + if (debug_logging_on) + // { std::string filename("viewer_stats_packet.xml"); llofstream of(filename.c_str()); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3cd7ccd3ee..16611734c2 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1696,6 +1696,8 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mNeedsAux = FALSE; destroyRawImage(); } + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + gTextureList.recalcImageDecodePriority(this); return res; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 88777fbc15..bb85c9054d 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -710,6 +710,8 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy addImageToList(new_image); mUUIDMap[key] = new_image; new_image->setTextureListType(tex_type); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + gTextureList.recalcImageDecodePriority(new_image); } @@ -721,6 +723,9 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) { mCallbackList.erase(image); } + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + mImagesWithChangedPriorities.erase(image); + LLTextureKey key(image->getID(), (ETexListType)image->getTextureListType()); llverify(mUUIDMap.erase(key) == 1); sNumImages--; @@ -855,121 +860,252 @@ void LLViewerTextureList::clearFetchingRequests() } } +// FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) +// NOTE: previous version retained as single block comment, changes extend to the end of updateOneImageDecodePriority +// void LLViewerTextureList::updateImagesDecodePriorities() +// { +// // Update the decode priority for N images each frame +// { +// F32 lazy_flush_timeout = 30.f; // stop decoding +// F32 max_inactive_time = 20.f; // actually delete +// S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + +// //reset imagep->getLastReferencedTimer() when screen is showing the progress view to avoid removing pre-fetched textures too soon. +// bool reset_timer = gViewerWindow->getProgressView()->getVisible(); + +// static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 +// const size_t max_update_count = llmin((S32) (MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); +// S32 update_counter = llmin(max_update_count, mUUIDMap.size()); +// uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); +// while ((update_counter-- > 0) && !mUUIDMap.empty()) +// { +// if (iter == mUUIDMap.end()) +// { +// iter = mUUIDMap.begin(); +// } +// mLastUpdateKey = iter->first; +// LLPointer imagep = iter->second; +// ++iter; // safe to increment now + +// if(imagep->isInDebug() || imagep->isUnremovable()) +// { +// update_counter--; +// continue; //is in debug, ignore. +// } + +// // +// // Flush formatted images using a lazy flush +// // +// S32 num_refs = imagep->getNumRefs(); +// if (num_refs == min_refs) +// { +// if(reset_timer) +// { +// imagep->getLastReferencedTimer()->reset(); +// } +// else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) +// { +// // Remove the unused image from the image list +// deleteImage(imagep); +// imagep = NULL; // should destroy the image +// } +// continue; +// } +// else +// { +// if(imagep->hasSavedRawImage()) +// { +// if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) +// { +// imagep->destroySavedRawImage() ; +// } +// } + +// if(imagep->isDeleted()) +// { +// continue ; +// } +// else if(imagep->isDeletionCandidate()) +// { +// imagep->destroyTexture() ; +// continue ; +// } +// else if(imagep->isInactive()) +// { +// if(reset_timer) +// { +// imagep->getLastReferencedTimer()->reset(); +// } +// else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) +// { +// imagep->setDeletionCandidate() ; +// } +// continue ; +// } +// else +// { +// imagep->getLastReferencedTimer()->reset(); + +// //reset texture state. +// imagep->setInactive() ; +// } +// } + +// if (!imagep->isInImageList()) +// { +// continue; +// } +// if(imagep->isInFastCacheList()) +// { +// continue; //wait for loading from the fast cache. +// } + +// imagep->processTextureStats(); +// F32 old_priority = imagep->getDecodePriority(); +// F32 old_priority_test = llmax(old_priority, 0.0f); +// F32 decode_priority = imagep->calcDecodePriority(); +// F32 decode_priority_test = llmax(decode_priority, 0.0f); +// // Ignore < 20% difference +// if ((decode_priority_test < old_priority_test * .8f) || +// (decode_priority_test > old_priority_test * 1.25f)) +// { +// mImageList.erase(imagep) ; +// imagep->setDecodePriority(decode_priority); +// mImageList.insert(imagep); +// } +// } +// } +// } + +void LLViewerTextureList::recalcImageDecodePriority(LLPointer image) +{ + mImagesWithChangedPriorities.insert(image); +} + void LLViewerTextureList::updateImagesDecodePriorities() { // Update the decode priority for N images each frame + static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 + const size_t max_update_count = llmin((S32)(MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); + S32 update_counter = llmin(max_update_count, (mImagesWithChangedPriorities.size() + mUUIDMap.size())); + + // First, process images whose decode priorities may have changed recently + image_list_t::iterator iter2 = mImagesWithChangedPriorities.begin(); + while ((update_counter-- > 0) && (iter2 != mImagesWithChangedPriorities.end())) { - F32 lazy_flush_timeout = 30.f; // stop decoding - F32 max_inactive_time = 20.f; // actually delete - S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + LLPointer imagep = *iter2; + iter2 = mImagesWithChangedPriorities.erase(iter2); + updateOneImageDecodePriority(imagep); + } - //reset imagep->getLastReferencedTimer() when screen is showing the progress view to avoid removing pre-fetched textures too soon. - bool reset_timer = gViewerWindow->getProgressView()->getVisible(); - - static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 - const size_t max_update_count = llmin((S32) (MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); - S32 update_counter = llmin(max_update_count, mUUIDMap.size()); - uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); - while ((update_counter-- > 0) && !mUUIDMap.empty()) + // Second, process all of the images + uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); + while ((update_counter-- > 0) && !mUUIDMap.empty()) + { + if (iter == mUUIDMap.end()) { - if (iter == mUUIDMap.end()) - { - iter = mUUIDMap.begin(); - } - mLastUpdateKey = iter->first; - LLPointer imagep = iter->second; - ++iter; // safe to increment now - - if(imagep->isInDebug() || imagep->isUnremovable()) - { - update_counter--; - continue; //is in debug, ignore. - } - - // - // Flush formatted images using a lazy flush - // - S32 num_refs = imagep->getNumRefs(); - if (num_refs == min_refs) - { - if(reset_timer) - { - imagep->getLastReferencedTimer()->reset(); - } - else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) - { - // Remove the unused image from the image list - deleteImage(imagep); - imagep = NULL; // should destroy the image - } - continue; - } - else - { - if(imagep->hasSavedRawImage()) - { - if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) - { - imagep->destroySavedRawImage() ; - } - } - - if(imagep->isDeleted()) - { - continue ; - } - else if(imagep->isDeletionCandidate()) - { - imagep->destroyTexture() ; - continue ; - } - else if(imagep->isInactive()) - { - if(reset_timer) - { - imagep->getLastReferencedTimer()->reset(); - } - else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) - { - imagep->setDeletionCandidate() ; - } - continue ; - } - else - { - imagep->getLastReferencedTimer()->reset(); - - //reset texture state. - imagep->setInactive() ; - } - } - - if (!imagep->isInImageList()) - { - continue; - } - if(imagep->isInFastCacheList()) - { - continue; //wait for loading from the fast cache. - } - - imagep->processTextureStats(); - F32 old_priority = imagep->getDecodePriority(); - F32 old_priority_test = llmax(old_priority, 0.0f); - F32 decode_priority = imagep->calcDecodePriority(); - F32 decode_priority_test = llmax(decode_priority, 0.0f); - // Ignore < 20% difference - if ((decode_priority_test < old_priority_test * .8f) || - (decode_priority_test > old_priority_test * 1.25f)) - { - mImageList.erase(imagep) ; - imagep->setDecodePriority(decode_priority); - mImageList.insert(imagep); - } + iter = mUUIDMap.begin(); } + mLastUpdateKey = iter->first; + LLPointer imagep = iter->second; + ++iter; // safe to increment now + updateOneImageDecodePriority(imagep); } } +void LLViewerTextureList::updateOneImageDecodePriority(LLPointer imagep) +{ + const F32 lazy_flush_timeout = 30.f; // stop decoding + const F32 max_inactive_time = 20.f; // actually delete + const S32 min_refs = 4; // 1 for mImageList, 1 for mUUIDMap, 2 for local references + + bool reset_timer = gViewerWindow->getProgressView()->getVisible(); + + if(imagep->isInDebug() || imagep->isUnremovable()) + { + return; //is in debug, ignore. + } + // + // Flush formatted images using a lazy flush + // + S32 num_refs = imagep->getNumRefs(); + if (num_refs == min_refs) + { + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) + { + // Remove the unused image from the image list + deleteImage(imagep); + imagep = NULL; // should destroy the image + } + return; + } + else + { + if(imagep->hasSavedRawImage()) + { + if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) + { + imagep->destroySavedRawImage() ; + } + } + + if(imagep->isDeleted()) + { + return; + } + else if(imagep->isDeletionCandidate()) + { + imagep->destroyTexture() ; + return; + } + else if(imagep->isInactive()) + { + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) + { + imagep->setDeletionCandidate() ; + } + return; + } + else + { + imagep->getLastReferencedTimer()->reset(); + //reset texture state. + imagep->setInactive() ; + } + } + if (!imagep->isInImageList()) + { + return; + } + if(imagep->isInFastCacheList()) + { + return; //wait for loading from the fast cache. + } + + imagep->processTextureStats(); + F32 old_priority = imagep->getDecodePriority(); + F32 old_priority_test = llmax(old_priority, 0.0f); + F32 decode_priority = imagep->calcDecodePriority(); + F32 decode_priority_test = llmax(decode_priority, 0.0f); + // Ignore < 20% difference + if ((decode_priority_test < old_priority_test * .8f) || + (decode_priority_test > old_priority_test * 1.25f)) + { + mImageList.erase(imagep) ; + imagep->setDecodePriority(decode_priority); + mImageList.insert(imagep); + } +} +// FIRE-30559 + void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level) { if(!tex->setDebugFetching(debug_level)) diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 6feae4d897..ca26883763 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -34,6 +34,7 @@ #include "llui.h" #include #include +#include #include "lluiimage.h" const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128; @@ -147,6 +148,8 @@ public: private: void updateImagesDecodePriorities(); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + void updateOneImageDecodePriority(LLPointer imagep); F32 updateImagesCreateTextures(F32 max_time); F32 updateImagesFetchTextures(F32 max_time); void updateImagesUpdateStats(); @@ -219,7 +222,12 @@ public: // Fast cache stats static U32 sNumFastCacheReads; - + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // Recalculate the image's Decode Priority. + // (We'll get to the image eventually even if this method isn't called, but this way it goes + // to the head(-ish) of the line.) + void recalcImageDecodePriority(LLPointer image); + // private: typedef std::map< LLTextureKey, LLPointer > uuid_map_t; uuid_map_t mUUIDMap; @@ -228,7 +236,11 @@ private: typedef std::set, LLViewerFetchedTexture::Compare> image_priority_list_t; image_priority_list_t mImageList; - + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // Images that should be handled first in updateImagesDecodePriorities() + image_list_t mImagesWithChangedPriorities; + // + // simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon std::set > mImagePreloads; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1ef53c5db2..751df0582d 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -229,6 +229,8 @@ #include "llviewermenufile.h" // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) +#include "rlvactions.h" +#include "rlveffects.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -489,6 +491,15 @@ public: camera_view_text = llformat("CameraAtAxis %f %f %f", (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); +// [RLVa:KB] - @showloc + if (!RlvActions::canShowLocation()) + { + agent_center_text = RlvStrings::getString(RlvStringKeys::Hidden::Generic); + agent_root_center_text = RlvStrings::getString(RlvStringKeys::Hidden::Generic); + camera_center_text = RlvStrings::getString(RlvStringKeys::Hidden::Generic); + } +// [/RLVa:KB] + addText(xpos, ypos, agent_center_text); ypos += y_inc; addText(xpos, ypos, agent_root_center_text); ypos += y_inc; addText(xpos, ypos, agent_view_text); ypos += y_inc; @@ -5928,7 +5939,10 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei if ((image_width <= gGLManager.mGLMaxTextureSize && image_height <= gGLManager.mGLMaxTextureSize) && (image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui) { - U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; + // FIRE-15667: 24bit depth maps + //U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; + U32 color_fmt = (type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH || type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH24) ? GL_DEPTH_COMPONENT : GL_RGBA; + // if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) { original_width = gPipeline.mDeferredScreen.getWidth(); @@ -7011,11 +7025,12 @@ void LLPickInfo::fetchResults() mPickPt = mMousePt; // [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) - if ( (gRlvHandler.isEnabled()) && (hit_object) && (!hit_object->isHUDAttachment()) ) + if ( (RlvActions::hasBehaviour(RLV_BHVR_SETOVERLAY)) && (hit_object) && (!hit_object->isHUDAttachment()) ) { - if (gRlvHandler.hitTestOverlay(mMousePt)) + if (auto* pOverlayEffect = LLVfxManager::instance().getEffect(EVisualEffect::RlvOverlay)) { - hit_object = nullptr; + if (pOverlayEffect->hitTest(mMousePt)) + hit_object = nullptr; } } // [/RLVa:KB] diff --git a/indra/newview/llvisualeffect.cpp b/indra/newview/llvisualeffect.cpp new file mode 100644 index 0000000000..af68a57413 --- /dev/null +++ b/indra/newview/llvisualeffect.cpp @@ -0,0 +1,140 @@ +/** + * + * Copyright (c) 2021, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" + +#include "llvisualeffect.h" + +#include +#include + +// ============================================================================ +// LLTweenableValue class +// + +template<> +float LLTweenableValueLerp::get() +{ + if (!m_CurValue) + { + float curFactor = (LLTimer::getElapsedSeconds() - m_StartTime) / m_Duration; + if (curFactor < 1.0) + return lerp(m_StartValue, m_EndValue, curFactor); + m_CurValue = m_EndValue; + } + return m_CurValue.get(); +} + +template<> +LLColor3 LLTweenableValueLerp::get() +{ + if (!m_CurValue) + { + float curFactor = (LLTimer::getElapsedSeconds() - m_StartTime) / m_Duration; + if (curFactor < 1.0) + return lerp(m_StartValue, m_EndValue, curFactor); + m_CurValue = m_EndValue; + } + return m_CurValue.get(); +} + +template<> +LLVector4 LLTweenableValueLerp::get() +{ + if (!m_CurValue) + { + float curFactor = (LLTimer::getElapsedSeconds() - m_StartTime) / m_Duration; + if (curFactor < 1.0) + return lerp(m_StartValue, m_EndValue, curFactor); + m_CurValue = m_EndValue; + } + return m_CurValue.get(); +} + +// ============================================================================ +// LLVfxManager class +// + +LLVfxManager::LLVfxManager() +{ + +} + +bool LLVfxManager::addEffect(LLVisualEffect* pEffectInst) +{ + if (m_Effects.end() != m_Effects.find(pEffectInst)) + return false; + + m_Effects.insert(pEffectInst); + + return true; +} + +LLVisualEffect* LLVfxManager::getEffect(const LLUUID& idEffect) const +{ + auto itEffect = std::find_if(m_Effects.begin(), m_Effects.end(), [&idEffect](const LLVisualEffect* pEffect) { return pEffect->getId() == idEffect; }); + return (m_Effects.end() != itEffect) ? *itEffect : nullptr; +} + +LLVisualEffect* LLVfxManager::getEffect(EVisualEffect eCode) const +{ + // NOTE: returns the first found but there could be more + auto itEffect = std::find_if(m_Effects.begin(), m_Effects.end(), [eCode](const LLVisualEffect* pEffect) { return pEffect->getCode() == eCode; }); + return (m_Effects.end() != itEffect) ? *itEffect : nullptr; +} + +bool LLVfxManager::removeEffect(const LLUUID& idEffect) +{ + auto itEffect = std::find_if(m_Effects.begin(), m_Effects.end(), [&idEffect](const LLVisualEffect* pEffect) { return pEffect->getId() == idEffect; }); + if (m_Effects.end() == itEffect) + return false; + + delete *itEffect; + m_Effects.erase(itEffect); + return true; +} + +void LLVfxManager::runEffect(EVisualEffect eCode, LLVisualEffectParams* pParams) +{ + // *TODO-Catz: once we're done, check whether iterating over the entire list still has negliable impact + auto pred = [eCode](const LLVisualEffect* pEffect) { return pEffect->getCode() == eCode; }; + + auto itEffect = boost::make_filter_iterator(pred, m_Effects.begin(), m_Effects.end()), + endEffect = boost::make_filter_iterator(pred, m_Effects.end(), m_Effects.end()); + for (; itEffect != endEffect; ++itEffect) + { + if (pParams) + pParams->step(itEffect == endEffect); + (*itEffect)->run(pParams); + } +} + +void LLVfxManager::runEffect(EVisualEffectType eType, LLVisualEffectParams* pParams) +{ + // *TODO-Catz: once we're done, check whether iterating over the entire list still has negliable impact + auto pred = [eType](const LLVisualEffect* pEffect) { return pEffect->getType() == eType; }; + + auto itEffect = boost::make_filter_iterator(pred, m_Effects.begin(), m_Effects.end()), + endEffect = boost::make_filter_iterator(pred, m_Effects.end(), m_Effects.end()); + for (; itEffect != endEffect; ++itEffect) + { + if (pParams) + pParams->step(itEffect == endEffect); + (*itEffect)->run(pParams); + } +} + +// ============================================================================ diff --git a/indra/newview/llvisualeffect.h b/indra/newview/llvisualeffect.h new file mode 100644 index 0000000000..41d10bda90 --- /dev/null +++ b/indra/newview/llvisualeffect.h @@ -0,0 +1,179 @@ +/** + * + * Copyright (c) 2021, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#pragma once + +#include "llsingleton.h" +#include +#include + +// ============================================================================ +// +// + +class LLRenderTarget; + +// ============================================================================ +// +// + +enum class EVisualEffect +{ + RlvOverlay, + RlvSphere, +}; + +enum class EVisualEffectType +{ + PostProcessShader, + Custom, +}; + +// ============================================================================ +// +// + +struct LLVisualEffectParams +{ + virtual void step(bool isLast) = 0; +}; + +struct LLShaderEffectParams : LLVisualEffectParams +{ + explicit LLShaderEffectParams(LLRenderTarget* pSrcBuffer, LLRenderTarget* pScratchBuffer, bool fBindLast) : m_pSrcBuffer(pScratchBuffer), m_pDstBuffer(pSrcBuffer), m_fBindLast(fBindLast) {} + + void step(bool isLast) override + { + LLRenderTarget* pPrevSrc = m_pSrcBuffer, *pPrevDst = m_pDstBuffer; + m_pSrcBuffer = pPrevDst; + m_pDstBuffer = (!isLast || !m_fBindLast) ? pPrevSrc : nullptr; + } + + LLRenderTarget* m_pSrcBuffer = nullptr; + LLRenderTarget* m_pDstBuffer = nullptr; + bool m_fBindLast = false; +}; + +// ============================================================================ +// +// + +class LLVisualEffect +{ +public: + LLVisualEffect(LLUUID id, EVisualEffect eCode, EVisualEffectType eType) + : m_id(id), m_eCode(eCode), m_eType(eType) + {} + virtual ~LLVisualEffect() {} + + EVisualEffect getCode() const { return m_eCode;} + const LLUUID& getId() const { return m_id;} + U32 getPriority() const { return m_nPriority; } + EVisualEffectType getType() const { return m_eType;} + + virtual void run(const LLVisualEffectParams* pParams) = 0; + + /* + * Member variables + */ +protected: + LLUUID m_id; + EVisualEffect m_eCode; + EVisualEffectType m_eType; + U32 m_nPriority; +}; + +// ============================================================================ +// +// + +template +class LLTweenableValue +{ +public: + LLTweenableValue(const T& defaultValue) : m_CurValue(defaultValue) {} + virtual ~LLTweenableValue() {} + + virtual T get() = 0; + virtual void start(const T& endValue, double duration) = 0; + + T& operator =(const T& value) { m_CurValue = value; } + + /* + * Member variables + */ +protected: + boost::optional m_CurValue; +}; + +template +class LLTweenableValueLerp : public LLTweenableValue +{ +public: + LLTweenableValueLerp(const T& defaultValue) : LLTweenableValue(defaultValue) {} + T get() override; + void start(const T& endValue, double duration) override + { + m_StartValue = get(); + this->m_CurValue = boost::none; + m_EndValue = endValue; + + m_StartTime = LLTimer::getElapsedSeconds(); + m_Duration = duration; + } + + /* + * Member variables + */ +protected: + double m_StartTime; + double m_Duration; + T m_StartValue; + T m_EndValue; +}; + +// ============================================================================ +// +// + +class LLVfxManager : public LLSingleton +{ + LLSINGLETON(LLVfxManager); +protected: + ~LLVfxManager() {} + + /* + * Member functions + */ +public: + bool addEffect(LLVisualEffect* pEffectInst); + LLVisualEffect* getEffect(const LLUUID& idEffect) const; + template T* getEffect(const LLUUID& idEffect) const { return dynamic_cast(getEffect(idEffect)); } + LLVisualEffect* getEffect(EVisualEffect eCode) const; + template T* getEffect(EVisualEffect eCode) const { return dynamic_cast(getEffect(eCode)); } + bool removeEffect(const LLUUID& idEffect); + void runEffect(EVisualEffect eCode, LLVisualEffectParams* pParams = nullptr); + void runEffect(EVisualEffectType eType, LLVisualEffectParams* pParams = nullptr); +protected: + + /* + * Member variables + */ +protected: + std::set m_Effects; +}; + +// ============================================================================ diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9ea5cfef74..f6c836c17e 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -131,6 +131,7 @@ #include "llviewernetwork.h" // [FS:CR] isInSecondlife() #include "llsidepanelappearance.h" #include "fsavatarrenderpersistence.h" +#include "fslslbridge.h" // Movelock position refresh #include "fsdiscordconnect.h" // tapping a place that happens on landing in world to start up discord @@ -3320,7 +3321,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) bool fRlvShowAvTag = true, fRlvShowAvName = true; if (RlvActions::isRlvEnabled()) { - fRlvShowAvTag = RlvActions::canShowName(RlvActions::SNC_NAMETAG, getID()); + fRlvShowAvTag = RlvActions::canShowNameTag(this); fRlvShowAvName = (fRlvShowAvTag) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID())); } // [/RLVa:KB] @@ -8235,6 +8236,13 @@ void LLVOAvatar::sitDown(BOOL bSitting) gRlvHandler.onSitOrStand(bSitting); } // [/RLVa:KB] + + // Refresh movelock position after sitting down to prevent pulling avatar back to previous one after standing up + if (bSitting && gSavedPerAccountSettings.getBOOL("UseMoveLock") && gSavedPerAccountSettings.getBOOL("RelockMoveLockAfterMovement")) + { + FSLSLBridge::instance().viewerToLSL("UseMoveLock|1|noreport"); + } + // } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 06225f21c1..7c4b5a3afc 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -115,6 +115,7 @@ #include "llprogressview.h" #include "llcleanup.h" // [RLVa:KB] - Checked: RLVa-2.0.0 +#include "llvisualeffect.h" #include "rlvactions.h" #include "rlvlocks.h" // [/RLVa:KB] @@ -376,6 +377,9 @@ bool LLPipeline::sRenderParticles; // flag to hold correct, user selecte // [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) bool LLPipeline::sRenderTextures = true; // [/SL:KB] +// [RLVa:KB] - @setsphere +bool LLPipeline::sUseDepthTexture = false; +// [/RLVa:KB] // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; @@ -1055,8 +1059,22 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mFXAABuffer.release(); mScreen.release(); mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first - mDeferredDepth.release(); - mOcclusionDepth.release(); +// [RLVa:KB] - @setsphere + if (!LLRenderTarget::sUseFBO || !LLPipeline::sUseDepthTexture) + { + mDeferredDepth.release(); + mOcclusionDepth.release(); + } + else + { + const U32 occlusion_divisor = 3; + if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!mOcclusionDepth.allocate(resX / occlusion_divisor, resY / occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (RlvActions::isRlvEnabled() && !mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + } +// [/RLVa:KB] +// mDeferredDepth.release(); +// mOcclusionDepth.release(); if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; } @@ -4591,7 +4609,17 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); LLGLSLShader::bindNoShader(); - doOcclusion(camera); +// [RLVa:KB] - @setsphere + if (LLPipeline::RenderDeferred || !LLRenderTarget::sUseFBO || !LLPipeline::sUseDepthTexture) + { + doOcclusion(camera); + } + else + { + doOcclusion(camera, mScreen, mOcclusionDepth, &mDeferredDepth); + } +// [/RLVa:KB] +// doOcclusion(camera); } pool_set_t::iterator iter2 = iter1; @@ -7898,6 +7926,9 @@ void LLPipeline::renderFinalize() LLVertexBuffer::unbind(); +// [RLVa:KB] - @setsphere + LLRenderTarget* pRenderBuffer = (RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE)) ? &mDeferredLight : nullptr; +// [/RLVa:KB] if (LLPipeline::sRenderDeferred) { @@ -7910,6 +7941,12 @@ void LLPipeline::renderFinalize() bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); exoPostProcess::instance().multisample = multisample; // Import Vignette from Exodus +// [RLVa:KB] - @setsphere + if (multisample && !pRenderBuffer) + { + pRenderBuffer = &mDeferredLight; + } +// [/RLVa:KB] gViewerWindow->setup3DViewport(); @@ -8108,11 +8145,18 @@ void LLPipeline::renderFinalize() } { // combine result based on alpha - if (multisample) +// if (multisample) +// { +// mDeferredLight.bindTarget(); +// glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); +// } +// [RLVa:KB] - @setsphere + if (pRenderBuffer) { - mDeferredLight.bindTarget(); + pRenderBuffer->bindTarget(); glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); } +// [/RLVa:KB] else { gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; @@ -8153,18 +8197,30 @@ void LLPipeline::renderFinalize() unbindDeferredShader(*shader); - if (multisample) +// [RLVa:KB] - @setsphere + if (pRenderBuffer) { - mDeferredLight.flush(); + pRenderBuffer->flush(); } +// [/RLVa:KB] +// if (multisample) +// { +// mDeferredLight.flush(); +// } } } else { - if (multisample) +// if (multisample) +// { +// mDeferredLight.bindTarget(); +// } +// [RLVa:KB] - @setsphere + if (pRenderBuffer) { - mDeferredLight.bindTarget(); + pRenderBuffer->bindTarget(); } +// [/RLVa:KB] LLGLSLShader *shader = &gDeferredPostNoDoFProgram; bindDeferredShader(*shader); @@ -8192,12 +8248,27 @@ void LLPipeline::renderFinalize() unbindDeferredShader(*shader); - if (multisample) +// [RLVa:KB] - @setsphere + if (pRenderBuffer) { - mDeferredLight.flush(); + pRenderBuffer->flush(); } +// [/RLVa:KB] +// if (multisample) +// { +// mDeferredLight.flush(); +// } } +// [RLVa:KB] - @setsphere + if (RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE)) + { + LLShaderEffectParams params(pRenderBuffer, &mScreen, !multisample); + LLVfxManager::instance().runEffect(EVisualEffect::RlvSphere, ¶ms); + pRenderBuffer = params.m_pDstBuffer; + } +// [/RLVa:KB] + if (multisample) { // bake out texture2D with RGBL for FXAA shader @@ -8212,11 +8283,18 @@ void LLPipeline::renderFinalize() shader->bind(); shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); +// S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); +// if (channel > -1) +// { +// mDeferredLight.bindTexture(0, channel); +// } +// [RLVa:KB] - @setsphere + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, pRenderBuffer->getUsage()); if (channel > -1) { - mDeferredLight.bindTexture(0, channel); + pRenderBuffer->bindTexture(0, channel); } +// [RLVa:KB] // FIRE-16829: Visual Artifacts with ALM enabled on AMD graphics //gGL.begin(LLRender::TRIANGLE_STRIP); @@ -8229,7 +8307,10 @@ void LLPipeline::renderFinalize() drawAuxiliaryVB(); // - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); +// [RLVa:KB] - @setsphere + shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, pRenderBuffer->getUsage()); +// [/RLVa:KB] +// shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); shader->unbind(); mFXAABuffer.flush(); @@ -8273,6 +8354,15 @@ void LLPipeline::renderFinalize() } else // not deferred { +// [RLVa:KB] - @setsphere + if (RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE)) + { + LLShaderEffectParams params(&mScreen, &mDeferredLight, false); + LLVfxManager::instance().runEffect(EVisualEffect::RlvSphere, ¶ms); + pRenderBuffer = params.m_pDstBuffer; + } +// [/RLVa:KB] + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; LLPointer buff = new LLVertexBuffer(mask, 0); buff->allocateBuffer(3, 0, TRUE); @@ -8315,7 +8405,10 @@ void LLPipeline::renderFinalize() } gGL.getTexUnit(0)->bind(&mGlow[1]); - gGL.getTexUnit(1)->bind(&mScreen); +// [RLVa:KB] - @setsphere + gGL.getTexUnit(1)->bind( pRenderBuffer ? pRenderBuffer : &mScreen ); +// [/RLVa:KB] +// gGL.getTexUnit(1)->bind(&mScreen); LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 75e2410147..570ed5e6a9 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -622,6 +622,9 @@ public: // [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) static bool sRenderTextures; // [/SL:KB] +// [RLVa:KB] - @setsphere + static bool sUseDepthTexture; +// [/RLVa:KB] static LLTrace::EventStatHandle sStatBatchSize; diff --git a/indra/newview/quickprefs.cpp b/indra/newview/quickprefs.cpp index b9d272ec4f..9ad3f15a62 100644 --- a/indra/newview/quickprefs.cpp +++ b/indra/newview/quickprefs.cpp @@ -616,7 +616,7 @@ BOOL FloaterQuickPrefs::postBuild() if (gRlvHandler.isEnabled()) { - enableWindlightButtons(!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)); + enableWindlightButtons(!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV) && !gRlvHandler.hasBehaviour(RLV_BHVR_SETSPHERE)); } // Dynamic quick prefs @@ -1026,7 +1026,7 @@ void FloaterQuickPrefs::refreshSettings() BOOL reflections = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps; mCtrlReflectionDetail->setEnabled(reflections); - mCtrlWindLight->setEnabled((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ); + mCtrlWindLight->setEnabled((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV) && !gRlvHandler.hasBehaviour(RLV_BHVR_SETSPHERE)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ); LLTextBox* sky_label = getChild("T_Sky_Detail"); LLSlider* sky_slider = getChild("SB_Sky_Detail"); @@ -1170,7 +1170,7 @@ void FloaterQuickPrefs::refreshSettings() void FloaterQuickPrefs::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) { - if (behavior == RLV_BHVR_SETENV) + if (behavior == RLV_BHVR_SETENV || behavior == RLV_BHVR_SETSPHERE) { enableWindlightButtons(type != RLV_TYPE_ADD); } diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp index fd77515434..690250c164 100644 --- a/indra/newview/rlvactions.cpp +++ b/indra/newview/rlvactions.cpp @@ -220,9 +220,6 @@ bool RlvActions::canShowName(EShowNamesContext eContext, const LLUUID& idAgent) { switch (eContext) { - // Show/hide avatar nametag - case SNC_NAMETAG: - return (gRlvHandler.isException(RLV_BHVR_SHOWNAMETAGS, idAgent)) || (gAgentID == idAgent); // Show/hide avatar name case SNC_DEFAULT: case SNC_TELEPORTOFFER: @@ -235,6 +232,19 @@ bool RlvActions::canShowName(EShowNamesContext eContext, const LLUUID& idAgent) return false; } +bool RlvActions::canShowNameTag(const LLVOAvatar* pAvatar) +{ + // An avatar's name tag can be shown if: + // - not restricted from seeing avatars' name tags + // - OR the avatar is a @shownametags exception + // - OR the avatar is within the distance that nametags can be shown + if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) || (gRlvHandler.isException(RLV_BHVR_SHOWNAMETAGS, pAvatar->getID())) || (gAgentID == pAvatar->getID()) ) + return true; + + const F32 nShowNameTagsDist = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SHOWNAMETAGSDIST)->getValue(); + return (nShowNameTagsDist != 0.f) && (dist_vec_squared(pAvatar->getPositionGlobal(), gAgent.getPositionGlobal()) < nShowNameTagsDist * nShowNameTagsDist); +} + bool RlvActions::canShowNearbyAgents() { return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNEARBY); @@ -586,6 +596,28 @@ bool RlvActions::canShowLocation() return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); } +// ============================================================================ +// World (General) +// + +bool RlvActions::canHighlightTransparent() +{ + // User cannot highlight transparent faces if: + // - prevented from editing (exceptions are not taken into account) + // - specifically prevented from highlight transparent faces + return !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +} + +bool RlvActions::canViewWireframe() +{ + // User can use wireframe rendering if: + // - no HUD attachment is (remove) locked + // - not specifically prevented from using wireframe mode + return + !gRlvAttachmentLocks.hasLockedHUD() && // Trivial function so no overhead when RLV is not enabled + !gRlvHandler.hasBehaviour(RLV_BHVR_VIEWWIREFRAME); +} + // ============================================================================ // Helper functions // diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h index c1f2f46ec8..39fd2beac7 100644 --- a/indra/newview/rlvactions.h +++ b/indra/newview/rlvactions.h @@ -28,6 +28,7 @@ class LLInventoryCategory; class LLInventoryItem; class LLViewerObject; +class LLVOAvatar; // ============================================================================ // RlvActions class declaration - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible @@ -124,8 +125,9 @@ public: * (This is used to hide an avatar name in one case but not a near-identical case - such as teleporting a friend vs a nearby agent - * in a way that limits the amount of code that needs to be changed to carry context from one function to another) */ - enum EShowNamesContext { SNC_DEFAULT = 0, SNC_NAMETAG, SNC_TELEPORTOFFER, SNC_TELEPORTREQUEST, SNC_COUNT }; + enum EShowNamesContext { SNC_DEFAULT = 0, SNC_TELEPORTOFFER, SNC_TELEPORTREQUEST, SNC_COUNT }; static bool canShowName(EShowNamesContext eContext, const LLUUID& idAgent = LLUUID::null); + static bool canShowNameTag(const LLVOAvatar* pAvatar); static void setShowName(EShowNamesContext eContext, bool fCanShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fCanShowName; } } /* @@ -301,6 +303,20 @@ public: */ static bool canTouch(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero); + // =============== + // World (General) + // =============== +public: + /* + * Returns true if the user can highlight transparent faces + */ + static bool canHighlightTransparent(); + + /* + * Returns true if the user can switch to wireframe rendering + */ + static bool canViewWireframe(); + // ================ // Helper functions // ================ diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index 6c37fa9d78..9b33285368 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -405,6 +405,8 @@ const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet) return "deprecated and disabled"; case RLV_RET_FAILED_NOBEHAVIOUR: return "no active behaviours"; + case RLV_RET_FAILED_UNHELDBEHAVIOUR: + return "base behaviour not held"; case RLV_RET_FAILED_BLOCKED: return "blocked object"; case RLV_RET_FAILED_THROTTLED: diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index 0dc9e0e3c4..a9fb8d6ce7 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -56,7 +56,7 @@ class RlvObject; struct RlvException; typedef boost::variant RlvExceptionOption; -typedef boost::variant RlvBehaviourModifierValue; +typedef boost::variant RlvBehaviourModifierValue; class RlvGCTimer; diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 2ae7d82b56..ceefa1c25a 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -26,19 +26,19 @@ // Version of the specifcation we report const S32 RLV_VERSION_MAJOR = 3; -const S32 RLV_VERSION_MINOR = 3; +const S32 RLV_VERSION_MINOR = 4; const S32 RLV_VERSION_PATCH = 3; const S32 RLV_VERSION_BUILD = 0; // Version of the specifcation we report (in compatibility mode) const S32 RLV_VERSION_MAJOR_COMPAT = 2; -const S32 RLV_VERSION_MINOR_COMPAT = 8; -const S32 RLV_VERSION_PATCH_COMPAT = 0; +const S32 RLV_VERSION_MINOR_COMPAT = 9; +const S32 RLV_VERSION_PATCH_COMPAT = 28; const S32 RLV_VERSION_BUILD_COMPAT = 0; // Implementation version const S32 RLVa_VERSION_MAJOR = 2; -const S32 RLVa_VERSION_MINOR = 3; +const S32 RLVa_VERSION_MINOR = 4; const S32 RLVa_VERSION_PATCH = 0; const S32 RLVa_IMPL_ID = 13; @@ -157,6 +157,8 @@ enum ERlvBehaviour { RLV_BHVR_BUY, // "buy" RLV_BHVR_EDIT, // "edit" RLV_BHVR_EDITOBJ, // "editobj" + RLV_BHVR_VIEWTRANSPARENT, + RLV_BHVR_VIEWWIREFRAME, RLV_BHVR_PAY, // "pay" RLV_BHVR_REZ, // "rez" RLV_BHVR_FARTOUCH, // "fartouch" @@ -243,12 +245,9 @@ enum ERlvBehaviour { // Camera (force) RLV_BHVR_SETCAM_MODE, // Switch the user's camera into the specified mode (e.g. mouselook or thirdview) - // Overlay + // Effects + RLV_BHVR_SETSPHERE, // Gives an object exclusive control of the 'vision spheres' effect RLV_BHVR_SETOVERLAY, // Gives an object exclusive control of the overlay - RLV_BHVR_SETOVERLAY_ALPHA, // Changes the overlay texture's transparency level - RLV_BHVR_SETOVERLAY_TEXTURE, // Changes the overlay texture - RLV_BHVR_SETOVERLAY_TINT, // Changes the tint that's applied to the overlay texture - RLV_BHVR_SETOVERLAY_TOUCH, // Block world interaction (=touching) based on the alpha channel of the overlay texture RLV_BHVR_SETOVERLAY_TWEEN, // Animate between the current overlay settings and the supplied values RLV_BHVR_COUNT, @@ -258,10 +257,6 @@ enum ERlvBehaviour { enum ERlvBehaviourModifier { RLV_MODIFIER_FARTOUCHDIST, // Radius of a sphere around the user in which they can interact with the world - RLV_MODIFIER_OVERLAY_ALPHA, // Transparency level of the overlay texture (in addition to the texture's own alpha channel) - RLV_MODIFIER_OVERLAY_TEXTURE, // Specifies the UUID of the overlay texture - RLV_MODIFIER_OVERLAY_TINT, // The tint that's applied to the overlay texture - RLV_MODIFIER_OVERLAY_TOUCH, // Determines whether the overlay texture's alpha channel will be used to allow/block world interaction RLV_MODIFIER_RECVIMDISTMIN, // Minimum distance to receive an IM from an otherwise restricted sender (squared value) RLV_MODIFIER_RECVIMDISTMAX, // Maximum distance to receive an IM from an otherwise restricted sender (squared value) RLV_MODIFIER_SENDIMDISTMIN, // Minimum distance to send an IM to an otherwise restricted recipient (squared value) @@ -279,6 +274,7 @@ enum ERlvBehaviourModifier RLV_MODIFIER_SETCAM_FOVMIN, // Minimum value for the camera's field of view (angle in radians) RLV_MODIFIER_SETCAM_FOVMAX, // Maximum value for the camera's field of view (angle in radians) RLV_MODIFIER_SETCAM_TEXTURE, // Specifies the UUID of the texture used to texture the world view + RLV_MODIFIER_SHOWNAMETAGSDIST, // Distance at which name tags will still be shown RLV_MODIFIER_SITTPDIST, RLV_MODIFIER_TPLOCALDIST, @@ -286,6 +282,28 @@ enum ERlvBehaviourModifier RLV_MODIFIER_UNKNOWN }; +enum class ERlvLocalBhvrModifier +{ + // @setoverlay + OverlayAlpha, // Transparency level of the overlay texture (in addition to the texture's own alpha channel) + OverlayTexture, // Specifies the UUID of the overlay texture + OverlayTint, // The tint that's applied to the overlay texture + OverlayTouch, // Determines whether the overlay texture's alpha channel will be used to allow/block world interaction + // @setsphere + SphereMode, // The type of effect that will apply to any pixel that intersects with the sphere (e.g. blend, blur, ...) + SphereOrigin, // The origin of the sphere can either be the avatar or the camera position + SphereColor, // [Blend only] Colour to mix with the actual pixel colour (stored as params) + SphereParams, // Effect parameters (dependent on mode - see RlvSphereEffect) + SphereDistMin, // Distance at which the effect starts and has weight minValue; e.g. for blend this would be colour = mix(colour, sphere_colour, min_alpha) + SphereDistMax, // Distance at which the effect starts and has weight maxValue; e.g. for blend this would be colour = mix(colour, sphere_colour, max_alpha) + SphereDistExtend, // Specifies the value beyond min dist or max dist (by default the sphere extends beyond max distance at max vlaue) + SphereValueMin, // Value of the effect at minimum distance + SphereValueMax, // Value of the effect at maximum distance + SphereTween, // Amount of seconds it takes to lerp from value A to value B + + Unknown, +}; + enum ERlvBehaviourOptionType { RLV_OPTION_NONE, // Behaviour takes no parameters @@ -323,6 +341,7 @@ enum ERlvCmdRet { RLV_RET_FAILED_NOSHAREDROOT, // Command failed (missing #RLV) RLV_RET_FAILED_DEPRECATED, // Command failed (deprecated and no longer supported) RLV_RET_FAILED_NOBEHAVIOUR, // Command failed (force modifier on an object with no active restrictions) + RLV_RET_FAILED_UNHELDBEHAVIOUR, // Command failed (local modifier on an object that doesn't hold the base behaviour) RLV_RET_FAILED_BLOCKED, // Command failed (object is blocked) RLV_RET_FAILED_THROTTLED, // Command failed (throttled) RLV_RET_NO_PROCESSOR // Command doesn't have a template processor define (legacy code) diff --git a/indra/newview/rlveffects.cpp b/indra/newview/rlveffects.cpp new file mode 100644 index 0000000000..6da6a15825 --- /dev/null +++ b/indra/newview/rlveffects.cpp @@ -0,0 +1,443 @@ +/** + * + * Copyright (c) 2021, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llfasttimer.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "pipeline.h" + +#include "rlveffects.h" +#include "rlvhandler.h" + +// ==================================================================================== +// RlvOverlayEffect class +// + +const float c_DefaultAlpha = 1.0f; +const float c_DefaultColor[3] = { 1.0f, 1.0f, 1.0f }; + +RlvOverlayEffect::RlvOverlayEffect(const LLUUID& idRlvObj) + : LLVisualEffect(idRlvObj, EVisualEffect::RlvOverlay, EVisualEffectType::Custom) + , m_nAlpha(c_DefaultAlpha) + , m_fBlockTouch(false) + , m_Color(LLColor3(c_DefaultColor)) +{ +} + +RlvOverlayEffect::~RlvOverlayEffect() +{ + clearImage(); +} + +// static +ERlvCmdRet RlvOverlayEffect::onAlphaValueChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvOverlayEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_nAlpha = (newValue) ? boost::get(newValue.value()) : c_DefaultAlpha; + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvOverlayEffect::onBlockTouchValueChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvOverlayEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_fBlockTouch = (newValue) ? boost::get(newValue.value()) : false; + } + return RLV_RET_SUCCESS; +} +// static +ERlvCmdRet RlvOverlayEffect::onColorValueChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvOverlayEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_Color = LLColor3( (newValue) ? boost::get(newValue.value()).mV : c_DefaultColor); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvOverlayEffect::onTextureChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvOverlayEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + if (newValue) + pEffect->setImage(boost::get(newValue.value())); + else + pEffect->clearImage(); + } + return RLV_RET_SUCCESS; +} + +void RlvOverlayEffect::clearImage() +{ + if (m_pImage) + { + m_pImage->setBoostLevel(m_nImageOrigBoost); + m_pImage = nullptr; + } +} + +bool RlvOverlayEffect::hitTest(const LLCoordGL& ptMouse) const +{ + if (!m_pImage) + return false; + + return (m_fBlockTouch) && (m_pImage->getMask(LLVector2((float)ptMouse.mX / gViewerWindow->getWorldViewWidthScaled(), (float)ptMouse.mY / gViewerWindow->getWorldViewHeightScaled()))); +} + +void RlvOverlayEffect::setImage(const LLUUID& idTexture) +{ + if ( (m_pImage) && (m_pImage->getID() == idTexture) ) + return; + + clearImage(); + m_pImage = LLViewerTextureManager::getFetchedTexture(idTexture, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + m_nImageOrigBoost = m_pImage->getBoostLevel(); + m_pImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + m_pImage->forceToSaveRawImage(0); +} + +void RlvOverlayEffect::run(const LLVisualEffectParams*) +{ + if (m_pImage) + { + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + int nWidth = gViewerWindow->getWorldViewWidthScaled(); + int nHeight = gViewerWindow->getWorldViewHeightScaled(); + + m_pImage->addTextureStats(nWidth * nHeight); + m_pImage->setKnownDrawSize(nWidth, nHeight); + + gGL.pushMatrix(); + LLGLSUIDefault glsUI; + gViewerWindow->setup2DRender(); + + const LLVector2& displayScale = gViewerWindow->getDisplayScale(); + gGL.scalef(displayScale.mV[VX], displayScale.mV[VY], 1.f); + + gGL.getTexUnit(0)->bind(m_pImage); + const LLColor3 col = m_Color.get(); + gGL.color4f(col.mV[0], col.mV[1], col.mV[2], llclamp(m_nAlpha.get(), 0.0f, 1.0f)); + + gl_rect_2d_simple_tex(nWidth, nHeight); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.popMatrix(); + gGL.flush(); + gViewerWindow->setup3DRender(); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + } +} + +// ==================================================================================== +// RlvSphereEffect class +// + +const int c_SphereDefaultMode = 0; +const int c_SphereDefaultOrigin = 0; +const float c_SphereDefaultColor[4] = { 0.0, 0.f, 0.f, 0.f }; +const float c_SphereDefaultDistance = 0.0f; +const int c_SphereDefaultDistanceExtend = 1; +const float c_SphereDefaultAlpha = 1.0f; + +RlvSphereEffect::RlvSphereEffect(const LLUUID& idRlvObj) + : LLVisualEffect(idRlvObj, EVisualEffect::RlvSphere, EVisualEffectType::PostProcessShader) + , m_eMode((ESphereMode)c_SphereDefaultMode) + , m_eOrigin((ESphereOrigin)c_SphereDefaultOrigin) + , m_Params(LLVector4(c_SphereDefaultColor)) + , m_nDistanceMin(c_SphereDefaultDistance), m_nDistanceMax(c_SphereDefaultDistance) + , m_eDistExtend((ESphereDistExtend)c_SphereDefaultDistanceExtend) + , m_nValueMin(c_SphereDefaultAlpha), m_nValueMax(c_SphereDefaultAlpha) + , m_nTweenDuration(0.f) +{ +} + +RlvSphereEffect::~RlvSphereEffect() +{ +} + +// static +ERlvCmdRet RlvSphereEffect::onModeChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_eMode = (ESphereMode)((newValue) ? boost::get(newValue.value()) : c_SphereDefaultMode); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onOriginChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_eOrigin = (ESphereOrigin)((newValue) ? boost::get(newValue.value()) : c_SphereDefaultOrigin); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onColorChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + LLVector4 vecColor = (newValue) ? LLVector4(boost::get(newValue.value()), 1.0f) : LLVector4(c_SphereDefaultColor); + if (!pEffect->m_nTweenDuration) + pEffect->m_Params = vecColor; + else + pEffect->m_Params.start(vecColor, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onDistMinChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + float nDistanceMin = (newValue) ? boost::get(newValue.value()) : c_SphereDefaultDistance; + if (!pEffect->m_nTweenDuration) + pEffect->m_nDistanceMin = nDistanceMin; + else + pEffect->m_nDistanceMin.start(nDistanceMin, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onDistMaxChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + float nDistanceMax = (newValue) ? boost::get(newValue.value()) : c_SphereDefaultDistance; + if (!pEffect->m_nTweenDuration) + pEffect->m_nDistanceMax = nDistanceMax; + else + pEffect->m_nDistanceMax.start(nDistanceMax, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onDistExtendChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_eDistExtend = (ESphereDistExtend)((newValue) ? boost::get(newValue.value()) : c_SphereDefaultDistanceExtend); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onParamsChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + LLVector4 params = LLVector4((newValue) ? boost::get(newValue.value()).mV : c_SphereDefaultColor); + if (!pEffect->m_nTweenDuration) + pEffect->m_Params = params; + else + pEffect->m_Params.start(params, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onTweenDurationChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + pEffect->m_nTweenDuration = (newValue) ? boost::get(newValue.value()) : 0; + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onValueMinChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + float nValueMin = (newValue) ? boost::get(newValue.value()) : c_SphereDefaultAlpha;; + if (!pEffect->m_nTweenDuration) + pEffect->m_nValueMin = nValueMin; + else + pEffect->m_nValueMin.start(nValueMin, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +// static +ERlvCmdRet RlvSphereEffect::onValueMaxChanged(const LLUUID& idRlvObj, const boost::optional newValue) +{ + if (RlvSphereEffect* pEffect = dynamic_cast(LLVfxManager::instance().getEffect(idRlvObj))) + { + float nValueMax = (newValue) ? boost::get(newValue.value()) : c_SphereDefaultAlpha; + if (!pEffect->m_nTweenDuration) + pEffect->m_nValueMax = nValueMax; + else + pEffect->m_nValueMax.start(nValueMax, pEffect->m_nTweenDuration); + } + return RLV_RET_SUCCESS; +} + +void RlvSphereEffect::setShaderUniforms(LLGLSLShader* pShader) +{ + pShader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, get_current_projection().inverse().m); + pShader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, gPipeline.mScreen.getWidth(), gPipeline.mScreen.getHeight()); + pShader->uniform1i(LLShaderMgr::RLV_EFFECT_MODE, llclamp((int)m_eMode, 0, (int)ESphereMode::Count)); + + // Pass the sphere origin to the shader + LLVector4 posSphereOrigin; + switch (m_eOrigin) + { + case ESphereOrigin::Camera: + posSphereOrigin.setVec(LLViewerCamera::instance().getOrigin(), 1.0f); + break; + case ESphereOrigin::Avatar: + default: + posSphereOrigin.setVec((isAgentAvatarValid()) ? gAgentAvatarp->getRenderPosition() : gAgent.getPositionAgent(), 1.0f); + break; + } + glh::vec4f posSphereOriginGl(posSphereOrigin.mV); + const glh::matrix4f& mvMatrix = gGLModelView; + mvMatrix.mult_matrix_vec(posSphereOriginGl); + pShader->uniform4fv(LLShaderMgr::RLV_EFFECT_PARAM1, 1, posSphereOriginGl.v); + + // Pack min/max distance and alpha together + float nDistMin = m_nDistanceMin.get(), nDistMax = m_nDistanceMax.get(); + const glh::vec4f sphereParams(m_nValueMin.get(), nDistMin, m_nValueMax.get(), (nDistMax >= nDistMin) ? nDistMax : nDistMin); + pShader->uniform4fv(LLShaderMgr::RLV_EFFECT_PARAM2, 1, sphereParams.v); + + // Pass dist extend + int eDistExtend = (int)m_eDistExtend; + pShader->uniform2f(LLShaderMgr::RLV_EFFECT_PARAM3, eDistExtend & (int)ESphereDistExtend::Min, eDistExtend & (int)ESphereDistExtend::Max); + + // Pass effect params + const glh::vec4f effectParams(m_Params.get().mV); + pShader->uniform4fv(LLShaderMgr::RLV_EFFECT_PARAM4, 1, effectParams.v); +} + +void RlvSphereEffect::renderPass(LLGLSLShader* pShader, const LLShaderEffectParams* pParams) const +{ + if (pParams->m_pDstBuffer) + { + pParams->m_pDstBuffer->bindTarget(); + } + else + { + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + } + RLV_ASSERT_DBG(pParams->m_pSrcBuffer); + + S32 nDiffuseChannel = pShader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, pParams->m_pSrcBuffer->getUsage()); + if (nDiffuseChannel > -1) + { + pParams->m_pSrcBuffer->bindTexture(0, nDiffuseChannel); + gGL.getTexUnit(nDiffuseChannel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + S32 nDepthChannel = pShader->enableTexture(LLShaderMgr::DEFERRED_DEPTH, gPipeline.mDeferredDepth.getUsage()); + if (nDepthChannel > -1) + { + gGL.getTexUnit(nDepthChannel)->bind(&gPipeline.mDeferredDepth, TRUE); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + + LLVector2 tc1(0, 0); + LLVector2 tc2((F32)gPipeline.mScreen.getWidth() * 2, (F32)gPipeline.mScreen.getHeight() * 2); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); + gGL.end(); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + pShader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, pParams->m_pSrcBuffer->getUsage()); + pShader->disableTexture(LLShaderMgr::DEFERRED_DEPTH, gPipeline.mDeferredDepth.getUsage()); + + if (pParams->m_pDstBuffer) + { + pParams->m_pDstBuffer->flush(); + } +} + +LLTrace::BlockTimerStatHandle FTM_RLV_EFFECT_SPHERE("Post-process (RLVa sphere)"); + +void RlvSphereEffect::run(const LLVisualEffectParams* pParams) +{ + LL_RECORD_BLOCK_TIME(FTM_RLV_EFFECT_SPHERE); + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + + gRlvSphereProgram.bind(); + setShaderUniforms(&gRlvSphereProgram); + + const LLShaderEffectParams* pShaderParams = static_cast(pParams); + switch (m_eMode) + { + case ESphereMode::Blend: + case ESphereMode::ChromaticAberration: + case ESphereMode::Pixelate: + renderPass(&gRlvSphereProgram, pShaderParams); + break; + case ESphereMode::Blur: + case ESphereMode::BlurVariable: + gRlvSphereProgram.uniform2f(LLShaderMgr::RLV_EFFECT_PARAM5, 1.f, 0.f); + renderPass(&gRlvSphereProgram, pShaderParams); + gRlvSphereProgram.uniform2f(LLShaderMgr::RLV_EFFECT_PARAM5, 0.f, 1.f); + renderPass(&gRlvSphereProgram, pShaderParams); + break; + default: + llassert(true); + } + + gRlvSphereProgram.unbind(); +} + +// ==================================================================================== diff --git a/indra/newview/rlveffects.h b/indra/newview/rlveffects.h new file mode 100644 index 0000000000..0b55b2a500 --- /dev/null +++ b/indra/newview/rlveffects.h @@ -0,0 +1,107 @@ +/** + * + * Copyright (c) 2021, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#pragma once + +#include "llvisualeffect.h" +#include "rlvhelper.h" + +// ============================================================================ +// Forward declarations +// + +class LLViewerFetchedTexture; + +// ==================================================================================== +// RlvOverlayEffect class +// + +class RlvOverlayEffect : public LLVisualEffect +{ +public: + RlvOverlayEffect(const LLUUID& idRlvObj); + ~RlvOverlayEffect(); + +public: + bool hitTest(const LLCoordGL& ptMouse) const; + void run(const LLVisualEffectParams*) override; + void tweenAlpha(float endAlpha, double duration) { m_nAlpha.start(endAlpha, duration); } + void tweenColor(LLColor3 endColor, double duration) { m_Color.start(endColor, duration); } + static ERlvCmdRet onAlphaValueChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onBlockTouchValueChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onColorValueChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onTextureChanged(const LLUUID& idRlvObj, const boost::optional newValue); +protected: + void clearImage(); + void setImage(const LLUUID& idTexture); + + /* + * Member variables + */ +protected: + LLTweenableValueLerp m_nAlpha; + bool m_fBlockTouch; + LLTweenableValueLerp m_Color; + + LLPointer m_pImage = nullptr; + int m_nImageOrigBoost = 0; +}; + +// ==================================================================================== +// RlvSphereEffect class +// + +class RlvSphereEffect : public LLVisualEffect +{ +public: + RlvSphereEffect(const LLUUID& idRlvObj); + ~RlvSphereEffect(); + +public: + void run(const LLVisualEffectParams* pParams) override; + static ERlvCmdRet onModeChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onOriginChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onColorChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onDistMinChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onDistMaxChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onDistExtendChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onParamsChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onTweenDurationChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onValueMinChanged(const LLUUID& idRlvObj, const boost::optional newValue); + static ERlvCmdRet onValueMaxChanged(const LLUUID& idRlvObj, const boost::optional newValue); +protected: + void renderPass(LLGLSLShader* pShader, const LLShaderEffectParams* pParams) const; + void setShaderUniforms(LLGLSLShader* pShader); + + /* + * Member variables + */ +protected: + enum class ESphereMode { Blend = 0, Blur, BlurVariable, ChromaticAberration, Pixelate, Count }; + ESphereMode m_eMode; + enum class ESphereOrigin { Avatar = 0, Camera, Count }; + ESphereOrigin m_eOrigin; + LLTweenableValueLerp m_Params; + LLTweenableValueLerp m_nDistanceMin; + LLTweenableValueLerp m_nDistanceMax; + enum class ESphereDistExtend { Max = 0x01, Min = 0x02, Both = 0x03 }; + ESphereDistExtend m_eDistExtend; + LLTweenableValueLerp m_nValueMin; + LLTweenableValueLerp m_nValueMax; + float m_nTweenDuration; +}; + +// ==================================================================================== diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp index 9a44df6778..faffcd5bb3 100644 --- a/indra/newview/rlvextensions.cpp +++ b/indra/newview/rlvextensions.cpp @@ -17,6 +17,7 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" #include "llagentcamera.h" +#include "llviewerwindow.h" #include "llvoavatarself.h" #include "rlvextensions.h" @@ -34,6 +35,7 @@ RlvExtGetSet::RlvExtGetSet() if (!m_DbgAllowed.size()) // m_DbgAllowed is static and should only be initialized once { m_DbgAllowed.insert(std::pair("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO)); + m_DbgAllowed.insert(std::pair("AspectRatio", DBG_READ | DBG_PSEUDO)); m_DbgAllowed.insert(std::pair("RenderResolutionDivisor", DBG_READ | DBG_WRITE)); m_DbgAllowed.insert(std::pair(RlvSettingNames::ForbidGiveToRlv, DBG_READ)); m_DbgAllowed.insert(std::pair(RlvSettingNames::NoSetEnv, DBG_READ)); @@ -196,6 +198,10 @@ std::string RlvExtGetSet::onGetPseudoDebug(const std::string& strSetting) return llformat("%d", (gAgentAvatarp->getSex() == SEX_MALE)); // [See LLFloaterCustomize::LLFloaterCustomize()] } } + else if ("AspectRatio" == strSetting) + { + return llformat("%.3f", (float)gViewerWindow->getWorldViewWidthScaled() / gViewerWindow->getWorldViewHeightScaled()); + } return std::string(); } diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp index 5f90fa1259..b0b089e138 100644 --- a/indra/newview/rlvfloaters.cpp +++ b/indra/newview/rlvfloaters.cpp @@ -813,7 +813,7 @@ void RlvFloaterConsole::onInput(LLUICtrl* pCtrl, const LLSD& sdParam) strCmd.clear(); // Only show feedback on successful commands when there's an informational notice if (!pstr->empty()) - pstr->push_back(','); + pstr->append(", "); pstr->append(strCmd); } diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 1ed14a45d5..19a8d49739 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -50,15 +50,17 @@ #include "lltabcontainer.h" // @showinv - Tab container control for inventory tabs #include "lltoolmgr.h" // @edit #include "llviewercamera.h" // @setcam and related +#include "llviewershadermgr.h" // @setsphere #include "llworldmapmessage.h" // @tpto #include "llviewertexturelist.h" // @setcam_texture -#include "llviewerwindow.h" // @setoverlay +#include "pipeline.h" // @setsphere // RLVa includes #include "rlvactions.h" #include "rlvenvironment.h" #include "rlvfloaters.h" #include "rlvactions.h" +#include "rlveffects.h" #include "rlvhandler.h" #include "rlvhelper.h" #include "rlvinventory.h" @@ -184,7 +186,6 @@ void RlvHandler::cleanup() RLV_ASSERT(std::all_of(m_Behaviours, m_Behaviours + RLV_BHVR_COUNT, [](S16 cnt) { return !cnt; })); RLV_ASSERT(m_CurCommandStack.empty()); RLV_ASSERT(m_CurObjectStack.empty()); - RLV_ASSERT(m_pOverlayImage.isNull()); // // Clean up what's left @@ -1728,6 +1729,8 @@ ERlvCmdRet RlvCommandHandlerBaseImpl::processCommand(const RlvC { if (rlvCmd.isStrict()) gRlvHandler.removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + if (RlvObject* pRlvObj = gRlvHandler.getObject(rlvCmd.getObjectID())) + pRlvObj->clearModifiers(eBhvr); gRlvHandler.m_Behaviours[eBhvr]--; } @@ -1794,7 +1797,7 @@ ERlvCmdRet RlvBehaviourGenericHandler::onCommand(const RlvC // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); RlvBehaviourModifierValue modValue; - if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), pBhvrModifier->getType(), modValue)) ) return RLV_RET_FAILED_OPTION; // HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here @@ -1815,15 +1818,22 @@ ERlvCmdRet RlvBehaviourGenericHandler::onCommand(const RlvC return RLV_RET_SUCCESS; } -// Handles: @bhvr[:]=n|y +// Handles: @bhvr=n, @bhvr:=n|y and @bhvr:=force template<> ERlvCmdRet RlvBehaviourGenericHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) { - // If there is an option then it should specify a valid modifier (and reference count) - if (rlvCmd.hasOption()) + if ( (rlvCmd.getParamType() & RLV_TYPE_ADDREM) && (rlvCmd.hasOption()) ) + { + // @bhvr:=n|y : if there is an option then it should specify a valid global modifier and if so we reference count return RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); + } + else if (rlvCmd.getParamType() == RLV_TYPE_FORCE) + { + // @bhvr:=force : local modifiers hide behind their primary behaviour which knows how to handle them + return rlvCmd.getBehaviourInfo()->processModifier(rlvCmd); + } - // Add the default option on an empty modifier if needed + // @bhvr=n : add the default option on an empty modifier if needed RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) ) { @@ -2059,36 +2069,41 @@ void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhv template<> template<> void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) { - // Once an object has exclusive control over the overlay only its behaviours should be active. This affects: - // - behaviour modifiers => handled for us once we set the primary object - - LLUUID idRlvObject; if (fHasBhvr) - { - // Get the UUID of the primary object (there should only be one) - std::list lObjects; - gRlvHandler.findBehaviour(RLV_BHVR_SETOVERLAY, lObjects); - RLV_ASSERT(lObjects.size() == 1); - idRlvObject = lObjects.front()->getObjectID(); - } - - RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_ALPHA)->setPrimaryObject(idRlvObject); - RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TINT)->setPrimaryObject(idRlvObject); - RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TEXTURE)->setPrimaryObject(idRlvObject); - RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TOUCH)->setPrimaryObject(idRlvObject); + LLVfxManager::instance().addEffect(new RlvOverlayEffect(gRlvHandler.getCurrentObject())); + else + LLVfxManager::instance().removeEffect(gRlvHandler.getCurrentObject()); } -// Handles: @setoverlay_texture:=n|y changes -template<> -void RlvBehaviourModifierHandler::onValueChange() const +// Handles: @setsphere=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) { - if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TEXTURE)) + // *TODO: this needs to be done in a cleaner way but FS needs to release ASAP + if (RLV_TYPE_ADD == rlvCmd.getParamType() && gRlvHandler.m_Behaviours[RLV_BHVR_SETSPHERE] >= 6) + return RLV_RET_FAILED_LOCK; + + ERlvCmdRet eRet = RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (!rlvCmd.isModifier()) ) { - if (pBhvrModifier->hasValue()) - gRlvHandler.setOverlayImage(pBhvrModifier->getValue()); + // If we're not using deferred but are using Windlight shaders we need to force use of FBO and depthmap texture + if ( (!LLPipeline::RenderDeferred) && (LLPipeline::WindLightUseAtmosShaders) && (!LLPipeline::sUseDepthTexture) ) + { + LLRenderTarget::sUseFBO = true; + LLPipeline::sUseDepthTexture = true; + + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); + LLViewerShaderMgr::instance()->setShaders(); + } + + if (gRlvHandler.hasBehaviour(rlvCmd.getObjectID(), rlvCmd.getBehaviourType())) + LLVfxManager::instance().addEffect(new RlvSphereEffect(rlvCmd.getObjectID())); else - gRlvHandler.clearOverlayImage(); + LLVfxManager::instance().removeEffect(gRlvHandler.getCurrentObject()); } + return eRet; } // Handles: @sendchannel[:]=n|y and @sendchannel_except[:]=n|y @@ -2598,28 +2613,31 @@ ERlvCmdRet RlvBehaviourHandler::onCommand(const RlvCommand& return eRet; } -// Handles: @shownametags[:]=n|y toggles -template<> template<> -void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +// Handles: @shownametags[:] value changes +template<> +void RlvBehaviourModifierHandler::onValueChange() const { if (LLApp::isExiting()) return; // Nothing to do if the viewer is shutting down - // Update the shownames context - RlvActions::setShowName(RlvActions::SNC_NAMETAG, !fHasBhvr); - // Refresh all name tags LLVOAvatar::invalidateNameTags(); } -// Handles: @shownametags[:]=n|y +// Handles: @shownametags[:]=n|y template<> template<> ERlvCmdRet RlvBehaviourHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) { - ERlvCmdRet eRet = RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); - if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) ) - LLVOAvatar::invalidateNameTag(RlvCommandOptionHelper::parseOption(rlvCmd.getOption())); - return eRet; + LLUUID idOption; + if ( (rlvCmd.hasOption()) && (RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idOption)) ) + { + ERlvCmdRet eRet = RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); + if (RLV_RET_SUCCESS == eRet) + LLVOAvatar::invalidateNameTag(idOption); + fRefCount = false; + return eRet; + } + return RlvBehaviourGenericHandler::onCommand(rlvCmd, fRefCount); } // Handles: @shownearby=n|y toggles @@ -2671,6 +2689,26 @@ void RlvBehaviourShowSelfToggleHandler::onCommandToggle(ERlvBehaviour eBvhr, boo gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); } +// Handles: @viewtransparent toggles +template<> template<> +void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + LLDrawPoolAlpha::sShowDebugAlpha = false; + } +} + +// Handles: @viewwireframe toggles +template<> template<> +void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + set_use_wireframe(false); + } +} + // ============================================================================ // Command handlers (RLV_TYPE_FORCE) // @@ -2691,7 +2729,7 @@ ERlvCmdRet RlvForceGenericHandler::onCommand(const RlvComma // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); RlvBehaviourModifierValue modValue; - if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), pBhvrModifier->getType(), modValue)) ) return RLV_RET_FAILED_OPTION; pBhvrModifier->setValue(modValue, rlvCmd.getObjectID()); @@ -3046,6 +3084,14 @@ ERlvCmdRet RlvForceHandler::onCommand(const RlvCommand& rl template<> template<> ERlvCmdRet RlvForceHandler::onCommand(const RlvCommand& rlvCmd) { + RlvObject* pRlvObj = gRlvHandler.getObject(rlvCmd.getObjectID()); + if (!pRlvObj) + return RLV_RET_FAILED_NOBEHAVIOUR; + + RlvOverlayEffect* pOverlayEffect = LLVfxManager::instance().getEffect(rlvCmd.getObjectID()); + if (!pOverlayEffect) + return RLV_RET_FAILED_LOCK; + std::vector optionList; if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (3 != optionList.size()) ) return RLV_RET_FAILED_OPTION; @@ -3058,12 +3104,18 @@ ERlvCmdRet RlvForceHandler::onCommand(const RlvComman // Process the overlay alpha tween (if there is one and it is a valid value) float overlayAlpha = .0f; if (RlvCommandOptionHelper::parseOption(optionList[0], overlayAlpha)) - RlvBehaviourModifierAnimator::instance().addTween(rlvCmd.getObjectID(), RLV_MODIFIER_OVERLAY_ALPHA, RlvBehaviourModifierAnimationType::Lerp, overlayAlpha, tweenDuration); + { + pOverlayEffect->tweenAlpha(overlayAlpha, tweenDuration); + pRlvObj->setModifierValue(ERlvLocalBhvrModifier::OverlayAlpha, overlayAlpha); + } // Process the overlay tint tween (if there is one and it is a valid value) LLVector3 overlayColor; if (RlvCommandOptionHelper::parseOption(optionList[1], overlayColor)) - RlvBehaviourModifierAnimator::instance().addTween(rlvCmd.getObjectID(), RLV_MODIFIER_OVERLAY_TINT, RlvBehaviourModifierAnimationType::Lerp, overlayColor, tweenDuration); + { + pOverlayEffect->tweenColor(LLColor3(overlayColor.mV), tweenDuration); + pRlvObj->setModifierValue(ERlvLocalBhvrModifier::OverlayTint, overlayColor); + } return RLV_RET_SUCCESS; } @@ -3851,76 +3903,4 @@ ERlvCmdRet RlvHandler::onGetPath(const RlvCommand& rlvCmd, std::string& strReply // Command specific helper functions - @setoverlay // -void RlvHandler::clearOverlayImage() -{ - if (m_pOverlayImage) - { - m_pOverlayImage->setBoostLevel(m_nOverlayOrigBoost); - m_pOverlayImage = nullptr; - } -} - -bool RlvHandler::hitTestOverlay(const LLCoordGL& ptMouse) const -{ - if (!m_pOverlayImage) - return false; - - RlvBehaviourModifier* pTouchModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TOUCH); - return (pTouchModifier) && (pTouchModifier->hasValue()) && (pTouchModifier->getValue()) && - (m_pOverlayImage->getMask(LLVector2((float)ptMouse.mX / gViewerWindow->getWorldViewWidthScaled(), (float)ptMouse.mY / gViewerWindow->getWorldViewHeightScaled()))); -} - -void RlvHandler::renderOverlay() -{ - if ( (hasBehaviour(RLV_BHVR_SETOVERLAY)) && (m_pOverlayImage) ) - { - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - int nWidth = gViewerWindow->getWorldViewWidthScaled(); - int nHeight = gViewerWindow->getWorldViewHeightScaled(); - - m_pOverlayImage->addTextureStats(nWidth * nHeight); - m_pOverlayImage->setKnownDrawSize(nWidth, nHeight); - - gGL.pushMatrix(); - LLGLSUIDefault glsUI; - gViewerWindow->setup2DRender(); - - const LLVector2& displayScale = gViewerWindow->getDisplayScale(); - gGL.scalef(displayScale.mV[VX], displayScale.mV[VY], 1.f); - - gGL.getTexUnit(0)->bind(m_pOverlayImage); - const LLVector3 overlayTint = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TINT)->getValue(); - gGL.color4f(overlayTint.mV[0], overlayTint.mV[1], overlayTint.mV[2], llclamp(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_ALPHA)->getValue(), 0.0f, 1.0f)); - - gl_rect_2d_simple_tex(nWidth, nHeight); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - gGL.popMatrix(); - gGL.flush(); - gViewerWindow->setup3DRender(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - } -} - -void RlvHandler::setOverlayImage(const LLUUID& idTexture) -{ - if ( (m_pOverlayImage) && (m_pOverlayImage->getID() == idTexture) ) - return; - - clearOverlayImage(); - m_pOverlayImage = LLViewerTextureManager::getFetchedTexture(idTexture, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - m_nOverlayOrigBoost = m_pOverlayImage->getBoostLevel(); - m_pOverlayImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - m_pOverlayImage->forceToSaveRawImage(0); -} - // ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index c5b20de417..01da4b6269 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -23,13 +23,9 @@ #include "rlvcommon.h" #include "rlvhelper.h" - // ============================================================================ - // Forward declarations - // - -class LLViewerFetchedTexture; - // ============================================================================ +// RlvHandler class +// class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGroupObserver { @@ -56,6 +52,8 @@ public: public: // Returns a list of all objects containing the specified behaviour bool findBehaviour(ERlvBehaviour eBhvr, std::list& lObjects) const; + // Returns a pointer to an RLV object instance (DO NOT STORE THIS!) + RlvObject* getObject(const LLUUID& idRlvObj) const; // Returns TRUE is at least one object contains the specified behaviour (and optional option) bool hasBehaviour(ERlvBehaviour eBhvr) const { return (eBhvr < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBhvr]) : false; } bool hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const; @@ -123,9 +121,7 @@ public: // Command specific helper functions bool filterChat(std::string& strUTF8Text, bool fFilterEmote) const; // @sendchat, @recvchat and @redirchat - bool hitTestOverlay(const LLCoordGL& ptMouse) const; // @setoverlay bool redirectChatOrEmote(const std::string& strUTF8Test) const; // @redirchat and @rediremote - void renderOverlay(); // @setoverlay // Command processing helper functions ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj); @@ -144,11 +140,9 @@ public: protected: // Command specific helper functions (NOTE: these generally do not perform safety checks) bool checkActiveGroupThrottle(const LLUUID& idRlvObj); // @setgroup=force - void clearOverlayImage(); // @setoverlay=n void setActiveGroup(const LLUUID& idGroup); // @setgroup=force void setActiveGroupRole(const LLUUID& idGroup, const std::string& strRole); // @setgroup=force void setCameraOverride(bool fOverride); // @setcam family - void setOverlayImage(const LLUUID& idTexture); // @setoverlay=n void onIMQueryListResponse(const LLSD& sdNotification, const LLSD sdResponse); @@ -275,8 +269,6 @@ protected: mutable LLUUID m_idAgentGroup; // @setgroup=n std::pair m_PendingGroupChange; // @setgroup=force std::pair m_GroupChangeExpiration; // @setgroup=force - LLPointer m_pOverlayImage = nullptr; // @setoverlay=n - int m_nOverlayOrigBoost = 0; // @setoverlay=n std::string m_strCameraPresetRestore; // @setcam_eyeoffset, @setcam_eyeoffsetscale and @setcam_focusoffset @@ -313,6 +305,12 @@ inline RlvHandler* RlvHandler::getInstance() return &gRlvHandler; } +inline RlvObject* RlvHandler::getObject(const LLUUID& idRlvObj) const +{ + auto itObj = m_Objects.find(idRlvObj); + return (m_Objects.end() != itObj) ? const_cast(&itObj->second) : nullptr; +} + inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const { return hasBehaviourExcept(eBhvr, strOption, LLUUID::null); diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index e333350d68..3ca2a4d725 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -26,6 +26,7 @@ // FIRE-4453 #include "rlvcommon.h" +#include "rlveffects.h" #include "rlvhelper.h" #include "rlvhandler.h" #include "rlvinventory.h" @@ -104,6 +105,8 @@ RlvBehaviourDictionary::RlvBehaviourDictionary() addEntry(new RlvBehaviourInfo("detachallthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); addEntry(new RlvBehaviourGenericToggleProcessor("edit")); addEntry(new RlvBehaviourGenericProcessor("editobj", RLV_BHVR_EDITOBJ)); + addEntry(new RlvBehaviourGenericToggleProcessor("viewtransparent", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor("viewwireframe", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericProcessor("emote", RLV_BHVR_EMOTE)); addEntry(new RlvBehaviourGenericProcessor("fartouch", RLV_BHVR_FARTOUCH)); addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifierCompMin)); @@ -147,7 +150,8 @@ RlvBehaviourDictionary::RlvBehaviourDictionary() addEntry(new RlvBehaviourGenericProcessor("showloc", RLV_BHVR_SHOWLOC)); addEntry(new RlvBehaviourGenericProcessor("showminimap", RLV_BHVR_SHOWMINIMAP)); addEntry(new RlvBehaviourToggleProcessor("shownames", RlvBehaviourInfo::BHVR_STRICT)); - addEntry(new RlvBehaviourToggleProcessor("shownametags", RlvBehaviourInfo::BHVR_STRICT )); + addEntry(new RlvBehaviourProcessor("shownametags", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_SHOWNAMETAGS, RLV_MODIFIER_SHOWNAMETAGSDIST, new RlvBehaviourModifierHandler("Name Tags - Visible Distance", 0.0f, true, new RlvBehaviourModifierCompMin)); addEntry(new RlvBehaviourGenericToggleProcessor("shownearby", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("showself", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); addEntry(new RlvBehaviourGenericToggleProcessor("showselfhead", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); @@ -219,17 +223,28 @@ RlvBehaviourDictionary::RlvBehaviourDictionary() addEntry(new RlvBehaviourGenericToggleProcessor("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); // Overlay - addEntry(new RlvBehaviourGenericToggleProcessor("setoverlay", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); - addModifier(new RlvForceGenericProcessor("setoverlay_alpha", RLV_BHVR_SETOVERLAY_ALPHA, RlvBehaviourInfo::BHVR_EXPERIMENTAL), - RLV_MODIFIER_OVERLAY_ALPHA, new RlvBehaviourModifier("Overlay - Alpha", 1.0f, false, new RlvBehaviourModifierComp())); - addModifier(new RlvForceGenericProcessor("setoverlay_texture", RLV_BHVR_SETOVERLAY_TEXTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL), - RLV_MODIFIER_OVERLAY_TEXTURE, new RlvBehaviourModifierHandler("Overlay - Texture", LLUUID::null, false, new RlvBehaviourModifierComp())); - addModifier(new RlvForceGenericProcessor("setoverlay_tint", RLV_BHVR_SETOVERLAY_TINT, RlvBehaviourInfo::BHVR_EXPERIMENTAL), - RLV_MODIFIER_OVERLAY_TINT, new RlvBehaviourModifier("Overlay - Tint", LLVector3(1.0f, 1.0f, 1.0f), false, new RlvBehaviourModifierComp())); - addModifier(new RlvBehaviourGenericProcessor("setoverlay_touch", RLV_BHVR_SETOVERLAY_TOUCH, RlvBehaviourInfo::BHVR_EXPERIMENTAL), - RLV_MODIFIER_OVERLAY_TOUCH, new RlvBehaviourModifier("Overlay - Touch", true, true, new RlvBehaviourModifierComp())); + RlvBehaviourInfo* pSetOverlayBhvr = new RlvBehaviourGenericToggleProcessor("setoverlay"); + pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayAlpha, typeid(float), "alpha", &RlvOverlayEffect::onAlphaValueChanged); + pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayTexture, typeid(LLUUID), "texture", &RlvOverlayEffect::onTextureChanged); + pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayTint, typeid(LLVector3), "tint", &RlvOverlayEffect::onColorValueChanged); + pSetOverlayBhvr->addModifier(ERlvLocalBhvrModifier::OverlayTouch, typeid(LLVector3), "touch", &RlvOverlayEffect::onBlockTouchValueChanged); + addEntry(pSetOverlayBhvr); addEntry(new RlvForceProcessor("setoverlay_tween", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + // Sphere + RlvBehaviourInfo* pSetSphereBhvr = new RlvBehaviourProcessor("setsphere", RlvBehaviourInfo::BHVR_EXPERIMENTAL); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereMode, typeid(int), "mode", &RlvSphereEffect::onModeChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereOrigin, typeid(int), "origin", &RlvSphereEffect::onOriginChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereColor, typeid(LLVector3), "color", &RlvSphereEffect::onColorChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistMin, typeid(float), "distmin", &RlvSphereEffect::onDistMinChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistMax, typeid(float), "distmax", &RlvSphereEffect::onDistMaxChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereDistExtend, typeid(int), "distextend", &RlvSphereEffect::onDistExtendChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereParams, typeid(LLVector4), "param", &RlvSphereEffect::onParamsChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereTween, typeid(float), "tween", &RlvSphereEffect::onTweenDurationChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereValueMin, typeid(float), "valuemin", &RlvSphereEffect::onValueMinChanged); + pSetSphereBhvr->addModifier(ERlvLocalBhvrModifier::SphereValueMax, typeid(float), "valuemax", &RlvSphereEffect::onValueMaxChanged); + addEntry(pSetSphereBhvr); + // // Force-wear // @@ -398,20 +413,50 @@ void RlvBehaviourDictionary::clearModifiers(const LLUUID& idRlvObj) } } -const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const +const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(ERlvBehaviour eBhvr, ERlvParamType eParamType) const { - bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec"); + const RlvBehaviourInfo* pBhvrInfo = nullptr; + for (auto itBhvrLower = m_Bhvr2InfoMap.lower_bound(eBhvr), itBhvrUpper = m_Bhvr2InfoMap.upper_bound(eBhvr); + std::find_if(itBhvrLower, itBhvrUpper, [eParamType](const rlv_bhvr2info_map_t::value_type& bhvrEntry) { return bhvrEntry.second->getParamTypeMask() == eParamType; }) != itBhvrUpper; + ++itBhvrLower) + { + if (pBhvrInfo) + return nullptr; + pBhvrInfo = itBhvrLower->second; + } + return pBhvrInfo; +} + +const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict, ERlvLocalBhvrModifier* peBhvrModifier) 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 fStrict = (strBhvrLastPart.compare("sec") == 0); if (pfStrict) *pfStrict = fStrict; + ERlvLocalBhvrModifier eBhvrModifier = ERlvLocalBhvrModifier::Unknown; rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); - return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL; + if ( (m_String2InfoMap.end() == itBhvr) && (!fStrict) && (!strBhvrLastPart.empty()) && (RLV_TYPE_FORCE == eParamType) ) + { + // No match found but it could still be a local scope modifier + auto itBhvrMod = m_String2InfoMap.find(std::make_pair(strBhvr.substr(0, idxBhvrLastPart), RLV_TYPE_ADDREM)); + if ( (m_String2InfoMap.end() != itBhvrMod) && (eBhvrModifier = itBhvrMod->second->lookupBehaviourModifier(strBhvrLastPart)) != ERlvLocalBhvrModifier::Unknown) + itBhvr = itBhvrMod; + } + + if (peBhvrModifier) + *peBhvrModifier = eBhvrModifier; + return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : nullptr; } ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const { - const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict); - return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; + ERlvLocalBhvrModifier eBhvrModifier; + const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict, &eBhvrModifier); + // Filter out locally scoped modifier commands since they don't actually have a unique behaviour value of their own + return (pBhvrInfo && ERlvLocalBhvrModifier::Unknown == eBhvrModifier) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; } bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list& cmdList) const @@ -460,6 +505,42 @@ void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERl } } +// ============================================================================ +// RlvBehaviourInfo +// + +// virtual +ERlvCmdRet RlvBehaviourInfo::processModifier(const RlvCommand& rlvCmd) const +{ + // The object should have the base behaviour set (or else there's nothing to modify) + if (!gRlvHandler.hasBehaviour(rlvCmd.getObjectID(), rlvCmd.getBehaviourType())) + return RLV_RET_FAILED_UNHELDBEHAVIOUR; + + auto itBhvrModifier = std::find_if(m_BhvrModifiers.begin(), m_BhvrModifiers.end(), [&rlvCmd](const modifier_lookup_t::value_type& entry) { return std::get<0>(entry.second) == rlvCmd.getBehaviourModifier(); }); + if (m_BhvrModifiers.end() == itBhvrModifier) + return RLV_RET_FAILED_UNKNOWN; + + ERlvCmdRet eCmdRet; const modifier_handler_func_t& fnHandler = std::get<2>(itBhvrModifier->second); + if (rlvCmd.hasOption()) + { + // If there's an option parse it (and perform type checking) + RlvBehaviourModifierValue modValue; + if ( (rlvCmd.hasOption()) && (!RlvBehaviourModifier::convertOptionValue(rlvCmd.getOption(), std::get<1>(itBhvrModifier->second), modValue)) ) + return RLV_RET_FAILED_OPTION; + eCmdRet = (fnHandler) ? fnHandler(rlvCmd.getObjectID(), modValue) : RLV_RET_SUCCESS; + if (RLV_RET_SUCCESS == eCmdRet) + gRlvHandler.getObject(rlvCmd.getObjectID())->setModifierValue(rlvCmd.getBehaviourModifier(), modValue); + } + else + { + eCmdRet = (fnHandler) ? fnHandler(rlvCmd.getObjectID(), boost::none) : RLV_RET_SUCCESS; + if (RLV_RET_SUCCESS == eCmdRet) + gRlvHandler.getObject(rlvCmd.getObjectID())->clearModifierValue(rlvCmd.getBehaviourModifier()); + } + + return eCmdRet; +} + // ============================================================================ // RlvBehaviourModifier // @@ -499,7 +580,6 @@ void RlvBehaviourModifier::clearValues(const LLUUID& idRlvObj) [&idRlvObj](const RlvBehaviourModifierValueTuple& modValue) { return (std::get<1>(modValue) == idRlvObj) && (std::get<2>(modValue) == RLV_BHVR_UNKNOWN); }), m_Values.end()); - RlvBehaviourModifierAnimator::instance().clearTweens(idRlvObj); if (origCount != m_Values.size()) { onValueChange(); @@ -574,21 +654,22 @@ void RlvBehaviourModifier::setValue(const RlvBehaviourModifierValue& modValue, c } } -bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const +// static +bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, const std::type_index& modType, RlvBehaviourModifierValue& modValue) { try { - if (typeid(float) == m_DefaultValue.type()) + if (modType == typeid(float)) { modValue = std::stof(optionValue); return true; } - else if (typeid(int) == m_DefaultValue.type()) + else if (modType == typeid(int)) { modValue = std::stoi(optionValue); return true; } - else if (typeid(LLVector3) == m_DefaultValue.type()) + else if (modType == typeid(LLVector3)) { LLVector3 vecOption; if (3 == sscanf(optionValue.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2)) @@ -597,7 +678,16 @@ bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, Rl return true; } } - else if (typeid(LLUUID) == m_DefaultValue.type()) + else if (modType == typeid(LLVector4)) + { + LLVector4 vecOption; + if (4 == sscanf(optionValue.c_str(), "%f/%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2, vecOption.mV + 3)) + { + modValue = vecOption; + return true; + } + } + else if (modType == typeid(LLUUID)) { LLUUID idOption; if (LLUUID::parseUUID(optionValue, &idOption)) @@ -619,7 +709,7 @@ bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, Rl // RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) - : m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false) + : m_idObj(idObj) { if ((m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam))) { @@ -647,13 +737,13 @@ RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) return; } - m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict); + m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict, &m_eBhvrModifier); } RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType) : m_fValid(rlvCmd.m_fValid), m_idObj(rlvCmd.m_idObj), m_strBehaviour(rlvCmd.m_strBehaviour), m_pBhvrInfo(rlvCmd.m_pBhvrInfo) - , m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType),m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption) - , m_strParam(rlvCmd.m_strParam), m_fRefCounted(rlvCmd.m_fRefCounted) + , m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType), m_eBhvrModifier(rlvCmd.m_eBhvrModifier) + , m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(rlvCmd.m_fRefCounted) { } @@ -1107,6 +1197,31 @@ std::string RlvObject::getStatusString(const std::string& strFilter, const std:: return strStatus; } +void RlvObject::clearModifiers(ERlvBehaviour eBhvr) +{ + if (const RlvBehaviourInfo* pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(eBhvr, RLV_TYPE_ADDREM)) + { + for (const auto& modifierEntry : pBhvrInfo->getModifiers()) + { + clearModifierValue(std::get<0>(modifierEntry.second)); + } + } +} + +void RlvObject::clearModifierValue(ERlvLocalBhvrModifier eBhvrModifier) +{ + m_Modifiers.erase(eBhvrModifier); +} + +void RlvObject::setModifierValue(ERlvLocalBhvrModifier eBhvrModifier, const RlvBehaviourModifierValue& newValue) +{ + auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier); + if (m_Modifiers.end() != itBhvrModifierValue) + itBhvrModifierValue->second = newValue; + else + m_Modifiers.insert(std::make_pair(eBhvrModifier, newValue)); +} + // ============================================================================ // RlvForceWear // diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 68a41615d7..1577510c01 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -38,7 +38,10 @@ struct RlvBehaviourModifierComp; class RlvBehaviourInfo { + typedef std::function)> modifier_handler_func_t; public: + typedef std::map> modifier_lookup_t; + enum EBehaviourFlags { // General behaviour flags @@ -65,24 +68,29 @@ public: : m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {} virtual ~RlvBehaviourInfo() {} - const std::string& getBehaviour() const { return m_strBhvr; } - ERlvBehaviour getBehaviourType() const { return m_eBhvr; } - U32 getBehaviourFlags() const { return m_nBhvrFlags; } - U32 getParamTypeMask() const { return m_maskParamType; } - bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; } - bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; } - bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; } - bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; } - bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; } - void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable); + void addModifier(ERlvLocalBhvrModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler = nullptr); + const std::string& getBehaviour() const { return m_strBhvr; } + ERlvBehaviour getBehaviourType() const { return m_eBhvr; } + U32 getBehaviourFlags() const { return m_nBhvrFlags; } + U32 getParamTypeMask() const { return m_maskParamType; } + const modifier_lookup_t& getModifiers() const { return m_BhvrModifiers; } + bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; } + bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; } + bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; } + bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; } + bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; } + ERlvLocalBhvrModifier lookupBehaviourModifier(const std::string& strBhvrMod) const; + void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable); virtual ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const { return RLV_RET_NO_PROCESSOR; } + virtual ERlvCmdRet processModifier(const RlvCommand& rlvCmd) const; protected: std::string m_strBhvr; ERlvBehaviour m_eBhvr; U32 m_nBhvrFlags; U32 m_maskParamType; + modifier_lookup_t m_BhvrModifiers; }; // ============================================================================ @@ -106,7 +114,8 @@ public: public: void clearModifiers(const LLUUID& idRlvObj); ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; - const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; + const RlvBehaviourInfo* getBehaviourInfo(ERlvBehaviour eBhvr, ERlvParamType eParamType) const; + const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = nullptr, ERlvLocalBhvrModifier* peBhvrModifier = nullptr) const; bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list& cmdList) const; bool getHasStrict(ERlvBehaviour eBhvr) const; RlvBehaviourModifier* getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; } @@ -244,12 +253,13 @@ protected: virtual void onValueChange() const {} public: bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN); - bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const; + static bool convertOptionValue(const std::string& optionValue, const std::type_index& modType, RlvBehaviourModifierValue& modValue); void clearValues(const LLUUID& idRlvObj); bool getAddDefault() const { return m_fAddDefaultOnEmpty; } const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; } const LLUUID& getPrimaryObject() const; const std::string& getName() const { return m_strName; } + const std::type_info& getType() const { return m_DefaultValue.type(); } const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? std::get<0>(m_Values.front()) : m_DefaultValue; } template const T& getValue() const { return boost::get(getValue()); } bool hasValue() const; @@ -289,14 +299,17 @@ public: public: std::string asString() const; const std::string& getBehaviour() const { return m_strBehaviour; } + const RlvBehaviourInfo* getBehaviourInfo() const { return m_pBhvrInfo; } ERlvBehaviour getBehaviourType() const { return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; } U32 getBehaviourFlags() const{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourFlags() : 0; } + ERlvLocalBhvrModifier getBehaviourModifier() const { return m_eBhvrModifier; } const LLUUID& getObjectID() const { return m_idObj; } const std::string& getOption() const { return m_strOption; } const std::string& getParam() const { return m_strParam; } ERlvParamType getParamType() const { return m_eParamType; } bool hasOption() const { return !m_strOption.empty(); } bool isBlocked() const { return (m_pBhvrInfo) ? m_pBhvrInfo->isBlocked() : false; } + bool isModifier() const { return ERlvLocalBhvrModifier::Unknown != m_eBhvrModifier; } bool isRefCounted() const { return m_fRefCounted; } bool isStrict() const { return m_fStrict; } bool isValid() const { return m_fValid; } @@ -316,15 +329,16 @@ public: * Member variables */ protected: - bool m_fValid; + bool m_fValid = false; LLUUID m_idObj; std::string m_strBehaviour; - const RlvBehaviourInfo* m_pBhvrInfo; - ERlvParamType m_eParamType; - bool m_fStrict; + const RlvBehaviourInfo* m_pBhvrInfo = nullptr; + ERlvParamType m_eParamType = RLV_TYPE_UNKNOWN; + ERlvLocalBhvrModifier m_eBhvrModifier = ERlvLocalBhvrModifier::Unknown; + bool m_fStrict = false; std::string m_strOption; std::string m_strParam; - mutable bool m_fRefCounted; + mutable bool m_fRefCounted = false; friend class RlvHandler; friend class RlvObject; @@ -452,6 +466,15 @@ public: bool hasLookup() const { return m_fLookup; } const rlv_command_list_t& getCommandList() const { return m_Commands; } + /* + * Local-scope modifiers + */ +public: + void clearModifiers(ERlvBehaviour eBhvr); + void clearModifierValue(ERlvLocalBhvrModifier eBhvrMod); + template bool getModifierValue(ERlvLocalBhvrModifier eBhvrModifier, T& value) const; + void setModifierValue(ERlvLocalBhvrModifier eBhvrMod, const RlvBehaviourModifierValue& modValue); + /* * Member variables */ @@ -462,6 +485,8 @@ protected: bool m_fLookup; // TRUE if the object existed in gObjectList at one point in time S16 m_nLookupMisses; // Count of unsuccessful lookups in gObjectList by the GC rlv_command_list_t m_Commands; // List of behaviours held by this object (in the order they were received) + typedef std::map bhvr_modifier_map_t; + bhvr_modifier_map_t m_Modifiers; // List of (local scope) modifiers set on this object friend class RlvHandler; }; @@ -668,6 +693,19 @@ std::string rlvGetLastParenthesisedText(const std::string& strText, std::string: // Inlined class member functions // +inline void RlvBehaviourInfo::addModifier(ERlvLocalBhvrModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler) +{ + RLV_ASSERT_DBG(m_BhvrModifiers.find(strBhvrMod) == m_BhvrModifiers.end()); + + m_BhvrModifiers.insert(std::make_pair(strBhvrMod, std::make_tuple(eBhvrMod, std::type_index(valueType), fnHandler))); +} + +inline ERlvLocalBhvrModifier RlvBehaviourInfo::lookupBehaviourModifier(const std::string& strBhvrMod) const +{ + auto itBhvrModifier = m_BhvrModifiers.find(strBhvrMod); + return (m_BhvrModifiers.end() != itBhvrModifier) ? std::get<0>(itBhvrModifier->second) : ERlvLocalBhvrModifier::Unknown; +} + inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable) { if (fEnable) @@ -692,6 +730,18 @@ inline bool RlvCommand::operator ==(const RlvCommand& rhs) const ( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) ); } +template +inline bool RlvObject::getModifierValue(ERlvLocalBhvrModifier eBhvrModifier, T& value) const +{ + auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier); + if (m_Modifiers.end() != itBhvrModifierValue) + { + value = boost::get(itBhvrModifierValue->second); + return true; + } + return false; +} + // Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem) { diff --git a/indra/newview/rlvmodifiers.cpp b/indra/newview/rlvmodifiers.cpp deleted file mode 100644 index ce082254f2..0000000000 --- a/indra/newview/rlvmodifiers.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - * Copyright (c) 2009-2018, Kitty Barnett - * - * The source code in this file is provided to you under the terms of the - * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt - * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt - * - * By copying, modifying or distributing this software, you acknowledge that - * you have read and understood your obligations described above, and agree to - * abide by those obligations. - * - */ - -#include "llviewerprecompiledheaders.h" - -#include "rlvmodifiers.h" - -// ==================================================================================== -// RlvBehaviourModifierAnimator -// - -RlvBehaviourModifierAnimator::~RlvBehaviourModifierAnimator() -{ - if (!m_TimerHandle.isDead()) - m_TimerHandle.markDead(); -} - -void RlvBehaviourModifierAnimator::addTween(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod, RlvBehaviourModifierAnimationType eAnimType, const RlvBehaviourModifierValue& endValue, float nDuration) -{ - // Make sure we don't run two animations on the same modifier for the same object - const auto itTween = std::find_if(m_Tweens.begin(), m_Tweens.end(), [&idObject, eBhvrMod](const RlvBehaviourModifierTween& t) { return t.idObject == idObject && t.eBhvrMod == eBhvrMod; }); - if (m_Tweens.end() != itTween) - m_Tweens.erase(itTween); - - if (const RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(eBhvrMod)) - { - RlvBehaviourModifierTween newTween; - newTween.idObject = idObject; - newTween.eBhvrMod = eBhvrMod; - newTween.eAnimType = RlvBehaviourModifierAnimationType::Lerp; - newTween.nStartTime = LLTimer::getElapsedSeconds(); - newTween.nDuration = nDuration; - newTween.startValue = pBhvrModifier->getValue(); - newTween.endValue = endValue; - if (newTween.startValue.which() == newTween.endValue.which()) - { - if (m_TimerHandle.isDead()) - m_TimerHandle = (new AnimationTimer())->getHandle(); - m_Tweens.emplace_back(std::move(newTween)); - } - } -} - -void RlvBehaviourModifierAnimator::clearTweens(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod) -{ - m_Tweens.erase(std::remove_if(m_Tweens.begin(), m_Tweens.end(), - [&idObject, eBhvrMod](const RlvBehaviourModifierTween& cmpTween) - { - return cmpTween.idObject == idObject && ((cmpTween.eBhvrMod == eBhvrMod) || (RLV_MODIFIER_UNKNOWN == eBhvrMod)); - }), m_Tweens.end()); -} - -// ==================================================================================== -// RlvBehaviourModifierAnimator timer -// - -RlvBehaviourModifierAnimator::AnimationTimer::AnimationTimer() - : LLEventTimer(1.f / RLV_MODIFIER_ANIMATION_FREQUENCY) -{ -} - - -BOOL RlvBehaviourModifierAnimator::AnimationTimer::tick() -{ - RlvBehaviourModifierAnimator& modAnimatior = RlvBehaviourModifierAnimator::instance(); - const double curTime = LLTimer::getElapsedSeconds(); - - const auto activeTweens = modAnimatior.m_Tweens; - for (const auto& curTween : activeTweens) - { - if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(curTween.eBhvrMod)) - { - // Update the modifier's value - float curFactor = (curTime - curTween.nStartTime) / curTween.nDuration; - if (curFactor < 1.0) - { - const auto& valueType = curTween.startValue.type(); - if (typeid(float) == valueType) - pBhvrModifier->setValue(lerp(boost::get(curTween.startValue), boost::get(curTween.endValue), curFactor), curTween.idObject); - else if (typeid(int) == valueType) - pBhvrModifier->setValue(lerp(boost::get(curTween.startValue), boost::get(curTween.endValue), curFactor), curTween.idObject); - else if (typeid(LLVector3) == valueType) - pBhvrModifier->setValue(lerp(boost::get(curTween.startValue), boost::get(curTween.endValue), curFactor), curTween.idObject); - } - else - { - pBhvrModifier->setValue(curTween.endValue, curTween.idObject); - auto itTween = std::find_if(modAnimatior.m_Tweens.begin(), modAnimatior.m_Tweens.end(), - [&curTween](const RlvBehaviourModifierTween& t) - { - // NOTE: implementation leak - taking advantage of the fact that we know there can only be one active tween per object/modifier/type combination - return t.idObject == curTween.idObject && t.eBhvrMod == curTween.eBhvrMod && t.eAnimType == curTween.eAnimType; - }); - modAnimatior.m_Tweens.erase(itTween); - } - } - } - - return modAnimatior.m_Tweens.empty(); -} - - // ==================================================================================== diff --git a/indra/newview/rlvmodifiers.h b/indra/newview/rlvmodifiers.h index 832e01de1e..374ef58567 100644 --- a/indra/newview/rlvmodifiers.h +++ b/indra/newview/rlvmodifiers.h @@ -73,56 +73,6 @@ struct RlvBehaviourModifierCompMax : public RlvBehaviourModifierComp } }; -// ==================================================================================== -// RlvBehaviourModifierAnimator - A class to animate behaviour modifiers -// - -enum class RlvBehaviourModifierAnimationType { Lerp }; - -struct RlvBehaviourModifierTween -{ - LLUUID idObject; - ERlvBehaviourModifier eBhvrMod; - RlvBehaviourModifierAnimationType eAnimType; - double nStartTime; - float nDuration; - RlvBehaviourModifierValue startValue; - RlvBehaviourModifierValue endValue; -}; - -class RlvBehaviourModifierAnimator : public LLSingleton -{ - LLSINGLETON_EMPTY_CTOR(RlvBehaviourModifierAnimator); -public: - ~RlvBehaviourModifierAnimator(); - - /* - * Member functions - */ -public: - void addTween(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod, RlvBehaviourModifierAnimationType eAnimType, const RlvBehaviourModifierValue& endValue, float nDuration); - void clearTweens(const LLUUID& idObject) { clearTweens(idObject, RLV_MODIFIER_UNKNOWN); } - void clearTweens(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod); - - /* - * Animation timer - */ -protected: - class AnimationTimer : public LLEventTimer, public LLHandleProvider - { - public: - AnimationTimer(); - BOOL tick() override; - }; - - /* - * Member variables - */ -protected: - LLHandle m_TimerHandle; - std::list< RlvBehaviourModifierTween> m_Tweens; -}; - // ==================================================================================== // RlvCachedBehaviourModifier - Provides an optimized way to access a modifier that's frequently accessed and rarely updated // diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 27e1a4cdf5..36968b04fc 100644 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -68,7 +68,7 @@ Fejl detaljer: Beskeden kaldet '[_NAME]' blev ikke fundet i notificati - Der opstod en fejl ved opdatering af [APP_NAME]. Please [http://get.secondlife.com download the latest version] of the Viewer. + Der opstod en fejl ved opdatering af [APP_NAME]. Please [https://www.firestormviewer.org/downloads download the latest version] of the Viewer. diff --git a/indra/newview/skins/default/xui/de/floater_fs_asset_blacklist.xml b/indra/newview/skins/default/xui/de/floater_fs_asset_blacklist.xml index ef4fb0f1b5..b3eaed78e0 100644 --- a/indra/newview/skins/default/xui/de/floater_fs_asset_blacklist.xml +++ b/indra/newview/skins/default/xui/de/floater_fs_asset_blacklist.xml @@ -34,5 +34,7 @@