implemented base transition support

While very much incomplete, transitions can now be created and will render
correctly.
This commit is contained in:
itsmattkc
2019-12-12 15:21:39 +11:00
parent 7b92b21df2
commit 76c0399b75
14 changed files with 267 additions and 84 deletions
+11 -1
View File
@@ -22,6 +22,8 @@
#include <QDebug>
#include "transition/transition.h"
Block::Block() :
previous_(nullptr),
next_(nullptr)
@@ -159,8 +161,16 @@ rational Block::MediaToSequenceTime(const rational &media_time) const
void Block::CopyParameters(const Block *source, Block *dest)
{
dest->set_block_name(source->block_name());
dest->set_length(source->length());
dest->set_media_in(source->media_in());
if (source->type() == kTransition && dest->type() == kTransition) {
const TransitionBlock* src_t = static_cast<const TransitionBlock*>(source);
TransitionBlock* dst_t = static_cast<TransitionBlock*>(dest);
dst_t->set_in_and_out_offset(src_t->in_offset(), src_t->out_offset());
} else {
dest->set_length(source->length());
}
}
void Block::Link(Block *a, Block *b)
@@ -7,7 +7,11 @@ CrossDissolveTransition::CrossDissolveTransition()
Node *CrossDissolveTransition::copy() const
{
return new CrossDissolveTransition();
CrossDissolveTransition* c = new CrossDissolveTransition();
CopyParameters(this, c);
return c;
}
QString CrossDissolveTransition::Name() const
+9 -4
View File
@@ -51,14 +51,19 @@ void TransitionBlock::set_length_and_media_in(const rational &length)
abort();
}
void TransitionBlock::set_in_offset(const rational &in_offset)
const rational &TransitionBlock::in_offset() const
{
in_offset_ = in_offset;
RecalculateLength();
return in_offset_;
}
void TransitionBlock::set_out_offset(const rational &out_offset)
const rational &TransitionBlock::out_offset() const
{
return out_offset_;
}
void TransitionBlock::set_in_and_out_offset(const rational &in_offset, const rational &out_offset)
{
in_offset_ = in_offset;
out_offset_ = out_offset;
RecalculateLength();
}
+3 -3
View File
@@ -12,7 +12,6 @@ public:
virtual QString Category() const override;
NodeInput* out_block_input() const;
NodeInput* in_block_input() const;
virtual void Retranslate() override;
@@ -20,8 +19,9 @@ public:
virtual void set_length(const rational &length) override;
virtual void set_length_and_media_in(const rational &length) override;
void set_in_offset(const rational& in_offset);
void set_out_offset(const rational& out_offset);
const rational& in_offset() const;
const rational& out_offset() const;
void set_in_and_out_offset(const rational& in_offset, const rational& out_offset);
private:
void RecalculateLength();
+27 -2
View File
@@ -1,7 +1,9 @@
#include "openglworker.h"
#include "common/clamp.h"
#include "core.h"
#include "functions.h"
#include "node/block/transition/transition.h"
#include "node/node.h"
#include "openglcolorprocessor.h"
#include "render/colormanager.h"
@@ -144,7 +146,7 @@ void OpenGLWorker::ParametersChangedEvent()
}
}
void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable *output_params)
void OpenGLWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, const NodeValueDatabase *input_params, NodeValueTable *output_params)
{
OpenGLShaderPtr shader = shader_cache_->Get(node->id());
@@ -206,6 +208,7 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase
break;
case NodeInput::kFootage:
case NodeInput::kTexture:
case NodeInput::kBuffer:
{
OpenGLTextureCache::ReferencePtr texture = value.value<OpenGLTextureCache::ReferencePtr>();
@@ -248,7 +251,6 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase
case NodeInput::kWholeNumber:
case NodeInput::kNumber:
case NodeInput::kString:
case NodeInput::kBuffer:
case NodeInput::kVector:
case NodeInput::kNone:
case NodeInput::kAny:
@@ -266,6 +268,29 @@ void OpenGLWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase
static_cast<GLfloat>(video_params().width()),
static_cast<GLfloat>(video_params().height()));
if (node->IsBlock()) {
const Block* block_node = static_cast<const Block*>(node);
if (block_node->type() == Block::kTransition) {
const TransitionBlock* transition_node = static_cast<const TransitionBlock*>(node);
// Provide transition information
rational internal_time = range.in() - block_node->in();
// Provides total transition progress from 0.0 (start) - 1.0 (end)
shader->setUniformValue("ove_tprog_all",
static_cast<GLfloat>(internal_time.toDouble() / block_node->length().toDouble()));
// Provides progress of out section from 1.0 (start) - 0.0 (end)
shader->setUniformValue("ove_tprog_out",
static_cast<GLfloat>(clamp(internal_time.toDouble() / transition_node->out_offset().toDouble(), 0.0, 1.0)));
// Provides progress of in section from 0.0 (start) - 1.0 (end)
shader->setUniformValue("ove_tprog_in",
static_cast<GLfloat>(clamp((internal_time - transition_node->out_offset()).toDouble() / transition_node->in_offset().toDouble(), 0.0, 1.0)));
}
}
// Blit this texture through this shader
olive::gl::Blit(shader);
+1 -1
View File
@@ -48,7 +48,7 @@ protected:
virtual void FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable* table) override;
virtual void RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params) override;
virtual void RunNodeAccelerated(const Node *node, const TimeRange &range, const NodeValueDatabase *input_params, NodeValueTable* output_params) override;
virtual void TextureToBuffer(const QVariant& texture, QByteArray& buffer) override;
+3 -2
View File
@@ -48,9 +48,10 @@ bool RenderWorker::OutputIsAccelerated(Node *output)
return false;
}
void RenderWorker::RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params)
void RenderWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, const NodeValueDatabase *input_params, NodeValueTable* output_params)
{
Q_UNUSED(node)
Q_UNUSED(range)
Q_UNUSED(input_params)
Q_UNUSED(output_params)
}
@@ -136,7 +137,7 @@ NodeValueTable RenderWorker::ProcessNode(const NodeDependency& dep)
NodeValueTable table = node->Value(database);
// Check if we have a shader for this output
RunNodeAccelerated(node, &database, &table);
RunNodeAccelerated(node, dep.range(), &database, &table);
return table;
}
+1 -1
View File
@@ -37,7 +37,7 @@ protected:
virtual bool OutputIsAccelerated(Node *output);
virtual void RunNodeAccelerated(const Node *node, const NodeValueDatabase *input_params, NodeValueTable* output_params);
virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, const NodeValueDatabase *input_params, NodeValueTable* output_params);
StreamPtr ResolveStreamFromInput(NodeInput* input);
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
+20 -7
View File
@@ -2,14 +2,27 @@
varying vec2 ove_texcoord;
uniform sampler2D base_in;
uniform sampler2D blend_in;
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_all;
void main(void) {
vec4 base_col = texture2D(base_in, ove_texcoord);
vec4 blend_col = texture2D(blend_in, ove_texcoord);
base_col *= 1.0 - blend_col.a;
base_col += blend_col;
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;
}
if (in_block_in_enabled) {
composite *= 1.0 - in_block_col.a;
composite += in_block_col;
}
gl_FragColor = base_col;
gl_FragColor = composite;
}
+1 -1
View File
@@ -60,7 +60,7 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
tools_.replace(olive::tool::kSlide, std::make_shared<SlideTool>(this));
tools_.replace(olive::tool::kHand, std::make_shared<HandTool>(this));
tools_.replace(olive::tool::kZoom, std::make_shared<ZoomTool>(this));
//tools_.replace(olive::tool::kTransition, new (this)); FIXME: Implement
tools_.replace(olive::tool::kTransition, std::make_shared<TransitionTool>(this));
//tools_.replace(olive::tool::kRecord, new PointerTool(this)); FIXME: Implement
tools_.replace(olive::tool::kAdd, std::make_shared<AddTool>(this));
+28 -23
View File
@@ -206,9 +206,9 @@ private:
public:
RazorTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event);
virtual void MouseMove(TimelineViewMouseEvent *event);
virtual void MouseRelease(TimelineViewMouseEvent *event);
virtual void MousePress(TimelineViewMouseEvent *event) override;
virtual void MouseMove(TimelineViewMouseEvent *event) override;
virtual void MouseRelease(TimelineViewMouseEvent *event) override;
private:
QVector<TrackReference> split_tracks_;
@@ -269,9 +269,9 @@ private:
public:
HandTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event);
virtual void MouseMove(TimelineViewMouseEvent *event);
virtual void MouseRelease(TimelineViewMouseEvent *event);
virtual void MousePress(TimelineViewMouseEvent *event) override;
virtual void MouseMove(TimelineViewMouseEvent *event) override;
virtual void MouseRelease(TimelineViewMouseEvent *event) override;
private:
QPoint screen_drag_start_;
QPoint scrollbar_start_;
@@ -282,19 +282,9 @@ private:
public:
ZoomTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event);
virtual void MouseMove(TimelineViewMouseEvent *event);
virtual void MouseRelease(TimelineViewMouseEvent *event);
};
class TransitionTool : public Tool
{
public:
TransitionTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event);
virtual void MouseMove(TimelineViewMouseEvent *event);
virtual void MouseRelease(TimelineViewMouseEvent *event);
virtual void MousePress(TimelineViewMouseEvent *event) override;
virtual void MouseMove(TimelineViewMouseEvent *event) override;
virtual void MouseRelease(TimelineViewMouseEvent *event) override;
};
class AddTool : public Tool
@@ -302,12 +292,27 @@ private:
public:
AddTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event);
virtual void MouseMove(TimelineViewMouseEvent *event);
virtual void MouseRelease(TimelineViewMouseEvent *event);
virtual void MousePress(TimelineViewMouseEvent *event) override;
virtual void MouseMove(TimelineViewMouseEvent *event) override;
virtual void MouseRelease(TimelineViewMouseEvent *event) override;
protected:
void MouseMoveInternal(const rational& cursor_frame, bool outwards);
private:
TimelineViewGhostItem* ghost_;
rational drag_start_point_;
};
class TransitionTool : public AddTool
{
public:
TransitionTool(TimelineWidget* parent);
virtual void MousePress(TimelineViewMouseEvent *event) override;
virtual void MouseMove(TimelineViewMouseEvent *event) override;
virtual void MouseRelease(TimelineViewMouseEvent *event) override;
protected:
};
void SetBlockLinksSelected(Block *block, bool selected);
+42 -25
View File
@@ -17,42 +17,25 @@ void TimelineWidget::AddTool::MousePress(TimelineViewMouseEvent *event)
return;
}
drag_start_point_ = event->GetCoordinates().GetFrame();
ghost_ = new TimelineViewGhostItem();
ghost_->SetIn(event->GetCoordinates().GetFrame());
ghost_->SetOut(event->GetCoordinates().GetFrame());
ghost_->SetIn(drag_start_point_);
ghost_->SetOut(drag_start_point_);
ghost_->SetTrack(track);
ghost_->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track));
parent()->AddGhost(ghost_);
snap_points_.append(event->GetCoordinates().GetFrame());
snap_points_.append(drag_start_point_);
}
void TimelineWidget::AddTool::MouseMove(TimelineViewMouseEvent *event)
{
const rational& cursor_frame = event->GetCoordinates().GetFrame();
// Calculate movement
rational movement = cursor_frame - ghost_->Out();
// Snap movement
SnapPoint(snap_points_, &movement);
// Validation: Ensure in point never goes below 0
if (movement < -ghost_->In()) {
movement = -ghost_->In();
if (!ghost_) {
return;
}
// Make adjustment
if (!movement) {
ghost_->SetInAdjustment(0);
ghost_->SetOutAdjustment(0);
} else if (movement > 0) {
ghost_->SetInAdjustment(0);
ghost_->SetOutAdjustment(movement);
} else if (movement < 0) {
ghost_->SetInAdjustment(movement);
ghost_->SetOutAdjustment(0);
}
MouseMoveInternal(event->GetCoordinates().GetFrame(), event->GetModifiers() & Qt::AltModifier);
}
void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event)
@@ -76,3 +59,37 @@ void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event)
ghost_ = nullptr;
}
}
void TimelineWidget::AddTool::MouseMoveInternal(const rational &cursor_frame, bool outwards)
{
// Calculate movement
rational movement = cursor_frame - drag_start_point_;
// Snap movement
bool snapped = SnapPoint(snap_points_, &movement);
// If alt is held, our movement goes both ways (outwards)
if (!snapped && outwards) {
// Snap backwards too
movement = -movement;
SnapPoint(snap_points_, &movement);
// We don't need to un-neg here because outwards means all future processing will be done both pos and neg
}
// Validation: Ensure in point never goes below 0
if (movement < -ghost_->In() || (outwards && -movement < -ghost_->In())) {
movement = -ghost_->In();
}
// Make adjustment
if (!movement) {
ghost_->SetInAdjustment(0);
ghost_->SetOutAdjustment(0);
} else if (movement > 0) {
ghost_->SetInAdjustment(outwards ? -movement : 0);
ghost_->SetOutAdjustment(movement);
} else if (movement < 0) {
ghost_->SetInAdjustment(movement);
ghost_->SetOutAdjustment(outwards ? -movement : 0);
}
}
+84 -9
View File
@@ -1,29 +1,104 @@
#include "widget/timelinewidget/timelinewidget.h"
#include "node/block/transition/crossdissolve/crossdissolve.h"
#include "widget/nodeview/nodeviewundo.h"
TimelineWidget::TransitionTool::TransitionTool(TimelineWidget *parent) :
Tool(parent)
AddTool(parent)
{
}
void TimelineWidget::TransitionTool::MousePress(TimelineViewMouseEvent *event)
{
TimelineViewBlockItem* item = GetItemAtScenePos(event->GetCoordinates());
const TrackReference& track = event->GetCoordinates().GetTrack();
TrackOutput* t = parent()->GetTrackFromReference(track);
rational cursor_frame = event->GetCoordinates().GetFrame();
bool selectable_item = (item != nullptr
&& item->flags() & QGraphicsItem::ItemIsSelectable
&& !parent()->GetTrackFromReference(item->Track())->IsLocked());
if (!selectable_item) {
if (!t || t->IsLocked()) {
return;
}
Block* block_at_time = t->BlockAtTime(event->GetCoordinates().GetFrame());
if (!block_at_time || block_at_time->type() != Block::kClip) {
return;
}
// Determine which side of the clip the transition belongs to
rational transition_start_point;
olive::timeline::MovementMode trim_mode;
rational halfway_point = block_at_time->in() + block_at_time->length() / 2;
if (cursor_frame < halfway_point) {
transition_start_point = block_at_time->in();
trim_mode = olive::timeline::kTrimIn;
} else {
transition_start_point = block_at_time->out();
trim_mode = olive::timeline::kTrimOut;
}
// Create ghost
ghost_ = new TimelineViewGhostItem();
ghost_->SetTrack(track);
ghost_->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track));
ghost_->SetIn(transition_start_point);
ghost_->SetOut(transition_start_point);
ghost_->SetMode(trim_mode);
ghost_->setData(TimelineViewGhostItem::kAttachedBlock, Node::PtrToValue(block_at_time));
parent()->AddGhost(ghost_);
snap_points_.append(transition_start_point);
// Set the drag start point
drag_start_point_ = cursor_frame;
}
void TimelineWidget::TransitionTool::MouseMove(TimelineViewMouseEvent *event)
{
Q_UNUSED(event)
if (!ghost_) {
return;
}
MouseMoveInternal(event->GetCoordinates().GetFrame(), false);
}
void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
{
Q_UNUSED(event)
MouseMove(event);
const TrackReference& track = ghost_->Track();
if (ghost_) {
if (!ghost_->AdjustedLength().isNull()) {
Block* block_to_transition = Node::ValueToPtr<Block>(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();
// Place transition in place
new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()),
track.index(),
transition,
ghost_->GetAdjustedIn(),
command);
// Connect block to transition
new NodeEdgeAddCommand(block_to_transition->output(),
transition_input_to_connect,
command);
olive::undo_stack.push(command);
}
parent()->ClearGhosts();
snap_points_.clear();
ghost_ = nullptr;
}
}
@@ -28,6 +28,7 @@
#include <QStyleOptionGraphicsItem>
#include "common/qtversionabstraction.h"
#include "node/block/transition/transition.h"
TimelineViewBlockItem::TimelineViewBlockItem(QGraphicsItem* parent) :
TimelineViewRect(parent),
@@ -80,14 +81,14 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
switch (block_->type()) {
case Block::kClip:
case Block::kTransition: // FIXME: Temporary, the transition should have its own UI representation at some point
/*QLinearGradient grad;
{
QLinearGradient grad;
grad.setStart(0, rect().top());
grad.setFinalStop(0, rect().bottom());
grad.setColorAt(0.0, QColor(160, 160, 240));
grad.setColorAt(1.0, QColor(128, 128, 192));
painter->fillRect(rect(), grad);*/
painter->fillRect(rect(), QColor(128, 128, 192));
painter->fillRect(rect(), grad);
//painter->fillRect(rect(), QColor(128, 128, 192));
if (option->state & QStyle::State_Selected) {
painter->fillRect(rect(), QColor(0, 0, 0, 64));
@@ -114,12 +115,39 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
painter->drawLine(QPointF(rect().left(), rect().bottom() - 1), QPointF(rect().right(), rect().bottom() - 1));
painter->drawLine(QPointF(rect().right(), rect().bottom() - 1), QPointF(rect().right(), rect().top()));
break;
}
case Block::kGap:
if (option->state & QStyle::State_Selected) {
// FIXME: Make this palette or CSS
painter->fillRect(rect(), Qt::white);
}
break;
case Block::kTransition:
{
painter->setBrush(QColor(128, 96, 192));
painter->setPen(QColor(48, 32, 64));
painter->drawRect(rect());
TransitionBlock* t = static_cast<TransitionBlock*>(block_);
if (t->out_block_input()->IsConnected()) {
// Transition fades something out, we'll draw a line
painter->drawLine(rect().topLeft(), rect().bottomRight());
}
if (t->in_block_input()->IsConnected()) {
// Transition fades something in, we'll draw a line
painter->drawLine(rect().bottomLeft(), rect().topRight());
}
if (t->out_block_input()->IsConnected() && t->in_block_input()->IsConnected()) {
// Draw line between out offset and in offset
qreal crossover_line = rect().left();
crossover_line += TimeToScene(t->out_offset());
painter->drawLine(qRound(crossover_line),
qRound(rect().top()),
qRound(crossover_line),
qRound(rect().bottom()));
}
break;
}
case Block::kTrack:
break;
}