mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-17 21:29:59 +01:00
Cleanup source tree
Move all C++ source files in the src subfolder. Adapted the cmake process accordingly and cleanup.
This commit is contained in:
392
src/MixingGroup.cpp
Normal file
392
src/MixingGroup.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* This file is part of vimix - video live mixer
|
||||
*
|
||||
* **Copyright** (C) 2019-2022 Bruno Herbelin <bruno.herbelin@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtx/rotate_vector.hpp>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Source.h"
|
||||
#include "Decorations.h"
|
||||
#include "Visitor.h"
|
||||
#include "BaseToolkit.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "MixingGroup.h"
|
||||
|
||||
|
||||
MixingGroup::MixingGroup (SourceList sources) : parent_(nullptr), root_(nullptr), lines_(nullptr), center_(nullptr),
|
||||
center_pos_(glm::vec2(0.f, 0.f)), active_(true), update_action_(ACTION_NONE), updated_source_(nullptr)
|
||||
{
|
||||
// create unique id
|
||||
id_ = BaseToolkit::uniqueId();
|
||||
|
||||
// fill the vector of sources with the given list
|
||||
for (auto it = sources.begin(); it != sources.end(); ++it){
|
||||
// add only if not linked already
|
||||
if ((*it)->mixinggroup_ == nullptr) {
|
||||
(*it)->mixinggroup_ = this;
|
||||
sources_.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// scene elements
|
||||
root_ = new Group;
|
||||
root_->visible_ = false;
|
||||
center_ = new Symbol(Symbol::CIRCLE_POINT);
|
||||
center_->visible_ = false;
|
||||
center_->color = glm::vec4(COLOR_MIXING_GROUP, 0.75f);
|
||||
center_->scale_ = glm::vec3(0.6f, 0.6f, 1.f);
|
||||
root_->attach(center_);
|
||||
|
||||
// create
|
||||
recenter();
|
||||
createLineStrip();
|
||||
}
|
||||
|
||||
MixingGroup::~MixingGroup ()
|
||||
{
|
||||
for (auto it = sources_.begin(); it != sources_.end(); ++it)
|
||||
(*it)->clearMixingGroup();
|
||||
|
||||
if (parent_)
|
||||
parent_->detach( root_ );
|
||||
delete root_;
|
||||
}
|
||||
|
||||
void MixingGroup::accept(Visitor& v)
|
||||
{
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
void MixingGroup::attachTo( Group *parent )
|
||||
{
|
||||
if (parent_ != nullptr)
|
||||
parent_->detach( root_ );
|
||||
|
||||
parent_ = parent;
|
||||
|
||||
if (parent_ != nullptr)
|
||||
parent_->attach(root_);
|
||||
}
|
||||
|
||||
void MixingGroup::recenter()
|
||||
{
|
||||
// compute barycenter (0)
|
||||
center_pos_ = glm::vec2(0.f, 0.f);
|
||||
for (auto it = sources_.begin(); it != sources_.end(); ++it){
|
||||
// compute barycenter (1)
|
||||
center_pos_ += glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
}
|
||||
// compute barycenter (2)
|
||||
center_pos_ /= sources_.size();
|
||||
|
||||
// set center
|
||||
center_->translation_ = glm::vec3(center_pos_, 0.f);
|
||||
}
|
||||
|
||||
void MixingGroup::setAction (Action a)
|
||||
{
|
||||
if (a == ACTION_UPDATE) {
|
||||
// accept UPDATE action only if no other action is ongoing
|
||||
if (update_action_ == ACTION_NONE)
|
||||
update_action_ = ACTION_UPDATE;
|
||||
}
|
||||
else if (a == ACTION_FINISH) {
|
||||
// only needs to finish if an action was done
|
||||
if (update_action_ != ACTION_NONE)
|
||||
update_action_ = ACTION_FINISH;
|
||||
}
|
||||
else
|
||||
update_action_ = a;
|
||||
}
|
||||
|
||||
void MixingGroup::update (float)
|
||||
{
|
||||
// after creation, root is not visible: wait that all sources are initialized to make it visible
|
||||
if (!root_->visible_) {
|
||||
auto unintitializedsource = std::find_if_not(sources_.begin(), sources_.end(), Source::isInitialized);
|
||||
root_->visible_ = (unintitializedsource == sources_.end());
|
||||
}
|
||||
|
||||
// group is active if one source in the group is current
|
||||
auto currentsource = std::find_if(sources_.begin(), sources_.end(), Source::isCurrent);
|
||||
setActive(currentsource != sources_.end());
|
||||
|
||||
// perform action
|
||||
if (update_action_ == ACTION_FINISH ) {
|
||||
// update barycenter
|
||||
recenter();
|
||||
// clear index, delete lines_, and recreate path and index with remaining sources
|
||||
createLineStrip();
|
||||
// update only once
|
||||
update_action_ = ACTION_NONE;
|
||||
}
|
||||
else if (update_action_ == ACTION_UPDATE ) {
|
||||
|
||||
std::vector<glm::vec2> p = lines_->path();
|
||||
|
||||
// compute barycenter (0)
|
||||
center_pos_ = glm::vec2(0.f, 0.f);
|
||||
auto it = sources_.begin();
|
||||
for (; it != sources_.end(); ++it){
|
||||
// update point
|
||||
p[ index_points_[*it] ] = glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
|
||||
// compute barycenter (1)
|
||||
center_pos_ += glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
}
|
||||
// compute barycenter (2)
|
||||
center_pos_ /= sources_.size();
|
||||
center_->translation_ = glm::vec3(center_pos_, 0.f);
|
||||
|
||||
// update path
|
||||
lines_->changePath(p);
|
||||
|
||||
// update only once
|
||||
update_action_ = ACTION_NONE;
|
||||
}
|
||||
else if (update_action_ != ACTION_NONE && updated_source_ != nullptr) {
|
||||
|
||||
if (update_action_ == ACTION_GRAB_ONE ) {
|
||||
|
||||
// update path
|
||||
move(updated_source_);
|
||||
recenter();
|
||||
}
|
||||
else if (update_action_ == ACTION_GRAB_ALL ) {
|
||||
|
||||
std::vector<glm::vec2> p = lines_->path();
|
||||
glm::vec2 displacement = glm::vec2(updated_source_->group(View::MIXING)->translation_);
|
||||
displacement -= p[ index_points_[updated_source_] ];
|
||||
|
||||
// compute barycenter (0)
|
||||
center_pos_ = glm::vec2(0.f, 0.f);
|
||||
auto it = sources_.begin();
|
||||
for (; it != sources_.end(); ++it){
|
||||
|
||||
// modify all but the already updated source
|
||||
if ( *it != updated_source_ && !(*it)->locked() ) {
|
||||
(*it)->group(View::MIXING)->translation_.x += displacement.x;
|
||||
(*it)->group(View::MIXING)->translation_.y += displacement.y;
|
||||
(*it)->touch();
|
||||
}
|
||||
|
||||
// update point
|
||||
p[ index_points_[*it] ] = glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
|
||||
// compute barycenter (1)
|
||||
center_pos_ += glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
}
|
||||
// compute barycenter (2)
|
||||
center_pos_ /= sources_.size();
|
||||
center_->translation_ = glm::vec3(center_pos_, 0.f);
|
||||
|
||||
// update path
|
||||
lines_->changePath(p);
|
||||
}
|
||||
else if (update_action_ == ACTION_ROTATE_ALL ) {
|
||||
|
||||
std::vector<glm::vec2> p = lines_->path();
|
||||
|
||||
// get angle rotation and distance scaling
|
||||
glm::vec2 pos_first = glm::vec2(updated_source_->group(View::MIXING)->translation_) -center_pos_;
|
||||
float angle = glm::orientedAngle( glm::normalize(pos_first), glm::vec2(1.f, 0.f) );
|
||||
float dist = glm::length( pos_first );
|
||||
glm::vec2 pos_second = glm::vec2(p[ index_points_[updated_source_] ]) -center_pos_;
|
||||
angle -= glm::orientedAngle( glm::normalize(pos_second), glm::vec2(1.f, 0.f) );
|
||||
dist /= glm::length( pos_second );
|
||||
|
||||
int numactions = 0;
|
||||
auto it = sources_.begin();
|
||||
for (; it != sources_.end(); ++it){
|
||||
|
||||
// modify all but the already updated source
|
||||
if ( *it != updated_source_ && !(*it)->locked() ) {
|
||||
glm::vec2 vec = glm::vec2((*it)->group(View::MIXING)->translation_) -center_pos_;
|
||||
vec = glm::rotate(vec, -angle) * dist;
|
||||
vec += center_pos_;
|
||||
|
||||
(*it)->group(View::MIXING)->translation_.x = vec.x;
|
||||
(*it)->group(View::MIXING)->translation_.y = vec.y;
|
||||
(*it)->touch();
|
||||
numactions++;
|
||||
}
|
||||
|
||||
// update point
|
||||
p[ index_points_[*it] ] = glm::vec2((*it)->group(View::MIXING)->translation_);
|
||||
}
|
||||
// update path
|
||||
lines_->changePath(p);
|
||||
// no source was rotated? better action is thus to grab
|
||||
if (numactions<1)
|
||||
update_action_ = ACTION_GRAB_ALL;
|
||||
}
|
||||
|
||||
// done
|
||||
updated_source_ = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MixingGroup::setActive (bool on)
|
||||
{
|
||||
active_ = on;
|
||||
|
||||
// overlays
|
||||
lines_->shader()->color.a = active_ ? 0.96f : 0.5f;
|
||||
center_->visible_ = update_action_ > ACTION_GRAB_ONE;
|
||||
}
|
||||
|
||||
void MixingGroup::detach (Source *s)
|
||||
{
|
||||
// find the source
|
||||
SourceList::iterator its = std::find(sources_.begin(), sources_.end(), s);
|
||||
// ok, its in the list !
|
||||
if (its != sources_.end()) {
|
||||
// tell the source
|
||||
(*its)->clearMixingGroup();
|
||||
// erase the source from the list
|
||||
sources_.erase(its);
|
||||
// update barycenter
|
||||
recenter();
|
||||
// clear index, delete lines_, and recreate path and index with remaining sources
|
||||
createLineStrip();
|
||||
}
|
||||
}
|
||||
|
||||
void MixingGroup::detach (SourceList l)
|
||||
{
|
||||
for (auto sit = l.begin(); sit != l.end(); ++sit) {
|
||||
// find the source
|
||||
SourceList::iterator its = std::find(sources_.begin(), sources_.end(), *sit);
|
||||
// ok, its in the list !
|
||||
if (its != sources_.end()) {
|
||||
// tell the source
|
||||
(*its)->clearMixingGroup();
|
||||
// erase the source from the list
|
||||
sources_.erase(its);
|
||||
}
|
||||
}
|
||||
// update barycenter
|
||||
recenter();
|
||||
// clear index, delete lines_, and recreate path and index with remaining sources
|
||||
createLineStrip();
|
||||
}
|
||||
|
||||
|
||||
void MixingGroup::attach (Source *s)
|
||||
{
|
||||
// if source is not already in a group (this or other)
|
||||
if (s->mixinggroup_ == nullptr) {
|
||||
// tell the source
|
||||
s->mixinggroup_ = this;
|
||||
// add the source
|
||||
sources_.push_back(s);
|
||||
// update barycenter
|
||||
recenter();
|
||||
// clear index, delete lines_, and recreate path and index with remaining sources
|
||||
createLineStrip();
|
||||
}
|
||||
}
|
||||
|
||||
void MixingGroup::attach (SourceList l)
|
||||
{
|
||||
for (auto sit = l.begin(); sit != l.end(); ++sit) {
|
||||
if ( (*sit)->mixinggroup_ == nullptr) {
|
||||
// tell the source
|
||||
(*sit)->mixinggroup_ = this;
|
||||
// add the source
|
||||
sources_.push_back(*sit);
|
||||
}
|
||||
}
|
||||
// update barycenter
|
||||
recenter();
|
||||
// clear index, delete lines_, and recreate path and index with remaining sources
|
||||
createLineStrip();
|
||||
}
|
||||
|
||||
uint MixingGroup::size()
|
||||
{
|
||||
return sources_.size();
|
||||
}
|
||||
|
||||
SourceList MixingGroup::getCopy() const
|
||||
{
|
||||
SourceList sl = sources_;
|
||||
return sl;
|
||||
}
|
||||
|
||||
SourceList::iterator MixingGroup::begin ()
|
||||
{
|
||||
return sources_.begin();
|
||||
}
|
||||
|
||||
SourceList::iterator MixingGroup::end ()
|
||||
{
|
||||
return sources_.end();
|
||||
}
|
||||
|
||||
bool MixingGroup::contains (Source *s)
|
||||
{
|
||||
// find the source
|
||||
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 (sources_.size() > 1) {
|
||||
|
||||
if (lines_) {
|
||||
root_->detach(lines_);
|
||||
delete lines_;
|
||||
}
|
||||
|
||||
// sort the vector of sources in clockwise order around the center pos_
|
||||
sources_ = mixing_sorted( sources_, center_pos_);
|
||||
|
||||
// start afresh list of indices
|
||||
index_points_.clear();
|
||||
|
||||
// path linking all sources
|
||||
std::vector<glm::vec2> path;
|
||||
for (auto it = sources_.begin(); it != sources_.end(); ++it){
|
||||
index_points_[*it] = path.size();
|
||||
path.push_back(glm::vec2((*it)->group(View::MIXING)->translation_));
|
||||
}
|
||||
|
||||
// create
|
||||
lines_ = new LineLoop(path, 1.5f);
|
||||
lines_->shader()->color = glm::vec4(COLOR_MIXING_GROUP, 0.96f);
|
||||
root_->attach(lines_);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user