From e76de9823424d5ee970c61b47c0d177ff01c9ab7 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:30:11 +0100 Subject: [PATCH 1/3] Enable checking if temp var is in use --- lib/macro/macro-action-variable.cpp | 9 +++++ lib/macro/macro-action-variable.hpp | 1 + lib/macro/macro-condition-tempvar.cpp | 9 +++++ lib/macro/macro-condition-tempvar.hpp | 1 + lib/macro/macro-segment.cpp | 15 +++++++ lib/macro/macro-segment.hpp | 10 +++++ lib/utils/temp-variable.cpp | 58 +++++++++++++++++++++++++++ lib/utils/temp-variable.hpp | 4 ++ plugins/base/macro-action-filter.cpp | 9 +++++ plugins/base/macro-action-filter.hpp | 2 + plugins/base/macro-action-source.cpp | 9 +++++ plugins/base/macro-action-source.hpp | 18 ++++++--- 12 files changed, 139 insertions(+), 6 deletions(-) diff --git a/lib/macro/macro-action-variable.cpp b/lib/macro/macro-action-variable.cpp index 881c316c..e92329dc 100644 --- a/lib/macro/macro-action-variable.cpp +++ b/lib/macro/macro-action-variable.cpp @@ -17,6 +17,14 @@ namespace advss { const std::string MacroActionVariable::id = "variable"; +std::vector MacroActionVariable::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionVariable::_registered = MacroActionFactory::Register( MacroActionVariable::id, {MacroActionVariable::Create, MacroActionVariableEdit::Create, @@ -1450,6 +1458,7 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); SetWidgetVisibility(); } diff --git a/lib/macro/macro-action-variable.hpp b/lib/macro/macro-action-variable.hpp index cbcb2724..43d2a740 100644 --- a/lib/macro/macro-action-variable.hpp +++ b/lib/macro/macro-action-variable.hpp @@ -23,6 +23,7 @@ public: bool PostLoad(); std::string GetShortDesc() const; std::string GetId() const { return id; }; + std::vector GetTempVarRefs() const; static std::shared_ptr Create(Macro *m); std::shared_ptr Copy() const; void SetSegmentIndexValue(int); diff --git a/lib/macro/macro-condition-tempvar.cpp b/lib/macro/macro-condition-tempvar.cpp index 1b4adad9..db7ed2b3 100644 --- a/lib/macro/macro-condition-tempvar.cpp +++ b/lib/macro/macro-condition-tempvar.cpp @@ -6,6 +6,14 @@ namespace advss { const std::string MacroConditionTempVar::id = "temp_var"; +std::vector MacroConditionTempVar::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroConditionTempVar::_registered = MacroConditionFactory::Register( MacroConditionTempVar::id, {MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create, @@ -266,6 +274,7 @@ void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroConditionTempVarEdit::Variable2Changed(const QString &text) diff --git a/lib/macro/macro-condition-tempvar.hpp b/lib/macro/macro-condition-tempvar.hpp index 9d525622..681a8935 100644 --- a/lib/macro/macro-condition-tempvar.hpp +++ b/lib/macro/macro-condition-tempvar.hpp @@ -20,6 +20,7 @@ public: bool Load(obs_data_t *obj); std::string GetShortDesc() const; std::string GetId() const { return id; }; + std::vector GetTempVarRefs() const; static std::shared_ptr Create(Macro *m) { return std::make_shared(m); diff --git a/lib/macro/macro-segment.cpp b/lib/macro/macro-segment.cpp index 38a0cfba..f10907a8 100644 --- a/lib/macro/macro-segment.cpp +++ b/lib/macro/macro-segment.cpp @@ -13,6 +13,11 @@ namespace advss { +std::vector MacroSegment::GetTempVarRefs() const +{ + return {}; +} + MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue) : _macro(m), _supportsVariableValue(supportsVariableValue) @@ -152,6 +157,16 @@ void MacroSegment::AddTempvar(const std::string &id, const std::string &name, NotifyUIAboutTempVarChange(this); } +bool MacroSegment::IsTempVarInUse(const std::string &id) const +{ + for (const auto &var : _tempVariables) { + if (var.ID() == id) { + return var.IsInUse(); + } + } + return false; +} + void MacroSegment::SetTempVarValue(const std::string &id, const std::string &value) { diff --git a/lib/macro/macro-segment.hpp b/lib/macro/macro-segment.hpp index 39ff8835..803379d2 100644 --- a/lib/macro/macro-segment.hpp +++ b/lib/macro/macro-segment.hpp @@ -34,6 +34,7 @@ public: std::string GetCustomLabel() const { return _customLabel; } virtual bool Save(obs_data_t *obj) const = 0; virtual bool Load(obs_data_t *obj) = 0; + virtual std::vector GetTempVarRefs() const; virtual bool PostLoad(); virtual std::string GetShortDesc() const; virtual std::string GetId() const = 0; @@ -54,6 +55,7 @@ protected: void AddTempvar(const std::string &id, const std::string &name, const std::string &description = ""); + bool IsTempVarInUse(const std::string &id) const; void SetTempVarValue(const std::string &id, const std::string &value); template>> + void SetTempVarValue(const std::string &id, F &&valueProvider) + { + if (IsTempVarInUse(id)) { + SetTempVarValue(id, valueProvider()); + } + } + private: void ClearAvailableTempvars(); std::optional diff --git a/lib/utils/temp-variable.cpp b/lib/utils/temp-variable.cpp index df37c89b..15005af7 100644 --- a/lib/utils/temp-variable.cpp +++ b/lib/utils/temp-variable.cpp @@ -10,9 +10,12 @@ #include #include +#include Q_DECLARE_METATYPE(advss::TempVariableRef); +static std::atomic tempVarInUseGeneration{0}; + namespace advss { TempVariable::TempVariable(const std::string &id, const std::string &name, @@ -120,6 +123,60 @@ TempVariableRef TempVariable::GetRef() const return ref; } +static bool refsContain(const std::vector &refs, + const TempVariableRef &ref) +{ + for (const auto &r : refs) { + if (r == ref) { + return true; + } + } + return false; +} + +template +static bool segmentsReferTo(const T &segments, const TempVariableRef &ref) +{ + for (const auto &segment : segments) { + if (refsContain(segment->GetTempVarRefs(), ref)) { + return true; + } + } + return false; +} + +bool TempVariable::IsInUse() const +{ + const auto currentGen = + tempVarInUseGeneration.load(std::memory_order_relaxed); + if (_isInUseCacheGeneration == currentGen) { + return _isInUseCache; + } + + bool inUse = false; + const auto ref = GetRef(); + + if (ref.HasValidID()) { + for (const auto ¯o : GetAllMacros()) { + if (segmentsReferTo(macro->Conditions(), ref) || + segmentsReferTo(macro->Actions(), ref) || + segmentsReferTo(macro->ElseActions(), ref)) { + inUse = true; + break; + } + } + } + + _isInUseCache = inUse; + _isInUseCacheGeneration = currentGen; + return inUse; +} + +void IncrementTempVarInUseGeneration() +{ + tempVarInUseGeneration.fetch_add(1, std::memory_order_relaxed); +} + TempVariableRef::SegmentType TempVariableRef::GetType() const { auto segment = _segment.lock(); @@ -665,6 +722,7 @@ TempVarSignalManager *TempVarSignalManager::Instance() void NotifyUIAboutTempVarChange(MacroSegment *segment) { + IncrementTempVarInUseGeneration(); obs_queue_task( OBS_TASK_UI, [](void *segment) { diff --git a/lib/utils/temp-variable.hpp b/lib/utils/temp-variable.hpp index b404d576..92c1edb2 100644 --- a/lib/utils/temp-variable.hpp +++ b/lib/utils/temp-variable.hpp @@ -44,6 +44,7 @@ public: void SetValue(const std::string &val); void InvalidateValue(); TempVariableRef GetRef() const; + EXPORT bool IsInUse() const; private: std::string _id = ""; @@ -53,6 +54,8 @@ private: mutable std::mutex _lastValuesMutex; std::vector _lastValues; bool _valueIsValid = false; + mutable bool _isInUseCache = false; + mutable uint64_t _isInUseCacheGeneration = UINT64_MAX; std::weak_ptr _segment; friend TempVariableSelection; @@ -122,5 +125,6 @@ private: }; void NotifyUIAboutTempVarChange(MacroSegment *); +EXPORT void IncrementTempVarInUseGeneration(); } // namespace advss diff --git a/plugins/base/macro-action-filter.cpp b/plugins/base/macro-action-filter.cpp index b63d6c57..2fd6b66c 100644 --- a/plugins/base/macro-action-filter.cpp +++ b/plugins/base/macro-action-filter.cpp @@ -9,6 +9,14 @@ namespace advss { const std::string MacroActionFilter::id = "filter"; +std::vector MacroActionFilter::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionFilter::_registered = MacroActionFactory::Register( MacroActionFilter::id, {MacroActionFilter::Create, MacroActionFilterEdit::Create, @@ -428,6 +436,7 @@ void MacroActionFilterEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting) diff --git a/plugins/base/macro-action-filter.hpp b/plugins/base/macro-action-filter.hpp index 19da4425..f8d2ea45 100644 --- a/plugins/base/macro-action-filter.hpp +++ b/plugins/base/macro-action-filter.hpp @@ -41,6 +41,8 @@ public: SettingsInputMethod _settingsInputMethod = SettingsInputMethod::INDIVIDUAL_MANUAL; + std::vector GetTempVarRefs() const; + SourceSelection _source; FilterSelection _filter; Action _action = Action::ENABLE; diff --git a/plugins/base/macro-action-source.cpp b/plugins/base/macro-action-source.cpp index cc88ca8a..1c4c13f0 100644 --- a/plugins/base/macro-action-source.cpp +++ b/plugins/base/macro-action-source.cpp @@ -13,6 +13,14 @@ namespace advss { const std::string MacroActionSource::id = "source"; +std::vector MacroActionSource::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionSource::_registered = MacroActionFactory::Register( MacroActionSource::id, {MacroActionSource::Create, MacroActionSourceEdit::Create, @@ -652,6 +660,7 @@ void MacroActionSourceEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroActionSourceEdit::SettingsInputMethodChanged(int idx) diff --git a/plugins/base/macro-action-source.hpp b/plugins/base/macro-action-source.hpp index ebb4c42f..d6ea7324 100644 --- a/plugins/base/macro-action-source.hpp +++ b/plugins/base/macro-action-source.hpp @@ -15,16 +15,22 @@ namespace advss { class MacroActionSource : public MacroAction { public: MacroActionSource(Macro *m) : MacroAction(m) {} - bool PerformAction(); - void LogAction() const; - bool Save(obs_data_t *obj) const; - bool Load(obs_data_t *obj); - std::string GetShortDesc() const; - std::string GetId() const { return id; }; + static std::shared_ptr Create(Macro *m); std::shared_ptr Copy() const; + + bool PerformAction(); + void LogAction() const; + + bool Save(obs_data_t *obj) const; + bool Load(obs_data_t *obj); + + std::string GetShortDesc() const; + std::string GetId() const { return id; }; + void ResolveVariablesToFixedValues(); void SetupTempVars(); + std::vector GetTempVarRefs() const; enum class Action { ENABLE, From dcb8a727a3183d7a86da4696429340e75969905e Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:19:00 +0100 Subject: [PATCH 2/3] Rework pattern count temp var --- plugins/video/macro-condition-video.cpp | 14 +++++++++--- plugins/video/opencv-helpers.cpp | 29 +++++++++++++++++++++++++ plugins/video/opencv-helpers.hpp | 1 + 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/plugins/video/macro-condition-video.cpp b/plugins/video/macro-condition-video.cpp index 425d5704..04746a5f 100644 --- a/plugins/video/macro-condition-video.cpp +++ b/plugins/video/macro-condition-video.cpp @@ -283,10 +283,18 @@ bool MacroConditionVideo::ScreenshotContainsPattern() SetTempVarValue("patternCount", "0"); return false; } - const auto count = countNonZero(result); + SetTempVarValue("similarity", std::to_string(bestMatchValue)); - SetTempVarValue("patternCount", std::to_string(count)); - return count > 0; + + if (IsTempVarInUse("patternCount")) { + const auto count = CountPatternMatches( + result, {_patternImageData.rgbaPattern.cols, + _patternImageData.rgbaPattern.rows}); + SetTempVarValue("patternCount", std::to_string(count)); + return count > 0; + } + + return countNonZero(result) > 0; } bool MacroConditionVideo::FileInputIsUpToDate() const diff --git a/plugins/video/opencv-helpers.cpp b/plugins/video/opencv-helpers.cpp index 63a920d0..df0f1f10 100644 --- a/plugins/video/opencv-helpers.cpp +++ b/plugins/video/opencv-helpers.cpp @@ -97,6 +97,35 @@ double MatchPattern(QImage &img, const PatternImageData &patternData, return bestFitValue; } +int CountPatternMatches(const cv::Mat &result, const cv::Size &patternSize) +{ + if (result.empty()) { + return 0; + } + + cv::Mat work = result.clone(); + int count = 0; + + while (true) { + double maxVal; + cv::Point maxLoc; + cv::minMaxLoc(work, nullptr, &maxVal, nullptr, &maxLoc); + if (maxVal <= 0.0) { + break; + } + count++; + // Suppress the template-sized region around this match so + // overlapping high-scoring positions are not counted separately + int x = std::max(0, maxLoc.x - patternSize.width / 2); + int y = std::max(0, maxLoc.y - patternSize.height / 2); + int w = std::min(patternSize.width, work.cols - x); + int h = std::min(patternSize.height, work.rows - y); + work(cv::Rect(x, y, w, h)) = 0.0f; + } + + return count; +} + double MatchPattern(QImage &img, QImage &pattern, double threshold, cv::Mat &result, bool useAlphaAsMask, cv::TemplateMatchModes matchColor) diff --git a/plugins/video/opencv-helpers.hpp b/plugins/video/opencv-helpers.hpp index 5f95d545..9ed6a95a 100644 --- a/plugins/video/opencv-helpers.hpp +++ b/plugins/video/opencv-helpers.hpp @@ -68,6 +68,7 @@ double MatchPattern(QImage &img, const PatternImageData &patternData, double MatchPattern(QImage &img, QImage &pattern, double threshold, cv::Mat &result, bool useAlphaAsMask, cv::TemplateMatchModes matchMode); +int CountPatternMatches(const cv::Mat &result, const cv::Size &patternSize); std::vector MatchObject(QImage &img, cv::CascadeClassifier &cascade, double scaleFactor, int minNeighbors, const cv::Size &minSize, From cc509282854bdc6b0cf1d66cc9de845d2cdf40c5 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Sat, 21 Mar 2026 23:14:10 +0100 Subject: [PATCH 3/3] Adjust video condition temp vars --- data/locale/en-US.ini | 2 ++ plugins/video/macro-condition-video.cpp | 26 ++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 2724ba74..6db83513 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -2215,6 +2215,8 @@ AdvSceneSwitcher.tempVar.video.text="OCR text" AdvSceneSwitcher.tempVar.video.text.description="The text detected in a given video input frame." AdvSceneSwitcher.tempVar.video.color="Average color" AdvSceneSwitcher.tempVar.video.color.description="The average RGB color in a given video input frame in HexArgb format." +AdvSceneSwitcher.tempVar.video.dominantColor="Dominant color" +AdvSceneSwitcher.tempVar.video.dominantColor.description="The most dominant RGB color in a given video input frame in HexArgb format." AdvSceneSwitcher.tempVar.websocket.message="Received websocket message" AdvSceneSwitcher.tempVar.websocket.message.description="The received websocket message, which matched the given pattern" diff --git a/plugins/video/macro-condition-video.cpp b/plugins/video/macro-condition-video.cpp index 04746a5f..adb3db8b 100644 --- a/plugins/video/macro-condition-video.cpp +++ b/plugins/video/macro-condition-video.cpp @@ -377,13 +377,19 @@ bool MacroConditionVideo::CheckColor() _screenshotData.GetImage(), _colorParameters.color, _colorParameters.colorThreshold, _colorParameters.matchThreshold); - // Way too slow for now - //SetTempVarValue("dominantColor", GetDominantColor(_screenshotData.image, 3) - // .name(QColor::HexArgb) - // .toStdString()); - SetTempVarValue("color", GetAverageColor(_screenshotData.GetImage()) - .name(QColor::HexArgb) - .toStdString()); + + SetTempVarValue("color", [&]() { + return GetAverageColor(_screenshotData.GetImage()) + .name(QColor::HexArgb) + .toStdString(); + }); + + SetTempVarValue("dominantColor", [&]() { + return GetDominantColor(_screenshotData.GetImage(), 3) + .name(QColor::HexArgb) + .toStdString(); + }); + return ret; } @@ -479,6 +485,12 @@ void MacroConditionVideo::SetupTempVars() obs_module_text("AdvSceneSwitcher.tempVar.video.color"), obs_module_text( "AdvSceneSwitcher.tempVar.video.color.description")); + AddTempvar( + "dominantColor", + obs_module_text( + "AdvSceneSwitcher.tempVar.video.dominantColor"), + obs_module_text( + "AdvSceneSwitcher.tempVar.video.dominantColor.description")); break; case VideoCondition::MATCH: case VideoCondition::DIFFER: