From 788fa693fd65d45f0ddfe8bb4cfae7f22cc9aa51 Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Tue, 6 Apr 2021 23:20:13 +0200 Subject: [PATCH] Draft implementation of Following mechanism for Image processing --- ImGuiVisitor.cpp | 75 ++++++++++++++++++++++++++++++++++++------------ Source.cpp | 15 +++++++++- Source.h | 7 ++++- SourceList.cpp | 63 ++++++++++++++++++++++++++++++++++++++++ SourceList.h | 21 ++++++++++++++ 5 files changed, 160 insertions(+), 21 deletions(-) diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 88588ae..92a1874 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -473,25 +473,51 @@ void ImGuiVisitor::visit (Source& s) ImGui::OpenPopup( "MenuImageProcessing" ); if (ImGui::BeginPopup( "MenuImageProcessing" )) { - if (ImGui::MenuItem("Reset" )){ - ImageProcessingShader defaultvalues; - s.processingShader()->copy(defaultvalues); - std::ostringstream oss; - oss << s.name() << ": " << "Reset Filter"; - Action::manager().store(oss.str()); + if (s.processingshader_link_.connected()) { + if (ImGui::MenuItem( "Unfollow" )){ + s.processingshader_link_.disconnect(); + } } - if (ImGui::MenuItem("Copy" )){ - std::string clipboard = SessionVisitor::getClipboard(s.processingShader()); - if (!clipboard.empty()) - ImGui::SetClipboardText(clipboard.c_str()); - } - const char *clipboard = ImGui::GetClipboardText(); - const bool can_paste = (clipboard != nullptr && SessionLoader::isClipboard(clipboard)); - if (ImGui::MenuItem("Paste", NULL, false, can_paste)) { - SessionLoader::applyImageProcessing(s, clipboard); - std::ostringstream oss; - oss << s.name() << ": " << "Change Filter"; - Action::manager().store(oss.str()); + else { + if (ImGui::MenuItem("Reset" )){ + ImageProcessingShader defaultvalues; + s.processingShader()->copy(defaultvalues); + s.processingshader_link_.disconnect(); + std::ostringstream oss; + oss << s.name() << ": " << "Reset Filter"; + Action::manager().store(oss.str()); + } + if (ImGui::MenuItem("Copy" )){ + std::string clipboard = SessionVisitor::getClipboard(s.processingShader()); + if (!clipboard.empty()) + ImGui::SetClipboardText(clipboard.c_str()); + } + const char *clipboard = ImGui::GetClipboardText(); + const bool can_paste = (clipboard != nullptr && SessionLoader::isClipboard(clipboard)); + if (ImGui::MenuItem("Paste", NULL, false, can_paste)) { + SessionLoader::applyImageProcessing(s, clipboard); + std::ostringstream oss; + oss << s.name() << ": " << "Change Filter"; + Action::manager().store(oss.str()); + } + ImGui::Separator(); + if (ImGui::BeginMenu("Follow")) + { + for (auto mpit = Mixer::manager().session()->begin(); + mpit != Mixer::manager().session()->end(); mpit++ ) + { + std::string label = (*mpit)->name(); + if ( (*mpit)->id() != s.id() && + (*mpit)->imageProcessingEnabled() && + !(*mpit)->processingshader_link_.connected()) { + if (ImGui::MenuItem( label.c_str() )){ + s.processingshader_link_.connect(*mpit); + s.touch(); + } + } + } + ImGui::EndMenu(); + } } ImGui::EndPopup(); @@ -499,7 +525,18 @@ void ImGuiVisitor::visit (Source& s) // full panel for image processing ImGui::SetCursorPos( ImVec2( pos.x, pos.y + preview_height)); // ...come back - s.processingShader()->accept(*this); + + if (s.processingshader_link_.connected()) { + ImGuiToolkit::Icon(6, 2); + ImGui::SameLine(0, 10); + ImGui::Text("Filters"); + Source *target = s.processingshader_link_.source(); + ImGui::Text("Following"); + if ( ImGui::Button(target->name().c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + Mixer::manager().setCurrentSource(target); + } + else + s.processingShader()->accept(*this); } // geometry direct control for DEBUG diff --git a/Source.cpp b/Source.cpp index 4668bbf..bd2238b 100644 --- a/Source.cpp +++ b/Source.cpp @@ -12,7 +12,6 @@ #include "ImageShader.h" #include "ImageProcessingShader.h" #include "SystemToolkit.h" -#include "SessionVisitor.h" #include "Log.h" #include "MixingGroup.h" @@ -234,6 +233,10 @@ Source::Source() : initialized_(false), symbol_(nullptr), active_(true), locked_ Source::~Source() { + // inform links that they lost their target + while ( !links_.empty() ) + links_.front()->disconnect(); + // inform clones that they lost their origin for (auto it = clones_.begin(); it != clones_.end(); it++) (*it)->detach(); @@ -649,6 +652,15 @@ void Source::update(float dt) need_update_ = false; } + if (processingshader_link_.connected() && imageProcessingEnabled()) { + Source *ref_source = processingshader_link_.source(); + if (ref_source!=nullptr) { + if (ref_source->imageProcessingEnabled()) + processingshader_->copy( *ref_source->processingShader() ); + else + processingshader_link_.disconnect(); + } + } } FrameBuffer *Source::frame() const @@ -749,6 +761,7 @@ void Source::clearMixingGroup() overlay_mixinggroup_->visible_ = false; } + CloneSource *Source::clone() { CloneSource *s = new CloneSource(this); diff --git a/Source.h b/Source.h index 5b3a400..6c033c3 100644 --- a/Source.h +++ b/Source.h @@ -15,7 +15,6 @@ class MaskShader; class ImageProcessingShader; class FrameBuffer; class FrameBufferSurface; -class Session; class Frame; class Handles; class Symbol; @@ -26,6 +25,7 @@ typedef std::list CloneList; class Source { + friend class SourceLink; friend class CloneSource; friend class View; friend class MixingView; @@ -198,6 +198,8 @@ public: // class-dependent icon virtual glm::ivec2 icon () const { return glm::ivec2(12, 11); } + SourceLink processingshader_link_; + protected: // name std::string name_; @@ -263,6 +265,9 @@ protected: // clones CloneList clones_; + // links + SourceLinkList links_; + // Mixing MixingGroup *mixinggroup_; Switch *overlay_mixinggroup_; diff --git a/SourceList.cpp b/SourceList.cpp index a579669..f0d33da 100644 --- a/SourceList.cpp +++ b/SourceList.cpp @@ -4,6 +4,8 @@ #include #include "Source.h" +#include "Session.h" + #include "SourceList.h" // utility to sort Sources by depth @@ -118,3 +120,64 @@ SourceList join (const SourceList &first, const SourceList &second) return l; } + +void SourceLink::connect(uint64_t id, Session *se) +{ + if (connected()) + disconnect(); + + id_ = id; + host_ = se; +} + +void SourceLink::connect(Source *s) +{ + if (connected()) + disconnect(); + + target_ = s; + id_ = s->id(); + target_->links_.push_back(this); + // TODO veryfy circular dependency recursively ? +} + +void SourceLink::disconnect() +{ + if (target_) + target_->links_.remove(this); + + id_ = 0; + target_ = nullptr; + host_ = nullptr; +} + +SourceLink::~SourceLink() +{ + disconnect(); +} + +Source *SourceLink::source() +{ + // no link to pointer yet? + if ( target_ == nullptr ) { + // to find a source, we need a host and an id + if ( id_ > 0 && host_ != nullptr) { + // find target in session + SourceList::iterator it = host_->find(id_); + // found: keep pointer + if (it != host_->end()) { + target_ = *it; + target_->links_.push_back(this); + } + // not found: invalidate link + else + disconnect(); + } + // no host: invalidate link + else + disconnect(); + } + + return target_; +} + diff --git a/SourceList.h b/SourceList.h index be2dcd3..59bb871 100644 --- a/SourceList.h +++ b/SourceList.h @@ -5,6 +5,7 @@ #include class Source; +class Session; typedef std::list SourceList; @@ -25,4 +26,24 @@ SourceListCompare compare (const SourceList &first, const SourceList &second); typedef std::list SourceIdList; SourceIdList ids (const SourceList &list); +class SourceLink { + +public: + SourceLink(): host_(nullptr), target_(nullptr), id_(0) { } + ~SourceLink(); + + void connect(uint64_t id, Session *se); + void connect(Source *s); + void disconnect(); + bool connected() { return id_ > 0; } + + Source *source(); + +protected: + Session *host_; + Source *target_; + uint64_t id_; +}; +typedef std::list SourceLinkList; + #endif // SOURCELIST_H