From c2e59b0855b1b267eec5049d2423f9965f778f48 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 6 Sep 2019 15:45:12 +1000 Subject: [PATCH] alpha over and opacity nodes are now functional --- app/common/rational.h | 4 ++-- app/core.cpp | 3 +++ app/node/blend/alphaover/alphaover.cpp | 14 ++++++++--- app/node/color/opacity/opacity.cpp | 16 ++++++++++++- app/node/node.cpp | 9 ++++++++ app/node/node.h | 3 +++ app/node/output/timeline/timeline.cpp | 23 +++++++++++++++++-- app/node/output/timeline/timeline.h | 4 ++++ app/node/param.cpp | 1 + app/node/param.h | 1 + app/node/processor/renderer/renderer.cpp | 21 +++++++++++++---- app/node/processor/renderer/renderer.h | 4 ++++ app/render/renderframebuffer.cpp | 14 ++++++----- app/render/renderframebuffer.h | 2 +- app/render/renderinstance.cpp | 1 + .../nodeparamviewwidgetbridge.cpp | 3 +++ 16 files changed, 104 insertions(+), 19 deletions(-) diff --git a/app/common/rational.h b/app/common/rational.h index 4a8d21382..cdf5e61f4 100644 --- a/app/common/rational.h +++ b/app/common/rational.h @@ -131,8 +131,8 @@ private: intType gcd(intType &x, intType &y); }; -#define RATIONAL_MIN rational(LONG_MIN, 1) -#define RATIONAL_MAX rational(LONG_MAX, 1) +#define RATIONAL_MIN rational(INT32_MIN, 1) +#define RATIONAL_MAX rational(INT32_MAX, 1) Q_DECLARE_METATYPE(rational) diff --git a/app/core.cpp b/app/core.cpp index 7833e0685..9118e12fb 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -307,6 +307,9 @@ void Core::CreateNewSequence() // Connect track to timeline NodeParam::ConnectEdge(to->track_output(), tb->track_input()); + // Connect timeline end point to renderer + NodeParam::ConnectEdge(tb->length_output(), rp->length_input()); + // FIXME: Test code AlphaOverBlend* blend = new AlphaOverBlend(); new_sequence->AddNode(blend); diff --git a/app/node/blend/alphaover/alphaover.cpp b/app/node/blend/alphaover/alphaover.cpp index 1ef4aaa4a..d8654f591 100644 --- a/app/node/blend/alphaover/alphaover.cpp +++ b/app/node/blend/alphaover/alphaover.cpp @@ -64,8 +64,13 @@ QVariant AlphaOverBlend::Value(NodeOutput *param, const rational &time) RenderTexturePtr base = base_input()->get_value(time).value(); RenderTexturePtr blend = blend_input()->get_value(time).value(); - // Set compositing strategy to alpha over - renderer->context()->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (base == nullptr && blend == nullptr) { + return 0; + } else if (base == nullptr) { + return QVariant::fromValue(blend); + } else if (blend == nullptr) { + return QVariant::fromValue(base); + } // Attach framebuffer to the backbuffer of base renderer->buffer()->Attach(base); @@ -74,13 +79,16 @@ QVariant AlphaOverBlend::Value(NodeOutput *param, const rational &time) // Bind blend blend->Bind(); + // Set compositing strategy to alpha over + renderer->context()->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // Draw blend on base olive::gl::Blit(renderer->default_pipeline()); // Release all blend->Release(); - renderer->buffer()->Detach(); renderer->buffer()->Release(); + renderer->buffer()->Detach(); // Return base texture which now has blend composited on top // NOTE: Blend texture will be implicitly deleted here (if it's not used anywhere else) diff --git a/app/node/color/opacity/opacity.cpp b/app/node/color/opacity/opacity.cpp index 8672d889d..4d89eb0b5 100644 --- a/app/node/color/opacity/opacity.cpp +++ b/app/node/color/opacity/opacity.cpp @@ -73,6 +73,10 @@ QVariant OpacityNode::Value(NodeOutput *output, const rational &time) if (output == texture_output_) { RenderTexturePtr input_tex = texture_input_->get_value(time).value(); + if (input_tex == nullptr) { + return 0; + } + // Attach texture's back buffer as frame buffer renderer->buffer()->AttachBackBuffer(input_tex); renderer->buffer()->Bind(); @@ -82,17 +86,27 @@ QVariant OpacityNode::Value(NodeOutput *output, const rational &time) // Set opacity to value ShaderPtr pipeline = renderer->default_pipeline(); + pipeline->bind(); pipeline->setUniformValue("opacity", opacity_input_->get_value(time).toFloat()*0.01f); + pipeline->release(); + + renderer->context()->functions()->glBlendFunc(GL_ONE, GL_ZERO); // Blit - olive::gl::Blit(renderer->default_pipeline()); + olive::gl::Blit(pipeline); // Reset to full opacity + pipeline->bind(); pipeline->setUniformValue("opacity", 1.0f); + pipeline->release(); input_tex->Release(); renderer->buffer()->Release(); renderer->buffer()->Detach(); + + input_tex->SwapFrontAndBack(); + + return QVariant::fromValue(input_tex); } return 0; diff --git a/app/node/node.cpp b/app/node/node.cpp index f60740c57..3b91e0871 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -57,6 +57,8 @@ void Node::AddParameter(NodeParam *param) if (param->type() == NodeParam::kInput) { connect(param, SIGNAL(ValueChanged(rational, rational)), this, SLOT(InputChanged(rational, rational))); + connect(param, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); + connect(param, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); } } @@ -360,3 +362,10 @@ void Node::InputChanged(rational start, rational end) { InvalidateCache(start, end, static_cast(sender())); } + +void Node::InputConnectionChanged(NodeEdgePtr edge) +{ + Q_UNUSED(edge) + + InvalidateCache(RATIONAL_MIN, RATIONAL_MAX, static_cast(sender())); +} diff --git a/app/node/node.h b/app/node/node.h index 7a5f59430..128b623e9 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -288,6 +288,9 @@ private: private slots: void InputChanged(rational start, rational end); + + void InputConnectionChanged(NodeEdgePtr edge); + }; template diff --git a/app/node/output/timeline/timeline.cpp b/app/node/output/timeline/timeline.cpp index c4f365fb2..31ca0446f 100644 --- a/app/node/output/timeline/timeline.cpp +++ b/app/node/output/timeline/timeline.cpp @@ -32,6 +32,10 @@ TimelineOutput::TimelineOutput() : track_input_->add_data_input(NodeParam::kTrack); AddParameter(track_input_); + length_output_ = new NodeOutput("length_out"); + length_output_->set_data_type(NodeParam::kRational); + AddParameter(length_output_); + connect(this, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(TrackConnectionAdded(NodeEdgePtr))); connect(this, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(TrackConnectionRemoved(NodeEdgePtr))); } @@ -96,10 +100,25 @@ NodeInput *TimelineOutput::track_input() return track_input_; } +NodeOutput *TimelineOutput::length_output() +{ + return length_output_; +} + QVariant TimelineOutput::Value(NodeOutput *output, const rational &time) { - Q_UNUSED(output) - Q_UNUSED(time) + if (output == length_output_) { + Q_UNUSED(time) + + rational length; + + // Retrieve each track's end point and return the longest of the tracks + foreach (TrackOutput* track, track_cache_) { + length = qMax(track->in(), length); + } + + return QVariant::fromValue(length); + } return 0; } diff --git a/app/node/output/timeline/timeline.h b/app/node/output/timeline/timeline.h index 15bcb9817..c2fc80f60 100644 --- a/app/node/output/timeline/timeline.h +++ b/app/node/output/timeline/timeline.h @@ -45,6 +45,8 @@ public: NodeInput* track_input(); + NodeOutput* length_output(); + protected: virtual QVariant Value(NodeOutput* output, const rational& time) override; @@ -65,6 +67,8 @@ private: NodeInput* track_input_; + NodeOutput* length_output_; + /** * @brief A cache of connected Tracks */ diff --git a/app/node/param.cpp b/app/node/param.cpp index 2c267a9a8..d57d1effa 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -226,6 +226,7 @@ QString NodeParam::GetDefaultDataTypeName(const DataType& type) case kBlock: return tr("Block"); case kFootage: return tr("Footage"); case kTrack: return tr("Track"); + case kRational: return tr("Rational"); case kAny: return tr("Any"); } diff --git a/app/node/param.h b/app/node/param.h index 7a2efa6da..d5977f7b6 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -68,6 +68,7 @@ public: kBlock, kFootage, kTrack, + kRational, kAny }; diff --git a/app/node/processor/renderer/renderer.cpp b/app/node/processor/renderer/renderer.cpp index 9b0538dff..a1077efc4 100644 --- a/app/node/processor/renderer/renderer.cpp +++ b/app/node/processor/renderer/renderer.cpp @@ -42,6 +42,10 @@ RendererProcessor::RendererProcessor() : texture_input_->add_data_input(NodeInput::kTexture); AddParameter(texture_input_); + length_input_ = new NodeInput("length_in"); + length_input_->add_data_input(NodeInput::kRational); + AddParameter(length_input_); + texture_output_ = new NodeOutput("tex_out"); texture_output_->set_data_type(NodeInput::kTexture); AddParameter(texture_output_); @@ -126,18 +130,22 @@ void RendererProcessor::InvalidateCache(const rational &start_range, const ratio { Q_UNUSED(from) + // Adjust range to min/max values + rational start_range_adj = qMax(rational(0), start_range); + rational end_range_adj = qMin(length_input()->get_value(0).value(), end_range); + qDebug() << "[RendererProcessor] Cache invalidated between" - << start_range.toDouble() + << start_range_adj.toDouble() << "and" - << end_range.toDouble(); + << end_range_adj.toDouble(); // Snap start_range to timebase - double start_range_dbl = start_range.toDouble(); + double start_range_dbl = start_range_adj.toDouble(); double start_range_numf = start_range_dbl * static_cast(timebase_.denominator()); int64_t start_range_numround = qFloor(start_range_numf/static_cast(timebase_.numerator())) * timebase_.numerator(); rational true_start_range(start_range_numround, timebase_.denominator()); - for (rational r=true_start_range;r<=end_range;r+=timebase_) { + for (rational r=true_start_range;r<=end_range_adj;r+=timebase_) { if (!cache_queue_.contains(r)) { cache_queue_.append(r); } @@ -395,6 +403,11 @@ NodeInput *RendererProcessor::texture_input() return texture_input_; } +NodeInput *RendererProcessor::length_input() +{ + return length_input_; +} + NodeOutput *RendererProcessor::texture_output() { return texture_output_; diff --git a/app/node/processor/renderer/renderer.h b/app/node/processor/renderer/renderer.h index a50a954ca..98a77206c 100644 --- a/app/node/processor/renderer/renderer.h +++ b/app/node/processor/renderer/renderer.h @@ -100,6 +100,8 @@ public: NodeInput* texture_input(); + NodeInput* length_input(); + NodeOutput* texture_output(); protected: @@ -145,6 +147,8 @@ private: NodeInput* texture_input_; + NodeInput* length_input_; + NodeOutput* texture_output_; int width_; diff --git a/app/render/renderframebuffer.cpp b/app/render/renderframebuffer.cpp index 148be05a7..b4aa6aa80 100644 --- a/app/render/renderframebuffer.cpp +++ b/app/render/renderframebuffer.cpp @@ -95,7 +95,7 @@ void RenderFramebuffer::Attach(RenderTexturePtr texture) } texture_ = texture; - AttachInternal(texture_->texture()); + AttachInternal(texture_->texture(), false); } void RenderFramebuffer::AttachBackBuffer(RenderTexturePtr texture) @@ -105,10 +105,7 @@ void RenderFramebuffer::AttachBackBuffer(RenderTexturePtr texture) } texture_ = texture; - AttachInternal(texture_->back_texture()); - - context_->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - context_->functions()->glClear(GL_COLOR_BUFFER_BIT); + AttachInternal(texture_->back_texture(), true); } void RenderFramebuffer::Detach() @@ -137,7 +134,7 @@ const GLuint &RenderFramebuffer::buffer() const return buffer_; } -void RenderFramebuffer::AttachInternal(GLuint tex) +void RenderFramebuffer::AttachInternal(GLuint tex, bool clear) { Detach(); @@ -150,6 +147,11 @@ void RenderFramebuffer::AttachInternal(GLuint tex) GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0 ); + if (clear) { + context_->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + context_->functions()->glClear(GL_COLOR_BUFFER_BIT); + } + // release framebuffer f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } diff --git a/app/render/renderframebuffer.h b/app/render/renderframebuffer.h index c1353ad62..ef13d4a91 100644 --- a/app/render/renderframebuffer.h +++ b/app/render/renderframebuffer.h @@ -56,7 +56,7 @@ public slots: void Destroy(); private: - void AttachInternal(GLuint tex); + void AttachInternal(GLuint tex, bool clear); QOpenGLContext* context_; diff --git a/app/render/renderinstance.cpp b/app/render/renderinstance.cpp index 4bb685d1c..ca04f7b6b 100644 --- a/app/render/renderinstance.cpp +++ b/app/render/renderinstance.cpp @@ -77,6 +77,7 @@ bool RenderInstance::Start() // Set viewport to the compositing dimensions ctx_->functions()->glViewport(0, 0, width_, height_); + ctx_->functions()->glEnable(GL_BLEND); // Set up default pipeline default_pipeline_ = olive::ShaderGenerator::DefaultPipeline(); diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index b1b2391dc..572aded01 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -52,6 +52,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeParam::kTexture: case NodeParam::kMatrix: case NodeParam::kTrack: + case NodeParam::kRational: break; case NodeParam::kInt: { @@ -63,6 +64,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeParam::kFloat: { FloatSlider* slider = new FloatSlider(); + slider->SetValue(base_input->get_value(0).toDouble()); widgets_.append(slider); connect(slider, SIGNAL(ValueChanged(double)), this, SLOT(WidgetCallback())); break; @@ -125,6 +127,7 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeParam::kTexture: case NodeParam::kMatrix: case NodeParam::kTrack: + case NodeParam::kRational: break; case NodeParam::kInt: {