Almost done with implementation of Transition! Settings and UI side

pannel are operational. View is stable and animation with UpdateCallback
implemented.
This commit is contained in:
brunoherbelin
2020-07-06 00:06:49 +02:00
parent d4a22992eb
commit b5985847bf
14 changed files with 229 additions and 78 deletions

View File

@@ -290,6 +290,7 @@ set(VMIX_RSC_FILES
./rsc/mesh/icon_vimix.ply
./rsc/mesh/icon_empty.ply
./rsc/mesh/h_line.ply
./rsc/mesh/h_mark.ply
)
add_executable(${VMIX_BINARY}

View File

@@ -223,6 +223,10 @@ void Mixer::draw()
{
// draw the current view in the window
current_view_->draw();
// make sure we disable fading of session rendering
if (current_view_ != &transition_)
session_->fadeIn();
}
// manangement of sources

View File

@@ -34,7 +34,11 @@ Node::Node() : initialized_(false), visible_(true), refcount_(0)
Node::~Node ()
{
clearCallbacks();
}
void Node::clearCallbacks()
{
std::list<UpdateCallback *>::iterator iter;
for (iter=update_callbacks_.begin(); iter != update_callbacks_.end(); )
{

View File

@@ -75,6 +75,7 @@ public:
// animation update callbacks
// list of callbacks to call at each update
std::list<UpdateCallback *> update_callbacks_;
void clearCallbacks();
};

View File

@@ -131,6 +131,23 @@ void Session::setResolution(glm::vec3 resolution)
config_[View::RENDERING]->scale_ = resolution;
}
void Session::setFading(float f)
{
render_.setFading(f);
}
void Session::fadeIn() {
float f = render_.fading();
if ( f > EPSILON)
render_.setFading( f / 2.f);
}
void Session::fadeOut() {
float f = render_.fading();
if ( f < 1.f - EPSILON)
render_.setFading( f * 2.f);
}
SourceList::iterator Session::begin()
{
return sources_.begin();

View File

@@ -48,6 +48,11 @@ public:
// configure rendering resolution
void setResolution(glm::vec3 resolution);
// manipulate fading of output
void setFading(float f);
void fadeIn();
void fadeOut();
// configuration for group nodes of views
inline Group *config (View::Mode m) const { return config_.at(m); }

View File

@@ -58,6 +58,11 @@ SessionSource::SessionSource() : Source(), path_("")
groups_[View::TRANSITION]->attach(frames_[View::TRANSITION]);
overlays_[View::TRANSITION] = new Group;
overlays_[View::TRANSITION]->translation_.z = 0.1;
overlays_[View::TRANSITION]->visible_ = false;
Icon *center = new Icon(Icon::GENERIC, glm::vec3(0.f, 0.f, 0.1f));
overlays_[View::TRANSITION]->attach(center);
groups_[View::TRANSITION]->attach(overlays_[View::TRANSITION]);
loadFailed_ = false;
loadFinished_ = false;
@@ -81,6 +86,8 @@ SessionSource::~SessionSource()
delete session_;
}
void SessionSource::load(const std::string &p)
{
path_ = p;
@@ -172,7 +179,6 @@ void SessionSource::setActive (bool on)
void SessionSource::update(float dt)
{
// Log::Info("SessionSource::update %f", dt);
Source::update(dt);
// update content

View File

@@ -81,7 +81,7 @@ void Settings::Save()
// Transition
XMLElement *TransitionNode = xmlDoc.NewElement( "Transition" );
TransitionNode->SetAttribute("auto_start", application.transition.auto_start);
TransitionNode->SetAttribute("auto_end", application.transition.auto_open);
TransitionNode->SetAttribute("cross_fade", application.transition.cross_fade);
TransitionNode->SetAttribute("duration", application.transition.duration);
TransitionNode->SetAttribute("profile", application.transition.profile);
@@ -220,7 +220,7 @@ void Settings::Load()
// Transition
XMLElement * transitionnode = pRoot->FirstChildElement("Transition");
if (transitionnode != nullptr) {
transitionnode->QueryBoolAttribute("auto_start", &application.transition.auto_start);
transitionnode->QueryBoolAttribute("auto_end", &application.transition.auto_open);
transitionnode->QueryBoolAttribute("cross_fade", &application.transition.cross_fade);
transitionnode->QueryIntAttribute("duration", &application.transition.duration);
transitionnode->QueryIntAttribute("profile", &application.transition.profile);

View File

@@ -79,14 +79,14 @@ struct History
struct TransitionConfig
{
bool auto_start;
bool cross_fade;
bool auto_open;
int duration;
int profile;
TransitionConfig() {
auto_start = false;
cross_fade = false;
cross_fade = true;
auto_open = true;
duration = 1000;
profile = 0;
}

View File

@@ -11,30 +11,40 @@ UpdateCallback::UpdateCallback() : enabled_(true), finished_(false)
}
void MoveToCenterCallback::update(Node *n, float dt)
MoveToCallback::MoveToCallback(glm::vec3 target, float duration) : UpdateCallback(),
target_(target), duration_(duration), progress_(0.f), initialized_(false)
{
}
void MoveToCallback::update(Node *n, float dt)
{
// set start position on first run or upon call of reset()
if (!initialized_){
initial_position_ = n->translation_;
startingpoint_ = n->translation_;
target_.z = startingpoint_.z; // ignore depth
initialized_ = true;
}
// calculate amplitude of movement
progress_ += dt / duration_;
// perform movement : translation to the center (0, 0)
n->translation_.x = initial_position_.x - progress_ * initial_position_.x;
n->translation_.y = initial_position_.y - progress_ * initial_position_.y;
// perform movement
n->translation_ = startingpoint_ + progress_ * (target_ - startingpoint_);
// end of movement
if ( progress_ > 1.f ) {
n->translation_.x = 0.f;
n->translation_.y = 0.f;
n->translation_ = target_;
finished_ = true;
}
}
BounceScaleCallback::BounceScaleCallback(float duration) : UpdateCallback(),
duration_(duration), progress_(0.f), initialized_(false)
{
}
void BounceScaleCallback::update(Node *n, float dt)
{
// set start scale on first run or upon call of reset()

View File

@@ -21,16 +21,16 @@ protected:
bool finished_;
};
class MoveToCenterCallback : public UpdateCallback
class MoveToCallback : public UpdateCallback
{
float duration_;
float progress_;
bool initialized_;
glm::vec3 initial_position_;
glm::vec3 startingpoint_;
glm::vec3 target_;
public:
MoveToCenterCallback(float duration = 1000.f) : duration_(duration), progress_(0.f), initialized_(false) {}
MoveToCallback(glm::vec3 target, float duration = 1000.f);
void update(Node *n, float dt);
inline void reset() { initialized_ = false; }
@@ -44,8 +44,7 @@ class BounceScaleCallback : public UpdateCallback
glm::vec3 initial_scale_;
public:
BounceScaleCallback(float duration = 100.f) : duration_(duration), progress_(0.f), initialized_(false) {}
BounceScaleCallback(float duration = 100.f);
void update(Node *n, float dt);
};

View File

@@ -352,6 +352,7 @@ void UserInterface::handleMouse()
mouseclic[ImGuiMouseButton_Right] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Right].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Right].y* io.DisplayFramebufferScale.x);
static bool mousedown = false;
static View *view_drag = nullptr;
static std::pair<Node *, glm::vec2> picked = { nullptr, glm::vec2(0.f) };
// steal focus on right button clic
@@ -446,6 +447,7 @@ void UserInterface::handleMouse()
}
else if ( ImGui::IsMouseReleased(ImGuiMouseButton_Left) )
{
view_drag = nullptr;
mousedown = false;
picked = { nullptr, glm::vec2(0.f) };
}
@@ -470,24 +472,33 @@ void UserInterface::handleMouse()
// if ( mousedown && glm::distance(mouseclic[ImGuiMouseButton_Left], mousepos) > 3.f )
if ( ImGui::IsMouseDragging(ImGuiMouseButton_Left, 5.0f) )
{
Source *current = Mixer::manager().currentSource();
if (current)
{
// grab selected sources (current is also selected by default)
View::Cursor c = View::Cursor_Arrow;
for (auto it = Mixer::selection().begin(); it != Mixer::selection().end(); it++)
c = Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mousepos, picked);
setMouseCursor(io.MousePos, c);
}
else {
// Selection area
ImGui::GetBackgroundDrawList()->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos,
ImGui::GetColorU32(ImGuiCol_ResizeGripHovered));
ImGui::GetBackgroundDrawList()->AddRectFilled(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos,
ImGui::GetColorU32(ImGuiCol_ResizeGripHovered, 0.3f));
if(view_drag == nullptr)
view_drag = Mixer::manager().view();
// only operate if the view didn't change
if (view_drag == Mixer::manager().view()) {
// action on current source
Source *current = Mixer::manager().currentSource();
if (current)
{
// grab selected sources (current is also selected by default)
View::Cursor c = View::Cursor_Arrow;
for (auto it = Mixer::selection().begin(); it != Mixer::selection().end(); it++)
c = Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mousepos, picked);
setMouseCursor(io.MousePos, c);
}
// Selection area
else {
ImGui::GetBackgroundDrawList()->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos,
ImGui::GetColorU32(ImGuiCol_ResizeGripHovered));
ImGui::GetBackgroundDrawList()->AddRectFilled(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos,
ImGui::GetColorU32(ImGuiCol_ResizeGripHovered, 0.3f));
// Bounding box multiple sources selection
Mixer::manager().view()->select(mouseclic[ImGuiMouseButton_Left], mousepos);
}
// Bounding box multiple sources selection
Mixer::manager().view()->select(mouseclic[ImGuiMouseButton_Left], mousepos);
}
}
}
@@ -1230,7 +1241,7 @@ void Navigator::Render()
}
else {
// the "=" icon for menu
if (ImGui::Selectable( ICON_FA_BARS, &selected_button[NAV_TRANS], 0, iconsize))
if (ImGui::Selectable( ICON_FA_GREATER_THAN, &selected_button[NAV_TRANS], 0, iconsize))
{
// Mixer::manager().unsetCurrentSource();
applyButtonSelection(NAV_TRANS);
@@ -1497,6 +1508,11 @@ void Navigator::RenderNewPannel()
void Navigator::RenderTransitionPannel()
{
if (Settings::application.current_view < 4) {
hidePannel();
return;
}
// Next window is a side pannel
ImGui::SetNextWindowPos( ImVec2(width_, 0), ImGuiCond_Always );
ImGui::SetNextWindowSize( ImVec2(pannel_width_, height_), ImGuiCond_Always );
@@ -1509,6 +1525,27 @@ void Navigator::RenderTransitionPannel()
ImGui::Text("Transition");
ImGui::PopFont();
// Session menu
ImGui::SetCursorPosY(width_);
ImGui::Text("Behavior");
ImGuiToolkit::ButtonSwitch( ICON_FA_RANDOM " Cross fading", &Settings::application.transition.cross_fade);
ImGuiToolkit::ButtonSwitch( ICON_FA_SIGN_IN_ALT " Automatic open", &Settings::application.transition.auto_open);
// ImGuiToolkit::ButtonSwitch( ICON_FA_SIGN_OUT_ALT " Automatic start", &Settings::application.transition.auto_start);
// Transition options
ImGui::Text(" ");
ImGui::Text("Animation");
if (ImGuiToolkit::ButtonIcon(4, 13)) Settings::application.transition.duration = 1000;
ImGui::SameLine(0, 10);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::SliderInt("Duration", &Settings::application.transition.duration, 200, 5000, "%d ms");
if (ImGuiToolkit::ButtonIcon(9, 1)) Settings::application.transition.profile = 0;
ImGui::SameLine(0, 10);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("Curve", &Settings::application.transition.profile, "Linear\0Quadratic\0IExponent\0");
if ( ImGui::Button("Start", ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Settings::application.widget.media_player = true;
}
ImGui::End();

140
View.cpp
View File

@@ -9,20 +9,18 @@
#include <sstream>
#include <iomanip>
#include "View.h"
#include "defines.h"
#include "Settings.h"
#include "View.h"
#include "Session.h"
#include "Source.h"
#include "SessionSource.h"
#include "Primitives.h"
#include "Decorations.h"
#include "PickingVisitor.h"
#include "DrawVisitor.h"
#include "Mesh.h"
#include "Mixer.h"
#include "FrameBuffer.h"
#include "UserInterfaceManager.h"
#include "UpdateCallback.h"
#include "Log.h"
#define CIRCLE_PIXELS 64
@@ -314,7 +312,15 @@ void RenderView::setFading(float f)
if (fading_overlay_ == nullptr)
fading_overlay_ = new Surface;
fading_overlay_->shader()->color.a = CLAMP(f, 0.f, 1.f);
fading_overlay_->shader()->color.a = CLAMP( f < EPSILON ? 0.f : f, 0.f, 1.f);
}
float RenderView::fading() const
{
if (fading_overlay_)
return fading_overlay_->shader()->color.a;
else
return 0.f;
}
void RenderView::setResolution(glm::vec3 resolution)
@@ -706,7 +712,7 @@ View::Cursor LayerView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair
// TRANSITION
TransitionView::TransitionView() : View(TRANSITION), duration_(1000.f), transition_source_(nullptr)
TransitionView::TransitionView() : View(TRANSITION), transition_source_(nullptr)
{
// read default settings
if ( Settings::application.views[mode_].name.empty() )
@@ -721,10 +727,17 @@ TransitionView::TransitionView() : View(TRANSITION), duration_(1000.f), transiti
restoreSettings();
// Geometry Scene background
Mesh *circle = new Mesh("mesh/h_line.ply");
circle->shader()->color = glm::vec4( COLOR_TRANSITION_LINES, 0.9f );
Mesh *horizontal_line = new Mesh("mesh/h_line.ply");
horizontal_line->shader()->color = glm::vec4( COLOR_TRANSITION_LINES, 0.9f );
scene.fg()->attach(horizontal_line);
mark_half_ = new Mesh("mesh/h_mark.ply");
mark_half_->translation_ = glm::vec3(-0.5f, 0.f, 0.0f);
mark_half_->shader()->color = glm::vec4( COLOR_TRANSITION_LINES, 0.9f );
mark_half_->visible_ = false;
scene.fg()->attach(mark_half_);
// move the whole forground below
scene.fg()->translation_ = glm::vec3(0.f, -0.11f, 0.0f);
scene.fg()->attach(circle);
output_surface_ = new Surface;
output_surface_->shader()->color.a = 0.9f;
@@ -760,6 +773,50 @@ void TransitionView::update(float dt)
}
void TransitionView::draw()
{
// update the GUI depending on changes in settings
mark_half_->visible_ = !Settings::application.transition.cross_fade;
// draw scene of this view
scene.root()->draw(glm::identity<glm::mat4>(), Rendering::manager().Projection());
// Update transition source
if ( transition_source_ != nullptr) {
float d = transition_source_->group(View::TRANSITION)->translation_.x;
// Transfer this movement to changes in mixing
// cross fading
if ( Settings::application.transition.cross_fade )
{
// change alpha of session: identical coordinates in Mixing View
transition_source_->group(View::MIXING)->translation_.x = CLAMP(d, -1.f, 0.f);
transition_source_->group(View::MIXING)->translation_.y = 0.f;
}
// fade to black
else
{
// change alpha of session ; hidden before -0.5, visible after
transition_source_->group(View::MIXING)->translation_.x = d < -0.5f ? -1.f : 0.f;
transition_source_->group(View::MIXING)->translation_.y = 0.f;
// crossing the fade : fade-out [-1.0 -0.5], fade-in [-0.5 0.0]
float f = ABS(2.f * d + 1.f); // linear
// d = ( 2 * d + 1.f); // quadratic
// d *= d;
Mixer::manager().session()->setFading( 1.f - f );
}
// request update
transition_source_->touch();
if (d > 0.2f && Settings::application.transition.auto_open)
Mixer::manager().setView(View::MIXING);
}
}
void TransitionView::attach(SessionSource *ts)
{
// store source for later (detatch & interaction)
@@ -796,28 +853,45 @@ Session *TransitionView::detach()
return ret;
}
//void TransitionView::draw()
//{
// // draw scene of this view
// scene.root()->draw(glm::identity<glm::mat4>(), Rendering::manager().Projection());
// // maybe enough if scene contains the session source to transition
// // and the preview
//}
void TransitionView::zoom (float factor)
{
// float z = scene.root()->scale_.x;
// z = CLAMP( z + 0.1f * factor, LAYER_MIN_SCALE, LAYER_MAX_SCALE);
// scene.root()->scale_.x = z;
// scene.root()->scale_.y = z;
float d = transition_source_->group(View::TRANSITION)->translation_.x;
d += 0.1f * factor;
transition_source_->group(View::TRANSITION)->translation_.x = CLAMP(d, -1.f, 0.f);
}
void TransitionView::centerSource(Source *s)
std::pair<Node *, glm::vec2> TransitionView::pick(glm::vec2 P)
{
// TODO setup view when starting : anything to initialize ?
std::pair<Node *, glm::vec2> pick = View::pick(P);
// start animation when clic on target
if (pick.first == output_surface_)
play();
// otherwise cancel animation
else
transition_source_->group(View::TRANSITION)->clearCallbacks();
return pick;
}
void TransitionView::play()
{
if (transition_source_ != nullptr) {
float time = CLAMP(- transition_source_->group(View::TRANSITION)->translation_.x, 0.f, 1.f);
time *= float(Settings::application.transition.duration);
// if remaining time is more than 50ms
if (time > 50.f) {
// start animation
MoveToCallback *anim = new MoveToCallback(glm::vec3(0.4f, 0.0, 0.0), time);
transition_source_->group(View::TRANSITION)->update_callbacks_.push_back(anim);
// TODO : add time for doing the last 0.4 of translation
}
// otherwise finish animation
else
transition_source_->group(View::TRANSITION)->translation_.x = 0.4;
}
}
View::Cursor TransitionView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick)
@@ -835,24 +909,14 @@ View::Cursor TransitionView::grab (Source *s, glm::vec2 from, glm::vec2 to, std:
float d = s->stored_status_->translation_.x + gl_Position_to.x - gl_Position_from.x;
if (d > 0.2) {
s->group(View::TRANSITION)->translation_.x = 0.4;
info << "Ready";
info << "Make current";
}
else {
s->group(View::TRANSITION)->translation_.x = CLAMP(d, -1.f, 0.f);
info << "Alpha " << std::fixed << std::setprecision(3) << s->blendingShader()->color.a;
info << "Transition " << int( 100.f * (1.f + s->group(View::TRANSITION)->translation_.x)) << "%";
}
// copy identical coordinates in Mixing View
s->group(View::MIXING)->translation_.x = CLAMP(d, -1.f, 0.f);
s->group(View::MIXING)->translation_.y = 0.f;
// request update
s->touch();
// fade out output
return Cursor(Cursor_ResizeAll, info.str() );
return Cursor(Cursor_ResizeEW, info.str() );
}

9
View.h
View File

@@ -113,6 +113,7 @@ public:
glm::vec3 resolution() const { return frame_buffer_->resolution(); }
void setFading(float f = 0.f);
float fading() const;
inline FrameBuffer *frame () const { return frame_buffer_; }
};
@@ -155,16 +156,18 @@ public:
void attach(SessionSource *ts);
class Session *detach();
inline SessionSource * attached() { return transition_source_; }
void centerSource(Source *) override;
void play();
void draw () override;
void update (float dt) override;
void zoom (float factor) override;
std::pair<Node *, glm::vec2> pick(glm::vec2 P) override;
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
private:
float duration_;
class Surface *output_surface_;
class Mesh *mark_half_;
SessionSource *transition_source_;
};