diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8694d28390804ebb97a3021f97ad99dfa71e7526..6cc236faae09e2bfd50104cb1e6f28afd1e822b7 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -718,6 +718,7 @@ set(viewer_SOURCE_FILES rlvinventory.cpp rlvextensions.cpp rlvfloaters.cpp + rlvmodifiers.cpp rlvui.cpp ) @@ -1343,6 +1344,7 @@ set(viewer_HEADER_FILES rlvinventory.h rlvextensions.h rlvfloaters.h + rlvmodifiers.h rlvui.h roles_constants.h VertexCache.h diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 2a175ce659ac38e79846e353c855ceac69695250..f354bd002d0e47e85f7e0519948ef542977c3c5b 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -237,6 +237,7 @@ enum ERlvBehaviour { 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, RLV_BHVR_UNKNOWN diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 4dd0cc6b313435d8d844a0ee6618dad6a8363929..d998375444d7249acc5b98fbbbe26ccf06dcd261 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -60,6 +60,7 @@ #include "rlvhelper.h" #include "rlvinventory.h" #include "rlvlocks.h" +#include "rlvmodifiers.h" #include "rlvui.h" #include "rlvextensions.h" @@ -2595,6 +2596,32 @@ ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_MODE>::onCommand(const RlvCommand& rl return RLV_RET_SUCCESS; } +// Handles: @setoverlay_tween:[<alpha>];[<tint>];<duration>=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETOVERLAY_TWEEN>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (3 != optionList.size()) ) + return RLV_RET_FAILED_OPTION; + + // Parse the duration first (required param) + float tweenDuration = .0f; + if (!RlvCommandOptionHelper::parseOption(optionList[2], tweenDuration)) + return RLV_RET_FAILED_OPTION; + + // 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); + + // 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); + + return RLV_RET_SUCCESS; +} + // Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const { diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 5e2e2084ae03590bcd9700bbeb409dbeb7b4efb4..22256d1da4bcf358eb5b0d24800e51521ae6549b 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -25,6 +25,7 @@ #include "rlvhelper.h" #include "rlvhandler.h" #include "rlvinventory.h" +#include "rlvmodifiers.h" #include <boost/algorithm/string.hpp> @@ -215,6 +216,7 @@ RlvBehaviourDictionary::RlvBehaviourDictionary() RLV_MODIFIER_OVERLAY_TINT, new RlvBehaviourModifier("Overlay - Tint", LLVector3(1.0f, 1.0f, 1.0f), false, new RlvBehaviourModifier_Comp())); 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 RlvBehaviourModifier_Comp())); + addEntry(new RlvForceProcessor<RLV_BHVR_SETOVERLAY_TWEEN>("setoverlay_tween", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); // // Force-wear @@ -482,6 +484,7 @@ 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(); @@ -501,6 +504,11 @@ bool RlvBehaviourModifier::hasValue() const { return (!m_Values.empty()) ? std::get<1>(m_Values.front()) == m_pValueComparator->m_idPrimaryObject : false; } +bool RlvBehaviourModifier::hasValue(const LLUUID& idRlvObj) const +{ + return m_Values.end() != std::find_if(m_Values.begin(), m_Values.end(), [&idRlvObj](const RlvBehaviourModifierValueTuple& cmpValue) { return std::get<1>(cmpValue) == idRlvObj; }); +} + void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr) { if ( (modValue.which() == m_DefaultValue.which()) ) diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 67165de11ba4abfa2575fa519449022b4ad569e9..97116894d92fd62568b9712c512e6ed37ac38670 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -284,6 +284,7 @@ class RlvBehaviourModifier const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? std::get<0>(m_Values.front()) : m_DefaultValue; } template<typename T> const T& getValue() const { return boost::get<T>(getValue()); } bool hasValue() const; + bool hasValue(const LLUUID& idRlvObj) const; void removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN); void setValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj); void setPrimaryObject(const LLUUID& idPrimaryObject); diff --git a/indra/newview/rlvmodifiers.cpp b/indra/newview/rlvmodifiers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8df8ca294c5233f92c906b08fd24268eac5bdf47 --- /dev/null +++ b/indra/newview/rlvmodifiers.cpp @@ -0,0 +1,124 @@ +/** + * + * 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_pTimer) + { + delete m_pTimer; + m_pTimer = nullptr; + } +} + +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 (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_pTimer) + m_pTimer = new AnimationTimer(); + 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 +// + +#define ANIMATION_FREQUENCY 10 + +RlvBehaviourModifierAnimator::AnimationTimer::AnimationTimer() + : LLEventTimer(1.f / 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 combnination + return t.idObject == curTween.idObject && t.eBhvrMod == curTween.eBhvrMod && t.eAnimType == curTween.eAnimType; + }); + modAnimatior.m_Tweens.erase(itTween); + } + } + } + + if (modAnimatior.m_Tweens.empty()) + { + modAnimatior.m_pTimer = nullptr; + return true; + } + return false; +} + + // ==================================================================================== diff --git a/indra/newview/rlvmodifiers.h b/indra/newview/rlvmodifiers.h new file mode 100644 index 0000000000000000000000000000000000000000..5f36d310e2cce438d30a6481848263be32046c85 --- /dev/null +++ b/indra/newview/rlvmodifiers.h @@ -0,0 +1,75 @@ +/** + * + * 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. + * + */ + +#pragma once + +#include "llsingleton.h" +#include "rlvhelper.h" + +// ==================================================================================== +// RlvBehaviourModifierAnimator - Helper types +// + +enum class RlvBehaviourModifierAnimationType { Lerp }; + +struct RlvBehaviourModifierTween +{ + LLUUID idObject; + ERlvBehaviourModifier eBhvrMod; + RlvBehaviourModifierAnimationType eAnimType; + double nStartTime; + float nDuration; + RlvBehaviourModifierValue startValue; + RlvBehaviourModifierValue endValue; +}; + +// ==================================================================================== +// RlvBehaviourModifierAnimator - A class to animate behaviour modifiers +// + +class RlvBehaviourModifierAnimator : public LLSingleton<RlvBehaviourModifierAnimator> +{ + friend class AnimationTimer; + 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 + */ + class AnimationTimer : LLEventTimer + { + public: + AnimationTimer(); + BOOL tick() override; + }; + + /* + * Member variables + */ + std::list<struct RlvBehaviourModifierTween> m_Tweens; + AnimationTimer* m_pTimer = nullptr; +}; + +// ====================================================================================