diff --git a/ActionManager.cpp b/ActionManager.cpp index 5277192..9595ea5 100644 --- a/ActionManager.cpp +++ b/ActionManager.cpp @@ -169,7 +169,7 @@ void Action::restore(uint target, uint64_t id) return; // sessionsources contains list of ids of all sources currently in the session - std::list sessionsources = se->getIdList(); + SourceIdList sessionsources = se->getIdList(); // for( auto it = sessionsources.begin(); it != sessionsources.end(); it++) // Log::Info("sessionsources id %s", std::to_string(*it).c_str()); @@ -180,7 +180,7 @@ void Action::restore(uint target, uint64_t id) loader.load( sessionNode ); // loadersources contains list of ids of all sources generated by loader - std::list loadersources = loader.getIdList(); + SourceIdList loadersources = loader.getIdList(); // for( auto it = loadersources.begin(); it != loadersources.end(); it++) // Log::Info("loadersources id %s", std::to_string(*it).c_str()); diff --git a/CMakeLists.txt b/CMakeLists.txt index a91b219..eaf8498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,6 +280,7 @@ set(VMIX_SRCS TextureView.cpp TransitionView.cpp Source.cpp + SourceList.cpp Session.cpp Selection.cpp SessionSource.cpp diff --git a/LayerView.cpp b/LayerView.cpp index c073fe8..3a913dc 100644 --- a/LayerView.cpp +++ b/LayerView.cpp @@ -109,7 +109,7 @@ void LayerView::draw() // manipulation of sources in Mixing view if (ImGui::Selectable( ICON_FA_ALIGN_CENTER " Distribute" )){ - SourceList dsl = depthSorted(Mixer::selection().getCopy()); + SourceList dsl = depth_sorted(Mixer::selection().getCopy()); SourceList::iterator it = dsl.begin(); float depth = (*it)->depth(); float depth_inc = (dsl.back()->depth() - depth) / static_cast(Mixer::selection().size()-1); @@ -120,7 +120,7 @@ void LayerView::draw() View::need_deep_update_++; } if (ImGui::Selectable( ICON_FA_RULER_HORIZONTAL " Space equally" )){ - SourceList dsl = depthSorted(Mixer::selection().getCopy()); + SourceList dsl = depth_sorted(Mixer::selection().getCopy()); SourceList::iterator it = dsl.begin(); float depth = (*it)->depth(); for (it++; it != dsl.end(); it++) { @@ -130,7 +130,7 @@ void LayerView::draw() View::need_deep_update_++; } if (ImGui::Selectable( ICON_FA_EXCHANGE_ALT " Reverse order" )){ - SourceList dsl = depthSorted(Mixer::selection().getCopy()); + SourceList dsl = depth_sorted(Mixer::selection().getCopy()); SourceList::iterator it = dsl.begin(); SourceList::reverse_iterator rit = dsl.rbegin(); for (; it != dsl.end(); it++, rit++) { diff --git a/Mixer.cpp b/Mixer.cpp index da14cc7..f46430a 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -28,6 +28,7 @@ using namespace tinyxml2; #include "StreamSource.h" #include "NetworkSource.h" #include "ActionManager.h" +#include "MixingGroup.h" #include "Streamer.h" #include "Mixer.h" @@ -208,6 +209,22 @@ void Mixer::update() // update session and associated sources session_->update(dt_); + // update session's mixing groups + auto group_iter = session_->beginMixingGroup(); + while ( group_iter != session_->endMixingGroup() ){ + // update all valid groups + if ((*group_iter)->size() > 1) { + (*group_iter)->update(dt_); + group_iter++; + } + // delete invalid groups (singletons) + else { + mixing_.scene.fg()->detach( (*group_iter)->group() ); + delete (*group_iter); + group_iter = session_->eraseMixingGroup(group_iter); + } + } + // grab frames to recorders & streamers FrameGrabbing::manager().grabFrame(session_->frame(), dt_); @@ -768,7 +785,7 @@ Source * Mixer::findSource (uint64_t id) SourceList Mixer::findSources (float depth_from, float depth_to) { SourceList found; - SourceList dsl = depthSorted( session_->getCopy() ); + SourceList dsl = session_->depthSorted(); SourceList::iterator it = dsl.begin(); for (; it != dsl.end(); it++) { if ( (*it)->depth() > depth_to ) @@ -1037,6 +1054,16 @@ void Mixer::merge(Session *session) attach(s); } + // import and attach session's mixing groups + auto group_iter = session->beginMixingGroup(); + while ( group_iter != session->endMixingGroup() ){ + if (session_->addMixingGroup( *group_iter ) ) + mixing_.scene.fg()->attach( (*group_iter)->group() ); + else + delete (*group_iter); + group_iter = session->eraseMixingGroup(group_iter); + } + // needs to update ! View::need_deep_update_++; @@ -1064,7 +1091,7 @@ void Mixer::merge(SessionSource *source) float target_depth = source->depth(); // get how much space we need from there - SourceList dsl = depthSorted( session->getCopy() ); + SourceList dsl = session->depthSorted(); float start_depth = dsl.front()->depth(); float end_depth = dsl.back()->depth(); float need_depth = MAX( end_depth - start_depth, LAYER_STEP); @@ -1112,6 +1139,16 @@ void Mixer::merge(SessionSource *source) attach(s); } + // import and attach session's mixing groups + auto group_iter = session->beginMixingGroup(); + while ( group_iter != session->endMixingGroup() ){ + if (session_->addMixingGroup( *group_iter ) ) + mixing_.scene.fg()->attach( (*group_iter)->group() ); + else + delete (*group_iter); + group_iter = session->eraseMixingGroup(group_iter); + } + // needs to update ! View::need_deep_update_++; @@ -1133,6 +1170,9 @@ void Mixer::swap() // detatch current session's nodes from views for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++) detach(*source_iter); + // detatch current session's mixing groups + for (auto group_iter = session_->beginMixingGroup(); group_iter != session_->endMixingGroup(); group_iter++) + mixing_.scene.fg()->detach( (*group_iter)->group() ); } // swap back and front @@ -1150,6 +1190,10 @@ void Mixer::swap() layer_.scene.root()->copyTransform( session_->config(View::LAYER) ); appearance_.scene.root()->copyTransform( session_->config(View::TEXTURE) ); + // attach new session's mixing group to mixingview + for (auto group_iter = session_->beginMixingGroup(); group_iter != session_->endMixingGroup(); group_iter++) + mixing_.scene.fg()->attach( (*group_iter)->group() ); + // set resolution session_->setResolution( session_->config(View::RENDERING)->scale_ ); @@ -1258,4 +1302,6 @@ void Mixer::paste(const std::string& clipboard) } } + // TODO : Mixing groups + } diff --git a/MixingGroup.cpp b/MixingGroup.cpp index 933ec9d..81300be 100644 --- a/MixingGroup.cpp +++ b/MixingGroup.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -7,41 +6,33 @@ #include "defines.h" #include "Source.h" #include "Decorations.h" +#include "Visitor.h" #include "Mixer.h" #include "Log.h" #include "MixingGroup.h" -// utility to sort Sources in MixingView in a clockwise order -// in reference to a center point -struct clockwise_centered { - clockwise_centered(glm::vec2 c) : center(c) { } - bool operator() (Source * first, Source * second) { - glm::vec2 pos_first = glm::vec2(first->group(View::MIXING)->translation_)-center; - float angle_first = glm::orientedAngle( glm::normalize(pos_first), glm::vec2(1.f, 0.f) ); - glm::vec2 pos_second = glm::vec2(second->group(View::MIXING)->translation_)-center; - float angle_second = glm::orientedAngle( glm::normalize(pos_second), glm::vec2(1.f, 0.f) ); - return (angle_first < angle_second); - } - glm::vec2 center; -}; MixingGroup::MixingGroup (SourceList sources) : root_(nullptr), lines_(nullptr), center_(nullptr), - center_pos_(glm::vec2(0.f, 0.f)), active_(true) + center_pos_(glm::vec2(0.f, 0.f)), active_(true), update_action_(ACTION_NONE), updated_source_(nullptr) { // fill the vector of sources with the given list for (auto it = sources.begin(); it != sources.end(); it++){ - (*it)->mixinggroup_ = this; - sources_.push_back(*it); - // compute barycenter (1) - center_pos_ += glm::vec2((*it)->group(View::MIXING)->translation_); + // add only if not linked already + if ((*it)->mixinggroup_ == nullptr) { + (*it)->mixinggroup_ = this; + sources_.push_back(*it); + // compute barycenter on the way (1) + center_pos_ += glm::vec2((*it)->group(View::MIXING)->translation_); + } } // compute barycenter (2) center_pos_ /= sources_.size(); // sort the vector of sources in clockwise order around the center pos_ - std::sort(sources_.begin(), sources_.end(), clockwise_centered(center_pos_)); + sources_ = mixing_sorted( sources_, center_pos_); + // scene elements root_ = new Group; center_ = new Symbol(Symbol::CIRCLE_POINT); center_->visible_ = false; @@ -54,10 +45,17 @@ MixingGroup::MixingGroup (SourceList sources) : root_(nullptr), lines_(nullptr), MixingGroup::~MixingGroup () { - delete center_; + for (auto it = sources_.begin(); it != sources_.end(); it++) { + (*it)->mixinggroup_ = nullptr; + (*it)->overlay_mixinggroup_->visible_ = false; + } + delete root_; - if (lines_) - delete lines_; +} + +void MixingGroup::accept(Visitor& v) +{ + v.visit(*this); } void MixingGroup::update (float dt) @@ -168,9 +166,11 @@ void MixingGroup::setActive (bool on) void MixingGroup::detach (Source *s) { // find the source - std::vector::iterator its = std::find(sources_.begin(), sources_.end(), s); + SourceList::iterator its = std::find(sources_.begin(), sources_.end(), s); // ok, its in the list ! if (its != sources_.end()) { + // tell the source + (*its)->mixinggroup_ = nullptr; // erase the source from the list sources_.erase(its); // clear index, delete lines_, and recreate path and index with remaining sources @@ -178,32 +178,52 @@ void MixingGroup::detach (Source *s) } } -void MixingGroup::move (Source *s) + +uint MixingGroup::size() +{ + return sources_.size(); +} + +SourceList::iterator MixingGroup::begin () +{ + return sources_.begin(); +} + +SourceList::iterator MixingGroup::end () +{ + return sources_.end(); +} + +bool MixingGroup::contains (Source *s) { // find the source - std::vector::iterator its = std::find(sources_.begin(), sources_.end(), s); - // ok, its in the list ! - if (its != sources_.end() && lines_) { + SourceList::iterator its = std::find(sources_.begin(), sources_.end(), s); + // in the list ? + return its != sources_.end(); +} + +void MixingGroup::move (Source *s) +{ + if (contains(s) && lines_) { // modify one point in the path lines_->editPath(index_points_[s], glm::vec2(s->group(View::MIXING)->translation_)); } - } void MixingGroup::createLineStrip() { - if (lines_) { - root_->detach(lines_); - delete lines_; - } - - index_points_.clear(); - if (sources_.size() > 1) { + + if (lines_) { + root_->detach(lines_); + delete lines_; + } + + index_points_.clear(); + + // path linking all sources std::vector path; - auto it = sources_.begin(); - // link sources - for (; it != sources_.end(); it++){ + for (auto it = sources_.begin(); it != sources_.end(); it++){ index_points_[*it] = path.size(); path.push_back(glm::vec2((*it)->group(View::MIXING)->translation_)); } @@ -211,7 +231,6 @@ void MixingGroup::createLineStrip() // create lines_ = new LineLoop(path, 1.5f); lines_->shader()->color = glm::vec4(COLOR_MIXING_GROUP, 0.96f); - root_->attach(lines_); } } diff --git a/MixingGroup.h b/MixingGroup.h index 7a2d999..5e448ab 100644 --- a/MixingGroup.h +++ b/MixingGroup.h @@ -4,6 +4,7 @@ #include #include "View.h" +#include "SourceList.h" class LineLoop; class Symbol; @@ -15,29 +16,34 @@ public: MixingGroup (SourceList sources); ~MixingGroup (); + // actions for update typedef enum { ACTION_NONE = 0, ACTION_GRAB_ONE = 1, ACTION_GRAB_ALL = 2, ACTION_ROTATE_ALL = 3 } Action; - - // actions for update inline void setAction (Action a) { update_action_ = a; } inline Action action () { return update_action_; } inline void follow (Source *s) { updated_source_ = s; } - // get node to draw + // node to draw inline Group *group () { return root_; } + // accept all kind of visitors + virtual void accept (Visitor& v); + // to update in Mixing View void update (float dt); inline bool active () const { return active_; } void setActive (bool on); - // individual change of a source in the group + // Source list manipulation + SourceList::iterator begin (); + SourceList::iterator end (); + uint size (); + bool contains (Source *s); void detach (Source *s); - void move (Source *s); private: @@ -46,10 +52,11 @@ private: LineLoop *lines_; Symbol *center_; void createLineStrip(); + void move (Source *s); // properties linked to sources - glm::vec2 center_pos_; - std::vector sources_; + glm::vec2 center_pos_; + SourceList sources_; std::map< Source *, uint> index_points_; // status and actions diff --git a/MixingView.cpp b/MixingView.cpp index cb3a1cc..ab4574f 100644 --- a/MixingView.cpp +++ b/MixingView.cpp @@ -129,8 +129,7 @@ void MixingView::draw() // special action of Mixing view if (ImGui::Selectable( ICON_FA_DRAW_POLYGON " Link" )){ // TODO create MixingGroup - MixingGroup *mg = new MixingGroup(Mixer::selection().getCopy()); - groups_.push_back(mg); + MixingGroup *mg = Mixer::manager().session()->createMixingGroup(Mixer::selection().getCopy()); scene.fg()->attach(mg->group()); Source *cur = Mixer::selection().front(); Mixer::manager().unsetCurrentSource(); @@ -196,9 +195,9 @@ void MixingView::update(float dt) { View::update(dt); - // always update the mixinggroups - for (auto g = groups_.begin(); g != groups_.end(); g++) - (*g)->update(dt); +// // always update the mixinggroups +// for (auto g = groups_.begin(); g != groups_.end(); g++) +// (*g)->update(dt); // a more complete update is requested // for mixing, this means restore position of the fading slider @@ -398,8 +397,9 @@ void MixingView::terminate() { View::terminate(); - // terminate all group actions - for (auto g = groups_.begin(); g != groups_.end(); g++) + // terminate all mixing group actions + for (auto g = Mixer::manager().session()->beginMixingGroup(); + g != Mixer::manager().session()->endMixingGroup(); g++) (*g)->setAction( MixingGroup::ACTION_NONE ); } diff --git a/MixingView.h b/MixingView.h index bee41da..24cdad8 100644 --- a/MixingView.h +++ b/MixingView.h @@ -3,7 +3,7 @@ #include "View.h" -class MixingGroup; +//class MixingGroup; class MixingView : public View { @@ -36,9 +36,6 @@ private: Disk *stashCircle_; Mesh *mixingCircle_; Mesh *circle_; - - // linked sources - std::list< MixingGroup *> groups_; }; diff --git a/Selection.cpp b/Selection.cpp index 37867ae..c58c8e8 100644 --- a/Selection.cpp +++ b/Selection.cpp @@ -173,16 +173,15 @@ std::string Selection::xml() const SourceList selection_clones_; SessionVisitor sv(&xmlDoc, selectionNode); for (auto iter = selection_.begin(); iter != selection_.end(); iter++, sv.setRoot(selectionNode) ){ - // keep the clones for later + // start with clones CloneSource *clone = dynamic_cast(*iter); if (clone) (*iter)->accept(sv); else selection_clones_.push_back(*iter); } - // add the clones at the end + // add others in front for (auto iter = selection_clones_.begin(); iter != selection_clones_.end(); iter++, sv.setRoot(selectionNode) ){ - (*iter)->accept(sv); } diff --git a/Session.cpp b/Session.cpp index 10add59..2584914 100644 --- a/Session.cpp +++ b/Session.cpp @@ -7,6 +7,7 @@ #include "FrameGrabber.h" #include "SessionCreator.h" #include "SessionSource.h" +#include "MixingGroup.h" #include "Log.h" @@ -37,6 +38,9 @@ Session::Session() : failedSource_(nullptr), active_(true), fading_target_(0.f) Session::~Session() { + // TODO delete all mixing groups? + + // delete all sources for(auto it = sources_.begin(); it != sources_.end(); ) { // erase this source from the list @@ -87,6 +91,18 @@ void Session::update(float dt) } } +// // update the mixinggroups +// for (auto g = mixing_groups_.begin(); g != mixing_groups_.end(); ) { +// // update all valid groups +// if ((*g)->size() > 1) { +// (*g)->update(dt); +// g++; +// } +// // delete invalid groups (singletons) +// else +// g = deleteMixingGroup(g); +// } + // apply fading (smooth dicotomic reaching) float f = render_.fading(); if ( ABS_DIFF(f, fading_target_) > EPSILON) { @@ -139,6 +155,9 @@ SourceList::iterator Session::deleteSource(Source *s) if (its != sources_.end()) { // remove Node from the rendering scene render_.scene.ws()->detach( s->group(View::RENDERING) ); + // inform group + if (s->mixingGroup() != nullptr) + s->mixingGroup()->detach(s); // erase the source from the update list & get next element its = sources_.erase(its); // delete the source : safe now @@ -241,11 +260,9 @@ SourceList::iterator Session::find(float depth_from, float depth_to) return std::find_if(sources_.begin(), sources_.end(), Source::hasDepth(depth_from, depth_to)); } -SourceList Session::getCopy() const +SourceList Session::depthSorted() const { - SourceList list; - list = sources_; - return list; + return depth_sorted(sources_); } uint Session::numSource() const @@ -253,17 +270,9 @@ uint Session::numSource() const return sources_.size(); } -std::list Session::getIdList() const +SourceIdList Session::getIdList() const { - std::list idlist; - - for( auto sit = sources_.begin(); sit != sources_.end(); sit++) - idlist.push_back( (*sit)->id() ); - - // make sure no duplicate - idlist.unique(); - - return idlist; + return ids(sources_); } bool Session::empty() const @@ -315,6 +324,73 @@ void Session::move(int current_index, int target_index) sources_.insert(to, s); } +MixingGroup *Session::createMixingGroup(SourceList sources) +{ + // will return the pointer to created MixingGroup + MixingGroup *g = nullptr; + + // verify that all sources given are valid in the sesion + SourceList valid_sources; + for (auto _it = sources.begin(); _it != sources.end(); _it++) { + SourceList::iterator found = std::find(sources_.begin(), sources_.end(), *_it); + if ( found != sources_.end()) + valid_sources.push_back(*found); + } + + // create mixing group with valid sources (if it is a group of at least 2 sources) + if (valid_sources.size() > 1) { + g = new MixingGroup(valid_sources); + mixing_groups_.push_back(g); + } + + return g; +} + + +bool Session::addMixingGroup (MixingGroup *mg) +{ + // verify that all sources given in MixingGroup are valid in the sesion + bool ok = true; + for (auto _it = mg->begin(); _it != mg->end(); _it++) { + SourceList::iterator found = std::find(sources_.begin(), sources_.end(), *_it); + if ( found == sources_.end()) { + ok = false; + break; + } + } + if (ok) + mixing_groups_.push_back(mg); + return ok; +} + +void Session::createMixingGroups (std::list groups) +{ + // create mixing groups (if any) + for (auto group_it = groups.begin(); group_it != groups.end(); group_it++){ + createMixingGroup( *group_it ); + } +} + +std::vector::iterator Session::eraseMixingGroup (std::vector::iterator g) +{ + return mixing_groups_.erase(g); +} + +uint Session::numMixingGroup() const +{ + return mixing_groups_.size(); +} + +std::vector::iterator Session::beginMixingGroup() +{ + return mixing_groups_.begin(); +} + +std::vector::iterator Session::endMixingGroup() +{ + return mixing_groups_.end(); +} + void Session::lock() { access_.lock(); @@ -328,9 +404,11 @@ void Session::unlock() Session *Session::load(const std::string& filename, uint recursion) { + // create session SessionCreator creator(recursion); creator.load(filename); + // return created session return creator.session(); } diff --git a/Session.h b/Session.h index 38b31ea..80c985e 100644 --- a/Session.h +++ b/Session.h @@ -7,6 +7,7 @@ #include "Source.h" class FrameGrabber; +class MixingGroup; class Session { @@ -39,10 +40,10 @@ public: SourceList::iterator find (std::string name); SourceList::iterator find (Node *node); SourceList::iterator find (float depth_from, float depth_to); - SourceList getCopy() const; + SourceList depthSorted() const; SourceList::iterator find (uint64_t id); - std::list getIdList() const; + SourceIdList getIdList() const; SourceList::iterator at (int index); int index (SourceList::iterator it) const; @@ -75,6 +76,15 @@ public: void setFilename(const std::string &filename) { filename_ = filename; } std::string filename() const { return filename_; } + // mixing group + bool addMixingGroup(MixingGroup *mg); + MixingGroup *createMixingGroup (SourceList sources); + std::vector::iterator eraseMixingGroup (std::vector::iterator g); + void createMixingGroups (std::list groups); + uint numMixingGroup() const; + std::vector::iterator beginMixingGroup(); + std::vector::iterator endMixingGroup(); + // lock and unlock access (e.g. while saving) void lock(); void unlock(); @@ -84,6 +94,7 @@ protected: std::string filename_; Source *failedSource_; SourceList sources_; + std::vector mixing_groups_; std::map config_; bool active_; std::list grabbers_; diff --git a/SessionCreator.cpp b/SessionCreator.cpp index afe6644..5f9864c 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -91,8 +91,36 @@ void SessionCreator::load(const std::string& filename) // ready to read sources SessionLoader::load( xmlDoc_.FirstChildElement("Session") ); + // create groups + session_->createMixingGroups( getMixingGroups() ); + // all good session_->setFilename(filename); + +// for (std::map< uint64_t, Source* >::iterator qwe = sources_id_.begin(); qwe != sources_id_.end(); qwe++){ +// Log::Info("%ld - %ld ", qwe->first, qwe->second->id()); +// } + +// int count = 0; +// std::list< SourceIdList >::iterator git; +// for (git = groups_sources_id_.begin(); git != groups_sources_id_.end(); git++) +// { +// Log::Info("XML Groups %d", count++); +// std::list::iterator sit; +// for (sit = (*git).begin(); sit != (*git).end(); sit++ ) { +// Log::Info("- %ld", (*sit) ); +// } +// } + +// std::list< SourceList > ngrou = getMixingGroupsIdList(); +// count = 0; +// for (auto git = ngrou.begin(); git != ngrou.end(); git++) +// { +// Log::Info("NEW Groups %d", count++); +// for (auto sit = (*git).begin(); sit != (*git).end(); sit++ ) { +// Log::Info("- %ld", (*sit)->id() ); +// } +// } } @@ -108,11 +136,48 @@ void SessionCreator::loadConfig(XMLElement *viewsNode) } } -SessionLoader::SessionLoader(Session *session, int recursion): Visitor(), session_(session), recursion_(recursion) +SessionLoader::SessionLoader(Session *session, int recursion): Visitor(), + session_(session), xmlCurrent_(nullptr), recursion_(recursion) { } +// get the list of new source id (value in sources_id_ map) +SourceIdList SessionLoader::getIdList() const +{ + SourceIdList id_current_value; + for (auto it = sources_id_.begin(); it != sources_id_.end(); it++) + id_current_value.push_back( it->second->id() ); + + return id_current_value; +} + +// groups_sources_id_ is parsed in XML and contains list of groups of ids +// Here we return the list of groups of newly created sources +// based on correspondance map sources_id_ +// NB: importantly the list is cleared from duplicates +std::list< SourceList > SessionLoader::getMixingGroups() const +{ + std::list< SourceList > groups_new_sources_id; + + // perform conversion from xml id to new id + for (auto git = groups_sources_id_.begin(); git != groups_sources_id_.end(); git++) + { + SourceList new_sources; + for (auto sit = (*git).begin(); sit != (*git).end(); sit++ ) { + if (sources_id_.count(*sit) > 0) + new_sources.push_back( sources_id_.at(*sit) ); + } + new_sources.sort(); + groups_new_sources_id.push_back( new_sources ); + } + + // remove duplicates + groups_new_sources_id.unique(); + + return groups_new_sources_id; +} + void SessionLoader::load(XMLElement *sessionNode) { sources_id_.clear(); @@ -133,9 +198,9 @@ void SessionLoader::load(XMLElement *sessionNode) Source *load_source = nullptr; // check if a source with the given id exists in the session - uint64_t id__ = 0; - xmlCurrent_->QueryUnsigned64Attribute("id", &id__); - SourceList::iterator sit = session_->find(id__); + uint64_t id_xml_ = 0; + xmlCurrent_->QueryUnsigned64Attribute("id", &id_xml_); + SourceList::iterator sit = session_->find(id_xml_); // no source with this id exists if ( sit == session_->end() ) { @@ -179,8 +244,10 @@ void SessionLoader::load(XMLElement *sessionNode) // apply config to source load_source->accept(*this); load_source->touch(); + // remember - sources_id_.push_back( load_source->id() ); + sources_id_[id_xml_] = load_source; +// sources_id_[id_xml_] = load_source->id(); } // create clones after all sources, to be able to clone a source created above @@ -194,9 +261,9 @@ void SessionLoader::load(XMLElement *sessionNode) if ( pType && std::string(pType) == "CloneSource") { // check if a source with same id exists - uint64_t id__ = 0; - xmlCurrent_->QueryUnsigned64Attribute("id", &id__); - SourceList::iterator sit = session_->find(id__); + uint64_t id_xml_ = 0; + xmlCurrent_->QueryUnsigned64Attribute("id", &id_xml_); + SourceList::iterator sit = session_->find(id_xml_); // no source clone with this id exists if ( sit == session_->end() ) { @@ -210,20 +277,23 @@ void SessionLoader::load(XMLElement *sessionNode) if (origin != session_->end()) { // create a new source of type Clone Source *clone_source = (*origin)->clone(); + // add source to session session_->addSource(clone_source); + // apply config to source clone_source->accept(*this); clone_source->touch(); + // remember - sources_id_.push_back( clone_source->id() ); + sources_id_[id_xml_] = clone_source; +// sources_id_[id_xml_] = clone_source->id(); } } } } } - // make sure no duplicate - sources_id_.unique(); + } } @@ -514,6 +584,18 @@ void SessionLoader::visit (Source& s) s.setImageProcessingEnabled(on); } + xmlCurrent_ = sourceNode->FirstChildElement("MixingGroup"); + if (xmlCurrent_) { + SourceIdList idlist; + XMLElement* sourceNode = xmlCurrent_->FirstChildElement("source"); + for ( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement()) { + uint64_t id__ = 0; + sourceNode->QueryUnsigned64Attribute("id", &id__); + idlist.push_back(id__); + } + groups_sources_id_.push_back(idlist); + } + // restore current xmlCurrent_ = sourceNode; } diff --git a/SessionCreator.h b/SessionCreator.h index 3996632..0c637ee 100644 --- a/SessionCreator.h +++ b/SessionCreator.h @@ -1,10 +1,11 @@ #ifndef SESSIONCREATOR_H #define SESSIONCREATOR_H -#include +#include +#include #include "Visitor.h" -#include +#include "SourceList.h" class Session; @@ -17,7 +18,8 @@ public: inline Session *session() const { return session_; } void load(tinyxml2::XMLElement *sessionNode); - inline std::list getIdList() const { return sources_id_; } + SourceIdList getIdList() const; + std::list< SourceList > getMixingGroups() const; Source *createSource(tinyxml2::XMLElement *sourceNode, bool clone_duplicates = true); @@ -46,10 +48,16 @@ public: void visit (NetworkSource& s) override; protected: - tinyxml2::XMLElement *xmlCurrent_; + // result created session Session *session_; - std::list sources_id_; + // parsing current xml + tinyxml2::XMLElement *xmlCurrent_; + // level of loading recursion int recursion_; + // map of correspondance from xml source id (key) to new source pointer (value) + std::map< uint64_t, Source* > sources_id_; + // list of groups (lists of xml source id) + std::list< SourceIdList > groups_sources_id_; static void XMLToNode(tinyxml2::XMLElement *xml, Node &n); }; diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 2f8139b..068b7d3 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -13,6 +13,7 @@ #include "ImageShader.h" #include "ImageProcessingShader.h" #include "MediaPlayer.h" +#include "MixingGroup.h" #include @@ -274,16 +275,6 @@ void SessionVisitor::visit(LineStrip &n) points_node->InsertEndChild(p); } xmlCurrent_->InsertEndChild(points_node); - -// XMLElement *colors_node = xmlDoc_->NewElement("colors"); -// std::vector colors = n.getColors(); -// for(size_t i = 0; i < colors.size(); ++i) -// { -// XMLElement *p = XMLElementFromGLM(xmlDoc_, colors[i]); -// p->SetAttribute("index", (int) i); -// colors_node->InsertEndChild(p); -// } -// xmlCurrent_->InsertEndChild(colors_node); } void SessionVisitor::visit(LineSquare &) @@ -392,6 +383,12 @@ void SessionVisitor::visit (Source& s) sourceNode->InsertEndChild(xmlCurrent_); s.processingShader()->accept(*this); + if (s.mixingGroup()) { + xmlCurrent_ = xmlDoc_->NewElement( "MixingGroup" ); + sourceNode->InsertEndChild(xmlCurrent_); + s.mixingGroup()->accept(*this); + } + xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source) } @@ -423,11 +420,11 @@ void SessionVisitor::visit (SessionGroupSource& s) Session *se = s.session(); - XMLElement *rootgroup = xmlDoc_->NewElement("Session"); - xmlCurrent_->InsertEndChild(rootgroup); + XMLElement *sessionNode = xmlDoc_->NewElement("Session"); + xmlCurrent_->InsertEndChild(sessionNode); for (auto iter = se->begin(); iter != se->end(); iter++){ - setRoot(rootgroup); + setRoot(sessionNode); (*iter)->accept(*this); } @@ -469,3 +466,14 @@ void SessionVisitor::visit (NetworkSource& s) xmlCurrent_->SetAttribute("type", "NetworkSource"); xmlCurrent_->SetAttribute("connection", s.connection().c_str() ); } + +void SessionVisitor::visit (MixingGroup& g) +{ + xmlCurrent_->SetAttribute("size", g.size()); + + for (auto it = g.begin(); it != g.end(); it++) { + XMLElement *sour = xmlDoc_->NewElement("source"); + sour->SetAttribute("id", (*it)->id()); + xmlCurrent_->InsertEndChild(sour); + } +} diff --git a/SessionVisitor.h b/SessionVisitor.h index a16e113..564bbc5 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -50,6 +50,7 @@ public: void visit (PatternSource& s) override; void visit (DeviceSource& s) override; void visit (NetworkSource& s) override; + void visit (MixingGroup& s) override; static tinyxml2::XMLElement *NodeToXML(Node &n, tinyxml2::XMLDocument *doc); }; diff --git a/Source.cpp b/Source.cpp index 7cc950f..9fe7014 100644 --- a/Source.cpp +++ b/Source.cpp @@ -238,10 +238,6 @@ Source::~Source() (*it)->detach(); clones_.clear(); - // inform group - if (mixinggroup_) - mixinggroup_->detach(this); - // delete objects delete stored_status_; if (renderbuffer_) diff --git a/Source.h b/Source.h index 305ee0d..e2bf764 100644 --- a/Source.h +++ b/Source.h @@ -131,12 +131,17 @@ public: void setMask (FrameBufferImage *img); void storeMask (FrameBufferImage *img = nullptr); + // operations on depth float depth () const; void setDepth (float d); + // operations on alpha float alpha () const; void setAlpha (float a); + // groups for mixing + MixingGroup *mixingGroup() const { return mixinggroup_; } + struct hasNode: public std::unary_function { bool operator()(const Source* elem) const; @@ -179,6 +184,7 @@ public: float _to; }; + // class-dependent icon virtual glm::ivec2 icon () const { return glm::ivec2(12, 11); } // get the xml description text of a source diff --git a/SourceList.cpp b/SourceList.cpp new file mode 100644 index 0000000..b3a3b4f --- /dev/null +++ b/SourceList.cpp @@ -0,0 +1,118 @@ +#include + +#include +#include + +#include "Source.h" +#include "SourceList.h" + +// utility to sort Sources by depth +bool compare_depth (Source * first, Source * second) +{ + return ( first->depth() < second->depth() ); +} + +SourceList depth_sorted(SourceList list) +{ + SourceList sl = list; + sl.sort(compare_depth); + + return sl; +} + +// utility to sort Sources in MixingView in a clockwise order +// in reference to a center point +struct clockwise_centered { + clockwise_centered(glm::vec2 c) : center(c) { } + bool operator() (Source * first, Source * second) { + glm::vec2 pos_first = glm::vec2(first->group(View::MIXING)->translation_)-center; + float angle_first = glm::orientedAngle( glm::normalize(pos_first), glm::vec2(1.f, 0.f) ); + glm::vec2 pos_second = glm::vec2(second->group(View::MIXING)->translation_)-center; + float angle_second = glm::orientedAngle( glm::normalize(pos_second), glm::vec2(1.f, 0.f) ); + return (angle_first < angle_second); + } + glm::vec2 center; +}; + +SourceList mixing_sorted(SourceList list, glm::vec2 center) +{ + SourceList sl = list; + sl.sort(clockwise_centered(center)); + + return sl; +} + + +SourceIdList ids (SourceList list) +{ + SourceIdList idlist; + + for( auto sit = list.begin(); sit != list.end(); sit++) + idlist.push_back( (*sit)->id() ); + + // make sure no duplicate + idlist.unique(); + + return idlist; +} + + +SourceListCompare compare (SourceList first, SourceList second) +{ + SourceListCompare ret = SOURCELIST_DISTINCT; + if (first.empty() || first.empty()) + return ret; + + // a new test list: start with the second list and remove all commons with first list + SourceList test = second; + for (auto it = first.begin(); it != first.end(); it++){ + test.remove(*it); + } + + // all sources of the second list were in the first list + if (test.empty()) { + // same size, therefore they are the same! + if (first.size() == second.size()) + ret = SOURCELIST_EQUAL; + // otherwise, first list contains all sources of the second list. + else + ret = SOURCELIST_SECOND_IN_FIRST; + } + // some sources of the second list were in the first + else if ( second.size() != test.size() ){ + // if the number of sources removed from second is the number of sources in the first + if (second.size() - test.size() == first.size()) + ret = SOURCELIST_FIRST_IN_SECOND; + // else, there is a patrial intersection + else + ret = SOURCELIST_INTERSECT; + } + // else no intersection, lists are distinct (return detault) + + return ret; +} + + +SourceList intersect (SourceList first, SourceList second) +{ + // take second list and remove all elements also in first list + // -> builds the list of what remains in second list + SourceList l1 = second; + for (auto it = first.begin(); it != first.end(); it++) + l1.remove(*it); + // take second list and remove all elements in the remainer list + // -> builds the list of what is in second list and was part of the first list + SourceList l2 = second; + for (auto it = l1.begin(); it != l1.end(); it++) + l2.remove(*it); + return l2; +} + + +SourceList join (SourceList first, SourceList second) +{ + SourceList l = second; + for (auto it = first.begin(); it != first.end(); it++) + l.push_back(*it); + return l; +} diff --git a/SourceList.h b/SourceList.h new file mode 100644 index 0000000..52ea72a --- /dev/null +++ b/SourceList.h @@ -0,0 +1,28 @@ +#ifndef SOURCELIST_H +#define SOURCELIST_H + +#include +#include + +class Source; + +typedef std::list SourceList; + +SourceList depth_sorted (SourceList list); +SourceList mixing_sorted (SourceList list, glm::vec2 center = glm::vec2(0.f, 0.f)); +SourceList intersect (SourceList first, SourceList second); +SourceList join (SourceList first, SourceList second); + +typedef enum { + SOURCELIST_DISTINCT = 0, + SOURCELIST_INTERSECT = 1, + SOURCELIST_EQUAL = 2, + SOURCELIST_FIRST_IN_SECOND = 3, + SOURCELIST_SECOND_IN_FIRST = 4 +} SourceListCompare; +SourceListCompare compare (SourceList first, SourceList second); + +typedef std::list SourceIdList; +SourceIdList ids (SourceList list); + +#endif // SOURCELIST_H diff --git a/View.cpp b/View.cpp index a3ce5df..d42a87f 100644 --- a/View.cpp +++ b/View.cpp @@ -275,16 +275,3 @@ void View::updateSelectionOverlay() overlay_selection_->scale_ = glm::vec3(0.f, 0.f, 1.f); } - -bool compare_depth (Source * first, Source * second) -{ - return ( first->depth() < second->depth() ); -} - -SourceList depthSorted(SourceList list) -{ - SourceList dsl = list; - dsl.sort(compare_depth); - - return dsl; -} diff --git a/View.h b/View.h index 82cfed4..c21db46 100644 --- a/View.h +++ b/View.h @@ -5,6 +5,7 @@ #include "Scene.h" #include "FrameBuffer.h" +#include "SourceList.h" class Session; class SessionFileSource; @@ -16,8 +17,6 @@ class Disk; class Handles; class Source; -typedef std::list SourceList; -SourceList depthSorted(SourceList); class View { diff --git a/Visitor.h b/Visitor.h index da0bdff..2842cdd 100644 --- a/Visitor.h +++ b/Visitor.h @@ -37,6 +37,7 @@ class SessionGroupSource; class RenderSource; class CloneSource; class NetworkSource; +class MixingGroup; // Declares the interface for the visitors class Visitor { @@ -69,6 +70,7 @@ public: virtual void visit (ImageProcessingShader&) {} // utility + virtual void visit (MixingGroup&) {} virtual void visit (Source&) {} virtual void visit (MediaSource&) {} virtual void visit (NetworkSource&) {}