diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 994c0a2..012fc66 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -469,6 +469,9 @@ void ImGuiVisitor::visit (MediaSource& s) void ImGuiVisitor::visit (SessionSource& s) { + if (s.session() == nullptr) + return; + ImGuiToolkit::Icon(s.icon().x, s.icon().y); ImGui::SameLine(0, 10); ImGui::Text("Session File"); @@ -489,7 +492,7 @@ void ImGuiVisitor::visit (SessionSource& s) if ( ImGui::Button( ICON_FA_FILE_UPLOAD " Open Session", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Mixer::manager().set( s.detach() ); if ( ImGui::Button( ICON_FA_FILE_EXPORT " Import Session", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) - Mixer::manager().merge( s.detach() ); + Mixer::manager().import( &s ); ImGuiToolkit::ButtonOpenUrl( SystemToolkit::path_filename(s.path()).c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) ); } diff --git a/Mixer.cpp b/Mixer.cpp index 5c9066e..1b9243a 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -34,6 +34,7 @@ using namespace tinyxml2; #define THREADED_LOADING static std::vector< std::future > sessionLoaders_; static std::vector< std::future > sessionImporters_; +static std::vector< SessionSource * > sessionSourceToImport_; const std::chrono::milliseconds timeout_ = std::chrono::milliseconds(4); @@ -163,6 +164,18 @@ void Mixer::update() } #endif + // if there is a session source to import + if (!sessionSourceToImport_.empty()) { + // get the session source to be imported + SessionSource *source = sessionSourceToImport_.back(); + // merge the session inside this session source, and adjust alpha and depth + merge( source->detach(), source->alpha(), source->depth() ); + // important: delete the sessionsource itself + deleteSource(source); + // done with this session source + sessionSourceToImport_.pop_back(); + } + // if a change of session is requested if (sessionSwapRequested_) { sessionSwapRequested_ = false; @@ -839,20 +852,51 @@ void Mixer::import(const std::string& filename) #endif } -void Mixer::merge(Session *session) +void Mixer::import(SessionSource *s) +{ + sessionSourceToImport_.push_back( s ); +} + + +void Mixer::merge(Session *session, float alpha, float depth) { if ( session == nullptr ) { Log::Warning("Failed to import Session."); return; } + // new state in history manager + Action::manager().store( std::to_string(session->numSource()) + std::string(" sources imported.")); + // import every sources for ( Source *s = session->popSource(); s != nullptr; s = session->popSource()) { + // avoid name duplicates renameSource(s, s->name()); - insertSource(s); + + // scale alpha + if ( alpha > 0.f ) + s->setAlpha( s->alpha() * alpha ); + + // set depth at given location + if ( depth > 0.f ) + s->setDepth( depth + (s->depth() / MAX_DEPTH)); + + // Add source to Session + session_->addSource(s); + + // Attach source to Mixer + attach(s); } + + // needs to update ! + View::need_deep_update_++; + + // avoid display issues + current_view_->update(0.f); + } + void Mixer::swap() { if (!back_session_) diff --git a/Mixer.h b/Mixer.h index 04901ff..e8193d8 100644 --- a/Mixer.h +++ b/Mixer.h @@ -86,7 +86,8 @@ public: void saveas (const std::string& filename); void load (const std::string& filename); void import (const std::string& filename); - void merge (Session *s); + void import (SessionSource *s); + void merge (Session *s, float alpha = -1.f, float depth = -1.f); void set (Session *s); // operations depending on transition mode diff --git a/Source.cpp b/Source.cpp index 4f9017c..e727833 100644 --- a/Source.cpp +++ b/Source.cpp @@ -450,6 +450,48 @@ float sin_quad(float x, float y) { // return 0.5f + 0.5f * cos( M_PI * CLAMP( ( ( x * x ) + ( y * y ) ), 0.f, 1.f ) ); } + +float Source::depth() +{ + return groups_[View::RENDERING]->translation_.z; +} + +void Source::setDepth(float d) +{ + groups_[View::LAYER]->translation_.z = CLAMP(d, MIN_DEPTH, MAX_DEPTH); + groups_[View::LAYER]->translation_.x = -groups_[View::LAYER]->translation_.z; + touch(); +} + +float Source::alpha() +{ + return sin_quad( groups_[View::MIXING]->translation_.x, groups_[View::MIXING]->translation_.y ); +} + +void Source::setAlpha(float a) +{ + // todo clamp a + glm::vec2 dist = glm::vec2(groups_[View::MIXING]->translation_); + glm::vec2 step = glm::normalize(dist) * 0.01f; + + // special case: perfectly centered (step is null). + if ( glm::length(dist) < EPSILON) + // step in the diagonal + step = glm::vec2(0.01f, 0.01f); + + // converge linearly to reduce the difference of alpha + float delta = sin_quad(dist.x, dist.y) - a; + while ( glm::abs(delta) > 0.01 ){ + dist += step * glm::sign(delta); + delta = sin_quad(dist.x, dist.y) - a; + } + + // apply new mixing coordinates + groups_[View::MIXING]->translation_.x = dist.x; + groups_[View::MIXING]->translation_.y = dist.y; + touch(); +} + void Source::update(float dt) { // keep delta-t @@ -458,8 +500,6 @@ void Source::update(float dt) // update nodes if needed if (renderbuffer_ && mixingsurface_ && maskbuffer_ && need_update_) { -// Log::Info("UPDATE %s %f", initials_, dt); - // ADJUST alpha based on MIXING node // read position of the mixing node and interpret this as transparency of render output glm::vec2 dist = glm::vec2(groups_[View::MIXING]->translation_); @@ -497,11 +537,11 @@ void Source::update(float dt) // Update workspace based on depth, and // adjust vertical position of icon depending on workspace - if (groups_[View::LAYER]->translation_.x < -FOREGROUND_DEPTH) { + if (groups_[View::LAYER]->translation_.x < -LAYER_FOREGROUND) { groups_[View::LAYER]->translation_.y -= 0.3f; workspace_ = Source::FOREGROUND; } - else if (groups_[View::LAYER]->translation_.x < -BACKGROUND_DEPTH) { + else if (groups_[View::LAYER]->translation_.x < -LAYER_BACKGROUND) { groups_[View::LAYER]->translation_.y -= 0.15f; workspace_ = Source::STAGE; } diff --git a/Source.h b/Source.h index 2c6968a..2d2c2d5 100644 --- a/Source.h +++ b/Source.h @@ -128,6 +128,12 @@ public: FrameBufferImage *getMask() const { return maskimage_; } void setMask(FrameBufferImage *img); + float depth(); + void setDepth(float d); + + float alpha(); + void setAlpha(float a); + struct hasNode: public std::unary_function { bool operator()(const Source* elem) const; diff --git a/View.cpp b/View.cpp index b7709ea..b5020b6 100644 --- a/View.cpp +++ b/View.cpp @@ -1652,16 +1652,16 @@ float LayerView::setDepth(Source *s, float d) // negative or no depth given; find the front most depth if ( depth < 0.f ) { // default to place visible in front of background - depth = BACKGROUND_DEPTH + 0.25f; + depth = LAYER_BACKGROUND + LAYER_STEP; // find the front-most souce in the workspace (behind FOREGROUND) for (NodeSet::iterator node = scene.ws()->begin(); node != scene.ws()->end(); node++) { // place in front of previous sources - depth = MAX(depth, (*node)->translation_.z + 0.25f); + depth = MAX(depth, (*node)->translation_.z + LAYER_STEP); // in case node is already at max depth - if ((*node)->translation_.z + 0.05 > MAX_DEPTH ) - (*node)->translation_.z -= 0.05; + if ((*node)->translation_.z + DELTA_DEPTH > MAX_DEPTH ) + (*node)->translation_.z -= DELTA_DEPTH; } } diff --git a/defines.h b/defines.h index 391a4fb..8ce9dc6 100644 --- a/defines.h +++ b/defines.h @@ -24,15 +24,13 @@ #define ROUND(val, factor) float( int( val * factor ) ) / factor; #define SCENE_UNIT 5.f -#define CIRCLE_SQUARE_DIST(x,y) ( (x*x + y*y) / (SCENE_UNIT * SCENE_UNIT * SCENE_UNIT * SCENE_UNIT) ) #define MIN_SCALE 0.01f #define MAX_SCALE 10.f #define CLAMP_SCALE(x) SIGN(x) * CLAMP( ABS(x), MIN_SCALE, MAX_SCALE) #define SCENE_DEPTH 14.f #define MIN_DEPTH 0.f #define MAX_DEPTH 12.f -#define BACKGROUND_DEPTH 2.f -#define FOREGROUND_DEPTH 10.f +#define DELTA_DEPTH 0.05f #define MIXING_DEFAULT_SCALE 2.4f #define MIXING_MIN_SCALE 0.8f #define MIXING_MAX_SCALE 7.0f @@ -45,6 +43,9 @@ #define LAYER_MIN_SCALE 0.4f #define LAYER_MAX_SCALE 1.7f #define LAYER_PERSPECTIVE 2.0f +#define LAYER_BACKGROUND 2.f +#define LAYER_FOREGROUND 10.f +#define LAYER_STEP 0.25f #define APPEARANCE_DEFAULT_SCALE 2.f #define APPEARANCE_MIN_SCALE 0.4f #define APPEARANCE_MAX_SCALE 7.0f