From 2c8ebdf0d26065c3280fa875cb599637ece27262 Mon Sep 17 00:00:00 2001 From: Peter Eszlari Date: Mon, 4 May 2020 03:37:31 +0200 Subject: [PATCH 01/12] ocioconf: replace script with cmake --- app/render/ocioconf/CMakeLists.txt | 10 +++++++++- app/render/ocioconf/gen-qrc.sh | 17 ----------------- app/render/ocioconf/ocioconf.qrc | 19 ------------------- app/render/ocioconf/ocioconf.qrc.in | 5 +++++ 4 files changed, 14 insertions(+), 37 deletions(-) delete mode 100755 app/render/ocioconf/gen-qrc.sh delete mode 100644 app/render/ocioconf/ocioconf.qrc create mode 100644 app/render/ocioconf/ocioconf.qrc.in diff --git a/app/render/ocioconf/CMakeLists.txt b/app/render/ocioconf/CMakeLists.txt index 72fff96aa..faa7b5e40 100644 --- a/app/render/ocioconf/CMakeLists.txt +++ b/app/render/ocioconf/CMakeLists.txt @@ -14,8 +14,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +file(GLOB_RECURSE OCIOCONF_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.ocio *.spi3d *.spi1d) +set(QRC_BODY "") +foreach(OCIOCONF_FILE ${OCIOCONF_RESOURCES}) + string(APPEND QRC_BODY "${OCIOCONF_FILE}\n") + configure_file(${OCIOCONF_FILE} ${OCIOCONF_FILE} COPYONLY) +endforeach() +configure_file(ocioconf.qrc.in ocioconf.qrc @ONLY) + set(OLIVE_RESOURCES ${OLIVE_RESOURCES} - render/ocioconf/ocioconf.qrc + ${CMAKE_CURRENT_BINARY_DIR}/ocioconf.qrc PARENT_SCOPE ) diff --git a/app/render/ocioconf/gen-qrc.sh b/app/render/ocioconf/gen-qrc.sh deleted file mode 100755 index 448f6b4b2..000000000 --- a/app/render/ocioconf/gen-qrc.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -ourbasename=$(basename "$0") - -rm ocioconf.qrc -echo "" >> ocioconf.qrc -echo " " >> ocioconf.qrc - -for f in $(find * -type f) -do - if [ "$f" != "CMakeLists.txt" ] && [ "$f" != "ocioconf.qrc" ] && [ "$f" != "$ourbasename" ] - then - echo " $f" >> ocioconf.qrc - fi -done - -echo " " >> ocioconf.qrc -echo "" >> ocioconf.qrc diff --git a/app/render/ocioconf/ocioconf.qrc b/app/render/ocioconf/ocioconf.qrc deleted file mode 100644 index badfdb9b2..000000000 --- a/app/render/ocioconf/ocioconf.qrc +++ /dev/null @@ -1,19 +0,0 @@ - - - config.ocio - looks/Filmic_False_Colour.spi3d - looks/Filmic_to_0-35_1-30.spi1d - looks/Filmic_to_0-48_1-09.spi1d - looks/Filmic_to_0-60_1-04.spi1d - looks/Filmic_to_0-70_1-03.spi1d - looks/Filmic_to_0-85_1-011.spi1d - looks/Filmic_to_0.99_1-0075.spi1d - looks/Filmic_to_1.20_1-00.spi1d - luts/F-Log_to_Linear.spi1d - luts/V-Log_to_linear.spi1d - luts/V3_LogC_400_to_linear.spi1d - luts/V3_LogC_800_to_linear.spi1d - luts/desat65cube.spi3d - luts/sRGB_OETF_to_Linear.spi1d - - diff --git a/app/render/ocioconf/ocioconf.qrc.in b/app/render/ocioconf/ocioconf.qrc.in new file mode 100644 index 000000000..7d9cdfce9 --- /dev/null +++ b/app/render/ocioconf/ocioconf.qrc.in @@ -0,0 +1,5 @@ + + + @QRC_BODY@ + + From 51c896ed7e76af03aecc3634bfa654725928a274 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 02:41:16 +1000 Subject: [PATCH 02/12] scopes: moved all shared code to a base class to easily add more scopes --- app/widget/scope/CMakeLists.txt | 1 + app/widget/scope/histogram/histogram.cpp | 183 +--------------------- app/widget/scope/histogram/histogram.h | 68 +------- app/widget/scope/scopebase/CMakeLists.txt | 22 +++ app/widget/scope/scopebase/scopebase.cpp | 163 +++++++++++++++++++ app/widget/scope/scopebase/scopebase.h | 78 +++++++++ app/widget/scope/waveform/waveform.cpp | 168 +++++--------------- app/widget/scope/waveform/waveform.h | 36 +---- 8 files changed, 310 insertions(+), 409 deletions(-) create mode 100644 app/widget/scope/scopebase/CMakeLists.txt create mode 100644 app/widget/scope/scopebase/scopebase.cpp create mode 100644 app/widget/scope/scopebase/scopebase.h diff --git a/app/widget/scope/CMakeLists.txt b/app/widget/scope/CMakeLists.txt index a14b351dd..91c4f0b44 100644 --- a/app/widget/scope/CMakeLists.txt +++ b/app/widget/scope/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(histogram) +add_subdirectory(scopebase) add_subdirectory(waveform) set(OLIVE_SOURCES diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index b9028f85a..9665e32de 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -29,189 +29,8 @@ OLIVE_NAMESPACE_ENTER HistogramScope::HistogramScope(QWidget* parent) : - ManagedDisplayWidget(parent), - buffer_(nullptr) + ScopeBase(parent) { - EnableDefaultContextMenu(); - - connect(&worker_, &HistogramScopeWorker::Finished, this, &HistogramScope::FinishedProcessing, Qt::QueuedConnection); - worker_.start(QThread::IdlePriority); -} - -HistogramScope::~HistogramScope() -{ - worker_.Cancel(); - worker_.quit(); - worker_.wait(); -} - -void HistogramScope::SetBuffer(Frame* frame) -{ - buffer_ = frame; - - if (isVisible()) { - StartUpdate(); - } -} - -void HistogramScope::FinishedProcessing(QVector red, QVector green, QVector blue) -{ - red_val_ = red; - green_val_ = green; - blue_val_ = blue; - - update(); -} - -void HistogramScope::paintGL() -{ - QVector red_lines(red_val_.size()); - QVector green_lines(green_val_.size()); - QVector blue_lines(blue_val_.size()); - - for (int i=0;i data(w * kRGBChannels, 0); - - int max_w = w-1; - - for (int x=0;xConvertColor(c); - } - - data[qFloor(clamp(c.red(), 0.0f, 1.0f) * max_w)]++; - data[qFloor(clamp(c.green(), 0.0f, 1.0f) * max_w) + w]++; - data[qFloor(clamp(c.blue(), 0.0f, 1.0f) * max_w) + w * 2]++; - } - } - - int max_val = 0; - - foreach (const int& i, data) { - if (i > max_val) { - max_val = i; - } - } - - if (!max_val) { - // Prevent divide by zero - return; - } - - QVector red_lines(w); - QVector green_lines(w); - QVector blue_lines(w); - - for (int i=0;i(data.at(i)) / static_cast(max_val)); - green_lines.replace(i, static_cast(data.at(i + w)) / static_cast(max_val)); - blue_lines.replace(i, static_cast(data.at(i + w * 2)) / static_cast(max_val)); - } - - emit Finished(red_lines, green_lines, blue_lines); - } -} - -void HistogramScopeWorker::QueueNext(const Frame &f, ColorProcessorPtr processor, int width) -{ - next_lock_.lock(); - - next_ = f; - next_width_ = width; - next_processor_ = processor; - - next_wait_.wakeOne(); - - next_lock_.unlock(); -} - -void HistogramScopeWorker::Cancel() -{ - cancelled_ = true; - next_lock_.lock(); - next_wait_.wakeOne(); - next_lock_.unlock(); } OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/histogram/histogram.h b/app/widget/scope/histogram/histogram.h index 3efad3919..625074a89 100644 --- a/app/widget/scope/histogram/histogram.h +++ b/app/widget/scope/histogram/histogram.h @@ -21,80 +21,20 @@ #ifndef HISTOGRAMSCOPE_H #define HISTOGRAMSCOPE_H -#include -#include -#include - -#include "codec/frame.h" -#include "render/colorprocessor.h" -#include "widget/manageddisplay/manageddisplay.h" +#include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER -class HistogramScopeWorker : public QThread -{ - Q_OBJECT -public: - HistogramScopeWorker(); - - // Thread-safe - void QueueNext(const Frame& f, ColorProcessorPtr processor, int width); - - // Thread-safe - void Cancel(); - -protected: - virtual void run() override; - -signals: - void Finished(QVector red, QVector green, QVector blue); - -private: - QAtomicInt cancelled_; - - QMutex next_lock_; - QWaitCondition next_wait_; - Frame next_; - int next_width_; - ColorProcessorPtr next_processor_; - -}; - -class HistogramScope : public ManagedDisplayWidget +class HistogramScope : public ScopeBase { Q_OBJECT public: HistogramScope(QWidget* parent = nullptr); - virtual ~HistogramScope() override; - -public slots: - void SetBuffer(Frame* frame); - protected: - virtual void paintGL() override; + //virtual OpenGLShaderPtr CreateShader() override; - virtual void resizeEvent(QResizeEvent* e) override; - - virtual void ColorProcessorChangedEvent() override; - - virtual void showEvent(QShowEvent* e) override; - -private: - void StartUpdate(); - - Frame* buffer_; - - QVector red_val_; - - QVector green_val_; - - QVector blue_val_; - - HistogramScopeWorker worker_; - -private slots: - void FinishedProcessing(QVector red, QVector green, QVector blue); + //virtual void DrawScope() override; }; diff --git a/app/widget/scope/scopebase/CMakeLists.txt b/app/widget/scope/scopebase/CMakeLists.txt new file mode 100644 index 000000000..ca6d924c3 --- /dev/null +++ b/app/widget/scope/scopebase/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/scope/scopebase/scopebase.h + widget/scope/scopebase/scopebase.cpp + PARENT_SCOPE +) diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp new file mode 100644 index 000000000..c58b9e8bd --- /dev/null +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -0,0 +1,163 @@ +/*** + + 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 "scopebase.h" + +#include "render/backend/opengl/openglrenderfunctions.h" + +OLIVE_NAMESPACE_ENTER + +ScopeBase::ScopeBase(QWidget* parent) : + ManagedDisplayWidget(parent), + buffer_(nullptr) +{ + EnableDefaultContextMenu(); +} + +ScopeBase::~ScopeBase() +{ + CleanUp(); + + if (context()) { + disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp); + } +} + +void ScopeBase::SetBuffer(Frame *frame) +{ + buffer_ = frame; + + UploadTextureFromBuffer(); +} + +void ScopeBase::showEvent(QShowEvent* e) +{ + ManagedDisplayWidget::showEvent(e); + + UploadTextureFromBuffer(); +} + +OpenGLShaderPtr ScopeBase::CreateShader() +{ + return OpenGLShader::CreateDefault(); +} + +void ScopeBase::DrawScope() +{ + managed_tex().Bind(); + + OpenGLRenderFunctions::Blit(pipeline()); + + managed_tex().Release(); +} + +OpenGLShaderPtr ScopeBase::pipeline() +{ + return pipeline_; +} + +OpenGLTexture &ScopeBase::managed_tex() +{ + return managed_tex_; +} + +void ScopeBase::UploadTextureFromBuffer() +{ + if (!isVisible()) { + return; + } + + if (buffer_) { + makeCurrent(); + + if (!texture_.IsCreated() + || texture_.width() != buffer_->width() + || texture_.height() != buffer_->height() + || texture_.format() != buffer_->format()) { + texture_.Destroy(); + managed_tex_.Destroy(); + + texture_.Create(context(), buffer_); + managed_tex_.Create(context(), buffer_->video_params()); + } else { + texture_.Upload(buffer_); + } + + doneCurrent(); + } + + update(); +} + +void ScopeBase::CleanUp() +{ + makeCurrent(); + + pipeline_ = nullptr; + texture_.Destroy(); + managed_tex_.Destroy(); + framebuffer_.Destroy(); + + doneCurrent(); +} + +void ScopeBase::initializeGL() +{ + ManagedDisplayWidget::initializeGL(); + + pipeline_ = CreateShader(); + + framebuffer_.Create(context()); + + connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp, Qt::DirectConnection); + + UploadTextureFromBuffer(); +} + +void ScopeBase::paintGL() +{ + QOpenGLFunctions* f = context()->functions(); + + f->glClearColor(0, 0, 0, 0); + f->glClear(GL_COLOR_BUFFER_BIT); + + if (buffer_ && pipeline() && texture_.IsCreated()) { + // Convert reference frame to display space + framebuffer_.Attach(&managed_tex_); + framebuffer_.Bind(); + + texture_.Bind(); + + f->glViewport(0, 0, texture_.width(), texture_.height()); + + color_service()->ProcessOpenGL(); + + texture_.Release(); + + framebuffer_.Release(); + framebuffer_.Detach(); + + f->glViewport(0, 0, width(), height()); + + DrawScope(); + } +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/scopebase/scopebase.h b/app/widget/scope/scopebase/scopebase.h new file mode 100644 index 000000000..3098af212 --- /dev/null +++ b/app/widget/scope/scopebase/scopebase.h @@ -0,0 +1,78 @@ +/*** + + 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 SCOPEBASE_H +#define SCOPEBASE_H + +#include "codec/frame.h" +#include "render/backend/opengl/openglcolorprocessor.h" +#include "render/backend/opengl/openglframebuffer.h" +#include "render/backend/opengl/openglshader.h" +#include "render/backend/opengl/opengltexture.h" +#include "widget/manageddisplay/manageddisplay.h" + +OLIVE_NAMESPACE_ENTER + +class ScopeBase : public ManagedDisplayWidget +{ +public: + ScopeBase(QWidget* parent = nullptr); + + virtual ~ScopeBase() override; + +public slots: + void SetBuffer(Frame* frame); + +protected: + virtual void initializeGL() override; + + virtual void paintGL() override; + + virtual void showEvent(QShowEvent* e) override; + + virtual OpenGLShaderPtr CreateShader(); + + virtual void DrawScope(); + + OpenGLShaderPtr pipeline(); + + OpenGLTexture& managed_tex(); + +private: + void UploadTextureFromBuffer(); + + OpenGLShaderPtr pipeline_; + + OpenGLTexture texture_; + + OpenGLTexture managed_tex_; + + OpenGLFramebuffer framebuffer_; + + Frame* buffer_; + +private slots: + void CleanUp(); + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // SCOPEBASE_H diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 5f9225b3f..6c3c43fc7 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -32,59 +32,24 @@ OLIVE_NAMESPACE_ENTER WaveformScope::WaveformScope(QWidget* parent) : - ManagedDisplayWidget(parent), - buffer_(nullptr) + ScopeBase(parent) { - EnableDefaultContextMenu(); } -WaveformScope::~WaveformScope() +OpenGLShaderPtr WaveformScope::CreateShader() { - CleanUp(); + OpenGLShaderPtr pipeline = OpenGLShader::Create(); - if (context()) { - disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp); - } + pipeline->create(); + pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); + pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); + pipeline->link(); + + return pipeline; } -void WaveformScope::SetBuffer(Frame *frame) +void WaveformScope::DrawScope() { - buffer_ = frame; - - UploadTextureFromBuffer(); -} - -void WaveformScope::showEvent(QShowEvent* e) -{ - ManagedDisplayWidget::showEvent(e); - - UploadTextureFromBuffer(); -} - -void WaveformScope::initializeGL() -{ - ManagedDisplayWidget::initializeGL(); - - pipeline_ = OpenGLShader::Create(); - pipeline_->create(); - pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); - pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); - pipeline_->link(); - - framebuffer_.Create(context()); - - connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp, Qt::DirectConnection); - - UploadTextureFromBuffer(); -} - -void WaveformScope::paintGL() -{ - QOpenGLFunctions* f = context()->functions(); - - f->glClearColor(0, 0, 0, 0); - f->glClear(GL_COLOR_BUFFER_BIT); - float waveform_scale = 0.80f; float waveform_dim_x = width() * waveform_scale; float waveform_dim_y = height() * waveform_scale; @@ -93,59 +58,40 @@ void WaveformScope::paintGL() float waveform_end_dim_x = width() - waveform_start_dim_x; float waveform_end_dim_y = height() - waveform_start_dim_y; - if (buffer_ && pipeline_ && texture_.IsCreated()) { - // Convert reference frame to display space - framebuffer_.Attach(&managed_tex_); - framebuffer_.Bind(); + // Draw waveform through shader + pipeline()->bind(); + pipeline()->setUniformValue("ove_resolution", managed_tex().width(), managed_tex().height()); + pipeline()->setUniformValue("ove_viewport", width(), height()); + GLfloat luma[3] = {0.0, 0.0, 0.0}; + color_manager()->GetDefaultLumaCoefs(luma); + pipeline()->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); - texture_.Bind(); + // Scale of the waveform relative to the viewport surface. + pipeline()->setUniformValue("waveform_scale", waveform_scale); + pipeline()->setUniformValue( + "waveform_dims", waveform_dim_x, waveform_dim_y); - f->glViewport(0, 0, texture_.width(), texture_.height()); + pipeline()->setUniformValue( + "waveform_region", + waveform_start_dim_x, waveform_start_dim_y, + waveform_end_dim_x, waveform_end_dim_y); - color_service()->ProcessOpenGL(); + float waveform_start_uv_x = waveform_start_dim_x / width(); + float waveform_start_uv_y = waveform_start_dim_y / height(); + float waveform_end_uv_x = waveform_end_dim_x / width(); + float waveform_end_uv_y = waveform_end_dim_y / height(); + pipeline()->setUniformValue( + "waveform_uv", + waveform_start_uv_x, waveform_start_uv_y, + waveform_end_uv_x, waveform_end_uv_y); - texture_.Release(); + pipeline()->release(); - framebuffer_.Release(); - framebuffer_.Detach(); + managed_tex().Bind(); - // Draw waveform through shader - pipeline_->bind(); - pipeline_->setUniformValue("ove_resolution", texture_.width(), texture_.height()); - pipeline_->setUniformValue("ove_viewport", width(), height()); - GLfloat luma[3] = {0.0, 0.0, 0.0}; - color_manager()->GetDefaultLumaCoefs(luma); - pipeline_->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); + OpenGLRenderFunctions::Blit(pipeline()); - // Scale of the waveform relative to the viewport surface. - pipeline_->setUniformValue("waveform_scale", waveform_scale); - pipeline_->setUniformValue( - "waveform_dims", waveform_dim_x, waveform_dim_y); - - pipeline_->setUniformValue( - "waveform_region", - waveform_start_dim_x, waveform_start_dim_y, - waveform_end_dim_x, waveform_end_dim_y); - - float waveform_start_uv_x = waveform_start_dim_x / width(); - float waveform_start_uv_y = waveform_start_dim_y / height(); - float waveform_end_uv_x = waveform_end_dim_x / width(); - float waveform_end_uv_y = waveform_end_dim_y / height(); - pipeline_->setUniformValue( - "waveform_uv", - waveform_start_uv_x, waveform_start_uv_y, - waveform_end_uv_x, waveform_end_uv_y); - - pipeline_->release(); - - f->glViewport(0, 0, width(), height()); - - managed_tex_.Bind(); - - OpenGLRenderFunctions::Blit(pipeline_); - - managed_tex_.Release(); - } + managed_tex().Release(); // Draw line overlays QPainter p(this); @@ -179,44 +125,4 @@ void WaveformScope::paintGL() p.drawLines(ire_lines); } -void WaveformScope::UploadTextureFromBuffer() -{ - if (!isVisible()) { - return; - } - - if (buffer_) { - makeCurrent(); - - if (!texture_.IsCreated() - || texture_.width() != buffer_->width() - || texture_.height() != buffer_->height() - || texture_.format() != buffer_->format()) { - texture_.Destroy(); - managed_tex_.Destroy(); - - texture_.Create(context(), buffer_); - managed_tex_.Create(context(), buffer_->video_params()); - } else { - texture_.Upload(buffer_); - } - - doneCurrent(); - } - - update(); -} - -void WaveformScope::CleanUp() -{ - makeCurrent(); - - pipeline_ = nullptr; - texture_.Destroy(); - managed_tex_.Destroy(); - framebuffer_.Destroy(); - - doneCurrent(); -} - OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/waveform/waveform.h b/app/widget/scope/waveform/waveform.h index 4243a9d3a..04a464e52 100644 --- a/app/widget/scope/waveform/waveform.h +++ b/app/widget/scope/waveform/waveform.h @@ -21,48 +21,20 @@ #ifndef WAVEFORMSCOPE_H #define WAVEFORMSCOPE_H -#include "codec/frame.h" -#include "render/backend/opengl/openglcolorprocessor.h" -#include "render/backend/opengl/openglframebuffer.h" -#include "render/backend/opengl/openglshader.h" -#include "render/backend/opengl/opengltexture.h" -#include "widget/manageddisplay/manageddisplay.h" +#include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER -class WaveformScope : public ManagedDisplayWidget +class WaveformScope : public ScopeBase { Q_OBJECT public: WaveformScope(QWidget* parent = nullptr); - virtual ~WaveformScope() override; - -public slots: - void SetBuffer(Frame* frame); - protected: - virtual void initializeGL() override; + virtual OpenGLShaderPtr CreateShader() override; - virtual void paintGL() override; - - virtual void showEvent(QShowEvent* e) override; - -private: - void UploadTextureFromBuffer(); - - OpenGLShaderPtr pipeline_; - - OpenGLTexture texture_; - - OpenGLTexture managed_tex_; - - OpenGLFramebuffer framebuffer_; - - Frame* buffer_; - -private slots: - void CleanUp(); + virtual void DrawScope() override; }; From 911ef782f97b13d9454e4ef3f61dd020967802ce Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 14:48:09 +1000 Subject: [PATCH 03/12] colormanager: always temporarily set C locale when loading an OCIO config from file Fixes known bug in OCIO when loading files from non-English locales. --- .../projectproperties/projectproperties.cpp | 2 +- app/render/colormanager.cpp | 13 ++++- app/render/colormanager.h | 49 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index 6e79a1aae..e8dc50195 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -177,7 +177,7 @@ void ProjectPropertiesDialog::OCIOFilenameUpdated() if (ocio_filename_->text().isEmpty()) { c = ColorManager::GetDefaultConfig(); } else { - c = OCIO::Config::CreateFromFile(ocio_filename_->text().toUtf8()); + c = ColorManager::CreateConfigFromFile(ocio_filename_->text()); } ocio_filename_->setStyleSheet(QString()); diff --git a/app/render/colormanager.cpp b/app/render/colormanager.cpp index 3a907b3ae..0ecd73f83 100644 --- a/app/render/colormanager.cpp +++ b/app/render/colormanager.cpp @@ -49,6 +49,13 @@ OCIO::ConstConfigRcPtr ColorManager::GetConfig() const return config_; } +OCIO::ConstConfigRcPtr ColorManager::CreateConfigFromFile(const QString &filename) +{ + SetCLocale(); + + return OCIO::Config::CreateFromFile(filename.toUtf8()); +} + const QString &ColorManager::GetConfigFilename() const { return config_filename_; @@ -62,7 +69,9 @@ OCIO::ConstConfigRcPtr ColorManager::GetDefaultConfig() void ColorManager::SetUpDefaultConfig() { if (!qgetenv("OCIO").isEmpty()) { + // Attempt to set config from "OCIO" environment variable try { + SetCLocale(); default_config_ = OCIO::Config::CreateFromEnv(); return; @@ -71,7 +80,7 @@ void ColorManager::SetUpDefaultConfig() } } - // Kind of hacky, but it'll work + // Extract OCIO config - kind of hacky, but it'll work QString dir = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("ocioconf")); FileFunctions::CopyDirectory(QStringLiteral(":/ocioconf"), @@ -80,7 +89,7 @@ void ColorManager::SetUpDefaultConfig() qDebug() << "Extracting default OCIO config to" << dir; - default_config_ = OCIO::Config::CreateFromFile(QDir(dir).filePath(QStringLiteral("config.ocio")).toUtf8()); + default_config_ = CreateConfigFromFile(QDir(dir).filePath(QStringLiteral("config.ocio"))); } void ColorManager::SetConfig(const QString &filename) diff --git a/app/render/colormanager.h b/app/render/colormanager.h index af6146b86..f6ffb3349 100644 --- a/app/render/colormanager.h +++ b/app/render/colormanager.h @@ -36,6 +36,8 @@ public: OCIO::ConstConfigRcPtr GetConfig() const; + static OCIO::ConstConfigRcPtr CreateConfigFromFile(const QString& filename); + const QString& GetConfigFilename() const; static OCIO::ConstConfigRcPtr GetDefaultConfig(); @@ -90,6 +92,53 @@ public: static void SetOCIOMethodForMode(RenderMode::Mode mode, OCIOMethod method); + class SetCLocale + { + public: + SetCLocale() + { +#ifdef Q_OS_WINDOWS + // set locale will only change locale on the current thread + previousThreadConfig = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + + // get and store current locale + ssaLocale.convert(setlocale(LC_ALL, NULL)); + + // set to "C" locale + setlocale(LC_ALL, "C"); +#else + // set to C locale, saving the old one (returned from useLocale) + currentLocale = newlocale(LC_ALL_MASK,"C",NULL); + oldLocale = uselocale(currentLocale); +#endif + } + + ~SetCLocale() + { +#ifdef Q_OS_WINDOWS + // thread specific + setlocale(LC_ALL, ssaLocale.c_str()); + + // set back to global settings] + _configthreadlocale(previousThreadConfig); +#else + // restore the previous locale and freeing the created locale + uselocale(oldLocale); + freelocale(currentLocale); +#endif + } + + private: +#ifdef Q_OS_WINDOWS + SoStringA ssaLocale; + int previousThreadConfig; +#else + locale_t oldLocale; + locale_t currentLocale; +#endif + + }; + signals: void ConfigChanged(); From 1e81969fca71a606f281608e61417908374e9ba4 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 5 May 2020 11:29:15 +0100 Subject: [PATCH 04/12] Waveform fixes - Due to a floating point division error not all the bars on the waveform were being drawn. - Fix ratio in the fragment shader --- app/shaders/rgbwaveform.frag | 2 +- app/widget/scope/waveform/waveform.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/shaders/rgbwaveform.frag b/app/shaders/rgbwaveform.frag index 3e839b386..4e6b13f08 100644 --- a/app/shaders/rgbwaveform.frag +++ b/app/shaders/rgbwaveform.frag @@ -52,7 +52,7 @@ void main(void) { float waveform_x = (ove_texcoord.x - waveform_uv.x) / waveform_scale; float waveform_y = (ove_texcoord.y - waveform_uv.y) / waveform_scale; for (int i = 0; i < waveform_dims.y; i++) { - ratio = float(i) / float(waveform_dims.y); + ratio = float(i) / float(waveform_dims.y - 1); cur_col = texture( ove_maintex, vec2(waveform_x, ratio) diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 6c3c43fc7..842cc678c 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -98,7 +98,8 @@ void WaveformScope::DrawScope() QFontMetrics font_metrics = QFontMetrics(QFont()); QString label; float ire_increment = 0.1f; - float ire_steps = int(1.0 / ire_increment); + // Cast required to avoid floating point errors + int ire_steps = static_cast(std::round(1.0 / ire_increment)); QVector ire_lines(ire_steps + 1); int font_x_offset = 0; int font_y_offset = font_metrics.capHeight() / 2.0f; From 74d252c5c0a26d3267fbd4e315150ac062e94bb9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 22:12:15 +1000 Subject: [PATCH 05/12] nodes: use defined categories rather than arbitrary string based --- app/node/audio/pan/pan.cpp | 6 +-- app/node/audio/pan/pan.h | 2 +- app/node/audio/volume/volume.cpp | 4 +- app/node/audio/volume/volume.h | 2 +- app/node/block/block.cpp | 4 +- app/node/block/block.h | 2 +- .../block/transition/externaltransition.cpp | 2 +- .../block/transition/externaltransition.h | 2 +- app/node/external.cpp | 2 +- app/node/external.h | 2 +- app/node/factory.cpp | 39 +++++++------------ app/node/generator/matrix/matrix.cpp | 4 +- app/node/generator/matrix/matrix.h | 2 +- app/node/input/media/media.cpp | 4 +- app/node/input/media/media.h | 2 +- app/node/input/time/timeinput.cpp | 4 +- app/node/input/time/timeinput.h | 2 +- app/node/math/math/math.cpp | 4 +- app/node/math/math/math.h | 2 +- app/node/math/trigonometry/trigonometry.cpp | 4 +- app/node/math/trigonometry/trigonometry.h | 2 +- app/node/metareader.cpp | 18 +++++++-- app/node/metareader.h | 5 ++- app/node/node.cpp | 35 ++++++++++++++--- app/node/node.h | 23 ++++++++++- app/node/output/track/track.cpp | 4 +- app/node/output/track/track.h | 2 +- app/node/output/viewer/viewer.cpp | 4 +- app/node/output/viewer/viewer.h | 2 +- app/shaders/alphaover.xml | 2 +- app/shaders/blur.xml | 2 +- app/shaders/crossdissolve.xml | 2 +- app/shaders/diptoblack.xml | 2 +- 33 files changed, 123 insertions(+), 75 deletions(-) diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index baa9f4123..c9ef24520 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -49,9 +49,9 @@ QString PanNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.pan"); } -QString PanNode::Category() const +QList PanNode::Category() const { - return tr("Audio"); + return {kCategoryChannels}; } QString PanNode::Description() const @@ -64,7 +64,7 @@ Node::Capabilities PanNode::GetCapabilities(const NodeValueDatabase &) const return kSampleProcessor; } -NodeInput *PanNode::ProcessesSamplesFrom(const NodeValueDatabase &value) const +NodeInput *PanNode::ProcessesSamplesFrom(const NodeValueDatabase &) const { return samples_input_; } diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index b5e15b452..d4392ff9f 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 5d1c90b4f..9d815b19a 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -48,9 +48,9 @@ QString VolumeNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.volume"); } -QString VolumeNode::Category() const +QList VolumeNode::Category() const { - return tr("Audio"); + return {kCategoryFilter}; } QString VolumeNode::Description() const diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index db1f781af..71149f0bf 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 06e0237f6..98c716678 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -63,9 +63,9 @@ Block::Block() : set_length_and_media_out(1); } -QString Block::Category() const +QList Block::Category() const { - return tr("Block"); + return {kCategoryTimeline}; } const rational &Block::in() const diff --git a/app/node/block/block.h b/app/node/block/block.h index a36f91754..ca3c6b613 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -49,7 +49,7 @@ public: virtual Type type() const = 0; - virtual QString Category() const override; + virtual QList Category() const override; const rational& in() const; const rational& out() const; diff --git a/app/node/block/transition/externaltransition.cpp b/app/node/block/transition/externaltransition.cpp index 74bbf817d..798ae5b74 100644 --- a/app/node/block/transition/externaltransition.cpp +++ b/app/node/block/transition/externaltransition.cpp @@ -50,7 +50,7 @@ QString ExternalTransition::id() const return meta_.id(); } -QString ExternalTransition::Category() const +QList ExternalTransition::Category() const { return meta_.Category(); } diff --git a/app/node/block/transition/externaltransition.h b/app/node/block/transition/externaltransition.h index 91cbd0ca9..5962ecf9d 100644 --- a/app/node/block/transition/externaltransition.h +++ b/app/node/block/transition/externaltransition.h @@ -37,7 +37,7 @@ public: virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/external.cpp b/app/node/external.cpp index 6d6a20ac9..eddcf43be 100644 --- a/app/node/external.cpp +++ b/app/node/external.cpp @@ -52,7 +52,7 @@ QString ExternalNode::id() const return meta_.id(); } -QString ExternalNode::Category() const +QList ExternalNode::Category() const { return meta_.Category(); } diff --git a/app/node/external.h b/app/node/external.h index b9a50a313..046539534 100644 --- a/app/node/external.h +++ b/app/node/external.h @@ -41,7 +41,7 @@ public: virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 09791c6a5..fe7361389 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -73,34 +73,25 @@ Menu *NodeFactory::CreateMenu(QWidget* parent) // Make sure nodes are up-to-date with the current translation n->Retranslate(); - QStringList path = n->Category().split('/'); + Menu* destination = nullptr; - Menu* destination = menu; + QString category_name = Node::GetCategoryName(n->Category().isEmpty() + ? Node::kCategoryUnknown + : n->Category().first()); - // Find destination menu based on category hierarchy - foreach (const QString& dir_name, path) { - // Ignore an empty directory - if (dir_name.isEmpty()) { - continue; + // See if a menu with this category name already exists + QList menu_actions = menu->actions(); + foreach (QAction* action, menu_actions) { + if (action->menu() && action->menu()->title() == category_name) { + destination = static_cast(action->menu()); + break; } + } - // See if a menu with this dir_name already exists - bool found_cat = false; - QList menu_actions = destination->actions(); - foreach (QAction* action, menu_actions) { - if (action->menu() && action->menu()->title() == dir_name) { - destination = static_cast(action->menu()); - found_cat = true; - break; - } - } - - // Create menu here if it doesn't exist - if (!found_cat) { - Menu* new_category = new Menu(dir_name, destination); - destination->InsertAlphabetically(new_category); - destination = new_category; - } + // Create menu here if it doesn't exist + if (!destination) { + destination = new Menu(category_name, menu); + menu->InsertAlphabetically(destination); } // Add entry to menu diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index ac406d47f..29871b6f8 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -69,9 +69,9 @@ QString MatrixGenerator::id() const return QStringLiteral("org.olivevideoeditor.Olive.transform"); } -QString MatrixGenerator::Category() const +QList MatrixGenerator::Category() const { - return tr("Generator"); + return {kCategoryGenerator, kCategoryMath}; } QString MatrixGenerator::Description() const diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 7f723e4ab..88e8caeb4 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -36,7 +36,7 @@ public: virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index b7bad0efc..b3a3697f0 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -35,9 +35,9 @@ MediaInput::MediaInput() : AddInput(footage_input_); } -QString MediaInput::Category() const +QList MediaInput::Category() const { - return tr("Input"); + return {kCategoryInput}; } StreamPtr MediaInput::footage() diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index a7c15e37b..ba89f3168 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -35,7 +35,7 @@ class MediaInput : public Node public: MediaInput(); - virtual QString Category() const override; + virtual QList Category() const override; StreamPtr footage(); void SetFootage(StreamPtr f); diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index fa15de735..fee052c3c 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -41,9 +41,9 @@ QString TimeInput::id() const return QStringLiteral("org.olivevideoeditor.Olive.time"); } -QString TimeInput::Category() const +QList TimeInput::Category() const { - return tr("Input"); + return {kCategoryInput}; } QString TimeInput::Description() const diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index b912ed4b1..e79d1b333 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -35,7 +35,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 93e802481..9f2f4ca3e 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -61,9 +61,9 @@ QString MathNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.math"); } -QString MathNode::Category() const +QList MathNode::Category() const { - return tr("Math"); + return {kCategoryMath}; } QString MathNode::Description() const diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 1909c4bd5..4327bb36a 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index af073c3c5..7ab8ddb3a 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -48,9 +48,9 @@ QString TrigonometryNode::id() const return QStringLiteral("org.olivevideoeditor.Olive.trigonometry"); } -QString TrigonometryNode::Category() const +QList TrigonometryNode::Category() const { - return tr("Math"); + return {kCategoryMath}; } QString TrigonometryNode::Description() const diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index c999104eb..9af68472f 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -34,7 +34,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; diff --git a/app/node/metareader.cpp b/app/node/metareader.cpp index 007d7ec7b..e09386df4 100644 --- a/app/node/metareader.cpp +++ b/app/node/metareader.cpp @@ -71,9 +71,9 @@ const QString &NodeMetaReader::id() const return id_; } -QString NodeMetaReader::Category() const +QList NodeMetaReader::Category() const { - return GetStringForCurrentLanguage(&categories_); + return categories_; } QString NodeMetaReader::Description() const @@ -187,7 +187,19 @@ void NodeMetaReader::XMLReadEffect(QXmlStreamReader* reader) XMLReadLanguageString(reader, &short_names_); } else if (reader->name() == QStringLiteral("category")) { // Pick up category - XMLReadLanguageString(reader, &categories_); + QStringList category_ids = reader->readElementText().split(':'); + + foreach (const QString& id, category_ids) { + bool ok; + + int try_parse = id.toInt(&ok); + + if (!ok || try_parse < 0 || try_parse >= Node::kCategoryCount) { + continue; + } + + categories_.append(static_cast(try_parse)); + } } else if (reader->name() == QStringLiteral("description")) { // Pick up description XMLReadLanguageString(reader, &descriptions_); diff --git a/app/node/metareader.h b/app/node/metareader.h index 13c965a87..9efb6441d 100644 --- a/app/node/metareader.h +++ b/app/node/metareader.h @@ -26,6 +26,7 @@ #include #include "input.h" +#include "node/node.h" OLIVE_NAMESPACE_ENTER @@ -37,7 +38,7 @@ public: QString Name() const; QString ShortName() const; const QString& id() const; - QString Category() const; + QList Category() const; QString Description() const; const QString& filename() const; @@ -70,7 +71,7 @@ private: LanguageMap names_; LanguageMap short_names_; LanguageMap descriptions_; - LanguageMap categories_; + QList categories_; QMap param_names_; QMap > combo_names_; QMap > combo_descriptions_; diff --git a/app/node/node.cpp b/app/node/node.cpp index 49c48cfdb..7a149d3ad 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -127,12 +127,6 @@ QString Node::ShortName() const return Name(); } -QString Node::Category() const -{ - // Return an empty category for any nodes that don't use one - return QString(); -} - QString Node::Description() const { // Return an empty string by default @@ -560,6 +554,35 @@ void Node::DisconnectAll() } } +QString Node::GetCategoryName(const CategoryID &c) +{ + switch (c) { + case kCategoryInput: + return tr("Input"); + case kCategoryOutput: + return tr("Output"); + case kCategoryGeneral: + return tr("General"); + case kCategoryMath: + return tr("Math"); + case kCategoryColor: + return tr("Color"); + case kCategoryFilter: + return tr("Filter"); + case kCategoryTimeline: + return tr("Timeline"); + case kCategoryGenerator: + return tr("Generator"); + case kCategoryChannels: + return tr("Channel"); + case kCategoryUnknown: + case kCategoryCount: + break; + } + + return tr("Uncategorized"); +} + QList Node::TransformTimeTo(const TimeRange &time, Node *target, NodeParam::Type direction) { QList paths_found; diff --git a/app/node/node.h b/app/node/node.h index 3b5d09f09..f9f64898d 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -61,6 +61,22 @@ public: kSampleProcessor = 0x2 }; + enum CategoryID { + kCategoryUnknown = -1, + + kCategoryInput, + kCategoryOutput, + kCategoryGenerator, + kCategoryMath, + kCategoryFilter, + kCategoryColor, + kCategoryGeneral, + kCategoryTimeline, + kCategoryChannels, + + kCategoryCount + }; + Node(); virtual ~Node() override; @@ -115,7 +131,7 @@ public: * interpreted as an empty string category. This value should be run through a translator as its largely user * oriented. */ - virtual QString Category() const; + virtual QList Category() const = 0; /** * @brief Return a description of this node's purpose (optional for subclassing, but recommended) @@ -241,6 +257,11 @@ public: */ void DisconnectAll(); + /** + * @brief Get the human-readable name for any category + */ + static QString GetCategoryName(const CategoryID &c); + /** * @brief Transforms time from this node through the connections it takes to get to the specified node */ diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index da545cd6e..9d6f75b53 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -80,9 +80,9 @@ QString TrackOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.track"); } -QString TrackOutput::Category() const +QList TrackOutput::Category() const { - return tr("Output"); + return {kCategoryTimeline}; } QString TrackOutput::Description() const diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 0922d54fc..781c4eb96 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -44,7 +44,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; QString GetTrackName(); diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index e06c5443d..445598cb0 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -72,9 +72,9 @@ QString ViewerOutput::id() const return QStringLiteral("org.olivevideoeditor.Olive.vieweroutput"); } -QString ViewerOutput::Category() const +QList ViewerOutput::Category() const { - return tr("Output"); + return {kCategoryOutput}; } QString ViewerOutput::Description() const diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index 57101b67a..3a5b3fa78 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -49,7 +49,7 @@ public: virtual QString Name() const override; virtual QString id() const override; - virtual QString Category() const override; + virtual QList Category() const override; virtual QString Description() const override; NodeInput* texture_input() const; diff --git a/app/shaders/alphaover.xml b/app/shaders/alphaover.xml index e9df1a47b..0f98ea7f0 100644 --- a/app/shaders/alphaover.xml +++ b/app/shaders/alphaover.xml @@ -4,7 +4,7 @@ Alpha Over - Blend + 3 diff --git a/app/shaders/blur.xml b/app/shaders/blur.xml index 2d49a43b6..6942d8749 100644 --- a/app/shaders/blur.xml +++ b/app/shaders/blur.xml @@ -4,7 +4,7 @@ Blur - Blur + 4 diff --git a/app/shaders/crossdissolve.xml b/app/shaders/crossdissolve.xml index 7e7c1855f..3338f6e86 100644 --- a/app/shaders/crossdissolve.xml +++ b/app/shaders/crossdissolve.xml @@ -4,7 +4,7 @@ Cross Dissolve - Transition + diff --git a/app/shaders/diptoblack.xml b/app/shaders/diptoblack.xml index 7a4127ded..1bca1af4e 100644 --- a/app/shaders/diptoblack.xml +++ b/app/shaders/diptoblack.xml @@ -4,7 +4,7 @@ Dip to Black - Transition + From 0628ddb901db15e3facd02d8458291ae4019f09a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 23:24:00 +1000 Subject: [PATCH 06/12] nodes: use different colors from config based on category --- app/config/config.cpp | 10 ++++++++++ app/render/color.cpp | 5 +++++ app/render/color.h | 4 ++++ app/widget/colorwheel/colorswatchwidget.cpp | 4 +--- app/widget/nodeview/nodeviewitem.cpp | 14 ++++++++++++-- app/widget/nodeview/nodeviewitem.h | 7 ------- 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/app/config/config.cpp b/app/config/config.cpp index 6870ad296..a5d031c47 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -83,6 +83,16 @@ void Config::SetDefaults() config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; config_map_["Loop"] = false; + config_map_["NodeCatColor0"] = QVariant::fromValue(Color(0.25, 0.25, 0.65)); + config_map_["NodeCatColor1"] = QVariant::fromValue(Color(0.6, 0.6, 0.85)); + config_map_["NodeCatColor2"] = QVariant::fromValue(Color(0.75, 0.75, 0.45)); + config_map_["NodeCatColor3"] = QVariant::fromValue(Color(0.25, 0.5, 0.25)); + config_map_["NodeCatColor4"] = QVariant::fromValue(Color(0.25, 0.65, 0.25)); + config_map_["NodeCatColor5"] = QVariant::fromValue(Color(0.35, 0.35, 0.35)); + config_map_["NodeCatColor6"] = QVariant::fromValue(Color(0.45, 0.45, 0.45)); + config_map_["NodeCatColor7"] = QVariant::fromValue(Color(0.7, 0.3, 0.7)); + config_map_["NodeCatColor8"] = QVariant::fromValue(Color(0.85, 0.65, 0.4)); + config_map_["AudioOutput"] = QString(); config_map_["AudioInput"] = QString(); diff --git a/app/render/color.cpp b/app/render/color.cpp index 14f7e62e1..1a520b175 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -207,6 +207,11 @@ QColor Color::toQColor() const return c; } +float Color::GetRoughLuminance() const +{ + return (2*red()+blue()+3*green())/6.0f; +} + const Color &Color::operator+=(const Color &rhs) { for (int i=0;i 0.66) { + if (GetSelectedColor().GetRoughLuminance() > 0.66) { return Qt::black; } else { return Qt::white; diff --git a/app/widget/nodeview/nodeviewitem.cpp b/app/widget/nodeview/nodeviewitem.cpp index 45eafa7e2..763b10281 100644 --- a/app/widget/nodeview/nodeviewitem.cpp +++ b/app/widget/nodeview/nodeviewitem.cpp @@ -28,6 +28,7 @@ #include "common/flipmodifiers.h" #include "common/qtutils.h" +#include "config/config.h" #include "core.h" #include "nodeview.h" #include "nodeviewscene.h" @@ -260,8 +261,11 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti // Draw the titlebar if (!hide_titlebar_ && node_) { + Color node_color = Config::Current()[QStringLiteral("NodeCatColor%1") + .arg(node_->Category().first())].value(); + painter->setPen(Qt::black); - painter->setBrush(css_proxy_.TitleBarColor()); + painter->setBrush(node_color.toQColor()); painter->drawRect(title_bar_rect_); @@ -293,6 +297,12 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti } } + if (node_color.GetRoughLuminance() > 0.66) { + painter->setPen(Qt::black); + } else { + painter->setPen(Qt::white); + } + // Draw the text in a rect (the rect is sized around text already in the constructor) painter->drawText(title_bar_rect_, Qt::AlignCenter, @@ -307,7 +317,7 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti if (option->state & QStyle::State_Selected) { border_pen.setColor(app_pal.color(QPalette::Highlight)); } else { - border_pen.setColor(css_proxy_.BorderColor()); + border_pen.setColor(Qt::black); } painter->setPen(border_pen); diff --git a/app/widget/nodeview/nodeviewitem.h b/app/widget/nodeview/nodeviewitem.h index 0a02b7e3e..226929872 100644 --- a/app/widget/nodeview/nodeviewitem.h +++ b/app/widget/nodeview/nodeviewitem.h @@ -130,13 +130,6 @@ private: */ QList node_inputs_; - /** - * @brief A QWidget that can receive CSS properties that NodeViewItem can use - * - * \see NodeViewItemWidget - */ - NodeViewItemWidget css_proxy_; - /** * @brief Rectangle of the Node's title bar (equal to rect() when collapsed) */ From af994cd1b6d8d1784434fa3d9c243d87ea26895b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 5 May 2020 23:47:03 +1000 Subject: [PATCH 07/12] preferences: added preference for node color scheme --- .../tabs/preferencesappearancetab.cpp | 57 ++++++++++++++++++- .../tabs/preferencesappearancetab.h | 11 ++++ app/render/color.cpp | 8 +++ app/render/color.h | 2 + 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index 0324fc661..4078c1f0f 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -20,10 +20,14 @@ #include "preferencesappearancetab.h" +#include #include #include +#include #include -#include + +#include "node/node.h" +#include "widget/colorbutton/colorbutton.h" OLIVE_NAMESPACE_ENTER @@ -44,7 +48,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() style_list_ = StyleManager::ListInternal(); - foreach (StyleDescriptor s, style_list_) { + foreach (const StyleDescriptor& s, style_list_) { style_->addItem(s.name(), s.path()); if (s.path() == StyleManager::GetStyle()) { @@ -52,10 +56,34 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() } } - appearance_layout->addWidget(style_, row, 1, 1, 2); + appearance_layout->addWidget(style_, row, 1); row++; + { + QGroupBox* color_group = new QGroupBox(); + color_group->setTitle(tr("Node Color Scheme")); + + QGridLayout* color_layout = new QGridLayout(color_group); + + for (int i=0; i(i)); + color_layout->addWidget(new QLabel(cat_name), i, 0); + + Color c = Config::Current()[QStringLiteral("NodeCatColor%1").arg(i)].value(); + colors_.append(c.toQColor()); + + QPushButton* color_btn = new QPushButton(); + connect(color_btn, &QPushButton::clicked, this, &PreferencesAppearanceTab::ColorButtonClicked); + color_layout->addWidget(color_btn, i, 1); + color_btns_.append(color_btn); + + UpdateButtonColor(i); + } + + appearance_layout->addWidget(color_group, row, 0, 1, 2); + } + layout->addStretch(); } @@ -67,6 +95,29 @@ void PreferencesAppearanceTab::Accept() StyleManager::SetStyle(style_path); Config::Current()["Style"] = style_path; } + + for (int i=0;isetStyleSheet(QStringLiteral("background: %1;") + .arg(colors_.at(index).name())); +} + +void PreferencesAppearanceTab::ColorButtonClicked() +{ + int index = color_btns_.indexOf(static_cast(sender())); + + QColor new_color = QColorDialog::getColor(colors_.at(index), this); + + if (new_color.isValid()) { + colors_.replace(index, new_color); + + UpdateButtonColor(index); + } } OLIVE_NAMESPACE_EXIT diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.h b/app/dialog/preferences/tabs/preferencesappearancetab.h index cf3b97d71..1ab267eb5 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.h +++ b/app/dialog/preferences/tabs/preferencesappearancetab.h @@ -23,6 +23,7 @@ #include #include +#include #include "preferencestab.h" #include "ui/style/style.h" @@ -43,6 +44,8 @@ private: */ void BrowseForCSS(); + void UpdateButtonColor(int index); + /** * @brief UI widget for selecting the current UI style */ @@ -54,6 +57,14 @@ private: QList style_list_; QString custom_style_path_; + + QList colors_; + + QList color_btns_; + +private slots: + void ColorButtonClicked(); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/color.cpp b/app/render/color.cpp index 1a520b175..e0b20d6e2 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -78,6 +78,14 @@ Color::Color(const char *data, const PixelFormat::Format &format) } } +Color::Color(const QColor &c) +{ + set_red(c.redF()); + set_green(c.greenF()); + set_blue(c.blueF()); + set_alpha(c.alphaF()); +} + void Color::toHsv(float *hue, float *sat, float *val) const { float fCMax = qMax(qMax(red(), green()), blue()); diff --git a/app/render/color.h b/app/render/color.h index 385a26932..f2e6070d8 100644 --- a/app/render/color.h +++ b/app/render/color.h @@ -52,6 +52,8 @@ public: Color(const char *data, const PixelFormat::Format &format); + Color(const QColor& c); + /** * @brief Creates a Color struct from hue/saturation/value * From 17876410b5c93b84d2ab0a0c168739ff65e1d7a9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 6 May 2020 00:10:10 +1000 Subject: [PATCH 08/12] rewrote OCIO C locale patch Previous build was getting optimized out. This one shouldn't. --- app/render/colormanager.cpp | 16 +++++++++++-- app/render/colormanager.h | 45 +++++------------------------------ app/render/colorprocessor.cpp | 2 ++ 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/app/render/colormanager.cpp b/app/render/colormanager.cpp index 0ecd73f83..5b2cc1838 100644 --- a/app/render/colormanager.cpp +++ b/app/render/colormanager.cpp @@ -51,7 +51,7 @@ OCIO::ConstConfigRcPtr ColorManager::GetConfig() const OCIO::ConstConfigRcPtr ColorManager::CreateConfigFromFile(const QString &filename) { - SetCLocale(); + OCIO_SET_C_LOCALE_FOR_SCOPE; return OCIO::Config::CreateFromFile(filename.toUtf8()); } @@ -68,10 +68,11 @@ OCIO::ConstConfigRcPtr ColorManager::GetDefaultConfig() void ColorManager::SetUpDefaultConfig() { + OCIO_SET_C_LOCALE_FOR_SCOPE; + if (!qgetenv("OCIO").isEmpty()) { // Attempt to set config from "OCIO" environment variable try { - SetCLocale(); default_config_ = OCIO::Config::CreateFromEnv(); return; @@ -381,4 +382,15 @@ void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *d } } +ColorManager::SetLocale::SetLocale(const char* new_locale) +{ + old_locale_ = setlocale(LC_NUMERIC, nullptr); + setlocale(LC_NUMERIC, new_locale); +} + +ColorManager::SetLocale::~SetLocale() +{ + setlocale(LC_NUMERIC, old_locale_.toUtf8()); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/render/colormanager.h b/app/render/colormanager.h index f6ffb3349..e4e6ff1d8 100644 --- a/app/render/colormanager.h +++ b/app/render/colormanager.h @@ -26,6 +26,8 @@ #include "codec/frame.h" #include "colorprocessor.h" +#define OCIO_SET_C_LOCALE_FOR_SCOPE ColorManager::SetLocale d("C") + OLIVE_NAMESPACE_ENTER class ColorManager : public QObject @@ -92,50 +94,15 @@ public: static void SetOCIOMethodForMode(RenderMode::Mode mode, OCIOMethod method); - class SetCLocale + class SetLocale { public: - SetCLocale() - { -#ifdef Q_OS_WINDOWS - // set locale will only change locale on the current thread - previousThreadConfig = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + SetLocale(const char* new_locale); - // get and store current locale - ssaLocale.convert(setlocale(LC_ALL, NULL)); - - // set to "C" locale - setlocale(LC_ALL, "C"); -#else - // set to C locale, saving the old one (returned from useLocale) - currentLocale = newlocale(LC_ALL_MASK,"C",NULL); - oldLocale = uselocale(currentLocale); -#endif - } - - ~SetCLocale() - { -#ifdef Q_OS_WINDOWS - // thread specific - setlocale(LC_ALL, ssaLocale.c_str()); - - // set back to global settings] - _configthreadlocale(previousThreadConfig); -#else - // restore the previous locale and freeing the created locale - uselocale(oldLocale); - freelocale(currentLocale); -#endif - } + ~SetLocale(); private: -#ifdef Q_OS_WINDOWS - SoStringA ssaLocale; - int previousThreadConfig; -#else - locale_t oldLocale; - locale_t currentLocale; -#endif + QString old_locale_; }; diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 6f4a18e52..4b98a5133 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -44,10 +44,12 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const display_transform->setLooksOverrideEnabled(true); } + OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(display_transform); } else { + OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); From 721f6a79b472964bb057491c0ae88de94012f079 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 6 May 2020 00:22:43 +1000 Subject: [PATCH 09/12] mild conform to the rest of the code --- app/widget/scope/waveform/waveform.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 842cc678c..daefe84e7 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -98,8 +98,7 @@ void WaveformScope::DrawScope() QFontMetrics font_metrics = QFontMetrics(QFont()); QString label; float ire_increment = 0.1f; - // Cast required to avoid floating point errors - int ire_steps = static_cast(std::round(1.0 / ire_increment)); + int ire_steps = qRound(1.0 / ire_increment); QVector ire_lines(ire_steps + 1); int font_x_offset = 0; int font_y_offset = font_metrics.capHeight() / 2.0f; From fb625cb76ecb919674f71f02c44a722f80b320e7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 6 May 2020 15:06:37 +1000 Subject: [PATCH 10/12] nodes: removed XML infrastructure --- app/codec/oiio/oiiodecoder.cpp | 7 +- app/node/CMakeLists.txt | 5 +- app/node/block/transition/CMakeLists.txt | 2 - .../block/transition/externaltransition.cpp | 93 ---- app/node/external.cpp | 95 ----- app/node/factory.cpp | 21 +- app/node/factory.h | 4 + app/node/filter/CMakeLists.txt | 23 + app/node/filter/blur/CMakeLists.txt | 22 + app/node/filter/blur/blur.cpp | 104 +++++ .../blur/blur.h} | 30 +- app/node/filter/stroke/CMakeLists.txt | 22 + app/node/filter/stroke/stroke.cpp | 95 +++++ .../{external.h => filter/stroke/stroke.h} | 33 +- app/node/generator/CMakeLists.txt | 1 + app/node/generator/solid/CMakeLists.txt | 22 + app/node/generator/solid/solid.cpp | 76 ++++ app/node/generator/solid/solid.h | 52 +++ app/node/math/CMakeLists.txt | 1 + app/node/math/merge/CMakeLists.txt | 22 + app/node/math/merge/merge.cpp | 85 ++++ app/node/math/merge/merge.h | 57 +++ app/node/metareader.cpp | 398 ------------------ app/node/metareader.h | 92 ---- app/node/output/track/tracklist.cpp | 7 +- app/shaders/CMakeLists.txt | 10 +- app/shaders/alphaover.xml | 24 -- app/shaders/blur.xml | 70 --- app/shaders/crossdissolve.xml | 16 - app/shaders/diptoblack.xml | 16 - app/shaders/dropshadow.frag | 62 --- app/shaders/dropshadow.xml | 64 --- app/shaders/shaders.qrc | 22 - app/shaders/shaders.qrc.in | 5 + app/shaders/solid.xml | 31 -- app/shaders/stroke.frag | 7 +- app/shaders/stroke.xml | 55 --- 37 files changed, 661 insertions(+), 1090 deletions(-) delete mode 100644 app/node/block/transition/externaltransition.cpp delete mode 100644 app/node/external.cpp create mode 100644 app/node/filter/CMakeLists.txt create mode 100644 app/node/filter/blur/CMakeLists.txt create mode 100644 app/node/filter/blur/blur.cpp rename app/node/{block/transition/externaltransition.h => filter/blur/blur.h} (76%) create mode 100644 app/node/filter/stroke/CMakeLists.txt create mode 100644 app/node/filter/stroke/stroke.cpp rename app/node/{external.h => filter/stroke/stroke.h} (68%) create mode 100644 app/node/generator/solid/CMakeLists.txt create mode 100644 app/node/generator/solid/solid.cpp create mode 100644 app/node/generator/solid/solid.h create mode 100644 app/node/math/merge/CMakeLists.txt create mode 100644 app/node/math/merge/merge.cpp create mode 100644 app/node/math/merge/merge.h delete mode 100644 app/node/metareader.cpp delete mode 100644 app/node/metareader.h delete mode 100644 app/shaders/alphaover.xml delete mode 100644 app/shaders/blur.xml delete mode 100644 app/shaders/crossdissolve.xml delete mode 100644 app/shaders/diptoblack.xml delete mode 100644 app/shaders/dropshadow.frag delete mode 100644 app/shaders/dropshadow.xml delete mode 100644 app/shaders/shaders.qrc create mode 100644 app/shaders/shaders.qrc.in delete mode 100644 app/shaders/solid.xml delete mode 100644 app/shaders/stroke.xml diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 27e02991f..1f2b136b3 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -174,9 +174,10 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider FramePtr frame = Frame::Create(); - frame->set_video_params(VideoRenderingParams(buffer_->spec().width / divider, - buffer_->spec().height / divider, - pix_fmt_)); + frame->set_video_params(VideoRenderingParams(buffer_->spec().width, + buffer_->spec().height, + pix_fmt_, + divider)); frame->allocate(); if (divider == 1) { diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index 965982241..8930b3979 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(audio) add_subdirectory(block) +add_subdirectory(filter) add_subdirectory(generator) add_subdirectory(input) add_subdirectory(math) @@ -27,8 +28,6 @@ set(OLIVE_SOURCES node/dependency.cpp node/edge.h node/edge.cpp - node/external.h - node/external.cpp node/factory.h node/factory.cpp node/graph.h @@ -39,8 +38,6 @@ set(OLIVE_SOURCES node/inputarray.cpp node/keyframe.h node/keyframe.cpp - node/metareader.h - node/metareader.cpp node/node.h node/node.cpp node/output.h diff --git a/app/node/block/transition/CMakeLists.txt b/app/node/block/transition/CMakeLists.txt index 0ca1160b9..65f672588 100644 --- a/app/node/block/transition/CMakeLists.txt +++ b/app/node/block/transition/CMakeLists.txt @@ -16,8 +16,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - node/block/transition/externaltransition.h - node/block/transition/externaltransition.cpp node/block/transition/transition.h node/block/transition/transition.cpp PARENT_SCOPE diff --git a/app/node/block/transition/externaltransition.cpp b/app/node/block/transition/externaltransition.cpp deleted file mode 100644 index 798ae5b74..000000000 --- a/app/node/block/transition/externaltransition.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*** - - 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 "externaltransition.h" - -OLIVE_NAMESPACE_ENTER - -ExternalTransition::ExternalTransition(const QString &xml_meta_filename) : - meta_(xml_meta_filename) -{ - foreach (NodeInput* input, meta_.inputs()) { - AddInput(input); - } -} - -Node *ExternalTransition::copy() const -{ - return new ExternalTransition(meta_.filename()); -} - -QString ExternalTransition::Name() const -{ - return meta_.Name(); -} - -QString ExternalTransition::ShortName() const -{ - return meta_.ShortName(); -} - -QString ExternalTransition::id() const -{ - return meta_.id(); -} - -QList ExternalTransition::Category() const -{ - return meta_.Category(); -} - -QString ExternalTransition::Description() const -{ - return meta_.Description(); -} - -void ExternalTransition::Retranslate() -{ - meta_.Retranslate(); -} - -Node::Capabilities ExternalTransition::GetCapabilities(const NodeValueDatabase &) const -{ - return kShader; -} - -QString ExternalTransition::ShaderVertexCode(const NodeValueDatabase &) const -{ - return meta_.vert_code(); -} - -QString ExternalTransition::ShaderFragmentCode(const NodeValueDatabase&) const -{ - return meta_.frag_code(); -} - -int ExternalTransition::ShaderIterations() const -{ - return meta_.iterations(); -} - -NodeInput *ExternalTransition::ShaderIterativeInput() const -{ - return meta_.iteration_input(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/external.cpp b/app/node/external.cpp deleted file mode 100644 index eddcf43be..000000000 --- a/app/node/external.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/*** - - 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 "external.h" - -#include - -OLIVE_NAMESPACE_ENTER - -ExternalNode::ExternalNode(const QString &xml_meta_filename) : - meta_(xml_meta_filename) -{ - foreach (NodeInput* input, meta_.inputs()) { - AddInput(input); - } -} - -Node *ExternalNode::copy() const -{ - return new ExternalNode(meta_.filename()); -} - -QString ExternalNode::Name() const -{ - return meta_.Name(); -} - -QString ExternalNode::ShortName() const -{ - return meta_.ShortName(); -} - -QString ExternalNode::id() const -{ - return meta_.id(); -} - -QList ExternalNode::Category() const -{ - return meta_.Category(); -} - -QString ExternalNode::Description() const -{ - return meta_.Description(); -} - -void ExternalNode::Retranslate() -{ - meta_.Retranslate(); -} - -Node::Capabilities ExternalNode::GetCapabilities(const NodeValueDatabase &) const -{ - return kShader; -} - -QString ExternalNode::ShaderVertexCode(const NodeValueDatabase&) const -{ - return meta_.vert_code(); -} - -QString ExternalNode::ShaderFragmentCode(const NodeValueDatabase&) const -{ - return meta_.frag_code(); -} - -int ExternalNode::ShaderIterations() const -{ - return meta_.iterations(); -} - -NodeInput *ExternalNode::ShaderIterativeInput() const -{ - return meta_.iteration_input(); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/factory.cpp b/app/node/factory.cpp index fe7361389..32846849a 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -24,16 +24,18 @@ #include "audio/volume/volume.h" #include "block/clip/clip.h" #include "block/gap/gap.h" -#include "block/transition/externaltransition.h" #include "generator/matrix/matrix.h" +#include "generator/solid/solid.h" +#include "filter/blur/blur.h" +#include "filter/stroke/stroke.h" #include "input/media/video/video.h" #include "input/media/audio/audio.h" #include "input/time/timeinput.h" #include "math/math/math.h" +#include "math/merge/merge.h" #include "math/trigonometry/trigonometry.h" #include "output/track/track.h" #include "output/viewer/viewer.h" -#include "external.h" OLIVE_NAMESPACE_ENTER QList NodeFactory::library_; @@ -47,13 +49,10 @@ void NodeFactory::Initialize() library_.append(CreateInternal(static_cast(i))); } - library_.append(new ExternalNode(":/shaders/blur.xml")); - library_.append(new ExternalNode(":/shaders/solid.xml")); - library_.append(new ExternalNode(":/shaders/stroke.xml")); - library_.append(new ExternalNode(":/shaders/alphaover.xml")); - library_.append(new ExternalNode(":/shaders/dropshadow.xml")); + /* library_.append(new ExternalTransition(":/shaders/crossdissolve.xml")); library_.append(new ExternalTransition(":/shaders/diptoblack.xml")); + */ } void NodeFactory::Destroy() @@ -152,6 +151,14 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id) return new TrigonometryNode(); case kTime: return new TimeInput(); + case kBlurFilter: + return new BlurFilterNode(); + case kSolidGenerator: + return new SolidGenerator(); + case kMerge: + return new MergeNode(); + case kStrokeFilter: + return new StrokeFilterNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index c6329de7e..1068d103c 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -44,6 +44,10 @@ public: kMath, kTime, kTrigonometry, + kBlurFilter, + kSolidGenerator, + kMerge, + kStrokeFilter, // Count value kInternalNodeCount diff --git a/app/node/filter/CMakeLists.txt b/app/node/filter/CMakeLists.txt new file mode 100644 index 000000000..4d7db901d --- /dev/null +++ b/app/node/filter/CMakeLists.txt @@ -0,0 +1,23 @@ +# 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 . + +add_subdirectory(blur) +add_subdirectory(stroke) + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + PARENT_SCOPE +) diff --git a/app/node/filter/blur/CMakeLists.txt b/app/node/filter/blur/CMakeLists.txt new file mode 100644 index 000000000..50bd90ad5 --- /dev/null +++ b/app/node/filter/blur/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/filter/blur/blur.h + node/filter/blur/blur.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp new file mode 100644 index 000000000..64d634d0c --- /dev/null +++ b/app/node/filter/blur/blur.cpp @@ -0,0 +1,104 @@ +/*** + + 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 "blur.h" + +OLIVE_NAMESPACE_ENTER + +BlurFilterNode::BlurFilterNode() +{ + texture_input_ = new NodeInput("tex_in", NodeParam::kTexture); + AddInput(texture_input_); + + method_input_ = new NodeInput("method_in", NodeParam::kCombo, 0); + AddInput(method_input_); + + radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); + radius_input_->set_property(QStringLiteral("min"), 0.0f); + AddInput(radius_input_); + + horiz_input_ = new NodeInput("horiz_in", NodeParam::kBoolean, true); + AddInput(horiz_input_); + + vert_input_ = new NodeInput("vert_in", NodeParam::kBoolean, true); + AddInput(vert_input_); + + repeat_edge_pixels_input_ = new NodeInput("repeat_edge_pixels_in", NodeParam::kBoolean, false); + AddInput(repeat_edge_pixels_input_); +} + +Node *BlurFilterNode::copy() const +{ + return new BlurFilterNode(); +} + +QString BlurFilterNode::Name() const +{ + return tr("Blur"); +} + +QString BlurFilterNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.blur"); +} + +QList BlurFilterNode::Category() const +{ + return {kCategoryFilter}; +} + +QString BlurFilterNode::Description() const +{ + return tr("Blurs an image."); +} + +void BlurFilterNode::Retranslate() +{ + texture_input_->set_name(tr("Input")); + method_input_->set_name(tr("Method")); + method_input_->set_combobox_strings({ tr("Box"), tr("Gaussian") }); + radius_input_->set_name(tr("Radius")); + horiz_input_->set_name(tr("Horizontal")); + vert_input_->set_name(tr("Vertical")); + repeat_edge_pixels_input_->set_name(tr("Repeat Edge Pixels")); +} + +Node::Capabilities BlurFilterNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString BlurFilterNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/blur.frag"); +} + +int BlurFilterNode::ShaderIterations() const +{ + // FIXME: Optimize if horiz_in or vert_in is disabled + return 2; +} + +NodeInput *BlurFilterNode::ShaderIterativeInput() const +{ + return texture_input_; +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/transition/externaltransition.h b/app/node/filter/blur/blur.h similarity index 76% rename from app/node/block/transition/externaltransition.h rename to app/node/filter/blur/blur.h index 5962ecf9d..142f03985 100644 --- a/app/node/block/transition/externaltransition.h +++ b/app/node/filter/blur/blur.h @@ -18,24 +18,21 @@ ***/ -#ifndef EXTERNALTRANSITION_H -#define EXTERNALTRANSITION_H +#ifndef BLURFILTERNODE_H +#define BLURFILTERNODE_H -#include "transition.h" - -#include "node/metareader.h" +#include "node/node.h" OLIVE_NAMESPACE_ENTER -class ExternalTransition : public TransitionBlock +class BlurFilterNode : public Node { public: - ExternalTransition(const QString& xml_meta_filename); + BlurFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; - virtual QString ShortName() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; @@ -43,15 +40,26 @@ public: virtual void Retranslate() override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; - virtual QString ShaderVertexCode(const NodeValueDatabase&) const override; virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; + virtual int ShaderIterations() const override; virtual NodeInput* ShaderIterativeInput() const override; private: - NodeMetaReader meta_; + NodeInput* texture_input_; + + NodeInput* method_input_; + + NodeInput* radius_input_; + + NodeInput* horiz_input_; + + NodeInput* vert_input_; + + NodeInput* repeat_edge_pixels_input_; + }; OLIVE_NAMESPACE_EXIT -#endif // EXTERNALTRANSITION_H +#endif // BLURFILTERNODE_H diff --git a/app/node/filter/stroke/CMakeLists.txt b/app/node/filter/stroke/CMakeLists.txt new file mode 100644 index 000000000..212f3bfe2 --- /dev/null +++ b/app/node/filter/stroke/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/filter/stroke/stroke.h + node/filter/stroke/stroke.cpp + PARENT_SCOPE +) diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp new file mode 100644 index 000000000..e87449db2 --- /dev/null +++ b/app/node/filter/stroke/stroke.cpp @@ -0,0 +1,95 @@ +/*** + + 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 "stroke.h" + +#include "render/color.h" + +OLIVE_NAMESPACE_ENTER + +StrokeFilterNode::StrokeFilterNode() +{ + tex_input_ = new NodeInput("tex_in", NodeParam::kTexture); + AddInput(tex_input_); + + color_input_ = new NodeInput("color_in", + NodeParam::kColor, + QVariant::fromValue(Color(1.0f, 1.0f, 1.0f, 1.0f))); + AddInput(color_input_); + + radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); + radius_input_->set_property("min", 0.0f); + AddInput(radius_input_); + + opacity_input_ = new NodeInput("opacity_in", NodeParam::kFloat, 1.0f); + opacity_input_->set_property("view", "percent"); + opacity_input_->set_property("min", 0.0f); + opacity_input_->set_property("max", 1.0f); + AddInput(opacity_input_); + + inner_input_ = new NodeInput("inner_in", NodeParam::kBoolean, false); + AddInput(inner_input_); +} + +Node *StrokeFilterNode::copy() const +{ + return new StrokeFilterNode(); +} + +QString StrokeFilterNode::Name() const +{ + return tr("Stroke"); +} + +QString StrokeFilterNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.stroke"); +} + +QList StrokeFilterNode::Category() const +{ + return {kCategoryFilter}; +} + +QString StrokeFilterNode::Description() const +{ + return tr("Creates a stroke outline around an image."); +} + +void StrokeFilterNode::Retranslate() +{ + tex_input_->set_name(tr("Input")); + color_input_->set_name(tr("Color")); + radius_input_->set_name(tr("Radius")); + opacity_input_->set_name(tr("Opacity")); + inner_input_->set_name(tr("Inner")); +} + +Node::Capabilities StrokeFilterNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString StrokeFilterNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/stroke.frag"); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/external.h b/app/node/filter/stroke/stroke.h similarity index 68% rename from app/node/external.h rename to app/node/filter/stroke/stroke.h index 046539534..06eb97f64 100644 --- a/app/node/external.h +++ b/app/node/filter/stroke/stroke.h @@ -18,28 +18,21 @@ ***/ -#ifndef EXTERNALNODE_H -#define EXTERNALNODE_H +#ifndef STROKEFILTERNODE_H +#define STROKEFILTERNODE_H -#include - -#include "node.h" -#include "metareader.h" +#include "node/node.h" OLIVE_NAMESPACE_ENTER -/** - * @brief A node generated from an external XML metadata file - */ -class ExternalNode : public Node +class StrokeFilterNode : public Node { public: - ExternalNode(const QString& xml_meta_filename); + StrokeFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; - virtual QString ShortName() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; @@ -47,15 +40,21 @@ public: virtual void Retranslate() override; virtual Capabilities GetCapabilities(const NodeValueDatabase&) const override; - virtual QString ShaderVertexCode(const NodeValueDatabase&) const override; virtual QString ShaderFragmentCode(const NodeValueDatabase&) const override; - virtual int ShaderIterations() const override; - virtual NodeInput* ShaderIterativeInput() const override; private: - NodeMetaReader meta_; + NodeInput* tex_input_; + + NodeInput* color_input_; + + NodeInput* radius_input_; + + NodeInput* opacity_input_; + + NodeInput* inner_input_; + }; OLIVE_NAMESPACE_EXIT -#endif // EXTERNALNODE_H +#endif // STROKEFILTERNODE_H diff --git a/app/node/generator/CMakeLists.txt b/app/node/generator/CMakeLists.txt index 9e8d25261..21566cbeb 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(solid) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/generator/solid/CMakeLists.txt b/app/node/generator/solid/CMakeLists.txt new file mode 100644 index 000000000..df388a97d --- /dev/null +++ b/app/node/generator/solid/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/solid/solid.h + node/generator/solid/solid.cpp + PARENT_SCOPE +) diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp new file mode 100644 index 000000000..d2ef7fd74 --- /dev/null +++ b/app/node/generator/solid/solid.cpp @@ -0,0 +1,76 @@ +/*** + + 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 "solid.h" + +#include "render/color.h" + +OLIVE_NAMESPACE_ENTER + +SolidGenerator::SolidGenerator() +{ + // Default to a color that isn't black + color_input_ = new NodeInput("color_in", + NodeInput::kColor, + QVariant::fromValue(Color(1.0f, 0.0f, 0.0f, 1.0f))); + AddInput(color_input_); +} + +Node *SolidGenerator::copy() const +{ + return new SolidGenerator(); +} + +QString SolidGenerator::Name() const +{ + return tr("Solid"); +} + +QString SolidGenerator::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.solidgenerator"); +} + +QList SolidGenerator::Category() const +{ + return {kCategoryGenerator}; +} + +QString SolidGenerator::Description() const +{ + return tr("Generate a solid color."); +} + +void SolidGenerator::Retranslate() +{ + color_input_->set_name(tr("Color")); +} + +Node::Capabilities SolidGenerator::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString SolidGenerator::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/solid.frag"); +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h new file mode 100644 index 000000000..8e5433e69 --- /dev/null +++ b/app/node/generator/solid/solid.h @@ -0,0 +1,52 @@ +/*** + + 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 SOLIDGENERATOR_H +#define SOLIDGENERATOR_H + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class SolidGenerator : public Node +{ +public: + SolidGenerator(); + + virtual Node* copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QList 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; + +private: + NodeInput* color_input_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // SOLIDGENERATOR_H diff --git a/app/node/math/CMakeLists.txt b/app/node/math/CMakeLists.txt index 1ae06847e..32ad7e923 100644 --- a/app/node/math/CMakeLists.txt +++ b/app/node/math/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(math) +add_subdirectory(merge) add_subdirectory(trigonometry) set(OLIVE_SOURCES diff --git a/app/node/math/merge/CMakeLists.txt b/app/node/math/merge/CMakeLists.txt new file mode 100644 index 000000000..a7472ded0 --- /dev/null +++ b/app/node/math/merge/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/math/merge/merge.h + node/math/merge/merge.cpp + PARENT_SCOPE +) diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp new file mode 100644 index 000000000..d154aa8b2 --- /dev/null +++ b/app/node/math/merge/merge.cpp @@ -0,0 +1,85 @@ +/*** + + 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 "merge.h" + +OLIVE_NAMESPACE_ENTER + +MergeNode::MergeNode() +{ + base_in_ = new NodeInput("base_in", NodeParam::kTexture); + AddInput(base_in_); + + blend_in_ = new NodeInput("blend_in", NodeParam::kTexture); + AddInput(blend_in_); +} + +Node *MergeNode::copy() const +{ + return new MergeNode(); +} + +QString MergeNode::Name() const +{ + return tr("Merge"); +} + +QString MergeNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.merge"); +} + +QList MergeNode::Category() const +{ + return {kCategoryMath}; +} + +QString MergeNode::Description() const +{ + return tr("Merge two textures together."); +} + +void MergeNode::Retranslate() +{ + base_in_->set_name(tr("Base")); + blend_in_->set_name(tr("Blend")); +} + +Node::Capabilities MergeNode::GetCapabilities(const NodeValueDatabase &) const +{ + return kShader; +} + +QString MergeNode::ShaderFragmentCode(const NodeValueDatabase &) const +{ + return ReadFileAsString(":/shaders/alphaover.frag"); +} + +NodeInput *MergeNode::base_in() const +{ + return base_in_; +} + +NodeInput *MergeNode::blend_in() const +{ + return blend_in_; +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h new file mode 100644 index 000000000..fda931a8e --- /dev/null +++ b/app/node/math/merge/merge.h @@ -0,0 +1,57 @@ +/*** + + 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 MERGENODE_H +#define MERGENODE_H + +#include "node/node.h" + +OLIVE_NAMESPACE_ENTER + +class MergeNode : public Node +{ +public: + MergeNode(); + + virtual Node* copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QList 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; + + NodeInput* base_in() const; + NodeInput* blend_in() const; + +private: + NodeInput* base_in_; + + NodeInput* blend_in_; + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // MERGENODE_H diff --git a/app/node/metareader.cpp b/app/node/metareader.cpp deleted file mode 100644 index e09386df4..000000000 --- a/app/node/metareader.cpp +++ /dev/null @@ -1,398 +0,0 @@ -/*** - - 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 "metareader.h" - -#include - -#include "common/xmlutils.h" -#include "config/config.h" -#include "node.h" - -OLIVE_NAMESPACE_ENTER - -NodeMetaReader::NodeMetaReader(const QString &xml_meta_filename) : - xml_filename_(xml_meta_filename), - iterations_(1), - iteration_input_(nullptr) -{ - QFile metadata_file(xml_filename_); - - if (metadata_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&metadata_file); - - while (XMLReadNextStartElement(&reader)) { - if (reader.name() == QStringLiteral("effect")) { - XMLReadEffect(&reader); - } else { - reader.skipCurrentElement(); - } - } - - metadata_file.close(); - } else { - qWarning() << "Failed to load node metadata file" << xml_filename_; - } -} - -QString NodeMetaReader::Name() const -{ - return GetStringForCurrentLanguage(&names_); -} - -QString NodeMetaReader::ShortName() const -{ - if (short_names_.isEmpty()) { - return Name(); - } else { - return GetStringForCurrentLanguage(&short_names_); - } -} - -const QString &NodeMetaReader::id() const -{ - return id_; -} - -QList NodeMetaReader::Category() const -{ - return categories_; -} - -QString NodeMetaReader::Description() const -{ - return GetStringForCurrentLanguage(&descriptions_); -} - -const QString &NodeMetaReader::filename() const -{ - return xml_filename_; -} - -const QString &NodeMetaReader::frag_code() const -{ - return frag_code_; -} - -const QString &NodeMetaReader::vert_code() const -{ - return vert_code_; -} - -const int &NodeMetaReader::iterations() const -{ - return iterations_; -} - -NodeInput *NodeMetaReader::iteration_input() const -{ - return iteration_input_; -} - -const QList &NodeMetaReader::inputs() const -{ - return inputs_; -} - -void NodeMetaReader::Retranslate() -{ - { - // Re-translate every parameter name - QMap::const_iterator iterator; - - // Iterate through parameter language tables that we have - for (iterator=param_names_.begin();iterator!=param_names_.end();iterator++) { - NodeInput* this_input = GetInputWithID(iterator.key()); - this_input->set_name(GetStringForCurrentLanguage(&iterator.value())); - } - } - - { - // Re-translate any combobox items - QMap >::const_iterator param_it; - - for (param_it=combo_names_.begin(); param_it!=combo_names_.end(); param_it++) { - NodeInput* input = GetInputWithID(param_it.key()); - - QStringList combo_items; - - foreach (const LanguageMap& lang_map, param_it.value()) { - combo_items.append(GetStringForCurrentLanguage(&lang_map)); - } - - input->set_combobox_strings(combo_items); - } - } -} - -void NodeMetaReader::XMLReadLanguageString(QXmlStreamReader* reader, LanguageMap* map) -{ - QString lang; - - // Traverse through name attributes for its language - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("lang")) { - lang = attr.value().toString(); - - // We don't recognize any other "name" attributes at this time - break; - } - } - - // Insert name with language into map - map->insert(lang, reader->readElementText().trimmed()); -} - -void NodeMetaReader::XMLReadEffect(QXmlStreamReader* reader) -{ - // Traverse through effect attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("id")) { - id_ = attr.value().toString(); - - // We don't recognize any other "effect" attributes at this time - break; - } - } - - if (id_.isEmpty()) { - qWarning() << "Effect metadata" << xml_filename_ << "has no ID"; - return; - } - - // Continue reading for other metadata - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("name")) { - // Pick up name - XMLReadLanguageString(reader, &names_); - } else if (reader->name() == QStringLiteral("shortnames")) { - // Pick up short name - XMLReadLanguageString(reader, &short_names_); - } else if (reader->name() == QStringLiteral("category")) { - // Pick up category - QStringList category_ids = reader->readElementText().split(':'); - - foreach (const QString& id, category_ids) { - bool ok; - - int try_parse = id.toInt(&ok); - - if (!ok || try_parse < 0 || try_parse >= Node::kCategoryCount) { - continue; - } - - categories_.append(static_cast(try_parse)); - } - } else if (reader->name() == QStringLiteral("description")) { - // Pick up description - XMLReadLanguageString(reader, &descriptions_); - } else if (reader->name() == QStringLiteral("iterations")) { - // Pick up iterations - XMLReadIterations(reader); - } else if (reader->name() == QStringLiteral("fragment")) { - // Pick up fragment shader code - XMLReadShader(reader, frag_code_); - } else if (reader->name() == QStringLiteral("vertex")) { - // Pick up vertex shader code - XMLReadShader(reader, vert_code_); - } else if (reader->name() == QStringLiteral("param")) { - // Pick up a parameter - XMLReadParam(reader); - } else { - reader->skipCurrentElement(); - } - } -} - -void NodeMetaReader::XMLReadIterations(QXmlStreamReader* reader) -{ - int iteration_pickup = reader->readElementText().toInt(); - - if (iterations_ > 0) { - iterations_ = iteration_pickup; - } else { - // If the iteration value is invalid, don't set it, print an error instead - qWarning() << "Invalid iteration number in" << xml_filename_ << "- setting to default (1)"; - } -} - -void NodeMetaReader::XMLReadParam(QXmlStreamReader *reader) -{ - QString param_id; - NodeParam::DataType param_type = NodeParam::kAny; - bool is_iterative = false; - - // Traverse through parameter attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("id")) { - param_id = attr.value().toString(); - } else if (attr.name() == QStringLiteral("type")) { - param_type = NodeParam::StringToDataType(attr.value().toString()); - } else if (attr.name() == QStringLiteral("iterative_input")) { - is_iterative = true; - } - } - - if (param_id.isEmpty()) { - qWarning() << "Effect metadata" << xml_filename_ << "contains a parameter with no ID - parameter was not added"; - return; - } - - QVector default_val; - QHash properties; - LanguageMap param_names; - QList combo_names; - QList combo_descriptions; - - // Traverse through param contents for more data - while (XMLReadNextStartElement(reader)) { - // NOTE: readElementText() returns a string, but for number types (which min and max apply to), QVariant will - // convert them automatically - if (reader->name() == QStringLiteral("name")) { - - // Insert language into map - XMLReadLanguageString(reader, ¶m_names); - - } else if (reader->name() == QStringLiteral("default")) { - - // Reads the default value - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("value")) { - default_val.append(NodeInput::StringToValue(param_type, reader->readElementText())); - } else { - reader->skipCurrentElement(); - } - } - - } else if (reader->name() == QStringLiteral("option")) { - - // Read names and descriptions - LanguageMap names; - LanguageMap descriptions; - - while (XMLReadNextStartElement(reader)) { - if (reader->name() == QStringLiteral("name")) { - XMLReadLanguageString(reader, &names); - } else if (reader->name() == QStringLiteral("description")) { - XMLReadLanguageString(reader, &descriptions); - } else { - reader->skipCurrentElement(); - } - } - - combo_names.append(names); - combo_descriptions.append(descriptions); - - } else { - properties.insert(reader->name().toString(), reader->readElementText()); - } - } - - param_names_.insert(param_id, param_names); - - // Insert combo options if they exist - if (!combo_names.isEmpty()) { - combo_names_.insert(param_id, combo_names); - combo_descriptions_.insert(param_id, combo_descriptions); - } - - NodeInput* input = new NodeInput(param_id, param_type, default_val); - - QHash::const_iterator iterator; - - for (iterator=properties.begin();iterator!=properties.end();iterator++) { - input->set_property(iterator.key(), iterator.value()); - } - - if (is_iterative) { - iteration_input_ = input; - } - - inputs_.append(input); -} - -void NodeMetaReader::XMLReadShader(QXmlStreamReader *reader, QString &destination) -{ - QString code_url; - - // Traverse through parameter attributes for an ID - XMLAttributeLoop(reader, attr) { - if (attr.name() == QStringLiteral("url")) { - code_url = attr.value().toString(); - - // We don't recognize any other "shader" attributes at this time - break; - } - } - - // Add code in file from URL - if (!code_url.isEmpty()) { - destination.append(Node::ReadFileAsString(code_url)); - } - - // Add any code that's inline in the XML - QString element_text = reader->readElementText().trimmed(); - if (!element_text.isEmpty()) { - destination.append(element_text); - } -} - -QString NodeMetaReader::GetStringForCurrentLanguage(const LanguageMap *language_map) -{ - if (language_map->isEmpty()) { - // There are no entries for this map, this must be an empty string - return QString(); - } - - // Get current language config - QString language = Config::Current()[QStringLiteral("Language")].toString(); - - // See if our map has an exact language match - QString str_for_lang = language_map->value(language); - if (!str_for_lang.isEmpty()) { - return str_for_lang; - } - - // If not, try to find a match with the same language but not the same derivation - QString base_lang = language.split('_').first(); - QList available_languages = language_map->keys(); - foreach (const QString& l, available_languages) { - if (l.startsWith(base_lang)) { - // This is the same language, so we can return this - return language_map->value(l); - } - } - - // We couldn't find an exact or close match, just return the first in the list - // (assume a string in the wrong language is better than no string at all) - return language_map->first(); -} - -NodeInput *NodeMetaReader::GetInputWithID(const QString &id) const -{ - foreach (NodeInput* input, inputs_) { - if (input->id() == id) { - return input; - } - } - return nullptr; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/node/metareader.h b/app/node/metareader.h deleted file mode 100644 index 9efb6441d..000000000 --- a/app/node/metareader.h +++ /dev/null @@ -1,92 +0,0 @@ -/*** - - 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 NODEMETAREADER_H -#define NODEMETAREADER_H - -#include -#include -#include - -#include "input.h" -#include "node/node.h" - -OLIVE_NAMESPACE_ENTER - -class NodeMetaReader -{ -public: - NodeMetaReader(const QString& xml_meta_filename); - - QString Name() const; - QString ShortName() const; - const QString& id() const; - QList Category() const; - QString Description() const; - - const QString& filename() const; - - const QString& frag_code() const; - const QString& vert_code() const; - - const int& iterations() const; - NodeInput* iteration_input() const; - - const QList& inputs() const; - - void Retranslate(); - -private: - using LanguageMap = QMap; - - void XMLReadLanguageString(QXmlStreamReader* reader, LanguageMap *map); - void XMLReadEffect(QXmlStreamReader *reader); - void XMLReadIterations(QXmlStreamReader* reader); - void XMLReadParam(QXmlStreamReader* reader); - void XMLReadShader(QXmlStreamReader* reader, QString& destination); - - static QString GetStringForCurrentLanguage(const LanguageMap *language_map); - - NodeInput* GetInputWithID(const QString& id) const; - - QString xml_filename_; - - LanguageMap names_; - LanguageMap short_names_; - LanguageMap descriptions_; - QList categories_; - QMap param_names_; - QMap > combo_names_; - QMap > combo_descriptions_; - - QString id_; - - QString frag_code_; - QString vert_code_; - - int iterations_; - NodeInput* iteration_input_; - - QList inputs_; -}; - -OLIVE_NAMESPACE_EXIT - -#endif // NODEMETAREADER_H diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index 07b7678c0..6165c11fb 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -22,6 +22,7 @@ #include "node/factory.h" #include "node/math/math/math.h" +#include "node/math/merge/merge.h" #include "node/output/viewer/viewer.h" OLIVE_NAMESPACE_ENTER @@ -104,11 +105,11 @@ TrackOutput* TrackList::AddTrack() switch (type_) { case Timeline::kTrackTypeVideo: { - Node* blend = NodeFactory::CreateFromID(QStringLiteral("org.olivevideoeditor.Olive.alphaoverblend")); + MergeNode* blend = new MergeNode(); GetParentGraph()->AddNode(blend); - NodeParam::ConnectEdge(track->output(), static_cast(blend->GetInputWithID("blend_in"))); - NodeParam::ConnectEdge(last_track->output(), static_cast(blend->GetInputWithID("base_in"))); + NodeParam::ConnectEdge(track->output(), blend->blend_in()); + NodeParam::ConnectEdge(last_track->output(), blend->base_in()); NodeParam::ConnectEdge(blend->output(), edge->input()); break; } diff --git a/app/shaders/CMakeLists.txt b/app/shaders/CMakeLists.txt index 762945e1b..a9ad28c12 100644 --- a/app/shaders/CMakeLists.txt +++ b/app/shaders/CMakeLists.txt @@ -14,8 +14,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +file(GLOB_RECURSE SHADER_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.frag *.vert) +set(QRC_BODY "") +foreach(SHADER_FILE ${SHADER_RESOURCES}) + string(APPEND QRC_BODY "${SHADER_FILE}\n") + configure_file(${SHADER_FILE} ${SHADER_FILE} COPYONLY) +endforeach() +configure_file(shaders.qrc.in shaders.qrc @ONLY) + set(OLIVE_RESOURCES ${OLIVE_RESOURCES} - shaders/shaders.qrc + ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc PARENT_SCOPE ) diff --git a/app/shaders/alphaover.xml b/app/shaders/alphaover.xml deleted file mode 100644 index 0f98ea7f0..000000000 --- a/app/shaders/alphaover.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - Alpha Over - - - 3 - - - - A blending node that composites one texture over another using its alpha channel. - - - - - Base - - - Blend - - - - - diff --git a/app/shaders/blur.xml b/app/shaders/blur.xml deleted file mode 100644 index 6942d8749..000000000 --- a/app/shaders/blur.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - Blur - - - 4 - - - - Blurs an image. - - - - - Input - - - - - Method - - - - - - - Radius - 0 - - 10 - - - - - - Horizontal - - 1 - - - - - - Vertical - - 1 - - - - - - Repeat Edge Pixels - - 0 - - - - - - - - 2 - diff --git a/app/shaders/crossdissolve.xml b/app/shaders/crossdissolve.xml deleted file mode 100644 index 3338f6e86..000000000 --- a/app/shaders/crossdissolve.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Cross Dissolve - - - - - - - A smooth fade transition from one video clip to another. - - - - - diff --git a/app/shaders/diptoblack.xml b/app/shaders/diptoblack.xml deleted file mode 100644 index 1bca1af4e..000000000 --- a/app/shaders/diptoblack.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Dip to Black - - - - - - - A smooth dip to transparency and back into another clip. - - - - - diff --git a/app/shaders/dropshadow.frag b/app/shaders/dropshadow.frag deleted file mode 100644 index 0a35c7517..000000000 --- a/app/shaders/dropshadow.frag +++ /dev/null @@ -1,62 +0,0 @@ -#version 150 - -#define M_PI 3.1415926535897932384626433832795 - -uniform sampler2D tex_in; -uniform vec3 color_in; -uniform float softness_in; -uniform float opacity_in; -uniform float distance_in; -uniform float direction_in; - -uniform vec2 ove_resolution; - -in vec2 ove_texcoord; - -out vec4 fragColor; - -void main(void) { - // Use pythagoras with the distance (hypotenuse) to find the shadow offset - float direction_radians = direction_in * (M_PI / 180.0); - - float opposite = sin(direction_radians) * distance_in; - float adjacent = cos(direction_radians) * distance_in; - - vec2 angle = vec2(adjacent, opposite); - - // Convert distance from pixels to 0.0 - 1.0 texture coordinates - angle /= ove_resolution; - - float shadow_alpha; - - // For a soft shadow, we use a box blur-like formula - if (softness_in > 0.0) { - float radius = ceil(softness_in); - float divider = 1.0 / pow(softness_in, 2.0); - shadow_alpha = 0.0; - - for (float x = -radius + 0.5; x <= radius; x += 2.0) { - for (float y = -radius + 0.5; y <= radius; y += 2.0) { - vec2 pixel_coord = ove_texcoord - angle; - pixel_coord.x += x / ove_resolution.x; - pixel_coord.y += y / ove_resolution.y; - vec4 pixel_color = texture(tex_in, pixel_coord); - - shadow_alpha += pixel_color.a * divider; - } - } - } else { - // Perfectly hard shadow - vec4 src_color = texture(tex_in, ove_texcoord - angle); - shadow_alpha = src_color.a; - } - - vec4 shadow_px = vec4(color_in, shadow_alpha * opacity_in * 0.01); - - // Get current pixel and perform an alpha over for it over the shadow we've made - vec4 dst_color = texture(tex_in, ove_texcoord); - shadow_px *= (1.0 - dst_color.a); - shadow_px += dst_color; - - fragColor = shadow_px; -} diff --git a/app/shaders/dropshadow.xml b/app/shaders/dropshadow.xml deleted file mode 100644 index 20e77fb84..000000000 --- a/app/shaders/dropshadow.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - Drop Shadow - - - Stylize - Stylise - - - - Generate a drop shadow of a clip. - - - - - Input - - - - - Color - Colour - - - - - Softness - 0 - - 10 - - - - - - Opacity - 0 - - 80 - - 100 - - - - - Distance - 0 - - 10 - - - - - - Direction - - 45 - - - - - - diff --git a/app/shaders/shaders.qrc b/app/shaders/shaders.qrc deleted file mode 100644 index 7e6f4876c..000000000 --- a/app/shaders/shaders.qrc +++ /dev/null @@ -1,22 +0,0 @@ - - - alphaover.frag - alphaover.xml - blur.frag - blur.xml - colorgradient.frag - colorwheel.frag - crossdissolve.frag - crossdissolve.xml - dropshadow.frag - dropshadow.xml - diptoblack.frag - diptoblack.xml - rgbwaveform.frag - solid.frag - solid.xml - stroke.frag - stroke.xml - matrix.vert - - diff --git a/app/shaders/shaders.qrc.in b/app/shaders/shaders.qrc.in new file mode 100644 index 000000000..e1366f006 --- /dev/null +++ b/app/shaders/shaders.qrc.in @@ -0,0 +1,5 @@ + + + @QRC_BODY@ + + diff --git a/app/shaders/solid.xml b/app/shaders/solid.xml deleted file mode 100644 index d45fef56f..000000000 --- a/app/shaders/solid.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - Solid - - - Generator - - - - Generate a solid color. - - - Generate a solid colour. - - - - - Color - Colour - - 1.0 - 0.0 - 0.0 - 1.0 - - - - - - diff --git a/app/shaders/stroke.frag b/app/shaders/stroke.frag index 8d43b34ea..bdd7d2691 100644 --- a/app/shaders/stroke.frag +++ b/app/shaders/stroke.frag @@ -2,7 +2,7 @@ // Node parameter inputs uniform sampler2D tex_in; -uniform vec3 color_in; +uniform vec4 color_in; uniform float radius_in; uniform float opacity_in; uniform bool inner_in; @@ -61,15 +61,14 @@ void main(void) { } } - stroke_weight *= opacity_in * 0.01; + stroke_weight *= opacity_in; if (inner_in) { stroke_weight *= pixel_here.a; } // Make RGBA color - vec4 stroke_col = vec4(vec3(1.0) * stroke_weight, stroke_weight); - //vec4 stroke_col = vec4(color_in * stroke_weight, stroke_weight); + vec4 stroke_col = color_in * stroke_weight; if (inner_in) { // Alpha over the stroke over the texture diff --git a/app/shaders/stroke.xml b/app/shaders/stroke.xml deleted file mode 100644 index 1f562eef0..000000000 --- a/app/shaders/stroke.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - Stroke - - - Stylize - Stylise - - - - Creates a stroke outline around an image. - - - - - Input - - - - - Color - Colour - - - - - Radius - 0 - - 10 - - - - - - Opacity - 0 - - 100 - - 100 - - - - - Inner - - false - - - - - - From d49c6a059cdc06e9c5c4eac45e002fd485c9c91c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 6 May 2020 15:56:39 +1000 Subject: [PATCH 11/12] nodes: optimize blocks so they don't unnecessarily change the hash --- app/node/block/block.cpp | 5 +++++ app/node/block/block.h | 2 ++ app/node/block/clip/clip.cpp | 9 +++++++++ app/node/block/clip/clip.h | 2 ++ app/node/block/transition/transition.cpp | 10 ++++++++-- app/node/output/track/track.cpp | 4 ++-- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 98c716678..1597d737d 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -365,4 +365,9 @@ void Block::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput * Node::InvalidateCache(range, from, source); } +void Block::Hash(QCryptographicHash &, const rational &) const +{ + // A block does nothing by default +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/block.h b/app/node/block/block.h index ca3c6b613..f69b568b8 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -99,6 +99,8 @@ public: virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source) override; + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + public slots: signals: diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 8db5efdd5..413050d98 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -119,4 +119,13 @@ void ClipBlock::Retranslate() texture_input_->set_name(tr("Buffer")); } +void ClipBlock::Hash(QCryptographicHash &hash, const rational &time) const +{ + if (texture_input_->IsConnected()) { + rational t = InputTimeAdjustment(texture_input_, TimeRange(time, time)).in(); + + texture_input_->get_connected_node()->Hash(hash, t); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 56f81c927..375f319ce 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -54,6 +54,8 @@ public: virtual void Retranslate() override; + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + signals: void PreviewUpdated(); diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index cdb0b8489..e0d66e69e 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -131,8 +131,6 @@ double TransitionBlock::GetInProgress(const rational &time) const void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const { - Block::Hash(hash, time); - double all_prog = GetTotalProgress(time); double in_prog = GetInProgress(time); double out_prog = GetOutProgress(time); @@ -140,6 +138,14 @@ void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const hash.addData(reinterpret_cast(&all_prog), sizeof(double)); hash.addData(reinterpret_cast(&in_prog), sizeof(double)); hash.addData(reinterpret_cast(&out_prog), sizeof(double)); + + if (out_block_input_->IsConnected()) { + out_block_input_->get_connected_node()->Hash(hash, time); + } + + if (in_block_input_->IsConnected()) { + in_block_input_->get_connected_node()->Hash(hash, time); + } } double TransitionBlock::GetInternalTransitionTime(const rational &time) const diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 9d6f75b53..240dc514e 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -420,11 +420,11 @@ NodeInputArray *TrackOutput::block_input() const void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const { - // Resolve block list Block* b = BlockAtTime(time); + // Defer to block at this time, don't add any of our own information to the hash if (b) { - return b->Hash(hash, time); + b->Hash(hash, time); } } From 78e305a593e2f597f19b424a14a31636adefd9cb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 6 May 2020 16:14:27 +1000 Subject: [PATCH 12/12] mergenode: optimize so null textures (gaps, etc.) don't affect the hash --- app/node/math/merge/merge.cpp | 11 +++++++++++ app/node/math/merge/merge.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index d154aa8b2..e5c039a6e 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -82,4 +82,15 @@ NodeInput *MergeNode::blend_in() const return blend_in_; } +void MergeNode::Hash(QCryptographicHash &hash, const rational &time) const +{ + if (base_in_->IsConnected()) { + base_in_->get_connected_node()->Hash(hash, time); + } + + if (blend_in_->IsConnected()) { + blend_in_->get_connected_node()->Hash(hash, time); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index fda931a8e..63a17cb2d 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -45,6 +45,8 @@ public: NodeInput* base_in() const; NodeInput* blend_in() const; + virtual void Hash(QCryptographicHash &hash, const rational &time) const override; + private: NodeInput* base_in_;