From e8a0915b4d313ddcb2cf9a0b34fa55f695fe96af Mon Sep 17 00:00:00 2001
From: Kitty Barnett <develop@catznip.com>
Date: Tue, 5 Jan 2021 04:58:09 +0100
Subject: [PATCH] Rework @setoverlay into a visual effect and move all the code
 out of RlvHandler

---
 indra/newview/CMakeLists.txt      |  19 ++--
 indra/newview/llviewerdisplay.cpp |   7 +-
 indra/newview/llviewerwindow.cpp  |   9 +-
 indra/newview/rlvdefines.h        |  20 ++--
 indra/newview/rlveffects.cpp      | 175 ++++++++++++++++++++++++++++++
 indra/newview/rlveffects.h        |  64 +++++++++++
 indra/newview/rlvhandler.cpp      | 125 ++++-----------------
 indra/newview/rlvhandler.h        |  22 ++--
 indra/newview/rlvhelper.cpp       |  31 +++---
 indra/newview/rlvhelper.h         |  30 ++---
 indra/newview/rlvmodifiers.cpp    | 115 --------------------
 indra/newview/rlvmodifiers.h      |  50 ---------
 12 files changed, 329 insertions(+), 338 deletions(-)
 create mode 100644 indra/newview/rlveffects.cpp
 create mode 100644 indra/newview/rlveffects.h
 delete mode 100644 indra/newview/rlvmodifiers.cpp

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 5803c59809d..2a83c30224d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -731,14 +731,14 @@ set(viewer_SOURCE_FILES
     noise.cpp
     pipeline.cpp
     rlvactions.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
     )
 
@@ -1366,14 +1366,15 @@ set(viewer_HEADER_FILES
     noise.h
     pipeline.h
     rlvactions.h
+    rlvcommon.h
     rlvdefines.h
+    rlveffects.h
+    rlvextensions.h
+    rlvfloaters.h
     rlvhandler.h
     rlvhelper.h
-    rlvcommon.h
-    rlvlocks.h
     rlvinventory.h
-    rlvextensions.h
-    rlvfloaters.h
+    rlvlocks.h
     rlvmodifiers.h
     rlvui.h
     roles_constants.h
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index be2fd55d7a7..817ff4ee531 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -79,7 +79,8 @@
 #include "llpostprocess.h"
 #include "llscenemonitor.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]
 
@@ -1310,9 +1311,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/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index adc56a8622f..6052d34f9a2 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -214,6 +214,8 @@
 #include "llcleanup.h"
 
 // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c)
+#include "rlvactions.h"
+#include "rlveffects.h"
 #include "rlvhandler.h"
 // [/RLVa:KB]
 
@@ -5663,11 +5665,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<RlvOverlayEffect>(EVisualEffect::RlvOverlay))
 		{
-			hit_object = nullptr;
+			if (pOverlayEffect->hitTest(mMousePt))
+				hit_object = nullptr;
 		}
 	}
 // [/RLVa:KB]
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 827a2d74c78..ea7bdeb8f94 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -240,12 +240,8 @@ 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_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,
@@ -255,10 +251,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)
@@ -283,6 +275,16 @@ enum ERlvBehaviourModifier
 	RLV_MODIFIER_UNKNOWN
 };
 
+enum class ERlvLocalBhvrModifier
+{
+	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
+
+	Unknown,
+};
+
 enum ERlvBehaviourOptionType
 {
 	RLV_OPTION_NONE,				// Behaviour takes no parameters
diff --git a/indra/newview/rlveffects.cpp b/indra/newview/rlveffects.cpp
new file mode 100644
index 00000000000..4750442089a
--- /dev/null
+++ b/indra/newview/rlveffects.cpp
@@ -0,0 +1,175 @@
+/**
+ *
+ * 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 "llglslshader.h"
+#include "llrender2dutils.h"
+#include "llviewertexturelist.h"
+#include "llviewerwindow.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))
+{
+	if (RlvObject* pRlvObj = gRlvHandler.getObject(idRlvObj))
+	{
+		float nAlpha;
+		if (pRlvObj->getModifierValue<float>(ERlvLocalBhvrModifier::OverlayAlpha, nAlpha))
+			m_nAlpha = nAlpha;
+
+		pRlvObj->getModifierValue<bool>(ERlvLocalBhvrModifier::OverlayTouch, m_fBlockTouch);
+
+		LLVector3 vecColor;
+		if (pRlvObj->getModifierValue<LLVector3>(ERlvLocalBhvrModifier::OverlayTint, vecColor))
+			m_Color = LLColor3(vecColor.mV);
+
+		LLUUID idTexture;
+		if ( (pRlvObj) && (pRlvObj->getModifierValue<LLUUID>(ERlvLocalBhvrModifier::OverlayTexture, idTexture)) )
+			setImage(idTexture);
+	}
+}
+
+RlvOverlayEffect::~RlvOverlayEffect()
+{
+	clearImage();
+}
+
+// static
+ERlvCmdRet RlvOverlayEffect::onAlphaValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue)
+{
+	if (RlvOverlayEffect* pEffect = dynamic_cast<RlvOverlayEffect*>(LLVfxManager::instance().getEffect(idRlvObj)))
+	{
+		pEffect->m_nAlpha = (newValue) ? boost::get<float>(newValue.value()) : c_DefaultAlpha;
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// static
+ERlvCmdRet RlvOverlayEffect::onBlockTouchValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue)
+{
+	if (RlvOverlayEffect* pEffect = dynamic_cast<RlvOverlayEffect*>(LLVfxManager::instance().getEffect(idRlvObj)))
+	{
+		pEffect->m_fBlockTouch = (newValue) ? boost::get<bool>(newValue.value()) : false;
+	}
+	return RLV_RET_SUCCESS;
+}
+// static
+ERlvCmdRet RlvOverlayEffect::onColorValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue)
+{
+	if (RlvOverlayEffect* pEffect = dynamic_cast<RlvOverlayEffect*>(LLVfxManager::instance().getEffect(idRlvObj)))
+	{
+		pEffect->m_Color = LLColor3( (newValue) ? boost::get<LLVector3>(newValue.value()).mV : c_DefaultColor);
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// static
+ERlvCmdRet RlvOverlayEffect::onTextureChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue)
+{
+	if (RlvOverlayEffect* pEffect = dynamic_cast<RlvOverlayEffect*>(LLVfxManager::instance().getEffect(idRlvObj)))
+	{
+		if (newValue)
+			pEffect->setImage(boost::get<LLUUID>(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()
+{
+	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();
+		}
+	}
+}
+
+// ====================================================================================
diff --git a/indra/newview/rlveffects.h b/indra/newview/rlveffects.h
new file mode 100644
index 00000000000..181187fe9da
--- /dev/null
+++ b/indra/newview/rlveffects.h
@@ -0,0 +1,64 @@
+/**
+ *
+ * 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:
+	void tweenAlpha(float endAlpha, double duration)    { m_nAlpha.start(endAlpha, duration); }
+	void tweenColor(LLColor3 endColor, double duration) { m_Color.start(endColor, duration); }
+	bool hitTest(const LLCoordGL& ptMouse) const;
+	static ERlvCmdRet onAlphaValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue);
+	static ERlvCmdRet onBlockTouchValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue);
+	static ERlvCmdRet onColorValueChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue);
+	static ERlvCmdRet onTextureChanged(const LLUUID& idRlvObj, const boost::optional<RlvBehaviourModifierValue> newValue);
+protected:
+	void clearImage();
+	void setImage(const LLUUID& idTexture);
+
+	void run() override;
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLTweenableValueLerp<float>    m_nAlpha;
+	bool                           m_fBlockTouch;
+	LLTweenableValueLerp<LLColor3> m_Color;
+
+	LLPointer<LLViewerFetchedTexture> m_pImage = nullptr;
+	int      m_nImageOrigBoost = 0;
+};
+
+// ====================================================================================
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index fd51bfac44f..a89338d5f95 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -53,12 +53,12 @@
 #include "llviewercamera.h"				// @setcam and related
 #include "llworldmapmessage.h"			// @tpto
 #include "llviewertexturelist.h"		// @setcam_texture
-#include "llviewerwindow.h"				// @setoverlay
 
 // RLVa includes
 #include "rlvactions.h"
 #include "rlvfloaters.h"
 #include "rlvactions.h"
+#include "rlveffects.h"
 #include "rlvhandler.h"
 #include "rlvhelper.h"
 #include "rlvinventory.h"
@@ -178,7 +178,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
@@ -2054,36 +2053,10 @@ void RlvBehaviourToggleHandler<RLV_BHVR_PAY>::onCommandToggle(ERlvBehaviour eBhv
 template<> template<>
 void RlvBehaviourToggleHandler<RLV_BHVR_SETOVERLAY>::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<const RlvObject*> 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);
-}
-
-// Handles: @setoverlay_texture:<uuid>=n|y changes
-template<>
-void RlvBehaviourModifierHandler<RLV_MODIFIER_OVERLAY_TEXTURE>::onValueChange() const
-{
-	if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TEXTURE))
-	{
-		if (pBhvrModifier->hasValue())
-			gRlvHandler.setOverlayImage(pBhvrModifier->getValue<LLUUID>());
-		else
-			gRlvHandler.clearOverlayImage();
-	}
+		LLVfxManager::instance().addEffect(new RlvOverlayEffect(gRlvHandler.getCurrentObject()));
+	else
+		LLVfxManager::instance().removeEffect(gRlvHandler.getCurrentObject());
 }
 
 // Handles: @sendchannel[:<channel>]=n|y and @sendchannel_except[:<channel>]=n|y
@@ -2984,6 +2957,14 @@ ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_MODE>::onCommand(const RlvCommand& rl
 template<> template<>
 ERlvCmdRet RlvForceHandler<RLV_BHVR_SETOVERLAY_TWEEN>::onCommand(const RlvCommand& rlvCmd)
 {
+	RlvObject* pRlvObj = gRlvHandler.getObject(rlvCmd.getObjectID());
+	if (!pRlvObj)
+		return RLV_RET_FAILED_NOBEHAVIOUR;
+
+	RlvOverlayEffect* pOverlayEffect = LLVfxManager::instance().getEffect<RlvOverlayEffect>(rlvCmd.getObjectID());
+	if (!pOverlayEffect)
+		return RLV_RET_FAILED_LOCK;
+
 	std::vector<std::string> optionList;
 	if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (3 != optionList.size()) )
 		return RLV_RET_FAILED_OPTION;
@@ -2996,12 +2977,18 @@ ERlvCmdRet RlvForceHandler<RLV_BHVR_SETOVERLAY_TWEEN>::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;
 }
@@ -3783,76 +3770,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<bool>()) &&
-	       (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<LLVector3>();
-		gGL.color4f(overlayTint.mV[0], overlayTint.mV[1], overlayTint.mV[2], llclamp(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_ALPHA)->getValue<float>(), 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 32eda851371..2aaea60c19a 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 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 public:
 	// Returns a list of all objects containing the specified behaviour
 	bool findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& 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 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 
 	// 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 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 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);
 
@@ -263,8 +257,6 @@ class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGrou
 	mutable LLUUID                          m_idAgentGroup;					// @setgroup=n
 	std::pair<LLUUID, std::string>          m_PendingGroupChange;			// @setgroup=force
 	std::pair<LLTimer, LLUUID>              m_GroupChangeExpiration;        // @setgroup=force
-	LLPointer<LLViewerFetchedTexture>       m_pOverlayImage = nullptr;		// @setoverlay=n
-	int                                     m_nOverlayOrigBoost = 0;		// @setoverlay=n
 
 	std::string                             m_strCameraPresetRestore;       // @setcam_eyeoffset, @setcam_eyeoffsetscale and @setcam_focusoffset
 
@@ -301,6 +293,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<RlvObject*>(&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 920bc31d222..1d19d096c1e 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -22,6 +22,7 @@
 #include "llviewerobjectlist.h"
 
 #include "rlvcommon.h"
+#include "rlveffects.h"
 #include "rlvhelper.h"
 #include "rlvhandler.h"
 #include "rlvinventory.h"
@@ -215,15 +216,12 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED));
 
 	// Overlay
-	addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETOVERLAY, RLV_OPTION_NONE>("setoverlay", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
-	addModifier(new RlvForceGenericProcessor<RLV_OPTION_MODIFIER>("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<RLV_OPTION_MODIFIER>("setoverlay_texture", RLV_BHVR_SETOVERLAY_TEXTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL),
-				RLV_MODIFIER_OVERLAY_TEXTURE, new RlvBehaviourModifierHandler<RLV_MODIFIER_OVERLAY_TEXTURE>("Overlay - Texture", LLUUID::null, false, new RlvBehaviourModifierComp()));
-	addModifier(new RlvForceGenericProcessor<RLV_OPTION_MODIFIER>("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<RLV_OPTION_NONE_OR_MODIFIER>("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<RLV_BHVR_SETOVERLAY, RLV_OPTION_NONE_OR_MODIFIER>("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<RLV_BHVR_SETOVERLAY_TWEEN>("setoverlay_tween", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
 
 	//
@@ -394,7 +392,7 @@ void RlvBehaviourDictionary::clearModifiers(const LLUUID& idRlvObj)
 	}
 }
 
-const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict, ERlvBehaviourModifier* peBhvrModifier) const
+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);
@@ -402,14 +400,14 @@ const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::stri
 	bool fStrict = (strBhvrLastPart.compare("sec") == 0);
 	if (pfStrict)
 		*pfStrict = fStrict;
-	ERlvBehaviourModifier eBhvrModifier = RLV_MODIFIER_UNKNOWN;
+	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));
 	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)) != RLV_MODIFIER_UNKNOWN)
+		if ( (m_String2InfoMap.end() != itBhvrMod) && (eBhvrModifier = itBhvrMod->second->lookupBehaviourModifier(strBhvrLastPart)) != ERlvLocalBhvrModifier::Unknown)
 			itBhvr = itBhvrMod;
 	}
 
@@ -420,10 +418,10 @@ const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::stri
 
 ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const
 {
-	ERlvBehaviourModifier eBhvrModifier;
+	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 && RLV_MODIFIER_UNKNOWN != eBhvrModifier) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
+	return (pBhvrInfo && ERlvLocalBhvrModifier::Unknown != eBhvrModifier) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN;
 }
 
 bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const
@@ -547,7 +545,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();
@@ -1127,12 +1124,12 @@ std::string RlvObject::getStatusString(const std::string& strFilter, const std::
 	return strStatus;
 }
 
-void RlvObject::clearModifierValue(ERlvBehaviourModifier eBhvrModifier)
+void RlvObject::clearModifierValue(ERlvLocalBhvrModifier eBhvrModifier)
 {
 	m_Modifiers.erase(eBhvrModifier);
 }
 
-void RlvObject::setModifierValue(ERlvBehaviourModifier eBhvrModifier, const RlvBehaviourModifierValue& newValue)
+void RlvObject::setModifierValue(ERlvLocalBhvrModifier eBhvrModifier, const RlvBehaviourModifierValue& newValue)
 {
 	auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier);
 	if (m_Modifiers.end() != itBhvrModifierValue)
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
index 322fd7dcda6..f5e9c7c6d22 100644
--- a/indra/newview/rlvhelper.h
+++ b/indra/newview/rlvhelper.h
@@ -66,7 +66,7 @@ class RlvBehaviourInfo
 		: m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {}
 	virtual ~RlvBehaviourInfo() {}
 
-	void                  addModifier(ERlvBehaviourModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler = nullptr);
+	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; }
@@ -76,7 +76,7 @@ class RlvBehaviourInfo
 	bool                  isExperimental() const    { return m_nBhvrFlags & BHVR_EXPERIMENTAL; }
 	bool                  isExtended() const        { return m_nBhvrFlags & BHVR_EXTENDED; }
 	bool                  isSynonym() const         { return m_nBhvrFlags & BHVR_SYNONYM; }
-	ERlvBehaviourModifier lookupBehaviourModifier(const std::string& strBhvrMod) const;
+	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; }
@@ -87,7 +87,7 @@ class RlvBehaviourInfo
 	ERlvBehaviour m_eBhvr;
 	U32           m_nBhvrFlags;
 	U32           m_maskParamType;
-	typedef std::map<std::string, std::tuple<ERlvBehaviourModifier, std::type_index, modifier_handler_func_t>> modifier_lookup_t;
+	typedef std::map<std::string, std::tuple<ERlvLocalBhvrModifier, std::type_index, modifier_handler_func_t>> modifier_lookup_t;
 	modifier_lookup_t m_BhvrModifiers;
 };
 
@@ -112,7 +112,7 @@ class RlvBehaviourDictionary : public LLSingleton<RlvBehaviourDictionary>
 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 = nullptr, ERlvBehaviourModifier* eBhvrModifier = nullptr) 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<std::string>& cmdList) const;
 	bool                    getHasStrict(ERlvBehaviour eBhvr) const;
 	RlvBehaviourModifier*   getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; }
@@ -299,14 +299,14 @@ class RlvCommand
 	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; }
-	ERlvBehaviourModifier   getBehaviourModifier() const { return m_eBhvrModifier; }
+	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 RLV_MODIFIER_UNKNOWN != m_eBhvrModifier; }
+	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; }
@@ -331,7 +331,7 @@ class RlvCommand
 	std::string             m_strBehaviour;
 	const RlvBehaviourInfo* m_pBhvrInfo = nullptr;
 	ERlvParamType           m_eParamType = RLV_TYPE_UNKNOWN;
-	ERlvBehaviourModifier   m_eBhvrModifier = RLV_MODIFIER_UNKNOWN;
+	ERlvLocalBhvrModifier   m_eBhvrModifier = ERlvLocalBhvrModifier::Unknown;
 	bool                    m_fStrict = false;
 	std::string             m_strOption;
 	std::string             m_strParam;
@@ -467,9 +467,9 @@ class RlvObject
 	 * Local-scope modifiers
 	 */
 public:
-	void                      clearModifierValue(ERlvBehaviourModifier eBhvrMod);
-	template<typename T> bool getModifierValue(ERlvBehaviourModifier eBhvrModifier, T& value) const;
-	void                      setModifierValue(ERlvBehaviourModifier eBhvrMod, const RlvBehaviourModifierValue& modValue);
+	void                      clearModifierValue(ERlvLocalBhvrModifier eBhvrMod);
+	template<typename T> bool getModifierValue(ERlvLocalBhvrModifier eBhvrModifier, T& value) const;
+	void                      setModifierValue(ERlvLocalBhvrModifier eBhvrMod, const RlvBehaviourModifierValue& modValue);
 
 	/*
 	 * Member variables
@@ -481,7 +481,7 @@ class RlvObject
 	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<ERlvBehaviourModifier, RlvBehaviourModifierValue> bhvr_modifier_map_t;
+	typedef std::map<ERlvLocalBhvrModifier, RlvBehaviourModifierValue> bhvr_modifier_map_t;
 	bhvr_modifier_map_t m_Modifiers;		// List of (local scope) modifiers set on this object
 
 	friend class RlvHandler;
@@ -707,17 +707,17 @@ std::string rlvGetLastParenthesisedText(const std::string& strText, std::string:
 // Inlined class member functions
 //
 
-inline void RlvBehaviourInfo::addModifier(ERlvBehaviourModifier eBhvrMod, const std::type_info& valueType, const std::string& strBhvrMod, modifier_handler_func_t fnHandler)
+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 ERlvBehaviourModifier RlvBehaviourInfo::lookupBehaviourModifier(const std::string& strBhvrMod) const
+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) : RLV_MODIFIER_UNKNOWN;
+	return (m_BhvrModifiers.end() != itBhvrModifier) ? std::get<0>(itBhvrModifier->second) : ERlvLocalBhvrModifier::Unknown;
 }
 
 inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable)
@@ -745,7 +745,7 @@ inline bool RlvCommand::operator ==(const RlvCommand& rhs) const
 }
 
 template <typename T>
-inline bool RlvObject::getModifierValue(ERlvBehaviourModifier eBhvrModifier, T& value) const
+inline bool RlvObject::getModifierValue(ERlvLocalBhvrModifier eBhvrModifier, T& value) const
 {
 	auto itBhvrModifierValue = m_Modifiers.find(eBhvrModifier);
 	if (m_Modifiers.end() != itBhvrModifierValue)
diff --git a/indra/newview/rlvmodifiers.cpp b/indra/newview/rlvmodifiers.cpp
deleted file mode 100644
index ce082254f2e..00000000000
--- 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<float>(curTween.startValue), boost::get<float>(curTween.endValue), curFactor), curTween.idObject);
-				else if (typeid(int) == valueType)
-					pBhvrModifier->setValue(lerp(boost::get<int>(curTween.startValue), boost::get<int>(curTween.endValue), curFactor), curTween.idObject);
-				else if (typeid(LLVector3) == valueType)
-					pBhvrModifier->setValue(lerp(boost::get<LLVector3>(curTween.startValue), boost::get<LLVector3>(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 3ccec3e71c3..374ef585670 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<RlvBehaviourModifierAnimator>
-{
-	LLSINGLETON_EMPTY_CTOR(RlvBehaviourModifierAnimator);
-public:
-	~RlvBehaviourModifierAnimator() override;
-
-	/*
-	 * 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<AnimationTimer>
-	{
-	public:
-		AnimationTimer();
-		BOOL tick() override;
-	};
-
-	/*
-	 * Member variables
-	 */
-protected:
-	LLHandle<AnimationTimer>              m_TimerHandle;
-	std::list< RlvBehaviourModifierTween> m_Tweens;
-};
-
 // ====================================================================================
 // RlvCachedBehaviourModifier - Provides an optimized way to access a modifier that's frequently accessed and rarely updated
 //
-- 
GitLab