diff --git a/app/node/block/transition/crossdissolve/crossdissolve.cpp b/app/node/block/transition/crossdissolve/crossdissolve.cpp index 1ea460724..ca9b1c25b 100644 --- a/app/node/block/transition/crossdissolve/crossdissolve.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolve.cpp @@ -1,10 +1,5 @@ #include "crossdissolve.h" -CrossDissolveTransition::CrossDissolveTransition() -{ - -} - Node *CrossDissolveTransition::copy() const { CrossDissolveTransition* c = new CrossDissolveTransition(); diff --git a/app/node/block/transition/crossdissolve/crossdissolve.h b/app/node/block/transition/crossdissolve/crossdissolve.h index c4102b06c..2472ea995 100644 --- a/app/node/block/transition/crossdissolve/crossdissolve.h +++ b/app/node/block/transition/crossdissolve/crossdissolve.h @@ -6,7 +6,7 @@ class CrossDissolveTransition : public TransitionBlock { public: - CrossDissolveTransition(); + CrossDissolveTransition() = default; virtual Node* copy() const override; diff --git a/app/node/block/transition/diptoblack/diptoblack.cpp b/app/node/block/transition/diptoblack/diptoblack.cpp index d07912c00..24f2f90a0 100644 --- a/app/node/block/transition/diptoblack/diptoblack.cpp +++ b/app/node/block/transition/diptoblack/diptoblack.cpp @@ -1,6 +1,35 @@ #include "diptoblack.h" -DipToBlackTransition::DipToBlackTransition() +Node *DipToBlackTransition::copy() const { + DipToBlackTransition* c = new DipToBlackTransition(); + CopyParameters(this, c); + + return c; +} + +QString DipToBlackTransition::Name() const +{ + return tr("Dip to Black"); +} + +QString DipToBlackTransition::id() const +{ + return "org.olivevideoeditor.Olive.diptoblack"; +} + +QString DipToBlackTransition::Description() const +{ + return tr("A smooth dip to transparency and back into another clip."); +} + +bool DipToBlackTransition::IsAccelerated() const +{ + return true; +} + +QString DipToBlackTransition::CodeFragment() const +{ + return ReadFileAsString(":/shaders/diptoblack.frag"); } diff --git a/app/node/block/transition/diptoblack/diptoblack.h b/app/node/block/transition/diptoblack/diptoblack.h index 3f0abaa11..f1a2b2856 100644 --- a/app/node/block/transition/diptoblack/diptoblack.h +++ b/app/node/block/transition/diptoblack/diptoblack.h @@ -6,7 +6,16 @@ class DipToBlackTransition : public TransitionBlock { public: - DipToBlackTransition(); + DipToBlackTransition() = default; + + virtual Node* copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QString Description() const override; + + virtual bool IsAccelerated() const override; + virtual QString CodeFragment() const override; }; #endif // DIPTOBLACKTRANSITION_H diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index 43a953736..11513ef00 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -275,19 +275,28 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, const TransitionBlock* transition_node = static_cast(node); // Provide transition information - rational internal_time = range.in() - block_node->in(); + double internal_time = (range.in() - block_node->in()).toDouble(); + + GLfloat all_prog = static_cast(internal_time / block_node->length().toDouble()); + GLfloat out_prog = 0; + GLfloat in_prog = 0; + + if (transition_node->out_offset() != 0) { + out_prog = static_cast(clamp(1.0 - (internal_time / transition_node->out_offset().toDouble()), 0.0, 1.0)); + } + + if (transition_node->in_offset() != 0) { + in_prog = static_cast(clamp((internal_time - transition_node->out_offset().toDouble()) / transition_node->in_offset().toDouble(), 0.0, 1.0)); + } // Provides total transition progress from 0.0 (start) - 1.0 (end) - shader->setUniformValue("ove_tprog_all", - static_cast(internal_time.toDouble() / block_node->length().toDouble())); + shader->setUniformValue("ove_tprog_all", all_prog); // Provides progress of out section from 1.0 (start) - 0.0 (end) - shader->setUniformValue("ove_tprog_out", - static_cast(clamp(internal_time.toDouble() / transition_node->out_offset().toDouble(), 0.0, 1.0))); + shader->setUniformValue("ove_tprog_out", out_prog); // Provides progress of in section from 0.0 (start) - 1.0 (end) - shader->setUniformValue("ove_tprog_in", - static_cast(clamp((internal_time - transition_node->out_offset()).toDouble() / transition_node->in_offset().toDouble(), 0.0, 1.0))); + shader->setUniformValue("ove_tprog_in", in_prog); } } diff --git a/app/shaders/crossdissolve.frag b/app/shaders/crossdissolve.frag index 0d7dda495..acc8e178d 100644 --- a/app/shaders/crossdissolve.frag +++ b/app/shaders/crossdissolve.frag @@ -10,16 +10,14 @@ uniform bool in_block_in_enabled; uniform float ove_tprog_all; void main(void) { - vec4 out_block_col = texture2D(out_block_in, ove_texcoord) * (1.0 - ove_tprog_all); - vec4 in_block_col = texture2D(in_block_in, ove_texcoord) * ove_tprog_all; - vec4 composite = vec4(0.0); if (out_block_in_enabled) { - composite += out_block_col; + composite += texture2D(out_block_in, ove_texcoord) * (1.0 - ove_tprog_all); } if (in_block_in_enabled) { + vec4 in_block_col = texture2D(in_block_in, ove_texcoord) * ove_tprog_all; composite *= 1.0 - in_block_col.a; composite += in_block_col; } diff --git a/app/shaders/diptoblack.frag b/app/shaders/diptoblack.frag new file mode 100644 index 000000000..28e8a7b78 --- /dev/null +++ b/app/shaders/diptoblack.frag @@ -0,0 +1,30 @@ +#version 110 + +varying vec2 ove_texcoord; + +uniform sampler2D out_block_in; +uniform sampler2D in_block_in; +uniform bool out_block_in_enabled; +uniform bool in_block_in_enabled; + +uniform float ove_tprog_out; +uniform float ove_tprog_in; + +void main(void) { + vec4 out_block_col; + vec4 in_block_col; + + if (out_block_in_enabled) { + out_block_col = texture2D(out_block_in, ove_texcoord) * pow(ove_tprog_out, 2.0); + } else { + out_block_col = vec4(0.0); + } + + if (in_block_in_enabled) { + in_block_col = texture2D(in_block_in, ove_texcoord) * pow(ove_tprog_in, 2.0); + } else { + in_block_col = vec4(0.0); + } + + gl_FragColor = out_block_col + in_block_col; +} diff --git a/app/shaders/shaders.qrc b/app/shaders/shaders.qrc index d183728bb..cd8fa6fd6 100644 --- a/app/shaders/shaders.qrc +++ b/app/shaders/shaders.qrc @@ -2,6 +2,7 @@ alphaover.frag crossdissolve.frag + diptoblack.frag opacity.frag solid.frag videoinput.frag diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index c13a441e1..c32790fe8 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -1,6 +1,7 @@ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/transition/crossdissolve/crossdissolve.h" +#include "node/block/transition/diptoblack/diptoblack.h" #include "widget/nodeview/nodeviewundo.h" TimelineWidget::TransitionTool::TransitionTool(TimelineWidget *parent) : @@ -88,17 +89,7 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event) if (ghost_) { if (!ghost_->AdjustedLength().isNull()) { - Block* block_to_transition = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kAttachedBlock)); CrossDissolveTransition* transition = new CrossDissolveTransition(); - NodeInput* transition_input_to_connect; - - if (ghost_->mode() == olive::timeline::kTrimIn) { - transition->set_in_and_out_offset(ghost_->AdjustedLength(), 0); - transition_input_to_connect = transition->in_block_input(); - } else { - transition->set_in_and_out_offset(0, ghost_->AdjustedLength()); - transition_input_to_connect = transition->out_block_input(); - } QUndoCommand* command = new QUndoCommand(); @@ -109,19 +100,42 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event) ghost_->GetAdjustedIn(), command); - // Connect block to transition - new NodeEdgeAddCommand(block_to_transition->output(), - transition_input_to_connect, - command); - - // Connect other block to transition if (dual_transition_) { - Block* other_block = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kReferenceBlock)); - NodeInput* alternate_transition_input = (transition_input_to_connect == transition->out_block_input()) - ? transition->in_block_input() - : transition->out_block_input(); - new NodeEdgeAddCommand(other_block->output(), - alternate_transition_input, + transition->set_in_and_out_offset(ghost_->AdjustedLength()/2, ghost_->AdjustedLength()/2); + + // Block mouse is hovering over + Block* active_block = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kAttachedBlock)); + + // Block mouse is next to + Block* friend_block = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kReferenceBlock)); + + // Use ghost mode to determine which block is which + Block* out_block = (ghost_->mode() == olive::timeline::kTrimIn) ? friend_block : active_block; + Block* in_block = (ghost_->mode() == olive::timeline::kTrimIn) ? active_block : friend_block; + + // Connect block to transition + new NodeEdgeAddCommand(out_block->output(), + transition->out_block_input(), + command); + + new NodeEdgeAddCommand(in_block->output(), + transition->in_block_input(), + command); + } else { + Block* block_to_transition = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kAttachedBlock)); + NodeInput* transition_input_to_connect; + + if (ghost_->mode() == olive::timeline::kTrimIn) { + transition->set_in_and_out_offset(ghost_->AdjustedLength(), 0); + transition_input_to_connect = transition->in_block_input(); + } else { + transition->set_in_and_out_offset(0, ghost_->AdjustedLength()); + transition_input_to_connect = transition->out_block_input(); + } + + // Connect block to transition + new NodeEdgeAddCommand(block_to_transition->output(), + transition_input_to_connect, command); }