From 95f05d64296a06de0f8a449f5b65528539784303 Mon Sep 17 00:00:00 2001 From: Troy James Sobotka Date: Mon, 4 May 2020 13:06:46 -0700 Subject: [PATCH 01/11] OCIO Fixes Change the allocation variables to be lower range and fit better. Should fix the 1.0 edge issue possibly. --- app/render/ocioconf/config.ocio | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/render/ocioconf/config.ocio b/app/render/ocioconf/config.ocio index 8a1150a1e..225372ed4 100755 --- a/app/render/ocioconf/config.ocio +++ b/app/render/ocioconf/config.ocio @@ -69,7 +69,7 @@ colorspaces: ITU BT.709 primaries based scene referred linear space. isdata: false allocation: lg2 - allocationvars: [-12.473931188, 12.526068812] + allocationvars: [-10.0, 10.0, 0.00392156862] # - ! # name: Debug @@ -80,10 +80,10 @@ colorspaces: # Debug purposes only. Do not use. # isdata: false # allocation: lg2 -# allocationvars: [-12.473931188, 12.526068812] +# allocationvars: [-10.0, 10.0, 0.00392156862] # from_reference: ! # children: -# - ! {allocation: lg2, vars: [-12.473931188, 12.526068812]} #[-12.473931188, 7.526068812]} +# - ! {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862]} #[-12.473931188, 7.526068812]} # - ! {allocation: uniform, vars: [0, 0.66]} #0.825 - ! @@ -95,13 +95,13 @@ colorspaces: Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range. isdata: false allocation: lg2 - allocationvars: [-12.473931188, 12.526068812] + allocationvars: [-10.0, 10.0, 0.00392156862] from_reference: ! children: - - ! {allocation: lg2, vars: [-12.473931188, 12.526068812]} + - ! {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862]} - ! {src: desat65cube.spi3d, interpolation: best} - ! {allocation: uniform, vars: [0, 0.66]} - to_reference: ! {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse} + to_reference: ! {allocation: lg2, vars: [-10, 6.5, 0.00392156862], direction: inverse} # - ! # name: Desat Log Encoding @@ -112,8 +112,8 @@ colorspaces: # Desaturation transform for proper crosstalk. Not intended for use. # isdata: false # allocation: lg2 -# allocationvars: [-12.473931188, 12.526068812] -# to_reference: ! {allocation: lg2, vars: [-12.473931188, 12.526068812], direction: inverse} +# allocationvars: [-10.0, 10.0, 0.00392156862] +# to_reference: ! {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862], direction: inverse} - ! name: sRGB OETF @@ -134,7 +134,7 @@ colorspaces: bitdepth: 32f isdata: false allocation: lg2 - allocationvars: [-12.4739, 12.5261] + allocationvars: [-10.0, 10.0, 0.00392156862] to_reference: ! children: - ! {matrix: [0.515121, 0.291977, 0.157104, 0, 0.241196, 0.692245, 0.0665741, 0, -0.00105286, 0.0418854, 0.784073, 0, 0, 0, 0, 1]} @@ -177,7 +177,7 @@ colorspaces: Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with Apple P3 primaries. isdata: false allocation: lg2 - allocationvars: [-12.473931188, 12.526068812] + allocationvars: [-10.0, 10.0, 0.00392156862] from_reference: ! children: - ! {src: Linear, dst: Filmic Log Encoding} @@ -189,7 +189,7 @@ colorspaces: - ! {value: [2.2, 2.2, 2.2, 1.0]} - ! {src: Apple DCI-P3 D65, dst: Linear} - ! {value: [2.2, 2.2, 2.2, 1.0], direction: inverse} - - ! {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse} + - ! {allocation: lg2, vars: [-10.0, 6.5, 0.00392156862], direction: inverse} - ! name: BT.1886 Filmic Log Encoding @@ -200,7 +200,7 @@ colorspaces: Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with REC.709 primaries. isdata: false allocation: lg2 - allocationvars: [-12.473931188, 12.526068812] + allocationvars: [-10.0, 10.0, 0.00392156862] from_reference: ! children: - ! {src: Linear, dst: Filmic Log Encoding} @@ -210,7 +210,7 @@ colorspaces: children: - ! {value: [2.4, 2.4, 2.4, 1.0]} - ! {value: [2.2, 2.2, 2.2, 1.0], direction: inverse} - - ! {allocation: lg2, vars: [-12.473931188, 4.026068812], direction: inverse} + - ! {allocation: lg2, vars: [-10.0, 10.0, 0.00392156862], direction: inverse} - ! name: Fuji F-Log OETF From 3600d1254ddcdad74d6d4a263c3dd93e920e8c02 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 04:06:03 +1000 Subject: [PATCH 02/11] config: shorten default cache length --- app/config/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/config.cpp b/app/config/config.cpp index c6e26a454..e3024ee18 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -98,8 +98,8 @@ void Config::SetDefaults() config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); config_map_["DiskCacheSize"] = 20.0; - config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(2)); - config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(10)); + config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1)); + config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5)); config_map_["ClearDiskCacheOnClose"] = false; config_map_["DefaultSequenceWidth"] = 1920; From d02e9090b9a10bdef73f9e0a38133ec32bcf8ff3 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 04:45:27 +1000 Subject: [PATCH 03/11] implemented core gizmo interaction functionality --- app/node/generator/matrix/matrix.cpp | 4 +- app/node/generator/matrix/matrix.h | 4 +- app/node/generator/polygon/polygon.cpp | 79 +++++++++++++++---- app/node/generator/polygon/polygon.h | 17 ++-- app/node/node.cpp | 6 +- app/node/node.h | 6 +- .../nodeparamviewarraywidget.cpp | 5 +- app/widget/viewer/viewerdisplay.cpp | 8 +- app/widget/viewer/viewerdisplay.h | 2 + 9 files changed, 95 insertions(+), 36 deletions(-) diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 66e7f57af..55f87357e 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -97,6 +97,7 @@ NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const return output; } +/* bool MatrixGenerator::HasGizmos() const { return true; @@ -105,7 +106,6 @@ bool MatrixGenerator::HasGizmos() const void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const { // FIXME: Implement this properly - /* p->setPen(Qt::white); // Fold values into a matrix @@ -116,8 +116,8 @@ void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVect // Draw ellipse p->drawEllipse(QRect(0, 0, 100, 100)); - */ } +*/ QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const { diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 901c3dc29..fce9c3a8d 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -43,8 +43,8 @@ public: virtual NodeValueTable Value(NodeValueDatabase& value) const override; - virtual bool HasGizmos() const override; - virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override; + //virtual bool HasGizmos() const override; + //virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override; private: QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const; diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 15ed05561..f14e4fa55 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -20,6 +20,7 @@ #include "polygon.h" +#include #include OLIVE_NAMESPACE_ENTER @@ -99,30 +100,20 @@ bool PolygonGenerator::HasGizmos() const return true; } -void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const +void PolygonGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const { if (!points_input_->GetSize()) { return; } - QVector points(points_input_->GetSize()); - p->setPen(Qt::white); p->setBrush(Qt::white); - int rect_sz = p->fontMetrics().height() / 8; + QVector points = GetGizmoCoordinates(db, scale); + QVector rects = GetGizmoRects(points); - for (int i=0;iGetSize();i++) { - QVector2D v = db[points_input_->At(i)].Take(NodeParam::kVec2).value(); - - v *= scale; - - QPointF pt = v.toPointF(); - points[i] = pt; - - QRectF rect(pt - QPointF(rect_sz, rect_sz), - pt + QPointF(rect_sz, rect_sz)); - p->drawRect(rect); + foreach (const QRectF& r, rects) { + p->drawRect(r); } points.append(points.first()); @@ -130,4 +121,62 @@ void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVec p->drawPolyline(points.constData(), points.size()); } +bool PolygonGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale) +{ + QVector points = GetGizmoCoordinates(db, scale); + QVector rects = GetGizmoRects(points); + + for (int i=0;iAt(i); + gizmo_drag_start_ = points.at(i); + return true; + } + } + + return false; +} + +void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale) +{ + QVector2D new_pos = QVector2D(p) / scale; + + gizmo_drag_->set_standard_value(new_pos.x(), 0); + gizmo_drag_->set_standard_value(new_pos.y(), 1); +} + +QVector PolygonGenerator::GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D& scale) const +{ + QVector points(points_input_->GetSize()); + + for (int i=0;iGetSize();i++) { + QVector2D v = db[points_input_->At(i)].Get(NodeParam::kVec2).value(); + + v *= scale; + + QPointF pt = v.toPointF(); + points[i] = pt; + } + + return points; +} + +QVector PolygonGenerator::GetGizmoRects(const QVector &points) const +{ + QVector rects(points.size()); + + int rect_sz = QFontMetrics(qApp->font()).height() / 8; + + for (int i=0;i GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D &scale) const; + + QVector GetGizmoRects(const QVector& points) const; + NodeInputArray* points_input_; NodeInput* color_input_; + NodeInput* gizmo_drag_; + QPointF gizmo_drag_start_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/node/node.cpp b/app/node/node.cpp index 724b77fe2..7a1b54b1a 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -287,16 +287,16 @@ bool Node::HasGizmos() const return false; } -void Node::DrawGizmos(NodeValueDatabase &, QPainter *, const QVector2D &) const +void Node::DrawGizmos(const NodeValueDatabase &, QPainter *, const QVector2D &) const { } -bool Node::GizmoPress(const QPointF &) +bool Node::GizmoPress(const NodeValueDatabase &, const QPointF &, const QVector2D &) { return false; } -void Node::GizmoMove(const QPointF &) +void Node::GizmoMove(const QPointF &, const QVector2D &) { } diff --git a/app/node/node.h b/app/node/node.h index acfe96d65..b97e0fdf1 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -383,10 +383,10 @@ public: virtual bool HasGizmos() const; - virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p, const QVector2D &scale) const; + virtual void DrawGizmos(const NodeValueDatabase& db, QPainter* p, const QVector2D &scale) const; - virtual bool GizmoPress(const QPointF& p); - virtual void GizmoMove(const QPointF& p); + virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF& p, const QVector2D &scale); + virtual void GizmoMove(const QPointF& p, const QVector2D &scale); virtual void GizmoRelease(const QPointF& p); const QString& GetLabel() const; diff --git a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp index 46418bb92..3e6df5614 100644 --- a/app/widget/nodeparamview/nodeparamviewarraywidget.cpp +++ b/app/widget/nodeparamview/nodeparamviewarraywidget.cpp @@ -31,9 +31,12 @@ NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidge QHBoxLayout* layout = new QHBoxLayout(this); count_lbl_ = new QLabel(); - layout->addWidget(count_lbl_, 1); + layout->addWidget(count_lbl_); + + layout->addStretch(); plus_btn_ = new QPushButton(tr("+")); + plus_btn_->setFixedWidth(plus_btn_->sizeHint().height()); layout->addWidget(plus_btn_); connect(plus_btn_, &QPushButton::clicked, this, &NodeParamViewArrayWidget::AddElement); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 22af4c754..e901dd6d5 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -192,7 +192,7 @@ void ViewerDisplayWidget::SetTime(const rational &time) void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (gizmos_) { - if (gizmos_->GizmoPress(GetTexturePosition(event->pos()))) { + if (gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())))) { gizmo_click_ = true; return; } @@ -206,7 +206,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { if (gizmo_click_) { - gizmos_->GizmoMove(GetTexturePosition(event->pos())); + gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size()))); return; } @@ -296,10 +296,10 @@ void ViewerDisplayWidget::paintGL() rational node_time = GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput); - NodeValueDatabase db = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); + gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); QPainter p(this); - gizmos_->DrawGizmos(db, &p, QVector2D(GetTexturePosition(size()))); + gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size()))); } // Draw action/title safe areas diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index a9903075e..eb020b9db 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -189,6 +189,8 @@ private: Node* gizmos_; + NodeValueDatabase gizmo_db_; + VideoRenderingParams gizmo_params_; bool gizmo_click_; From e45256f6abc3ec80fe39a41ae5942b7150d752aa Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 04:56:34 +1000 Subject: [PATCH 04/11] cmake: rdynamic needs to be a *link* flag (not a compile flag) --- app/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 162256626..4998e2a99 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -111,7 +111,7 @@ else() endif() if(UNIX AND NOT APPLE) - target_compile_options( + target_link_options( ${OLIVE_TARGET} PRIVATE -rdynamic From 3436740d2371679f4b7e4c7d8351adce36d51d42 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 14:41:50 +1000 Subject: [PATCH 05/11] gizmos: consolidated input param dragging code into reusable class --- app/node/CMakeLists.txt | 2 + app/node/generator/polygon/polygon.cpp | 22 +++- app/node/generator/polygon/polygon.h | 8 +- app/node/inputdragger.cpp | 118 ++++++++++++++++++ app/node/inputdragger.h | 60 +++++++++ app/node/node.cpp | 2 +- app/node/node.h | 2 +- .../nodeparamviewwidgetbridge.cpp | 79 ++---------- .../nodeparamview/nodeparamviewwidgetbridge.h | 6 +- app/widget/viewer/viewerdisplay.cpp | 19 +-- app/widget/viewer/viewerdisplay.h | 6 +- 11 files changed, 237 insertions(+), 87 deletions(-) create mode 100644 app/node/inputdragger.cpp create mode 100644 app/node/inputdragger.h diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index 8930b3979..6f31b252c 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -36,6 +36,8 @@ set(OLIVE_SOURCES node/input.cpp node/inputarray.h node/inputarray.cpp + node/inputdragger.h + node/inputdragger.cpp node/keyframe.h node/keyframe.cpp node/node.h diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index f14e4fa55..15441c1f9 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -139,12 +139,28 @@ bool PolygonGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, return false; } -void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale) +void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational& time) { QVector2D new_pos = QVector2D(p) / scale; - gizmo_drag_->set_standard_value(new_pos.x(), 0); - gizmo_drag_->set_standard_value(new_pos.y(), 1); + if (!gizmo_x_dragger_.IsStarted()) { + gizmo_x_dragger_.Start(gizmo_drag_, time, 0); + } + + if (!gizmo_y_dragger_.IsStarted()) { + gizmo_y_dragger_.Start(gizmo_drag_, time, 1); + } + + gizmo_x_dragger_.Drag(new_pos.x()); + gizmo_y_dragger_.Drag(new_pos.y()); + + InvalidateVisible(gizmo_drag_, gizmo_drag_); +} + +void PolygonGenerator::GizmoRelease(const QPointF &p) +{ + gizmo_x_dragger_.End(); + gizmo_y_dragger_.End(); } QVector PolygonGenerator::GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D& scale) const diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index cf907cf25..21d4e4106 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -22,6 +22,7 @@ #define POLYGONGENERATOR_H #include "node/node.h" +#include "node/inputdragger.h" OLIVE_NAMESPACE_ENTER @@ -46,8 +47,8 @@ public: virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override; virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale) override; - virtual void GizmoMove(const QPointF &p, const QVector2D &scale) override; - //virtual void GizmoRelease(const QPointF &p) override; + virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; + virtual void GizmoRelease(const QPointF &p) override; private: QVector GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D &scale) const; @@ -61,6 +62,9 @@ private: NodeInput* gizmo_drag_; QPointF gizmo_drag_start_; + NodeInputDragger gizmo_x_dragger_; + NodeInputDragger gizmo_y_dragger_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/node/inputdragger.cpp b/app/node/inputdragger.cpp new file mode 100644 index 000000000..f6e0cb60c --- /dev/null +++ b/app/node/inputdragger.cpp @@ -0,0 +1,118 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + 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 . + +***/ + +#include "inputdragger.h" + +#include "core.h" +#include "node.h" +#include "widget/nodeparamview/nodeparamviewundo.h" + +OLIVE_NAMESPACE_ENTER + +NodeInputDragger::NodeInputDragger() : + input_(nullptr) +{ + +} + +bool NodeInputDragger::IsStarted() const +{ + return input_; +} + +void NodeInputDragger::Start(NodeInput *input, const rational &time, int track) +{ + Q_ASSERT(!input_); + + // Set up new drag + input_ = input; + time_ = time; + track_ = track; + + // Cache current value + start_value_ = input_->get_value_at_time_for_track(time, track); + + // Determine whether we are creating a keyframe or not + if (input_->is_keyframing()) { + dragging_key_ = input_->get_keyframe_at_time_on_track(time, track); + drag_created_key_ = !dragging_key_; + + if (drag_created_key_) { + dragging_key_ = NodeKeyframe::Create(time, + start_value_, + input_->get_best_keyframe_type_for_time(time, track), + track); + + // We disable default signal emitting during the drag + input_->blockSignals(true); + input_->insert_keyframe(dragging_key_); + input_->blockSignals(false); + + emit input_->KeyframeAdded(dragging_key_); + } + } +} + +void NodeInputDragger::Drag(const QVariant& value) +{ + Q_ASSERT(input_); + + end_value_ = value; + + input_->blockSignals(true); + + if (input_->is_keyframing()) { + dragging_key_->set_value(value); + } else { + input_->set_standard_value(value, track_); + } + + input_->blockSignals(false); +} + +void NodeInputDragger::End() +{ + if (!IsStarted()) { + return; + } + + QUndoCommand* command = new QUndoCommand(); + + if (input_->is_keyframing()) { + if (drag_created_key_) { + // We created a keyframe in this process + new NodeParamInsertKeyframeCommand(input_, dragging_key_, true, command); + } + + // We just set a keyframe's value + // We do this even when inserting a keyframe because we don't actually perform an insert in this undo command + // so this will ensure the ValueChanged() signal is sent correctly + new NodeParamSetKeyframeValueCommand(dragging_key_, end_value_, start_value_, command); + } else { + // We just set the standard value + new NodeParamSetStandardValueCommand(input_, track_, end_value_, start_value_, command); + } + + Core::instance()->undo_stack()->push(command); + + input_ = nullptr; +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/inputdragger.h b/app/node/inputdragger.h new file mode 100644 index 000000000..f67f163a2 --- /dev/null +++ b/app/node/inputdragger.h @@ -0,0 +1,60 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + 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 . + +***/ + +#ifndef NODEINPUTDRAGGER_H +#define NODEINPUTDRAGGER_H + +#include "node/input.h" + +OLIVE_NAMESPACE_ENTER + +class NodeInputDragger +{ +public: + NodeInputDragger(); + + bool IsStarted() const; + + void Start(NodeInput* input, const rational& time, int track); + + void Drag(const QVariant &value); + + void End(); + +private: + NodeInput* input_; + + int track_; + + rational time_; + + QVariant start_value_; + + QVariant end_value_; + + NodeKeyframePtr dragging_key_; + + bool drag_created_key_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // NODEINPUTDRAGGER_H diff --git a/app/node/node.cpp b/app/node/node.cpp index 7a1b54b1a..2b702bf68 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -296,7 +296,7 @@ bool Node::GizmoPress(const NodeValueDatabase &, const QPointF &, const QVector2 return false; } -void Node::GizmoMove(const QPointF &, const QVector2D &) +void Node::GizmoMove(const QPointF &, const QVector2D &, const rational &) { } diff --git a/app/node/node.h b/app/node/node.h index b97e0fdf1..1f345428b 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -386,7 +386,7 @@ public: virtual void DrawGizmos(const NodeValueDatabase& db, QPainter* p, const QVector2D &scale) const; virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF& p, const QVector2D &scale); - virtual void GizmoMove(const QPointF& p, const QVector2D &scale); + virtual void GizmoMove(const QPointF& p, const QVector2D &scale, const rational &time); virtual void GizmoRelease(const QPointF& p); const QString& GetLabel() const; diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 67778be99..3f9933218 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -42,9 +42,7 @@ OLIVE_NAMESPACE_ENTER NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) : QObject(parent), - input_(input), - dragging_(false), - drag_created_keyframe_(false) + input_(input) { CreateWidgets(); @@ -227,74 +225,23 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant if (slider->IsDragging()) { // While we're dragging, we block the input's normal signalling and create our own - input_->blockSignals(true); - - if (!dragging_) { - // Set up new drag - dragging_ = true; - - // Cache current value - drag_old_value_ = input_->get_value_at_time_for_track(node_time, slider_track); - - // Determine whether we are creating a keyframe or not - if (input_->is_keyframing()) { - dragging_keyframe_ = input_->get_keyframe_at_time_on_track(node_time, slider_track); - drag_created_keyframe_ = !dragging_keyframe_; - - if (drag_created_keyframe_) { - dragging_keyframe_ = NodeKeyframe::Create(node_time, - value, - input_->get_best_keyframe_type_for_time(node_time, slider_track), - slider_track); - - input_->insert_keyframe(dragging_keyframe_); - - // We re-enable signals temporarily to emit the keyframe added signal - input_->blockSignals(false); - emit input_->KeyframeAdded(dragging_keyframe_); - input_->blockSignals(true); - } - } + if (!dragger_.IsStarted()) { + dragger_.Start(input_, node_time, slider_track); } - if (input_->is_keyframing()) { - dragging_keyframe_->set_value(value); - } else { - input_->set_standard_value(value, slider_track); - } - - input_->blockSignals(false); + dragger_.Drag(value); input_->parentNode()->InvalidateVisible(input_, input_); + } else if (dragger_.IsStarted()) { + + // We were dragging and just stopped + dragger_.Drag(value); + dragger_.End(); + } else { - if (dragging_) { - // We were dragging and just stopped - dragging_ = false; - - QUndoCommand* command = new QUndoCommand(); - - if (input_->is_keyframing()) { - if (drag_created_keyframe_) { - // We created a keyframe in this process - new NodeParamInsertKeyframeCommand(input_, dragging_keyframe_, true, command); - } - - // We just set a keyframe's value - // We do this even when inserting a keyframe because we don't actually perform an insert in this undo command - // so this will ensure the ValueChanged() signal is sent correctly - new NodeParamSetKeyframeValueCommand(dragging_keyframe_, value, drag_old_value_, command); - } else { - // We just set the standard value - new NodeParamSetStandardValueCommand(input_, slider_track, value, drag_old_value_, command); - } - - Core::instance()->undo_stack()->push(command); - - } else { - // No drag was involved, we can just push the value - SetInputValue(value, slider_track); - } + // No drag was involved, we can just push the value + SetInputValue(value, slider_track); } } @@ -529,7 +476,7 @@ rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range) { - if (!dragging_ && range.in() <= time_ && range.out() >= time_) { + if (!dragger_.IsStarted() && range.in() <= time_ && range.out() >= time_) { // We'll need to update the widgets because the values have changed on our current time UpdateWidgetValues(); } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 3d385a7bc..245a03171 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -24,6 +24,7 @@ #include #include "node/input.h" +#include "node/inputdragger.h" #include "widget/slider/sliderbase.h" #include "widget/timetarget/timetarget.h" @@ -60,10 +61,7 @@ private: rational time_; - bool dragging_; - bool drag_created_keyframe_; - QVariant drag_old_value_; - NodeKeyframePtr dragging_keyframe_; + NodeInputDragger dragger_; private slots: void WidgetCallback(); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index e901dd6d5..04a5dbc6f 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -191,11 +191,11 @@ void ViewerDisplayWidget::SetTime(const rational &time) void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { - if (gizmos_) { - if (gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())))) { - gizmo_click_ = true; - return; - } + if (gizmos_ + && gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())))) { + gizmo_click_ = true; + gizmo_drag_time_ = GetGizmoTime(); + return; } QOpenGLWidget::mousePressEvent(event); @@ -206,7 +206,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { if (gizmo_click_) { - gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size()))); + gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size())), gizmo_drag_time_); return; } @@ -294,7 +294,7 @@ void ViewerDisplayWidget::paintGL() if (gizmos_) { GizmoTraverser gt; - rational node_time = GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput); + rational node_time = GetGizmoTime(); gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); @@ -351,6 +351,11 @@ QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y y / gizmo_params_.height()); } +rational ViewerDisplayWidget::GetGizmoTime() +{ + return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput); +} + #ifdef Q_OS_LINUX void ViewerDisplayWidget::ShowNouveauWarning() { diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index eb020b9db..996758718 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -162,6 +162,8 @@ private: QPointF GetTexturePosition(const QSize& size); QPointF GetTexturePosition(const double& x, const double& y); + rational GetGizmoTime(); + /** * @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL(). */ @@ -188,11 +190,9 @@ private: ViewerSafeMarginInfo safe_margin_; Node* gizmos_; - NodeValueDatabase gizmo_db_; - + rational gizmo_drag_time_; VideoRenderingParams gizmo_params_; - bool gizmo_click_; rational time_; From 5b956729b339f35e5aba6914d34c204f847bc0dc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 7 May 2020 18:12:18 +1000 Subject: [PATCH 06/11] gizmos: work towards gizmos in the matrix transform node --- app/node/generator/matrix/matrix.cpp | 187 ++++++++++++++++++++++--- app/node/generator/matrix/matrix.h | 37 ++++- app/node/generator/polygon/polygon.cpp | 11 +- app/node/generator/polygon/polygon.h | 6 +- app/node/node.cpp | 6 +- app/node/node.h | 6 +- app/widget/viewer/viewerdisplay.cpp | 6 +- 7 files changed, 219 insertions(+), 40 deletions(-) diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 55f87357e..bafa5d530 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -20,9 +20,12 @@ #include "matrix.h" +#include #include #include +#include "common/range.h" + OLIVE_NAMESPACE_ENTER MatrixGenerator::MatrixGenerator() @@ -97,55 +100,201 @@ NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const return output; } -/* +bool MatrixGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize &viewport) +{ + GizmoSharedData gizmo_data(viewport, scale); + + QPointF anchor_pt = GetGizmoAnchorPoint(db, gizmo_data); + int anchor_radius = GetGizmoAnchorPointRadius(); + + if (InRange(p.x(), anchor_pt.x(), anchor_radius * 2.0) + && InRange(p.y(), anchor_pt.y(), anchor_radius * 2.0)) { + gizmo_drag_ = anchor_input_; + gizmo_start2_ = db[position_input_].Get(NodeParam::kVec2).value(); + } else { + gizmo_drag_ = position_input_; + } + + gizmo_start_ = db[gizmo_drag_].Get(NodeParam::kVec2).value(); + gizmo_mouse_start_ = p; + + return true; +} + +void MatrixGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) +{ + QVector2D movement = 2.0 * QVector2D(p - gizmo_mouse_start_) / scale; + QVector2D new_pos = gizmo_start_ + movement; + + if (!gizmo_x_dragger_.IsStarted()) { + gizmo_x_dragger_.Start(gizmo_drag_, time, 0); + } + + if (!gizmo_y_dragger_.IsStarted()) { + gizmo_y_dragger_.Start(gizmo_drag_, time, 1); + } + + gizmo_x_dragger_.Drag(new_pos.x()); + gizmo_y_dragger_.Drag(new_pos.y()); + + if (gizmo_drag_ == anchor_input_) { + // If we're dragging the anchor, counter the position at the same time + QVector2D new_pos2 = gizmo_start2_ + movement; + + if (!gizmo_x2_dragger_.IsStarted()) { + gizmo_x2_dragger_.Start(position_input_, time, 0); + } + + if (!gizmo_y2_dragger_.IsStarted()) { + gizmo_y2_dragger_.Start(position_input_, time, 1); + } + + gizmo_x2_dragger_.Drag(new_pos2.x()); + gizmo_y2_dragger_.Drag(new_pos2.y()); + + InvalidateVisible(position_input_, position_input_); + } + + InvalidateVisible(gizmo_drag_, gizmo_drag_); +} + +void MatrixGenerator::GizmoRelease() +{ + gizmo_x_dragger_.End(); + gizmo_y_dragger_.End(); + gizmo_x2_dragger_.End(); + gizmo_y2_dragger_.End(); +} + bool MatrixGenerator::HasGizmos() const { return true; } -void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const +void MatrixGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize& viewport) const { - // FIXME: Implement this properly p->setPen(Qt::white); - // Fold values into a matrix - QMatrix4x4 matrix = GenerateMatrix(db); + GizmoSharedData gizmo_data(viewport, scale); - // Set QPainter transform to our matrix - p->setTransform(matrix.toTransform()); + { + // Fold values into a matrix + QMatrix4x4 matrix; + matrix.scale(gizmo_data.half_scale); + matrix *= GenerateMatrix(db, false); + matrix.scale(gizmo_data.inverted_half_scale); - // Draw ellipse - p->drawEllipse(QRect(0, 0, 100, 100)); + // Create rect and transform it + QVector points = {QPointF(-100, -100), + QPointF(100, -100), + QPointF(100, 100), + QPointF(-100, 100), + QPointF(-100, -100)}; + QPolygonF poly(points); + poly = matrix.toTransform().map(poly); + poly.translate(gizmo_data.half_viewport); + + // Draw square + p->drawPolyline(poly); + } + + { + // Draw anchor point marker (with no anchor point translation) + QPointF pt = GetGizmoAnchorPoint(db, gizmo_data); + + // Draw anchor point + int anchor_pt_radius = GetGizmoAnchorPointRadius(); + + p->drawEllipse(pt, anchor_pt_radius, anchor_pt_radius); + + p->drawLines({QLineF(pt.x() - anchor_pt_radius, pt.y(), + pt.x() + anchor_pt_radius, pt.y()), + QLineF(pt.x(), pt.y() - anchor_pt_radius, + pt.x(), pt.y() + anchor_pt_radius)}); + } } -*/ QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const +{ + return GenerateMatrix(value[position_input_].Take(NodeParam::kVec2).value(), + value[rotation_input_].Take(NodeParam::kFloat).toFloat(), + value[scale_input_].Take(NodeParam::kVec2).value(), + value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(), + value[anchor_input_].Take(NodeParam::kVec2).value()); +} + +QMatrix4x4 MatrixGenerator::GenerateMatrix(const NodeValueDatabase &value, bool ignore_anchor) const +{ + QVector2D anchor; + + if (!ignore_anchor) { + anchor = value[anchor_input_].Get(NodeParam::kVec2).value(); + } + + return GenerateMatrix(value[position_input_].Get(NodeParam::kVec2).value(), + value[rotation_input_].Get(NodeParam::kFloat).toFloat(), + value[scale_input_].Get(NodeParam::kVec2).value(), + value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool(), + anchor); +} + +QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos, + const float& rot, + const QVector2D& scale, + bool uniform_scale, + const QVector2D& anchor) { QMatrix4x4 mat; - // Position translate - QVector2D pos = value[position_input_].Take(NodeParam::kVec2).value(); + // Position mat.translate(pos); // Rotation - mat.rotate(value[rotation_input_].Take(NodeParam::kFloat).toFloat(), 0, 0, 1); + mat.rotate(rot, 0, 0, 1); - // Scale and Uniform Scale - QVector2D scale = value[scale_input_].Take(NodeParam::kVec2).value(); - if (value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool()) { - scale.setY(scale.x()); + // Scale + if (uniform_scale) { + QVector2D uniformed(scale.x(), scale.x()); + mat.scale(uniformed); + } else { + mat.scale(scale); } - mat.scale(scale); // Anchor Point - mat.translate(-value[anchor_input_].Take(NodeParam::kVec2).value()); + mat.translate(-anchor); return mat; } +QPointF MatrixGenerator::GetGizmoAnchorPoint(const NodeValueDatabase &db, + const GizmoSharedData& gizmo_data) const +{ + QMatrix4x4 matrix; + matrix.scale(gizmo_data.half_scale); + matrix *= GenerateMatrix(db, true); + matrix.scale(gizmo_data.inverted_half_scale); + + QPointF pt = matrix.toTransform().map(QPointF()); + pt += gizmo_data.half_viewport; + + return pt; +} + +int MatrixGenerator::GetGizmoAnchorPointRadius() +{ + return QFontMetrics(qApp->font()).height() / 2; +} + void MatrixGenerator::UniformScaleChanged() { scale_input_->set_property("disabley", uniform_scale_input_->get_standard_value().toBool()); } +MatrixGenerator::GizmoSharedData::GizmoSharedData(const QSize &viewport, const QVector2D &scale) +{ + half_viewport = QPointF(viewport.width() / 2, viewport.height() / 2); + half_scale = scale * 0.5; + inverted_half_scale = QVector2D(1.0f / half_scale.x(), 1.0f / half_scale.y()); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index fce9c3a8d..453f8eb76 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -21,7 +21,10 @@ #ifndef MATRIXGENERATOR_H #define MATRIXGENERATOR_H +#include + #include "node/node.h" +#include "node/inputdragger.h" OLIVE_NAMESPACE_ENTER @@ -43,11 +46,33 @@ public: virtual NodeValueTable Value(NodeValueDatabase& value) const override; - //virtual bool HasGizmos() const override; - //virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override; + virtual bool HasGizmos() const override; + virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; + + virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; + virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; + virtual void GizmoRelease() override; private: + struct GizmoSharedData { + GizmoSharedData(const QSize& viewport, const QVector2D& scale); + + QPointF half_viewport; + QVector2D half_scale; + QVector2D inverted_half_scale; + }; + QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const; + QMatrix4x4 GenerateMatrix(const NodeValueDatabase& value, bool ignore_anchor) const; + static QMatrix4x4 GenerateMatrix(const QVector2D &pos, + const float &rot, + const QVector2D &scale, + bool uniform_scale, + const QVector2D &anchor); + + QPointF GetGizmoAnchorPoint(const NodeValueDatabase &db, const GizmoSharedData &gizmo_data) const; + static int GetGizmoAnchorPointRadius(); + NodeInput* gizmo_drag_; NodeInput* position_input_; @@ -59,6 +84,14 @@ private: NodeInput* anchor_input_; + QVector2D gizmo_start_; + QVector2D gizmo_start2_; + QPointF gizmo_mouse_start_; + NodeInputDragger gizmo_x_dragger_; + NodeInputDragger gizmo_y_dragger_; + NodeInputDragger gizmo_x2_dragger_; + NodeInputDragger gizmo_y2_dragger_; + private slots: void UniformScaleChanged(); diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 15441c1f9..37b896492 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -100,7 +100,7 @@ bool PolygonGenerator::HasGizmos() const return true; } -void PolygonGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale) const +void PolygonGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize &viewport) const { if (!points_input_->GetSize()) { return; @@ -112,16 +112,13 @@ void PolygonGenerator::DrawGizmos(const NodeValueDatabase &db, QPainter *p, cons QVector points = GetGizmoCoordinates(db, scale); QVector rects = GetGizmoRects(points); - foreach (const QRectF& r, rects) { - p->drawRect(r); - } - points.append(points.first()); p->drawPolyline(points.constData(), points.size()); + p->drawRects(rects); } -bool PolygonGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale) +bool PolygonGenerator::GizmoPress(const NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport) { QVector points = GetGizmoCoordinates(db, scale); QVector rects = GetGizmoRects(points); @@ -157,7 +154,7 @@ void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const InvalidateVisible(gizmo_drag_, gizmo_drag_); } -void PolygonGenerator::GizmoRelease(const QPointF &p) +void PolygonGenerator::GizmoRelease() { gizmo_x_dragger_.End(); gizmo_y_dragger_.End(); diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index 21d4e4106..01398eff4 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -44,11 +44,11 @@ public: virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; virtual bool HasGizmos() const override; - virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale) const override; + virtual void DrawGizmos(const NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; - virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale) override; + virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; - virtual void GizmoRelease(const QPointF &p) override; + virtual void GizmoRelease() override; private: QVector GetGizmoCoordinates(const NodeValueDatabase &db, const QVector2D &scale) const; diff --git a/app/node/node.cpp b/app/node/node.cpp index 2b702bf68..90283cb96 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -287,11 +287,11 @@ bool Node::HasGizmos() const return false; } -void Node::DrawGizmos(const NodeValueDatabase &, QPainter *, const QVector2D &) const +void Node::DrawGizmos(const NodeValueDatabase &, QPainter *, const QVector2D &, const QSize &) const { } -bool Node::GizmoPress(const NodeValueDatabase &, const QPointF &, const QVector2D &) +bool Node::GizmoPress(const NodeValueDatabase &, const QPointF &, const QVector2D &, const QSize &viewport) { return false; } @@ -300,7 +300,7 @@ void Node::GizmoMove(const QPointF &, const QVector2D &, const rational &) { } -void Node::GizmoRelease(const QPointF &) +void Node::GizmoRelease() { } diff --git a/app/node/node.h b/app/node/node.h index 1f345428b..0c03c0a7d 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -383,11 +383,11 @@ public: virtual bool HasGizmos() const; - virtual void DrawGizmos(const NodeValueDatabase& db, QPainter* p, const QVector2D &scale) const; + virtual void DrawGizmos(const NodeValueDatabase& db, QPainter* p, const QVector2D &scale, const QSize& viewport) const; - virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF& p, const QVector2D &scale); + virtual bool GizmoPress(const NodeValueDatabase& db, const QPointF& p, const QVector2D &scale, const QSize& viewport); virtual void GizmoMove(const QPointF& p, const QVector2D &scale, const rational &time); - virtual void GizmoRelease(const QPointF& p); + virtual void GizmoRelease(); const QString& GetLabel() const; void SetLabel(const QString& s); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 04a5dbc6f..62a551b1b 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -192,7 +192,7 @@ void ViewerDisplayWidget::SetTime(const rational &time) void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (gizmos_ - && gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())))) { + && gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())), size())) { gizmo_click_ = true; gizmo_drag_time_ = GetGizmoTime(); return; @@ -236,7 +236,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) { if (gizmo_click_) { - gizmos_->GizmoRelease(GetTexturePosition(event->pos())); + gizmos_->GizmoRelease(); gizmo_click_ = false; return; @@ -299,7 +299,7 @@ void ViewerDisplayWidget::paintGL() gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); QPainter p(this); - gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size()))); + gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size()); } // Draw action/title safe areas From 49b8e2bfabadc48bfdff790a9899eb3c89df93c4 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Thu, 7 May 2020 13:28:21 +0100 Subject: [PATCH 07/11] gitignore updates for Visual Studio with CMake Using Visual Studio and it's built in CMake generates a folder called .vs and a JSON file of CMamke settings called CMakeSettings.json. These have both been added to the .gitignore file. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f458ddfab..eaf33fa1c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ build/ .DS_Store .vscode +.vs +CmakeSettings.json # # Qt ignores taken from https://github.com/github/gitignore From 65705d580dbc8c5f6a9edf1526f6cc20c16059d2 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 8 May 2020 00:32:02 +1000 Subject: [PATCH 08/11] renderer: keep frames in vram while paused Saves some GPU cycles when adjusting parameters. --- app/common/define.h | 2 + app/project/item/footage/imagestream.cpp | 6 + app/project/item/footage/imagestream.h | 2 + app/render/backend/audio/audioworker.cpp | 10 +- app/render/backend/audio/audioworker.h | 2 +- app/render/backend/audiorenderworker.cpp | 11 ++ app/render/backend/audiorenderworker.h | 2 + app/render/backend/opengl/openglbackend.cpp | 6 +- app/render/backend/opengl/openglproxy.cpp | 174 +++++++++----------- app/render/backend/opengl/openglproxy.h | 19 +-- app/render/backend/opengl/openglworker.cpp | 36 +++- app/render/backend/opengl/openglworker.h | 14 +- app/render/backend/renderworker.cpp | 16 +- app/render/backend/renderworker.h | 6 +- app/render/backend/videorenderworker.cpp | 42 +++++ app/render/backend/videorenderworker.h | 12 ++ app/widget/viewer/viewerdisplay.cpp | 2 +- 17 files changed, 212 insertions(+), 150 deletions(-) diff --git a/app/common/define.h b/app/common/define.h index 405f34615..dd62ba73d 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -47,7 +47,9 @@ OLIVE_NAMESPACE_EXIT #define MACRO_NAME_AS_STR(s) #s #define MACRO_VAL_AS_STR(s) MACRO_NAME_AS_STR(s) +#define OLIVE_NS_CONST_ARG(x, y) QArgument("const " MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) #define OLIVE_NS_ARG(x, y) QArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) +#define OLIVE_NS_RETURN_ARG(x, y) QReturnArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) /** * Copy/move deleters. Similar to Q_DISABLE_COPY_MOVE, et al. but those functions are not present in Qt < 5.13 so we diff --git a/app/project/item/footage/imagestream.cpp b/app/project/item/footage/imagestream.cpp index 60eab29b9..9b679bc5d 100644 --- a/app/project/item/footage/imagestream.cpp +++ b/app/project/item/footage/imagestream.cpp @@ -120,6 +120,12 @@ void ImageStream::set_colorspace(const QString &color) emit ParametersChanged(); } +QString ImageStream::get_colorspace_match_string() const +{ + return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(), + colorspace()); +} + void ImageStream::ColorConfigChanged() { ColorManager* color_manager = footage()->project()->color_manager(); diff --git a/app/project/item/footage/imagestream.h b/app/project/item/footage/imagestream.h index ad12929b5..9e3b6f72b 100644 --- a/app/project/item/footage/imagestream.h +++ b/app/project/item/footage/imagestream.h @@ -48,6 +48,8 @@ public: const QString& colorspace(bool default_if_empty = true) const; void set_colorspace(const QString& color); + QString get_colorspace_match_string() const; + protected: virtual void FootageSetEvent(Footage*) override; diff --git a/app/render/backend/audio/audioworker.cpp b/app/render/backend/audio/audioworker.cpp index 5e0e38ee7..8c00e099d 100644 --- a/app/render/backend/audio/audioworker.cpp +++ b/app/render/backend/audio/audioworker.cpp @@ -27,21 +27,19 @@ AudioWorker::AudioWorker(QHash *copy_map, QObject *parent) : { } -void AudioWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) +NodeValue AudioWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) { - if (stream->type() != Stream::kAudio) { - return; - } - if (decoder->HasConformedVersion(audio_params())) { SampleBufferPtr frame = decoder->RetrieveAudio(range.in(), range.out() - range.in(), audio_params()); if (frame) { - table->Push(NodeParam::kSamples, QVariant::fromValue(frame)); + return NodeValue(NodeParam::kSamples, QVariant::fromValue(frame)); } } else { emit ConformUnavailable(decoder->stream(), CurrentPath().range(), range.out(), audio_params()); } + + return NodeValue(); } void AudioWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params_in, NodeValueTable &output_params) diff --git a/app/render/backend/audio/audioworker.h b/app/render/backend/audio/audioworker.h index 53192706f..fa642b11d 100644 --- a/app/render/backend/audio/audioworker.h +++ b/app/render/backend/audio/audioworker.h @@ -31,7 +31,7 @@ public: AudioWorker(QHash* copy_map, QObject* parent = nullptr); protected: - virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) override; + virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) override; virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, NodeValueDatabase& input_params, NodeValueTable& output_params) override; diff --git a/app/render/backend/audiorenderworker.cpp b/app/render/backend/audiorenderworker.cpp index 2365855a4..053a4c6f0 100644 --- a/app/render/backend/audiorenderworker.cpp +++ b/app/render/backend/audiorenderworker.cpp @@ -154,6 +154,17 @@ NodeValueTable AudioRenderWorker::RenderBlock(const TrackOutput *track, const Ti return merged_table; } +void AudioRenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable *table) +{ + if (stream->type() != Stream::kAudio) { + return; + } + + NodeValue value = GetDataFromStream(stream, input_time); + + table->Push(value); +} + const AudioRenderingParams &AudioRenderWorker::audio_params() const { return audio_params_; diff --git a/app/render/backend/audiorenderworker.h b/app/render/backend/audiorenderworker.h index 7da959984..29c1f3f52 100644 --- a/app/render/backend/audiorenderworker.h +++ b/app/render/backend/audiorenderworker.h @@ -43,6 +43,8 @@ protected: virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) override; + virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override; + const AudioRenderingParams& audio_params() const; private: diff --git a/app/render/backend/opengl/openglbackend.cpp b/app/render/backend/opengl/openglbackend.cpp index e1144dc5d..2f996e82c 100644 --- a/app/render/backend/opengl/openglbackend.cpp +++ b/app/render/backend/opengl/openglbackend.cpp @@ -63,13 +63,9 @@ bool OpenGLBackend::InitInternal() // Initiate one thread per CPU core for (int i=0;iSetParameters(params()); processors_.append(processor); - - connect(processor, &OpenGLWorker::RequestFrameToValue, proxy_, &OpenGLProxy::FrameToValue, Qt::BlockingQueuedConnection); - connect(processor, &OpenGLWorker::RequestTextureToBuffer, proxy_, &OpenGLProxy::TextureToBuffer, Qt::BlockingQueuedConnection); - connect(processor, &OpenGLWorker::RequestRunNodeAccelerated, proxy_, &OpenGLProxy::RunNodeAccelerated, Qt::BlockingQueuedConnection); } return true; diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index 649b2ba15..576fe81c0 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -67,133 +67,107 @@ bool OpenGLProxy::Init() return true; } -void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table) +NodeValue OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream) { - // Ensure stream is video or image type - if (stream->type() != Stream::kVideo && stream->type() != Stream::kImage) { - return; - } - ImageStreamPtr video_stream = std::static_pointer_cast(stream); // Set up OCIO context - QString colorspace_match = QStringLiteral("%1:%2").arg(video_stream->footage()->project()->color_manager()->GetConfigFilename(), video_stream->colorspace()); + QString colorspace_match = video_stream->get_colorspace_match_string(); - OpenGLTextureCache::ReferencePtr footage_tex_ref = nullptr; + OpenGLColorProcessorPtr color_processor = std::static_pointer_cast(color_cache_.Get(colorspace_match)); - if (stream->type() == Stream::kImage && still_image_cache_.Has(stream.get())) { - CachedStill cs = still_image_cache_.Get(stream.get()); + if (!color_processor) { + color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(), + video_stream->colorspace(), + video_stream->footage()->project()->color_manager()->GetReferenceColorSpace()); + color_cache_.Add(colorspace_match, color_processor); + } - if (cs.colorspace == colorspace_match - && cs.alpha_is_associated == video_stream->premultiplied_alpha() - && cs.divider == video_params_.divider()) { - footage_tex_ref = cs.texture; - } else { - still_image_cache_.Remove(stream.get()); + ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(video_params_.mode()); + + // OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU + if (ocio_method == ColorManager::kOCIOAccurate) { + bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format()); + + // Convert frame to float for OCIO + frame = PixelFormat::ConvertPixelFormat(frame, + has_alpha + ? PixelFormat::PIX_FMT_RGBA32F + : PixelFormat::PIX_FMT_RGB32F); + + // If alpha is associated, disassociate for the color transform + if (has_alpha && video_stream->premultiplied_alpha()) { + ColorManager::DisassociateAlpha(frame); + } + + // Perform color transform + color_processor->ConvertFrame(frame); + + // Associate alpha + if (has_alpha) { + if (video_stream->premultiplied_alpha()) { + ColorManager::ReassociateAlpha(frame); + } else { + ColorManager::AssociateAlpha(frame); + } } } - if (!footage_tex_ref) { - OpenGLColorProcessorPtr color_processor = std::static_pointer_cast(color_cache_.Get(colorspace_match)); + OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_.Get(ctx_, frame); - if (!color_processor) { - color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(), - video_stream->colorspace(), - video_stream->footage()->project()->color_manager()->GetReferenceColorSpace()); - color_cache_.Add(colorspace_match, color_processor); + if (ocio_method == ColorManager::kOCIOFast) { + if (!color_processor->IsEnabled()) { + color_processor->Enable(ctx_, video_stream->premultiplied_alpha()); } - ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(video_params_.mode()); + VideoRenderingParams frame_params = frame->video_params(); - // OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU - if (ocio_method == ColorManager::kOCIOAccurate) { - bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format()); + // Check frame aspect ratio + if (frame->sample_aspect_ratio() != 1 && frame->sample_aspect_ratio() != 0) { + int new_width = frame_params.width(); + int new_height = frame_params.height(); - // Convert frame to float for OCIO - frame = PixelFormat::ConvertPixelFormat(frame, - has_alpha - ? PixelFormat::PIX_FMT_RGBA32F - : PixelFormat::PIX_FMT_RGB32F); - - // If alpha is associated, disassociate for the color transform - if (has_alpha && video_stream->premultiplied_alpha()) { - ColorManager::DisassociateAlpha(frame); + // Scale the frame in a way that does not reduce the resolution + if (frame->sample_aspect_ratio() > 1) { + // Make wider + new_width = qRound(static_cast(new_width) * frame->sample_aspect_ratio().toDouble()); + } else { + // Make taller + new_height = qRound(static_cast(new_height) / frame->sample_aspect_ratio().toDouble()); } - // Perform color transform - color_processor->ConvertFrame(frame); - - // Associate alpha - if (has_alpha) { - if (video_stream->premultiplied_alpha()) { - ColorManager::ReassociateAlpha(frame); - } else { - ColorManager::AssociateAlpha(frame); - } - } + frame_params = VideoRenderingParams(new_width, + new_height, + frame_params.format(), + frame_params.divider()); } - footage_tex_ref = texture_cache_.Get(ctx_, frame); + VideoRenderingParams dest_params(frame_params.width(), + frame_params.height(), + video_params_.format(), + frame_params.divider()); - if (ocio_method == ColorManager::kOCIOFast) { - if (!color_processor->IsEnabled()) { - color_processor->Enable(ctx_, video_stream->premultiplied_alpha()); - } + // Create destination texture + OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params); - VideoRenderingParams frame_params = frame->video_params(); + buffer_.Attach(associated_tex_ref->texture(), true); + buffer_.Bind(); + footage_tex_ref->texture()->Bind(); - // Check frame aspect ratio - if (frame->sample_aspect_ratio() != 1 && frame->sample_aspect_ratio() != 0) { - int new_width = frame_params.width(); - int new_height = frame_params.height(); + // Set viewport for texture size + functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height()); - // Scale the frame in a way that does not reduce the resolution - if (frame->sample_aspect_ratio() > 1) { - // Make wider - new_width = qRound(static_cast(new_width) * frame->sample_aspect_ratio().toDouble()); - } else { - // Make taller - new_height = qRound(static_cast(new_height) / frame->sample_aspect_ratio().toDouble()); - } + // Blit old texture to new texture through OCIO shader + color_processor->ProcessOpenGL(); - frame_params = VideoRenderingParams(new_width, - new_height, - frame_params.format(), - frame_params.divider()); - } + footage_tex_ref->texture()->Release(); + buffer_.Release(); + buffer_.Detach(); - VideoRenderingParams dest_params(frame_params.width(), - frame_params.height(), - video_params_.format(), - frame_params.divider()); - - // Create destination texture - OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params); - - buffer_.Attach(associated_tex_ref->texture(), true); - buffer_.Bind(); - footage_tex_ref->texture()->Bind(); - - // Set viewport for texture size - functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height()); - - // Blit old texture to new texture through OCIO shader - color_processor->ProcessOpenGL(); - - footage_tex_ref->texture()->Release(); - buffer_.Release(); - buffer_.Detach(); - - footage_tex_ref = associated_tex_ref; - } - - if (stream->type() == Stream::kImage) { - // Since this is a still image, we could likely optimize this - still_image_cache_.Add(stream.get(), {footage_tex_ref, colorspace_match, video_stream->premultiplied_alpha(), video_params_.divider()}); - } + footage_tex_ref = associated_tex_ref; } - table->Push(NodeParam::kTexture, QVariant::fromValue(footage_tex_ref)); + return NodeValue(NodeParam::kTexture, QVariant::fromValue(footage_tex_ref)); } void OpenGLProxy::Close() diff --git a/app/render/backend/opengl/openglproxy.h b/app/render/backend/opengl/openglproxy.h index d9ba4e887..23f1f0501 100644 --- a/app/render/backend/opengl/openglproxy.h +++ b/app/render/backend/opengl/openglproxy.h @@ -31,7 +31,8 @@ OLIVE_NAMESPACE_ENTER -class OpenGLProxy : public QObject { +class OpenGLProxy : public QObject +{ Q_OBJECT public: OpenGLProxy(QObject* parent = nullptr); @@ -63,13 +64,14 @@ public: void Close(); - void FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table); + void SetParameters(const VideoRenderingParams& params); - void RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params); +public slots: + void RunNodeAccelerated(const OLIVE_NAMESPACE::Node *node, const OLIVE_NAMESPACE::TimeRange &range, OLIVE_NAMESPACE::NodeValueDatabase &input_params, OLIVE_NAMESPACE::NodeValueTable& output_params); void TextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize); - void SetParameters(const VideoRenderingParams& params); + OLIVE_NAMESPACE::NodeValue FrameToValue(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::StreamPtr stream); private: QOpenGLContext* ctx_; @@ -89,15 +91,6 @@ private: OpenGLTextureCache texture_cache_; - struct CachedStill { - OpenGLTextureCache::ReferencePtr texture; - QString colorspace; - bool alpha_is_associated; - int divider; - }; - - RenderCache still_image_cache_; - private slots: void FinishInit(); diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index aa31b9e32..e0d65f242 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -31,30 +31,54 @@ OLIVE_NAMESPACE_ENTER -OpenGLWorker::OpenGLWorker(VideoRenderFrameCache *frame_cache, QObject *parent) : - VideoRenderWorker(frame_cache, parent) +OpenGLWorker::OpenGLWorker(VideoRenderFrameCache *frame_cache, OpenGLProxy *proxy, QObject *parent) : + VideoRenderWorker(frame_cache, parent), + proxy_(proxy) { } -void OpenGLWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable *table) +NodeValue OpenGLWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) { FramePtr frame = decoder->RetrieveVideo(range.in(), video_params().divider(), video_params().mode() == RenderMode::kOffline); + NodeValue value; + if (frame) { - emit RequestFrameToValue(frame, stream, table); + QMetaObject::invokeMethod(proxy_, + "FrameToValue", + Qt::BlockingQueuedConnection, + OLIVE_NS_RETURN_ARG(NodeValue, value), + OLIVE_NS_ARG(FramePtr, frame), + OLIVE_NS_ARG(StreamPtr, stream)); } + + return value; } void OpenGLWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params) { - emit RequestRunNodeAccelerated(node, range, input_params, output_params); + QMetaObject::invokeMethod(proxy_, + "RunNodeAccelerated", + Qt::BlockingQueuedConnection, + OLIVE_NS_CONST_ARG(Node*, node), + OLIVE_NS_CONST_ARG(TimeRange&, range), + OLIVE_NS_ARG(NodeValueDatabase&, input_params), + OLIVE_NS_ARG(NodeValueTable&, output_params)); } void OpenGLWorker::TextureToBuffer(const QVariant &tex_in, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize) { - emit RequestTextureToBuffer(tex_in, width, height, matrix, buffer, linesize); + QMetaObject::invokeMethod(proxy_, + "TextureToBuffer", + Qt::BlockingQueuedConnection, + Q_ARG(const QVariant&, tex_in), + Q_ARG(int, width), + Q_ARG(int, height), + Q_ARG(const QMatrix4x4&, matrix), + Q_ARG(void*, buffer), + Q_ARG(int, linesize)); } OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglworker.h b/app/render/backend/opengl/openglworker.h index 5b2215eb7..da1d469e2 100644 --- a/app/render/backend/opengl/openglworker.h +++ b/app/render/backend/opengl/openglworker.h @@ -26,6 +26,7 @@ #include "../videorenderworker.h" #include "openglframebuffer.h" +#include "openglproxy.h" #include "openglshadercache.h" #include "opengltexturecache.h" @@ -35,22 +36,19 @@ class OpenGLWorker : public VideoRenderWorker { Q_OBJECT public: OpenGLWorker(VideoRenderFrameCache* frame_cache, + OpenGLProxy* proxy, QObject* parent = nullptr); -signals: - void RequestFrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table); - - void RequestRunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params); - - void RequestTextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize); - protected: - virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) override; + virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) override; virtual void RunNodeAccelerated(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable& output_params) override; virtual void TextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize) override; +private: + OpenGLProxy* proxy_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 04ccb1659..af23a08c3 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -98,18 +98,20 @@ DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream) return decoder; } -bool RenderWorker::IsStarted() -{ - return started_; -} - -void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange& input_time, NodeValueTable *table) +NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &input_time) { DecoderPtr decoder = ResolveDecoderFromInput(stream); if (decoder) { - FrameToValue(decoder, stream, input_time, table); + return FrameToValue(decoder, stream, input_time); } + + return NodeValue(); +} + +bool RenderWorker::IsStarted() +{ + return started_; } void RenderWorker::ProcessNodeEvent(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params) diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index aa03e7af1..0a811912f 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -57,14 +57,14 @@ protected: virtual void RunNodeAccelerated(const Node *node, const TimeRange& range, NodeValueDatabase &input_params, NodeValueTable &output_params); - virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) = 0; - - virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override; + virtual NodeValue FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range) = 0; virtual void ProcessNodeEvent(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params) override; DecoderPtr ResolveDecoderFromInput(StreamPtr stream); + NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time); + const NodeDependency& CurrentPath() const; private: diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp index 74c23ecd1..f1e3c508b 100644 --- a/app/render/backend/videorenderworker.cpp +++ b/app/render/backend/videorenderworker.cpp @@ -116,6 +116,48 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con return value; } +void VideoRenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable *table) +{ + if (stream->type() != Stream::kVideo && stream->type() != Stream::kImage) { + return; + } + + ImageStreamPtr video_stream = std::static_pointer_cast(stream); + rational time_match = (stream->type() == Stream::kImage) ? rational() : input_time.in(); + QString colorspace_match = video_stream->get_colorspace_match_string(); + + NodeValue value; + bool found_cache = false; + + if (still_image_cache_.Has(stream.get())) { + CachedStill cs = still_image_cache_.Get(stream.get()); + + if (cs.colorspace == colorspace_match + && cs.alpha_is_associated == video_stream->premultiplied_alpha() + && cs.divider == video_params_.divider() + && cs.time == time_match) { + value = cs.texture; + found_cache = true; + } else { + still_image_cache_.Remove(stream.get()); + } + } + + if (!found_cache) { + + value = GetDataFromStream(stream, input_time); + + still_image_cache_.Add(stream.get(), {value, + colorspace_match, + video_stream->premultiplied_alpha(), + video_params_.divider(), + time_match}); + + } + + table->Push(value); +} + void VideoRenderWorker::SetParameters(const VideoRenderingParams &video_params) { video_params_ = video_params; diff --git a/app/render/backend/videorenderworker.h b/app/render/backend/videorenderworker.h index 77ba6f2bb..e94c1a4c9 100644 --- a/app/render/backend/videorenderworker.h +++ b/app/render/backend/videorenderworker.h @@ -98,6 +98,8 @@ protected: virtual NodeValueTable RenderInternal(const NodeDependency& CurrentPath, const qint64& job_time) override; + virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override; + ColorProcessorCache* color_cache(); private: @@ -119,6 +121,16 @@ private: OperatingMode operating_mode_; + struct CachedStill { + NodeValue texture; + QString colorspace; + bool alpha_is_associated; + int divider; + rational time; + }; + + RenderCache still_image_cache_; + private slots: }; diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 62a551b1b..3d86eb5d6 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -328,7 +328,7 @@ void ViewerDisplayWidget::paintGL() int cross = qMin(w, h) / 32; - QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(), rect().center().x() + cross, rect().center().y()), + QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(),rect().center().x() + cross, rect().center().y()), QLine(rect().center().x(), rect().center().y() - cross, rect().center().x(), rect().center().y() + cross)}; p.drawLines(lines, 2); From 69941dc2dabd0f3b73395f01bedb9b0e09149c4c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 8 May 2020 00:37:43 +1000 Subject: [PATCH 09/11] nodes: added access to default value --- app/node/input.cpp | 7 +++++++ app/node/input.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/app/node/input.cpp b/app/node/input.cpp index 33ab85da4..17c41c02b 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -316,6 +316,8 @@ void NodeInput::Init(DataType type) void NodeInput::SetDefaultValue(const QVector &default_value) { + default_value_ = default_value; + for (int i=0;i &list, bool traverse, bool exclusi } } +QVariant NodeInput::GetDefaultValue() const +{ + return combine_track_values_into_normal_value(default_value_); +} + QList NodeInput::GetDependencies(bool traverse, bool exclusive_only) const { QList list; diff --git a/app/node/input.h b/app/node/input.h index 2f271a4a1..a8b776261 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -277,6 +277,8 @@ public: void GetDependencies(QList& list, bool traverse, bool exclusive_only) const; + QVariant GetDefaultValue() const; + QList GetDependencies(bool traverse = true, bool exclusive_only = false) const; QList GetExclusiveDependencies() const; @@ -368,6 +370,11 @@ private: */ QVector standard_value_; + /** + * @brief Default value that can be reset if the user requests + */ + QVector default_value_; + /** * @brief Internal keyframe array * From 8362a68aa96e0b570f8bc69357501a0aa7a4d03c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 8 May 2020 02:57:59 +1000 Subject: [PATCH 10/11] viewer: factor visibility into audio playback --- app/widget/viewer/viewer.cpp | 17 ++++++++++------- app/widget/viewer/viewer.h | 2 ++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 292d07cc0..5d8cf5e62 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -48,7 +48,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) : color_menu_enabled_(true), divider_(Config::Current()["DefaultViewerDivider"].toInt()), override_color_manager_(nullptr), - time_changed_from_timer_(false) + time_changed_from_timer_(false), + playback_is_audio_only_(false) { // Set up main layout QVBoxLayout* layout = new QVBoxLayout(this); @@ -379,10 +380,12 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) controls_->ShowPauseButton(); - if (stack_->currentWidget() == sizer_) { - connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); - } else { + playback_is_audio_only_ = (stack_->currentWidget() != sizer_ || !isVisible()); + + if (playback_is_audio_only_) { connect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate); + } else { + connect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); } } @@ -702,10 +705,10 @@ void ViewerWidget::Pause() playback_speed_ = 0; controls_->ShowPlayButton(); - if (stack_->currentWidget() == sizer_) { - disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); - } else { + if (playback_is_audio_only_) { disconnect(AudioManager::instance(), &AudioManager::OutputNotified, this, &ViewerWidget::PlaybackTimerUpdate); + } else { + disconnect(main_gl_widget(), &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::PlaybackTimerUpdate); } } } diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index afeeaadd0..164f77122 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -195,6 +195,8 @@ private: bool play_in_to_out_only_; + bool playback_is_audio_only_; + AudioWaveformView* waveform_view_; QList windows_; From 69884367537584302e56b2df3cc7c0386f4cf8af Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 8 May 2020 12:53:05 +1000 Subject: [PATCH 11/11] preferences: added minimums to cache ahead/behind Fixes sobotka/Olive#114 --- app/dialog/preferences/tabs/preferencesdisktab.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index ea93e102d..a961c5adf 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -85,12 +85,14 @@ PreferencesDiskTab::PreferencesDiskTab() cache_ahead_slider_ = new FloatSlider(); cache_ahead_slider_->SetFormat(tr("%1 seconds")); + cache_ahead_slider_->SetMinimum(0); cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value().toDouble()); cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1); cache_behavior_layout->addWidget(new QLabel(tr("Cache Behind:")), row, 2); cache_behind_slider_ = new FloatSlider(); + cache_behind_slider_->SetMinimum(0); cache_behind_slider_->SetFormat(tr("%1 seconds")); cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value().toDouble()); cache_behavior_layout->addWidget(cache_behind_slider_, row, 3);