From c387ce1cd7faac8e696bfcaab67701146eb72151 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 00:22:49 +1000 Subject: [PATCH] polygon node: early crude implementation --- app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/node/generator/CMakeLists.txt | 1 + app/node/generator/matrix/matrix.cpp | 58 +++++---- app/node/generator/matrix/matrix.h | 4 +- app/node/generator/polygon/CMakeLists.txt | 22 ++++ app/node/generator/polygon/polygon.cpp | 120 ++++++++++++++++++ app/node/generator/polygon/polygon.h | 63 +++++++++ app/node/node.cpp | 15 ++- app/node/node.h | 6 +- app/node/traverser.cpp | 39 ++++-- app/node/traverser.h | 7 +- app/panel/pixelsampler/pixelsamplerpanel.h | 2 +- app/render/backend/opengl/openglproxy.cpp | 25 +++- app/render/backend/renderworker.cpp | 22 +--- app/render/backend/renderworker.h | 4 +- app/render/backend/videorenderworker.cpp | 14 -- app/render/backend/videorenderworker.h | 4 +- app/shaders/polygon.frag | 44 +++++++ app/shaders/shaders.qrc | 1 + app/widget/CMakeLists.txt | 2 + app/widget/keyframeview/CMakeLists.txt | 2 - app/widget/keyframeview/keyframeviewbase.h | 2 +- app/widget/keyframeview/keyframeviewitem.h | 2 +- .../nodeparamviewkeyframecontrol.h | 2 +- .../nodeparamview/nodeparamviewwidgetbridge.h | 2 +- app/widget/pixelsampler/CMakeLists.txt | 22 ++++ .../pixelsampler.cpp} | 2 +- .../pixelsampler.h} | 0 app/widget/timetarget/CMakeLists.txt | 22 ++++ .../timetarget.cpp} | 2 +- .../timetarget.h} | 0 app/widget/viewer/CMakeLists.txt | 4 +- app/widget/viewer/gizmotraverser.cpp | 39 ++++++ app/widget/viewer/gizmotraverser.h | 40 ++++++ app/widget/viewer/viewer.cpp | 5 + app/widget/viewer/viewerdisplay.cpp | 77 ++++++++++- app/widget/viewer/viewerdisplay.h | 24 +++- 38 files changed, 611 insertions(+), 93 deletions(-) create mode 100644 app/node/generator/polygon/CMakeLists.txt create mode 100644 app/node/generator/polygon/polygon.cpp create mode 100644 app/node/generator/polygon/polygon.h create mode 100644 app/shaders/polygon.frag create mode 100644 app/widget/pixelsampler/CMakeLists.txt rename app/widget/{viewer/pixelsamplerwidget.cpp => pixelsampler/pixelsampler.cpp} (98%) rename app/widget/{viewer/pixelsamplerwidget.h => pixelsampler/pixelsampler.h} (100%) create mode 100644 app/widget/timetarget/CMakeLists.txt rename app/widget/{keyframeview/timetargetobject.cpp => timetarget/timetarget.cpp} (98%) rename app/widget/{keyframeview/timetargetobject.h => timetarget/timetarget.h} (100%) create mode 100644 app/widget/viewer/gizmotraverser.cpp create mode 100644 app/widget/viewer/gizmotraverser.h diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 09791c6a5..d276b94da 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -26,6 +26,7 @@ #include "block/gap/gap.h" #include "block/transition/externaltransition.h" #include "generator/matrix/matrix.h" +#include "generator/polygon/polygon.h" #include "input/media/video/video.h" #include "input/media/audio/audio.h" #include "input/time/timeinput.h" @@ -141,6 +142,8 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id) return new ClipBlock(); case kGapBlock: return new GapBlock(); + case kPolygonGenerator: + return new PolygonGenerator(); case kMatrixGenerator: return new MatrixGenerator(); case kVideoInput: diff --git a/app/node/factory.h b/app/node/factory.h index c6329de7e..f17a476dd 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -36,6 +36,7 @@ public: kClipBlock, kGapBlock, kAudioInput, + kPolygonGenerator, kMatrixGenerator, kVideoInput, kTrackOutput, diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt index 9e8d25261..88c7de6d8 100644 --- a/app/node/generator/CMakeLists.txt +++ b/app/node/generator/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(matrix) +add_subdirectory(polygon) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 604e36415..c1b7452ca 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -90,27 +90,9 @@ void MatrixGenerator::Retranslate() NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const { - QMatrix4x4 mat; - - // Position translate - QVector2D pos = value[position_input_].Get(NodeParam::kVec2).value(); - mat.translate(pos); - - // Rotation - mat.rotate(value[rotation_input_].Get(NodeParam::kFloat).toFloat(), 0, 0, 1); - - // Scale and Uniform Scale - QVector2D scale = value[scale_input_].Get(NodeParam::kVec2).value(); - if (value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool()) { - scale.setY(scale.x()); - } - mat.scale(scale); - - // Anchor Point - mat.translate(-value[anchor_input_].Get(NodeParam::kVec2).value()); - // Push matrix output - NodeValueTable output; + QMatrix4x4 mat = GenerateMatrix(value); + NodeValueTable output = value.Merge(); output.Push(NodeParam::kMatrix, mat); return output; } @@ -120,10 +102,42 @@ bool MatrixGenerator::HasGizmos() const return true; } -void MatrixGenerator::DrawGizmos(QPainter *p, const QRect& viewport) const +void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p) const { p->setPen(Qt::white); - p->drawEllipse(viewport); + + // Fold values into a matrix + QMatrix4x4 matrix = GenerateMatrix(db); + + // Set QPainter transform to our matrix + p->setTransform(matrix.toTransform()); + + // Draw ellipse + p->drawEllipse(QRect(0, 0, 100, 100)); +} + +QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const +{ + QMatrix4x4 mat; + + // Position translate + QVector2D pos = value[position_input_].Take(NodeParam::kVec2).value(); + mat.translate(pos); + + // Rotation + mat.rotate(value[rotation_input_].Take(NodeParam::kFloat).toFloat(), 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()); + } + mat.scale(scale); + + // Anchor Point + mat.translate(-value[anchor_input_].Take(NodeParam::kVec2).value()); + + return mat; } void MatrixGenerator::UniformScaleChanged() diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 116ef1602..2181e5791 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -44,9 +44,11 @@ public: virtual NodeValueTable Value(NodeValueDatabase& value) const override; virtual bool HasGizmos() const override; - virtual void DrawGizmos(QPainter *p, const QRect &viewport) const override; + virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) const override; private: + QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const; + NodeInput* position_input_; NodeInput* rotation_input_; diff --git a/app/node/generator/polygon/CMakeLists.txt b/app/node/generator/polygon/CMakeLists.txt new file mode 100644 index 000000000..a1a4b2cc5 --- /dev/null +++ b/app/node/generator/polygon/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/generator/polygon/polygon.h + node/generator/polygon/polygon.cpp + PARENT_SCOPE +) diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp new file mode 100644 index 000000000..5b4718c9e --- /dev/null +++ b/app/node/generator/polygon/polygon.cpp @@ -0,0 +1,120 @@ +/*** + + 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 "polygon.h" + +#include + +OLIVE_NAMESPACE_ENTER + +PolygonGenerator::PolygonGenerator() +{ + points_input_ = new NodeInputArray("points_in", NodeParam::kVec2); + AddInput(points_input_); + + color_input_ = new NodeInput("color_in", NodeParam::kColor); + AddInput(color_input_); + + // Default to "a color" that isn't + color_input_->set_standard_value(1.0, 0); + color_input_->set_standard_value(1.0, 1); + color_input_->set_standard_value(1.0, 2); + color_input_->set_standard_value(1.0, 3); + + // FIXME: Test code + points_input_->SetSize(5); + points_input_->At(0)->set_standard_value(960, 0); + points_input_->At(0)->set_standard_value(240, 1); + points_input_->At(1)->set_standard_value(640, 0); + points_input_->At(1)->set_standard_value(480, 1); + points_input_->At(2)->set_standard_value(760, 0); + points_input_->At(2)->set_standard_value(800, 1); + points_input_->At(3)->set_standard_value(1100, 0); + points_input_->At(3)->set_standard_value(800, 1); + points_input_->At(4)->set_standard_value(1280, 0); + points_input_->At(4)->set_standard_value(480, 1); + // End test +} + +Node *PolygonGenerator::copy() const +{ + return new PolygonGenerator(); +} + +QString PolygonGenerator::Name() const +{ + return tr("Polygon"); +} + +QString PolygonGenerator::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.polygon"); +} + +QString PolygonGenerator::Category() const +{ + return tr("Generator"); +} + +QString PolygonGenerator::Description() const +{ + return tr("Generate a 2D polygon of any amount of points."); +} + +void PolygonGenerator::Retranslate() +{ + points_input_->set_name(tr("Points")); + color_input_->set_name(tr("Color")); +} + +Node::Capabilities PolygonGenerator::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString PolygonGenerator::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return Node::ReadFileAsString(":/shaders/polygon.frag"); +} + +bool PolygonGenerator::HasGizmos() const +{ + return true; +} + +void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p) const +{ + QVector points(points_input_->GetSize()); + + p->setPen(Qt::white); + p->setBrush(Qt::white); + + for (int i=0;iGetSize();i++) { + points[i] = db[points_input_->At(i)].Take(NodeParam::kVec2).value().toPointF(); + + QRectF rect(points[i] - QPointF(10, 10), + points[i] + QPointF(10, 10)); + p->drawRect(rect); + } + + p->drawPolyline(points.constData(), points_input_->GetSize()); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h new file mode 100644 index 000000000..9c4e4d31b --- /dev/null +++ b/app/node/generator/polygon/polygon.h @@ -0,0 +1,63 @@ +/*** + + 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 POLYGONGENERATOR_H +#define POLYGONGENERATOR_H + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class PolygonGenerator : public Node +{ +public: + PolygonGenerator(); + + virtual Node* copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QString Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + + virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; + virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; + + virtual bool HasGizmos() const override; + virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) const override; + + /* + virtual bool GizmoPress(const QPointF &p) override; + virtual void GizmoMove(const QPointF &p) override; + virtual void GizmoRelease(const QPointF &p) override; + */ + +private: + NodeInputArray* points_input_; + + NodeInput* color_input_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // POLYGONGENERATOR_H diff --git a/app/node/node.cpp b/app/node/node.cpp index 76f82484c..f370e0fec 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -293,7 +293,20 @@ bool Node::HasGizmos() const return false; } -void Node::DrawGizmos(QPainter *, const QRect &) const +void Node::DrawGizmos(NodeValueDatabase &, QPainter *) const +{ +} + +bool Node::GizmoPress(const QPointF &) +{ + return false; +} + +void Node::GizmoMove(const QPointF &) +{ +} + +void Node::GizmoRelease(const QPointF &) { } diff --git a/app/node/node.h b/app/node/node.h index b623ca1d5..317bebcb4 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -362,7 +362,11 @@ public: virtual bool HasGizmos() const; - virtual void DrawGizmos(QPainter* p, const QRect &viewport) const; + virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p) const; + + virtual bool GizmoPress(const QPointF& p); + virtual void GizmoMove(const QPointF& p); + virtual void GizmoRelease(const QPointF& p); const QString& GetLabel() const; void SetLabel(const QString& s); diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index c4737cfd1..9f5a1f8f5 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -29,21 +29,29 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa NodeValueDatabase database; // We need to insert tables into the database for each input - foreach (NodeParam* param, node->parameters()) { + QList inputs = node->GetInputsIncludingArrays(); + + foreach (NodeInput* input, inputs) { if (IsCancelled()) { return NodeValueDatabase(); } - if (param->type() == NodeParam::kInput) { - NodeInput* input = static_cast(param); - TimeRange input_time = node->InputTimeAdjustment(input, range); + TimeRange input_time = node->InputTimeAdjustment(input, range); - NodeValueTable table = ProcessInput(input, input_time); + NodeValueTable table = ProcessInput(input, input_time); - InputProcessingEvent(input, input_time, &table); + // Exception for Footage types where we actually retrieve some Footage data from a decoder + if (input->data_type() == NodeParam::kFootage) { + StreamPtr stream = ResolveStreamFromInput(input); - database.Insert(input, table); + if (stream) { + + FootageProcessingEvent(stream, input_time, &table); + + } } + + database.Insert(input, table); } // Insert global variables @@ -79,8 +87,21 @@ NodeValueTable NodeTraverser::ProcessNode(const NodeDependency& dep) NodeValueTable NodeTraverser::RenderBlock(const TrackOutput *track, const TimeRange &range) { - // By default, don't bother traversing blocks - return NodeValueTable(); + // By default, just follow the in point + Block* active_block = track->BlockAtTime(range.in()); + + NodeValueTable table; + + if (active_block) { + table = ProcessNode(NodeDependency(active_block, range)); + } + + return table; +} + +StreamPtr NodeTraverser::ResolveStreamFromInput(NodeInput *input) +{ + return input->get_standard_value().value(); } NodeValueTable NodeTraverser::ProcessInput(const NodeInput *input, const TimeRange& range) diff --git a/app/node/traverser.h b/app/node/traverser.h index 7897cd7a1..4e80a2a68 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -37,17 +37,20 @@ public: NodeValueTable ProcessNode(const NodeDependency &dep); -protected: NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range); +protected: virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range); NodeValueTable ProcessInput(const NodeInput* input, const TimeRange &range); - virtual void InputProcessingEvent(NodeInput*, const TimeRange&, NodeValueTable*){} + virtual void FootageProcessingEvent(StreamPtr, const TimeRange&, NodeValueTable*){} virtual void ProcessNodeEvent(const Node*, const TimeRange&, NodeValueDatabase&, NodeValueTable&){} +private: + StreamPtr ResolveStreamFromInput(NodeInput* input); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/panel/pixelsampler/pixelsamplerpanel.h b/app/panel/pixelsampler/pixelsamplerpanel.h index 089de194c..6e91cce2f 100644 --- a/app/panel/pixelsampler/pixelsamplerpanel.h +++ b/app/panel/pixelsampler/pixelsamplerpanel.h @@ -22,7 +22,7 @@ #define PIXELSAMPLERPANEL_H #include "widget/panel/panel.h" -#include "widget/viewer/pixelsamplerwidget.h" +#include "widget/pixelsampler/pixelsampler.h" OLIVE_NAMESPACE_ENTER diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index 05b4e5609..649b2ba15 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -110,7 +110,10 @@ void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* 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); + 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()) { @@ -281,7 +284,25 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, N shader->setUniformValue(variable_location, value.toFloat()); break; case NodeInput::kVec2: - shader->setUniformValue(variable_location, value.value()); + if (input->IsArray()) { + NodeInputArray* array = static_cast(input); + QVector a(array->GetSize()); + + for (int i=0;iAt(i)].Get(NodeParam::kVec2).value(); + } + + shader->setUniformValueArray(variable_location, a.constData(), a.size()); + + int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(input->id())); + if (count_location > -1) { + shader->setUniformValue(count_location, + array->GetSize()); + } + + } else { + shader->setUniformValue(variable_location, value.value()); + } break; case NodeInput::kVec3: shader->setUniformValue(variable_location, value.value()); diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index c2b1b2311..04ccb1659 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -76,11 +76,6 @@ void RenderWorker::RunNodeAccelerated(const Node *node, const TimeRange &range, Q_UNUSED(output_params) } -StreamPtr RenderWorker::ResolveStreamFromInput(NodeInput *input) -{ - return input->get_standard_value().value(); -} - DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream) { // Access a map of Node inputs and decoder instances and retrieve a frame! @@ -108,21 +103,12 @@ bool RenderWorker::IsStarted() return started_; } -void RenderWorker::InputProcessingEvent(NodeInput* input, const TimeRange& input_time, NodeValueTable *table) +void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange& input_time, NodeValueTable *table) { - // Exception for Footage types where we actually retrieve some Footage data from a decoder - if (input->data_type() == NodeParam::kFootage) { - StreamPtr stream = ResolveStreamFromInput(input); + DecoderPtr decoder = ResolveDecoderFromInput(stream); - if (stream) { - DecoderPtr decoder = ResolveDecoderFromInput(stream); - - if (decoder) { - - FrameToValue(decoder, stream, input_time, table); - - } - } + if (decoder) { + FrameToValue(decoder, stream, input_time, table); } } diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index 17d8e600f..aa03e7af1 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -59,12 +59,10 @@ protected: virtual void FrameToValue(DecoderPtr decoder, StreamPtr stream, const TimeRange &range, NodeValueTable* table) = 0; - virtual void InputProcessingEvent(NodeInput *input, const TimeRange &input_time, NodeValueTable* table) override; + virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override; virtual void ProcessNodeEvent(const Node *node, const TimeRange &range, NodeValueDatabase &input_params, NodeValueTable &output_params) override; - StreamPtr ResolveStreamFromInput(NodeInput* input); - DecoderPtr ResolveDecoderFromInput(StreamPtr stream); const NodeDependency& CurrentPath() const; diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp index ffc568811..74c23ecd1 100644 --- a/app/render/backend/videorenderworker.cpp +++ b/app/render/backend/videorenderworker.cpp @@ -201,20 +201,6 @@ void VideoRenderWorker::ResizeDownloadBuffer() download_buffer_.resize(PixelFormat::GetBufferSize(video_params_.format(), video_params_.effective_width(), video_params_.effective_height())); } -NodeValueTable VideoRenderWorker::RenderBlock(const TrackOutput *track, const TimeRange &range) -{ - // A frame can only have one active block so we just validate the in point of the range - Block* active_block = track->BlockAtTime(range.in()); - - NodeValueTable table; - - if (active_block) { - table = ProcessNode(NodeDependency(active_block, range)); - } - - return table; -} - ColorProcessorCache *VideoRenderWorker::color_cache() { return &color_cache_; diff --git a/app/render/backend/videorenderworker.h b/app/render/backend/videorenderworker.h index a4737fcde..77ba6f2bb 100644 --- a/app/render/backend/videorenderworker.h +++ b/app/render/backend/videorenderworker.h @@ -92,14 +92,12 @@ protected: virtual void ParametersChangedEvent(){} - virtual void TextureToBuffer(const QVariant& texture, void *buffer, int linesize); + void TextureToBuffer(const QVariant& texture, void *buffer, int linesize); virtual void TextureToBuffer(const QVariant& texture, int width, int height, const QMatrix4x4& matrix, void *buffer, int linesize) = 0; virtual NodeValueTable RenderInternal(const NodeDependency& CurrentPath, const qint64& job_time) override; - virtual NodeValueTable RenderBlock(const TrackOutput *track, const TimeRange& range) override; - ColorProcessorCache* color_cache(); private: diff --git a/app/shaders/polygon.frag b/app/shaders/polygon.frag new file mode 100644 index 000000000..ae45ddf73 --- /dev/null +++ b/app/shaders/polygon.frag @@ -0,0 +1,44 @@ +#version 150 + +uniform vec2[256] points_in; +uniform int points_in_count; +uniform vec4 color_in; + +uniform vec2 ove_resolution; + +in vec2 ove_texcoord; + +out vec4 fragColor; + +/* +int pnpoly(int npol, float *xp, float *yp, float x, float y) { + int i, j, c = 0; + for (i = 0, j = npol-1; i < npol; j = i++) { + if ((((yp[i] <= y) && (y < yp[j])) || + ((yp[j] <= y) && (y < yp[i]))) && + (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])) + c = !c; + } + return c; +} +*/ + +bool pnpoly(vec2 p) { + bool c = false; + int i, j; + for (i = 0, j = points_in_count-1; i < points_in_count; j = i++) { + if ((((points_in[i].y <= p.y) && (p.y < points_in[j].y)) || + ((points_in[j].y <= p.y) && (p.y < points_in[i].y))) && + (p.x < (points_in[j].x - points_in[i].x) * (p.y - points_in[i].y) / (points_in[j].y - points_in[i].y) + points_in[i].x)) + c = !c; + } + return c; +} + +void main(void) { + if (points_in_count > 0 && pnpoly(ove_texcoord * ove_resolution)) { + fragColor = color_in; + } else { + fragColor = vec4(0.0, 0.0, 0.0, 0.0); + } +} diff --git a/app/shaders/shaders.qrc b/app/shaders/shaders.qrc index 7e6f4876c..1c7d8d061 100644 --- a/app/shaders/shaders.qrc +++ b/app/shaders/shaders.qrc @@ -12,6 +12,7 @@ dropshadow.xml diptoblack.frag diptoblack.xml + polygon.frag rgbwaveform.frag solid.frag solid.xml diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index f33f5d064..ddc6dfb72 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(nodecopypaste) add_subdirectory(nodeview) add_subdirectory(nodeparamview) add_subdirectory(panel) +add_subdirectory(pixelsampler) add_subdirectory(playbackcontrols) add_subdirectory(projectexplorer) add_subdirectory(projecttoolbar) @@ -41,6 +42,7 @@ add_subdirectory(taskview) add_subdirectory(timebased) add_subdirectory(timelinewidget) add_subdirectory(timeruler) +add_subdirectory(timetarget) add_subdirectory(toolbar) add_subdirectory(viewer) diff --git a/app/widget/keyframeview/CMakeLists.txt b/app/widget/keyframeview/CMakeLists.txt index 17f7bce21..713f9bb20 100644 --- a/app/widget/keyframeview/CMakeLists.txt +++ b/app/widget/keyframeview/CMakeLists.txt @@ -24,7 +24,5 @@ set(OLIVE_SOURCES widget/keyframeview/keyframeviewitem.cpp widget/keyframeview/keyframeviewundo.h widget/keyframeview/keyframeviewundo.cpp - widget/keyframeview/timetargetobject.h - widget/keyframeview/timetargetobject.cpp PARENT_SCOPE ) diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h index 000394641..04e7d6096 100644 --- a/app/widget/keyframeview/keyframeviewbase.h +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -23,7 +23,7 @@ #include "keyframeviewitem.h" #include "node/keyframe.h" -#include "timetargetobject.h" +#include "widget/timetarget/timetarget.h" #include "widget/curvewidget/beziercontrolpointitem.h" #include "widget/timelinewidget/view/timelineviewbase.h" diff --git a/app/widget/keyframeview/keyframeviewitem.h b/app/widget/keyframeview/keyframeviewitem.h index ca5a6d660..ee5c06031 100644 --- a/app/widget/keyframeview/keyframeviewitem.h +++ b/app/widget/keyframeview/keyframeviewitem.h @@ -24,7 +24,7 @@ #include #include "node/keyframe.h" -#include "timetargetobject.h" +#include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h index 395251099..002b00fc5 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h @@ -25,7 +25,7 @@ #include #include "node/input.h" -#include "widget/keyframeview/timetargetobject.h" +#include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index d1543c73e..3d385a7bc 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -24,8 +24,8 @@ #include #include "node/input.h" -#include "widget/keyframeview/timetargetobject.h" #include "widget/slider/sliderbase.h" +#include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER diff --git a/app/widget/pixelsampler/CMakeLists.txt b/app/widget/pixelsampler/CMakeLists.txt new file mode 100644 index 000000000..ecf7831f7 --- /dev/null +++ b/app/widget/pixelsampler/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/pixelsampler/pixelsampler.h + widget/pixelsampler/pixelsampler.cpp + PARENT_SCOPE +) diff --git a/app/widget/viewer/pixelsamplerwidget.cpp b/app/widget/pixelsampler/pixelsampler.cpp similarity index 98% rename from app/widget/viewer/pixelsamplerwidget.cpp rename to app/widget/pixelsampler/pixelsampler.cpp index c955d21ed..22cde93f5 100644 --- a/app/widget/viewer/pixelsamplerwidget.cpp +++ b/app/widget/pixelsampler/pixelsampler.cpp @@ -18,7 +18,7 @@ ***/ -#include "pixelsamplerwidget.h" +#include "pixelsampler.h" #include diff --git a/app/widget/viewer/pixelsamplerwidget.h b/app/widget/pixelsampler/pixelsampler.h similarity index 100% rename from app/widget/viewer/pixelsamplerwidget.h rename to app/widget/pixelsampler/pixelsampler.h diff --git a/app/widget/timetarget/CMakeLists.txt b/app/widget/timetarget/CMakeLists.txt new file mode 100644 index 000000000..98f834bd1 --- /dev/null +++ b/app/widget/timetarget/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/timetarget/timetarget.h + widget/timetarget/timetarget.cpp + PARENT_SCOPE +) diff --git a/app/widget/keyframeview/timetargetobject.cpp b/app/widget/timetarget/timetarget.cpp similarity index 98% rename from app/widget/keyframeview/timetargetobject.cpp rename to app/widget/timetarget/timetarget.cpp index 0ea00d0d9..51ec506d3 100644 --- a/app/widget/keyframeview/timetargetobject.cpp +++ b/app/widget/timetarget/timetarget.cpp @@ -18,7 +18,7 @@ ***/ -#include "timetargetobject.h" +#include "timetarget.h" OLIVE_NAMESPACE_ENTER diff --git a/app/widget/keyframeview/timetargetobject.h b/app/widget/timetarget/timetarget.h similarity index 100% rename from app/widget/keyframeview/timetargetobject.h rename to app/widget/timetarget/timetarget.h diff --git a/app/widget/viewer/CMakeLists.txt b/app/widget/viewer/CMakeLists.txt index e96b9e639..70df051ae 100644 --- a/app/widget/viewer/CMakeLists.txt +++ b/app/widget/viewer/CMakeLists.txt @@ -20,8 +20,8 @@ set(OLIVE_SOURCES widget/viewer/audiowaveformview.cpp widget/viewer/footageviewer.h widget/viewer/footageviewer.cpp - widget/viewer/pixelsamplerwidget.h - widget/viewer/pixelsamplerwidget.cpp + widget/viewer/gizmotraverser.h + widget/viewer/gizmotraverser.cpp widget/viewer/viewer.h widget/viewer/viewer.cpp widget/viewer/viewerdisplay.h diff --git a/app/widget/viewer/gizmotraverser.cpp b/app/widget/viewer/gizmotraverser.cpp new file mode 100644 index 000000000..1e77fd925 --- /dev/null +++ b/app/widget/viewer/gizmotraverser.cpp @@ -0,0 +1,39 @@ +/*** + + 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 "gizmotraverser.h" + +OLIVE_NAMESPACE_ENTER + +void GizmoTraverser::FootageProcessingEvent(StreamPtr stream, const TimeRange &/*input_time*/, NodeValueTable *table) +{ + if (stream->type() == Stream::kVideo || stream->type() == Stream::kAudio) { + + ImageStreamPtr image_stream = std::static_pointer_cast(stream); + + table->Push(NodeParam::kTexture, QSize(image_stream->width(), + image_stream->height())); + + } else if (stream->type() == Stream::kAudio) { + // FIXME: Get samples + } +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/widget/viewer/gizmotraverser.h b/app/widget/viewer/gizmotraverser.h new file mode 100644 index 000000000..97b2cfc43 --- /dev/null +++ b/app/widget/viewer/gizmotraverser.h @@ -0,0 +1,40 @@ +/*** + + 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 GIZMOTRAVERSER_H +#define GIZMOTRAVERSER_H + +#include "node/traverser.h" + +OLIVE_NAMESPACE_ENTER + +class GizmoTraverser : public NodeTraverser +{ +public: + GizmoTraverser() = default; + +protected: + virtual void FootageProcessingEvent(StreamPtr stream, const TimeRange &input_time, NodeValueTable* table) override; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // GIZMOTRAVERSER_H diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 6d5ae3976..8fd2bab3a 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -130,6 +130,8 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i) UpdateTextureFromNode(time_set); PushScrubbedAudio(); + + main_gl_widget()->SetTime(time_set); } last_time_ = i; @@ -335,6 +337,7 @@ ColorManager *ViewerWidget::color_manager() const void ViewerWidget::SetGizmos(Node *node) { + main_gl_widget()->SetTimeTarget(GetConnectedNode()); main_gl_widget()->SetGizmos(node); } @@ -537,6 +540,8 @@ void ViewerWidget::UpdateRendererParameters() video_renderer_->InvalidateCache(TimeRange(0, GetConnectedNode()->Length()), nullptr); } + main_gl_widget()->SetVideoParams(vparam); + AudioRenderingParams aparam(GetConnectedNode()->audio_params(), SampleFormat::kInternalFormat); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 99a0c7d03..ced00dd6b 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -30,6 +30,7 @@ #include #include "common/define.h" +#include "gizmotraverser.h" #include "render/backend/opengl/openglrenderfunctions.h" #include "render/backend/opengl/openglshader.h" #include "render/pixelformat.h" @@ -44,7 +45,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : ManagedDisplayWidget(parent), has_image_(false), signal_cursor_color_(false), - gizmos_(nullptr) + gizmos_(nullptr), + gizmo_click_(false) { } @@ -169,8 +171,33 @@ void ViewerDisplayWidget::SetGizmos(Node *node) update(); } +void ViewerDisplayWidget::SetVideoParams(const VideoRenderingParams ¶ms) +{ + gizmo_params_ = params; + + if (gizmos_) { + update(); + } +} + +void ViewerDisplayWidget::SetTime(const rational &time) +{ + time_ = time; + + if (gizmos_) { + update(); + } +} + void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { + if (gizmos_) { + if (gizmos_->GizmoPress(GetTexturePosition(event->pos()))) { + gizmo_click_ = true; + return; + } + } + QOpenGLWidget::mousePressEvent(event); emit DragStarted(); @@ -178,6 +205,11 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { + if (gizmo_click_) { + gizmos_->GizmoMove(GetTexturePosition(event->pos())); + return; + } + QOpenGLWidget::mouseMoveEvent(event); if (signal_cursor_color_) { @@ -201,6 +233,18 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) } } +void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (gizmo_click_) { + gizmos_->GizmoRelease(GetTexturePosition(event->pos())); + gizmo_click_ = false; + + return; + } + + QOpenGLWidget::mouseReleaseEvent(event); +} + void ViewerDisplayWidget::initializeGL() { ManagedDisplayWidget::initializeGL(); @@ -233,7 +277,7 @@ void ViewerDisplayWidget::paintGL() f->glClear(GL_COLOR_BUFFER_BIT); // We only draw if we have a pipeline - if (has_image_ && color_service() && texture_.IsCreated()) { + if (has_image_ && color_service()) { // Bind retrieved texture f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); @@ -248,8 +292,19 @@ void ViewerDisplayWidget::paintGL() // Draw gizmos if we have any if (gizmos_) { + GizmoTraverser gt; + + rational node_time = GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput); + + NodeValueDatabase db = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); + QPainter p(this); - gizmos_->DrawGizmos(&p, rect()); + + // Scale so that gizmos can just draw on the buffer + QPointF tex_point = GetTexturePosition(size()); + p.scale(tex_point.x(), tex_point.y()); + + gizmos_->DrawGizmos(db, &p); } // Draw action/title safe areas @@ -285,6 +340,22 @@ void ViewerDisplayWidget::paintGL() } } +QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos) +{ + return GetTexturePosition(screen_pos.x(), screen_pos.y()); +} + +QPointF ViewerDisplayWidget::GetTexturePosition(const QSize &size) +{ + return GetTexturePosition(size.width(), size.height()); +} + +QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y) +{ + return QPointF(x / gizmo_params_.width(), + y / gizmo_params_.height()); +} + #ifdef Q_OS_LINUX void ViewerDisplayWidget::ShowNouveauWarning() { diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 4d3abb1da..a9903075e 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -32,6 +32,7 @@ #include "render/colormanager.h" #include "viewersafemargininfo.h" #include "widget/manageddisplay/manageddisplay.h" +#include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER @@ -50,7 +51,7 @@ OLIVE_NAMESPACE_ENTER * the same texture object, use SetTexture() since it will nearly always be faster to just set it than to check *and* * set it. */ -class ViewerDisplayWidget : public ManagedDisplayWidget +class ViewerDisplayWidget : public ManagedDisplayWidget, public TimeTargetObject { Q_OBJECT public: @@ -78,6 +79,8 @@ public: void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); void SetGizmos(Node* node); + void SetVideoParams(const VideoRenderingParams& params); + void SetTime(const rational& time); public slots: /** @@ -126,15 +129,20 @@ signals: protected: /** - * @brief Override the mouse press event simply to emit the DragStarted() signal + * @brief Override the mouse press event for the DragStarted() signal and gizmos */ virtual void mousePressEvent(QMouseEvent* event) override; /** - * @brief Override mouse move to provide functionality for + * @brief Override mouse move to signal for the pixel sampler and gizmos */ virtual void mouseMoveEvent(QMouseEvent* event) override; + /** + * @brief Override mouse release event for gizmos + */ + virtual void mouseReleaseEvent(QMouseEvent* event) override; + /** * @brief Initialize function to set up the OpenGL context upon its construction * @@ -150,6 +158,10 @@ protected: virtual void paintGL() override; private: + QPointF GetTexturePosition(const QPoint& screen_pos); + QPointF GetTexturePosition(const QSize& size); + QPointF GetTexturePosition(const double& x, const double& y); + /** * @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL(). */ @@ -177,6 +189,12 @@ private: Node* gizmos_; + VideoRenderingParams gizmo_params_; + + bool gizmo_click_; + + rational time_; + private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources