From ff2eac55a53dd230830d2e74c13f387c50f67b0c Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 1 Feb 2022 16:12:08 +0000 Subject: [PATCH 01/96] First attempt at adding OCIO to nodes --- app/node/color/CMakeLists.txt | 2 + .../color/displaytransform/CMakeLists.txt | 22 +++ .../displaytransform/displaytransform.cpp | 108 +++++++++++ .../color/displaytransform/displaytransform.h | 54 ++++++ app/node/color/ociobase/CMakeLists.txt | 22 +++ app/node/color/ociobase/ociobase.cpp | 35 ++++ app/node/color/ociobase/ociobase.h | 51 +++++ app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/render/renderer.cpp | 175 +++++++++++------- app/render/renderer.h | 8 + app/shaders/displaytransform.frag | 12 ++ 12 files changed, 429 insertions(+), 64 deletions(-) create mode 100644 app/node/color/displaytransform/CMakeLists.txt create mode 100644 app/node/color/displaytransform/displaytransform.cpp create mode 100644 app/node/color/displaytransform/displaytransform.h create mode 100644 app/node/color/ociobase/CMakeLists.txt create mode 100644 app/node/color/ociobase/ociobase.cpp create mode 100644 app/node/color/ociobase/ociobase.h create mode 100644 app/shaders/displaytransform.frag diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index afaa401ff..ca29ad8db 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -15,6 +15,8 @@ # along with this program. If not, see . add_subdirectory(colormanager) +add_subdirectory(displaytransform) +add_subdirectory(ociobase) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/color/displaytransform/CMakeLists.txt b/app/node/color/displaytransform/CMakeLists.txt new file mode 100644 index 000000000..4bede1600 --- /dev/null +++ b/app/node/color/displaytransform/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/color/displaytransform/displaytransform.cpp + node/color/displaytransform/displaytransform.h + PARENT_SCOPE +) diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp new file mode 100644 index 000000000..dcaed76d0 --- /dev/null +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -0,0 +1,108 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "displaytransform.h" + +#include "node/project/project.h" +#include "render/colorprocessor.h" + +namespace olive { + +const QString DisplayTransformNode::kTextureInput = QStringLiteral("tex_in"); +const QString DisplayTransformNode::kDirectionInput = QStringLiteral("dir_in"); + +DisplayTransformNode::DisplayTransformNode() +{ + AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + AddInput(kDirectionInput, NodeValue::kCombo, 0); + + GenerateProcessor(true); +} + +void DisplayTransformNode::GenerateProcessor(bool direction) +{ + if (!project()) { + return; + } + reference_to_display_ = ColorProcessor::Create(project()->color_manager(), project()->color_manager()->GetReferenceColorSpace(), + project()->color_manager()->GetDefaultDisplay()); + + // Create shader description + shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); + shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); + shader_desc_->setFunctionName("DisplayTransform"); + shader_desc_->setResourcePrefix("ocio_"); + + // Generate shader + reference_to_display_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); +} + +Node *DisplayTransformNode::copy() const +{ + return new DisplayTransformNode(); +} + +QString DisplayTransformNode::Name() const +{ + return tr("Display Transform"); +} + +QString DisplayTransformNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.disaplaytransform"); +} + +QVector DisplayTransformNode::Category() const +{ + return {kCategoryColor}; +} + +QString DisplayTransformNode::Description() const +{ + return tr("Converts an image to/from display space"); +} + +void DisplayTransformNode::Retranslate() +{ + SetInputName(kTextureInput, tr("Input")); + SetInputName(kDirectionInput, tr("Direction")); + SetComboBoxStrings(kDirectionInput, {tr("Forward"), tr("Inverse")}); + GenerateProcessor(true); +} + +ShaderCode DisplayTransformNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + // Generate shader code using OCIO stub and our auto-generated name + QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/displaytransform.frag")) + .arg(shader_desc_->getShaderText()); + return ShaderCode(shader_frag); +} + +void DisplayTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + ShaderJob job; + job.InsertValue(value); + + renderer()->ShaderJobInsertTextures(reference_to_display_, &job, shader_desc_); + + // If there's no texture, no need to run an operation + if (!job.GetValue(kTextureInput).data().isNull()) { + table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); + } +} + +} diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h new file mode 100644 index 000000000..4975d49b7 --- /dev/null +++ b/app/node/color/displaytransform/displaytransform.h @@ -0,0 +1,54 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 DISPLAYTRANSFORMNODE_H +#define DISPLAYTRANSFORMNODE_H + +#include "node/color/ociobase/ociobase.h" + +namespace olive { +class DisplayTransformNode : public OCIONodeBase { + Q_OBJECT + public: + DisplayTransformNode(); + + NODE_DEFAULT_DESTRUCTOR(DisplayTransformNode) + + void GenerateProcessor(bool direction); + + virtual Node *copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QVector Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + + static const QString kTextureInput; + static const QString kDirectionInput; + + const QString shader_text_; + + ColorProcessorPtr reference_to_display_; + OCIO::GpuShaderDescRcPtr shader_desc_; +}; + +} // olive + +#endif diff --git a/app/node/color/ociobase/CMakeLists.txt b/app/node/color/ociobase/CMakeLists.txt new file mode 100644 index 000000000..fa00411a4 --- /dev/null +++ b/app/node/color/ociobase/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/color/ociobase/ociobase.cpp + node/color/ociobase/ociobase.h + PARENT_SCOPE +) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp new file mode 100644 index 000000000..2c4e2fdcc --- /dev/null +++ b/app/node/color/ociobase/ociobase.cpp @@ -0,0 +1,35 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "ociobase.h" + +#include "render/opengl/openglrenderer.h" + +namespace olive { + +OCIONodeBase::OCIONodeBase() +{ + if (true){//RenderManager::instance()->backend() == RenderManager::kOpenGL) { + // Create OpenGL renderer + attached_renderer_ = new OpenGLRenderer(this); + } +} + +} diff --git a/app/node/color/ociobase/ociobase.h b/app/node/color/ociobase/ociobase.h new file mode 100644 index 000000000..e74a97cb0 --- /dev/null +++ b/app/node/color/ociobase/ociobase.h @@ -0,0 +1,51 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 OCIOBASE_H +#define OCIOBASE_H + +#include "node/node.h" +#include "render/rendermanager.h" + +namespace olive { + +class OCIONodeBase : public Node +{ +public: + OCIONodeBase(); + + NODE_DEFAULT_DESTRUCTOR(OCIONodeBase); + +protected: + Renderer* renderer() const + { + return attached_renderer_; + } + + /** + * @brief Renderer abstraction + */ + Renderer* attached_renderer_; +}; + + +} // olive + +#endif // OCIOBASE_H diff --git a/app/node/factory.cpp b/app/node/factory.cpp index ed4645a60..ef6d262f0 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -29,6 +29,7 @@ #include "block/subtitle/subtitle.h" #include "block/transition/crossdissolve/crossdissolvetransition.h" #include "block/transition/diptocolor/diptocolortransition.h" +#include "color/displaytransform/displaytransform.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" #include "distort/transform/transformdistortnode.h" @@ -261,6 +262,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new FlipDistortNode(); case kNoiseGenerator: return new NoiseGeneratorNode(); + case kDisplayTransform: + return new DisplayTransformNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index c91895ff3..e7cca6a1e 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -65,6 +65,7 @@ public: kOpacityEffect, kFlipDistort, kNoiseGenerator, + kDisplayTransform, // Count value kInternalNodeCount diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index a3701c2ff..ef04d964f 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -62,6 +62,23 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); } +void Renderer::ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, + OCIO::GpuShaderDescRcPtr shader_desc) { + ColorContext color_ctx; + if (!GetCustomColorContext(color_processor, &color_ctx, shader_desc)) { + return; + } + + foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { + job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); + job->SetInterpolation(l.name, l.interpolation); + } + foreach (const ColorContext::LUT& l, color_ctx.lut1d_textures) { + job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); + job->SetInterpolation(l.name, l.interpolation); + } +} + TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms) { color_cache_mutex_.lock(); @@ -103,6 +120,95 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } +bool Renderer::GetCustomColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext* ctx, + OCIO::GpuShaderDescRcPtr shader_desc) { + QMutexLocker locker(&color_cache_mutex_); + + ColorContext& color_ctx = *ctx; + + if (color_cache_.contains(color_processor->id())) { + color_ctx = color_cache_.value(color_processor->id()); + return true; + } else { + if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { + return true; + } else { + qCritical() << "Failed to allocate OCIO shader textures"; + return false; + } + } +} + +bool Renderer::SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, + ColorProcessorPtr color_processor) { + color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); + for (unsigned int i = 0; i < shader_desc->getNum3DTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int edge_len = 0; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); + + if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !edge_len) { + qCritical() << "3D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->get3DTextureValues(i, values); + if (!values) { + qCritical() << "3D LUT texture values are missing"; + return false; + } + + // Allocate 3D LUT + color_ctx.lut3d_textures[i].texture = CreateTexture( + VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), + Texture::k3D, values); + color_ctx.lut3d_textures[i].name = sampler_name; + color_ctx.lut3d_textures[i].interpolation = + (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); + for (unsigned int i = 0; i < shader_desc->getNumTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int width = 0, height = 0; + OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); + + if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !width) { + qCritical() << "1D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->getTextureValues(i, values); + if (!values) { + qCritical() << "1D LUT texture values are missing"; + return false; + } + + // Allocate 1D LUT + color_ctx.lut1d_textures[i].texture = CreateTexture( + VideoParams(width, height, VideoParams::kFormatFloat32, + (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), + Texture::k2D, values); + color_ctx.lut1d_textures[i].name = sampler_name; + color_ctx.lut1d_textures[i].interpolation = + (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_cache_.insert(color_processor->id(), color_ctx); + + return true; + +} + bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) { QMutexLocker locker(&color_cache_mutex_); @@ -137,71 +243,12 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo return false; } - color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); - for (unsigned int i=0; igetNum3DTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int edge_len = 0; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); - - if (!tex_name || !*tex_name - || !sampler_name || !*sampler_name - || !edge_len) { - qCritical() << "3D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->get3DTextureValues(i, values); - if (!values) { - qCritical() << "3D LUT texture values are missing"; - return false; - } - - // Allocate 3D LUT - color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), - Texture::k3D, values); - color_ctx.lut3d_textures[i].name = sampler_name; - color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { + return true; + } else { + qCritical() << "Failed to allocate OCIO shader textures"; + return false; } - - color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); - for (unsigned int i=0; igetNumTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int width = 0, height = 0; - OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); - - if (!tex_name || !*tex_name - || !sampler_name || !*sampler_name - || !width) { - qCritical() << "1D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->getTextureValues(i, values); - if (!values) { - qCritical() << "1D LUT texture values are missing"; - return false; - } - - // Allocate 1D LUT - color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), - Texture::k2D, - values); - color_ctx.lut1d_textures[i].name = sampler_name; - color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; - } - - color_cache_.insert(color_processor->id(), color_ctx); - - return true; } } diff --git a/app/render/renderer.h b/app/render/renderer.h index 977fc98ce..ef41dfa93 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -63,6 +63,8 @@ public: Blit(shader, job, nullptr, params, clear_destination); } + void ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, OCIO::GpuShaderDescRcPtr shader_desc); + enum AlphaAssociated { kAlphaNone, kAlphaUnassociated, @@ -128,6 +130,12 @@ private: bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); + bool GetCustomColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, + OCIO::GpuShaderDescRcPtr shader_desc); + + bool SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, + ColorProcessorPtr color_processor); + void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, VideoParams params, bool clear_destination, diff --git a/app/shaders/displaytransform.frag b/app/shaders/displaytransform.frag new file mode 100644 index 000000000..e42554cf7 --- /dev/null +++ b/app/shaders/displaytransform.frag @@ -0,0 +1,12 @@ +uniform sampler2D tex_in; + +// Program will replace this with OCIO's auto-generated shader code +%1 + +void main() { + col = texture2D(tex_in, ove_texcoord); + + col = DIsplayTransform(col) + + gl_FragColor - col; +} From ac070dbc1a8a60e51883ffb409b7af75d7c21883 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 1 Feb 2022 18:44:08 +0000 Subject: [PATCH 02/96] Actually init GL renderer --- .../color/displaytransform/displaytransform.cpp | 13 ++++++++++++- app/node/color/displaytransform/displaytransform.h | 1 + app/node/color/ociobase/ociobase.cpp | 2 ++ app/render/colorprocessor.cpp | 7 +++++-- app/shaders/displaytransform.frag | 5 +++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index dcaed76d0..66f7ebb82 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -37,8 +37,11 @@ void DisplayTransformNode::GenerateProcessor(bool direction) if (!project()) { return; } + qDebug() << project()->color_manager()->GetReferenceColorSpace() << project()->color_manager()->GetDefaultDisplay(); + + ColorTransform transform("sRGB OETF"); reference_to_display_ = ColorProcessor::Create(project()->color_manager(), project()->color_manager()->GetReferenceColorSpace(), - project()->color_manager()->GetDefaultDisplay()); + transform); // Create shader description shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); @@ -83,6 +86,14 @@ void DisplayTransformNode::Retranslate() GenerateProcessor(true); } +void DisplayTransformNode::InputValueChangedEvent(const QString& input, int element) +{ + Q_UNUSED(element); + if (input == kDirectionInput) { + GenerateProcessor(true); + } +} + ShaderCode DisplayTransformNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index 4975d49b7..485bd0171 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -36,6 +36,7 @@ class DisplayTransformNode : public OCIONodeBase { virtual QString Description() const override; virtual void Retranslate() override; + virtual void InputValueChangedEvent(const QString &input, int element) override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index 2c4e2fdcc..ebe7c9790 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -29,6 +29,8 @@ OCIONodeBase::OCIONodeBase() if (true){//RenderManager::instance()->backend() == RenderManager::kOpenGL) { // Create OpenGL renderer attached_renderer_ = new OpenGLRenderer(this); + attached_renderer_->Init(); + attached_renderer_->PostInit(); } } diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 9d981871f..6198b6d94 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -69,8 +69,11 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const } else { OCIO_SET_C_LOCALE_FOR_SCOPE; - processor_ = config->GetConfig()->getProcessor(input.toUtf8(), - output.toUtf8()); + try { + processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); + } catch (OCIO::Exception &e) { + qWarning() << "ColorProcessor exception:" << e.what(); + } } diff --git a/app/shaders/displaytransform.frag b/app/shaders/displaytransform.frag index e42554cf7..d547b074f 100644 --- a/app/shaders/displaytransform.frag +++ b/app/shaders/displaytransform.frag @@ -1,12 +1,13 @@ uniform sampler2D tex_in; +varying vec2 ove_texcoord; // Program will replace this with OCIO's auto-generated shader code %1 void main() { - col = texture2D(tex_in, ove_texcoord); + vec4 col = texture2D(tex_in, ove_texcoord); - col = DIsplayTransform(col) + col = DisplayTransform(col); gl_FragColor - col; } From 4d5ca96b689810cc980435326dc7522ff67baafb Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 1 Feb 2022 20:45:59 +0000 Subject: [PATCH 03/96] cleanup --- app/render/renderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index ef04d964f..8d97aa654 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -140,7 +140,8 @@ bool Renderer::GetCustomColorContext(ColorProcessorPtr color_processor, Renderer } bool Renderer::SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, - ColorProcessorPtr color_processor) { + ColorProcessorPtr color_processor) +{ color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); for (unsigned int i = 0; i < shader_desc->getNum3DTextures(); i++) { const char* tex_name = nullptr; From 979095d2e05939b94f7aa6dc535e13212b25c0fa Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 8 Mar 2022 14:40:03 +0000 Subject: [PATCH 04/96] Get OCIO node groundwork working --- app/node/color/CMakeLists.txt | 1 - .../displaytransform/displaytransform.cpp | 5 +- .../color/displaytransform/displaytransform.h | 8 ++- app/node/color/ociobase/CMakeLists.txt | 22 -------- app/node/color/ociobase/ociobase.cpp | 37 -------------- app/node/color/ociobase/ociobase.h | 51 ------------------- app/node/hashtraverser.cpp | 2 +- app/node/hashtraverser.h | 2 +- app/node/traverser.cpp | 2 +- app/node/traverser.h | 2 +- app/render/job/shaderjob.h | 39 ++++++++++++++ app/render/renderprocessor.cpp | 7 ++- app/render/renderprocessor.h | 2 +- app/shaders/displaytransform.frag | 2 +- 14 files changed, 61 insertions(+), 121 deletions(-) delete mode 100644 app/node/color/ociobase/CMakeLists.txt delete mode 100644 app/node/color/ociobase/ociobase.cpp delete mode 100644 app/node/color/ociobase/ociobase.h diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index ca29ad8db..43b005216 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(colormanager) add_subdirectory(displaytransform) -add_subdirectory(ociobase) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 66f7ebb82..10e9caac7 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -107,8 +107,11 @@ void DisplayTransformNode::Value(const NodeValueRow &value, const NodeGlobals &g { ShaderJob job; job.InsertValue(value); + job.SetUseOCIO(true); + job.SetShaderDesc(shader_desc_); + job.SetColorProcessor(reference_to_display_); - renderer()->ShaderJobInsertTextures(reference_to_display_, &job, shader_desc_); + //renderer()->ShaderJobInsertTextures(reference_to_display_, &job, shader_desc_); // If there's no texture, no need to run an operation if (!job.GetValue(kTextureInput).data().isNull()) { diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index 485bd0171..074677b75 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -16,10 +16,11 @@ #ifndef DISPLAYTRANSFORMNODE_H #define DISPLAYTRANSFORMNODE_H -#include "node/color/ociobase/ociobase.h" +#include "node/node.h" +#include "render/colorprocessor.h" namespace olive { -class DisplayTransformNode : public OCIONodeBase { +class DisplayTransformNode : public Node { Q_OBJECT public: DisplayTransformNode(); @@ -41,6 +42,9 @@ class DisplayTransformNode : public OCIONodeBase { virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + ColorProcessorPtr GetColorProcessor() { return reference_to_display_; }; + OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; + static const QString kTextureInput; static const QString kDirectionInput; diff --git a/app/node/color/ociobase/CMakeLists.txt b/app/node/color/ociobase/CMakeLists.txt deleted file mode 100644 index fa00411a4..000000000 --- a/app/node/color/ociobase/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Olive - Non-Linear Video Editor -# Copyright (C) 2021 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/color/ociobase/ociobase.cpp - node/color/ociobase/ociobase.h - PARENT_SCOPE -) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp deleted file mode 100644 index ebe7c9790..000000000 --- a/app/node/color/ociobase/ociobase.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 "ociobase.h" - -#include "render/opengl/openglrenderer.h" - -namespace olive { - -OCIONodeBase::OCIONodeBase() -{ - if (true){//RenderManager::instance()->backend() == RenderManager::kOpenGL) { - // Create OpenGL renderer - attached_renderer_ = new OpenGLRenderer(this); - attached_renderer_->Init(); - attached_renderer_->PostInit(); - } -} - -} diff --git a/app/node/color/ociobase/ociobase.h b/app/node/color/ociobase/ociobase.h deleted file mode 100644 index e74a97cb0..000000000 --- a/app/node/color/ociobase/ociobase.h +++ /dev/null @@ -1,51 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 OCIOBASE_H -#define OCIOBASE_H - -#include "node/node.h" -#include "render/rendermanager.h" - -namespace olive { - -class OCIONodeBase : public Node -{ -public: - OCIONodeBase(); - - NODE_DEFAULT_DESTRUCTOR(OCIONodeBase); - -protected: - Renderer* renderer() const - { - return attached_renderer_; - } - - /** - * @brief Renderer abstraction - */ - Renderer* attached_renderer_; -}; - - -} // olive - -#endif // OCIOBASE_H diff --git a/app/node/hashtraverser.cpp b/app/node/hashtraverser.cpp index c4b7fa9a5..155842242 100644 --- a/app/node/hashtraverser.cpp +++ b/app/node/hashtraverser.cpp @@ -86,7 +86,7 @@ SampleBufferPtr HashTraverser::ProcessAudioFootage(const FootageJob &stream, con return buf; } -TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) +TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) { HashGenerateJob(node, &job); diff --git a/app/node/hashtraverser.h b/app/node/hashtraverser.h index 4eb0eb5cd..39957c9ed 100644 --- a/app/node/hashtraverser.h +++ b/app/node/hashtraverser.h @@ -37,7 +37,7 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 754995a5d..d32941253 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -292,7 +292,7 @@ SampleBufferPtr NodeTraverser::ProcessAudioFootage(const FootageJob& stream, con return SampleBuffer::Create(); } -TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) +TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) { Q_UNUSED(node) Q_UNUSED(range) diff --git a/app/node/traverser.h b/app/node/traverser.h index 839c8561b..3af7a300c 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -76,7 +76,7 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time); - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job); virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job); diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h index 3bbbac19d..ba5ad1427 100644 --- a/app/render/job/shaderjob.h +++ b/app/render/job/shaderjob.h @@ -24,6 +24,7 @@ #include #include "generatejob.h" +#include "render/colorprocessor.h" #include "render/texture.h" namespace olive { @@ -34,6 +35,7 @@ public: { iterations_ = 1; iterative_input_ = nullptr; + use_ocio_ = false; } const QString& GetShaderID() const @@ -87,6 +89,38 @@ public: interpolation_.insert(id, interp); } + bool UseOCIO() const + { + return use_ocio_; + } + + void SetUseOCIO(bool use_ocio) + { + use_ocio_ = use_ocio; + } + + ColorProcessorPtr ColorProcessor() + { + return color_processor_; + } + + void SetColorProcessor(ColorProcessorPtr processor) + { + color_processor_ = processor; + } + + OCIO::GpuShaderDescRcPtr ShaderDesc() + { + return shader_desc_; + } + + void SetShaderDesc(OCIO::GpuShaderDescRcPtr shader_desc) + { + shader_desc_ = shader_desc; + } + + + private: QString shader_id_; @@ -96,6 +130,11 @@ private: QHash interpolation_; + bool use_ocio_; + + ColorProcessorPtr color_processor_; + OCIO::GpuShaderDescRcPtr shader_desc_; + }; } diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 01bd95518..015070d0b 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -27,6 +27,7 @@ #include "node/block/clip/clip.h" #include "node/block/transition/transition.h" +#include "node/color/displaytransform/displaytransform.h" #include "node/project/project.h" #include "rendermanager.h" @@ -464,7 +465,7 @@ SampleBufferPtr RenderProcessor::ProcessAudioFootage(const FootageJob &stream, c return super::ProcessAudioFootage(stream, input_time); } -TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) +TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) { Q_UNUSED(range) @@ -475,6 +476,10 @@ TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &ran QVariant shader = shader_cache_->value(full_shader_id); if (shader.isNull()) { + if (job.UseOCIO()) { + render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); + } + // Since we have shader code, compile it now shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 213b2df16..7d655a986 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -48,7 +48,7 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; diff --git a/app/shaders/displaytransform.frag b/app/shaders/displaytransform.frag index d547b074f..d597f47d2 100644 --- a/app/shaders/displaytransform.frag +++ b/app/shaders/displaytransform.frag @@ -9,5 +9,5 @@ void main() { col = DisplayTransform(col); - gl_FragColor - col; + gl_FragColor = col; } From 5c2f6a8e863e0f8a8c7c80e2d7634c386d54e9e3 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 8 Mar 2022 16:32:14 +0000 Subject: [PATCH 05/96] Mostly complete the display transform node --- .../displaytransform/displaytransform.cpp | 59 +++++++++++++++---- .../color/displaytransform/displaytransform.h | 7 ++- app/render/renderprocessor.cpp | 1 - 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 10e9caac7..19f8d4dc1 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -21,27 +21,36 @@ namespace olive { const QString DisplayTransformNode::kTextureInput = QStringLiteral("tex_in"); +const QString DisplayTransformNode::kDisplayInput = QStringLiteral("display_in"); +const QString DisplayTransformNode::kViewInput = QStringLiteral("view_in"); const QString DisplayTransformNode::kDirectionInput = QStringLiteral("dir_in"); DisplayTransformNode::DisplayTransformNode() { AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + AddInput(kDisplayInput, NodeValue::kCombo, 0); + + AddInput(kViewInput, NodeValue::kCombo, 0); + AddInput(kDirectionInput, NodeValue::kCombo, 0); - GenerateProcessor(true); + Retranslate(); } -void DisplayTransformNode::GenerateProcessor(bool direction) +void DisplayTransformNode::GenerateProcessor() { if (!project()) { return; } - qDebug() << project()->color_manager()->GetReferenceColorSpace() << project()->color_manager()->GetDefaultDisplay(); + if (view_.isEmpty()) { + Retranslate(); + } - ColorTransform transform("sRGB OETF"); - reference_to_display_ = ColorProcessor::Create(project()->color_manager(), project()->color_manager()->GetReferenceColorSpace(), - transform); + ColorTransform transform(display_, view_, ""); + + reference_to_display_ = ColorProcessor::Create(project()->color_manager(), + project()->color_manager()->GetReferenceColorSpace(), transform); // Create shader description shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); @@ -81,17 +90,43 @@ QString DisplayTransformNode::Description() const void DisplayTransformNode::Retranslate() { SetInputName(kTextureInput, tr("Input")); + SetInputName(kDisplayInput, tr("Display")); + SetInputName(kViewInput, tr("View")); + + if (project()) { + SetComboBoxStrings(kDisplayInput, project()->color_manager()->ListAvailableDisplays()); + display_ = project()->color_manager()->ListAvailableDisplays().at( + GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); + + SetComboBoxStrings(kViewInput, project()->color_manager()->ListAvailableViews(display_)); + view_ = project()->color_manager()->ListAvailableViews(display_).at( + GetSplitStandardValue(kViewInput).at(0).toString().toInt()); + } + SetInputName(kDirectionInput, tr("Direction")); SetComboBoxStrings(kDirectionInput, {tr("Forward"), tr("Inverse")}); - GenerateProcessor(true); } -void DisplayTransformNode::InputValueChangedEvent(const QString& input, int element) -{ - Q_UNUSED(element); +void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element) { + Q_UNUSED(element); if (input == kDirectionInput) { - GenerateProcessor(true); + GenerateProcessor(); } + if (project()) { + if (input == kDisplayInput) { + display_ = project()->color_manager()->ListAvailableDisplays().at( + GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); + // If we change the display the view menu must be updated + Retranslate(); + GenerateProcessor(); + } + if (input == kViewInput) { + view_ = project()->color_manager()->ListAvailableViews(display_).at( + GetSplitStandardValue(kViewInput).at(0).toString().toInt()); + GenerateProcessor(); + } + } + } ShaderCode DisplayTransformNode::GetShaderCode(const QString &shader_id) const @@ -110,8 +145,6 @@ void DisplayTransformNode::Value(const NodeValueRow &value, const NodeGlobals &g job.SetUseOCIO(true); job.SetShaderDesc(shader_desc_); job.SetColorProcessor(reference_to_display_); - - //renderer()->ShaderJobInsertTextures(reference_to_display_, &job, shader_desc_); // If there's no texture, no need to run an operation if (!job.GetValue(kTextureInput).data().isNull()) { diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index 074677b75..b50e73e29 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -27,7 +27,7 @@ class DisplayTransformNode : public Node { NODE_DEFAULT_DESTRUCTOR(DisplayTransformNode) - void GenerateProcessor(bool direction); + void GenerateProcessor(); virtual Node *copy() const override; @@ -46,12 +46,17 @@ class DisplayTransformNode : public Node { OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; static const QString kTextureInput; + static const QString kDisplayInput; + static const QString kViewInput; static const QString kDirectionInput; const QString shader_text_; ColorProcessorPtr reference_to_display_; OCIO::GpuShaderDescRcPtr shader_desc_; + + QString display_; + QString view_; }; } // olive diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 015070d0b..fc6c04456 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -27,7 +27,6 @@ #include "node/block/clip/clip.h" #include "node/block/transition/transition.h" -#include "node/color/displaytransform/displaytransform.h" #include "node/project/project.h" #include "rendermanager.h" From 6464bdfd68ee015aa5d2fa47635dbf55f4d8bebd Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 13 Mar 2022 23:00:00 +0000 Subject: [PATCH 06/96] Add an OCIO Grading Transform Node --- app/common/ocioutils.cpp | 12 ++ app/common/ocioutils.h | 4 + app/node/color/CMakeLists.txt | 1 + .../color/ociogradingtransform/CMakeLists.txt | 22 ++ .../ociogradingtransform.cpp | 194 ++++++++++++++++++ .../ociogradingtransform.h | 75 +++++++ app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/render/colorprocessor.cpp | 3 + app/render/colorprocessor.h | 2 + app/shaders/ociogradingtransform.frag | 13 ++ 11 files changed, 330 insertions(+) create mode 100644 app/node/color/ociogradingtransform/CMakeLists.txt create mode 100644 app/node/color/ociogradingtransform/ociogradingtransform.cpp create mode 100644 app/node/color/ociogradingtransform/ociogradingtransform.h create mode 100644 app/shaders/ociogradingtransform.frag diff --git a/app/common/ocioutils.cpp b/app/common/ocioutils.cpp index b296f0305..950632c3e 100644 --- a/app/common/ocioutils.cpp +++ b/app/common/ocioutils.cpp @@ -44,4 +44,16 @@ OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format for return OCIO::BIT_DEPTH_UNKNOWN; } +OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(QVector4D vector) +{ + OCIO::GradingRGBM rgbm; + + rgbm.m_red = vector.x(); + rgbm.m_green = vector.y(); + rgbm.m_blue = vector.z(); + rgbm.m_master = vector.w(); + + return rgbm; +} + } diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 6fa294de7..511d7730b 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -24,6 +24,8 @@ #include namespace OCIO = OCIO_NAMESPACE; +#include + #include "render/videoparams.h" namespace olive { @@ -32,6 +34,8 @@ class OCIOUtils { public: static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); + + static OCIO::GradingRGBM QVec4ToRGBM(QVector4D vector); }; } diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index 43b005216..6f616da89 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(colormanager) add_subdirectory(displaytransform) +add_subdirectory(ociogradingtransform) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/color/ociogradingtransform/CMakeLists.txt b/app/node/color/ociogradingtransform/CMakeLists.txt new file mode 100644 index 000000000..ee382c689 --- /dev/null +++ b/app/node/color/ociogradingtransform/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/color/ociogradingtransform/ociogradingtransform.cpp + node/color/ociogradingtransform/ociogradingtransform.h + PARENT_SCOPE +) diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.cpp b/app/node/color/ociogradingtransform/ociogradingtransform.cpp new file mode 100644 index 000000000..10b63da54 --- /dev/null +++ b/app/node/color/ociogradingtransform/ociogradingtransform.cpp @@ -0,0 +1,194 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "ociogradingtransform.h" + +#include "common/ocioutils.h" +#include "node/project/project.h" +#include "render/colorprocessor.h" + +namespace olive { + +const QString OCIOGradingTransformNode::kTextureInput = QStringLiteral("tex_in"); +const QString OCIOGradingTransformNode::kTypeInput = QStringLiteral("type_in"); +const QString OCIOGradingTransformNode::kBrightnessInput = QStringLiteral("brightness_in"); +const QString OCIOGradingTransformNode::kContrastInput = QStringLiteral("contrast_in"); +const QString OCIOGradingTransformNode::kGammaInput = QStringLiteral("gamma_in"); +const QString OCIOGradingTransformNode::kOffsetInput = QStringLiteral("offset_in"); +const QString OCIOGradingTransformNode::kExposureInput = QStringLiteral("exposure_in"); +const QString OCIOGradingTransformNode::kLiftInput = QStringLiteral("lift_in"); +const QString OCIOGradingTransformNode::kGainInput = QStringLiteral("gain_in"); +const QString OCIOGradingTransformNode::kSaturationInput = QStringLiteral("saturation_in"); +const QString OCIOGradingTransformNode::kPivotInput = QStringLiteral("pivot_in"); +const QString OCIOGradingTransformNode::kPivotBlackInput = QStringLiteral("pivot_black_in"); +const QString OCIOGradingTransformNode::kPivotWhiteInput = QStringLiteral("pivot_white_in"); +const QString OCIOGradingTransformNode::kClampBlackInput = QStringLiteral("clamp_black_in"); +const QString OCIOGradingTransformNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); + +OCIOGradingTransformNode::OCIOGradingTransformNode() +{ + AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + AddInput(kTypeInput, NodeValue::kCombo, 0); + + //AddInput(kBrightnessInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); + + //AddInput(kGammaInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + + AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + //AddInput(kLiftInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + //AddInput(kGainInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + + AddInput(kSaturationInput, NodeValue::kFloat, 1.0); + SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); + + AddInput(kPivotInput, NodeValue::kFloat, 0.203919098); + + // AddInput(kPivotBlackInput, NodeValue::kFloat, 0.0); + + //AddInput(kPivotWhiteInput, NodeValue::kFloat, 1.0); + + AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); + + AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0); + + GenerateProcessor(); +} + +void OCIOGradingTransformNode::GenerateProcessor() +{ + if (!project()) { + return; + } + + // Create shader description + shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); + shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); + shader_desc_->setFunctionName("OCIOGradingTransform"); + shader_desc_->setResourcePrefix("ocio_"); + + OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); + //gp->makeDynamic(); + + OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; + //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); + gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); + gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); + //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); + //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); + gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); + gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); + gpdata.m_pivot = GetStandardValue(kPivotInput).value(); + gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); + gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); + //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); + //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); + try { + gp->setValue(gpdata); + + processor_ = std::make_shared(); + processor_->SetProsessor(project()->color_manager()->GetConfig()->getProcessor(gp)); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; + } + + processor_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); +} + +Node *OCIOGradingTransformNode::copy() const +{ + return new OCIOGradingTransformNode(); +} + +QString OCIOGradingTransformNode::Name() const +{ + return tr("OCIO Grading Transform"); +} + +QString OCIOGradingTransformNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.ociogradingtransform"); +} + +QVector OCIOGradingTransformNode::Category() const +{ + return {kCategoryColor}; +} + +QString OCIOGradingTransformNode::Description() const +{ + return tr("Simple color grading using OCIO"); +} + +void OCIOGradingTransformNode::Retranslate() +{ + SetInputName(kTextureInput, tr("Input")); + SetInputName(kTypeInput, tr("Type")); + //SetInputName(kBrightnessInput, tr("Brightness")); + SetInputName(kContrastInput, tr("Contrast")); + //SetInputName(kGammaInput, tr("Gamma")); + SetInputName(kOffsetInput, tr("Offset")); + SetInputName(kExposureInput, tr("Exposure")); + //SetInputName(kLiftInput, tr("Lift")); + //SetInputName(kGainInput, tr("Gain")); + SetInputName(kSaturationInput, tr("Saturation")); + SetInputName(kPivotInput, tr("Pivot")); + //SetInputName(kPivotBlackInput, tr("Black Pivot")); + //SetInputName(kPivotWhiteInput, tr("White Pivot")); + SetInputName(kClampBlackInput, tr("Black Clamp")); + SetInputName(kClampWhiteInput, tr("White Clamp")); + + SetComboBoxStrings(kTypeInput, {"Linear"}); +} + +void OCIOGradingTransformNode::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element); + GenerateProcessor(); +} + +ShaderCode OCIOGradingTransformNode::GetShaderCode(const QString &shader_id) const +{ + Q_UNUSED(shader_id) + // Generate shader code using OCIO stub and our auto-generated name + QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/ociogradingtransform.frag")) + .arg(shader_desc_->getShaderText()); + return ShaderCode(shader_frag); +} + +void OCIOGradingTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + ShaderJob job; + job.InsertValue(value); + job.SetUseOCIO(true); + job.SetShaderDesc(shader_desc_); + job.SetColorProcessor(processor_); + + // If there's no texture, no need to run an operation + if (!job.GetValue(kTextureInput).data().isNull()) { + table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); + } +} + +} diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.h b/app/node/color/ociogradingtransform/ociogradingtransform.h new file mode 100644 index 000000000..6de018d14 --- /dev/null +++ b/app/node/color/ociogradingtransform/ociogradingtransform.h @@ -0,0 +1,75 @@ +/*** + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 OCIOGRADINGTRANSFORMNODE_H +#define OCIOGRADINGTRANSFORMNODE_H + +#include "node/node.h" +#include "render/colorprocessor.h" + +namespace olive { +class OCIOGradingTransformNode : public Node { + Q_OBJECT + public: + OCIOGradingTransformNode(); + + NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformNode) + + void GenerateProcessor(); + + virtual Node *copy() const override; + + virtual QString Name() const override; + virtual QString id() const override; + virtual QVector Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + virtual void InputValueChangedEvent(const QString &input, int element) override; + + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + + ColorProcessorPtr GetColorProcessor() { return processor_; }; + OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; + + static const QString kTextureInput; + static const QString kTypeInput; + static const QString kBrightnessInput; + static const QString kContrastInput; + static const QString kGammaInput; + static const QString kOffsetInput; + static const QString kExposureInput; + static const QString kLiftInput; + static const QString kGainInput; + static const QString kSaturationInput; + static const QString kPivotInput; + static const QString kPivotBlackInput; + static const QString kPivotWhiteInput; + static const QString kClampBlackInput; + static const QString kClampWhiteInput; + + const QString shader_text_; + + ColorProcessorPtr processor_; + OCIO::GpuShaderDescRcPtr shader_desc_; + + QString display_; + QString view_; +}; + +} // olive + +#endif diff --git a/app/node/factory.cpp b/app/node/factory.cpp index f2dd7934c..4f1e0ae18 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -30,6 +30,7 @@ #include "block/transition/crossdissolve/crossdissolvetransition.h" #include "block/transition/diptocolor/diptocolortransition.h" #include "color/displaytransform/displaytransform.h" +#include "color/ociogradingtransform/ociogradingtransform.h" #include "distort/cornerpin/cornerpindistortnode.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" @@ -270,6 +271,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new CornerPinDistortNode(); case kDisplayTransform: return new DisplayTransformNode(); + case kOCIOGradingTransform: + return new OCIOGradingTransformNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index 58e2673a9..086ae9c3e 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -68,6 +68,7 @@ public: kTimeOffsetNode, kCornerPinDistort, kDisplayTransform, + kOCIOGradingTransform, // Count value kInternalNodeCount diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 6198b6d94..6080aae54 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -25,6 +25,9 @@ #include "node/color/colormanager/colormanager.h" namespace olive { +ColorProcessor::ColorProcessor() +{ +} ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform) { diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 60205055a..9a7c5552b 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -42,12 +42,14 @@ public: }; ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space); + ColorProcessor(); DISABLE_COPY_MOVE(ColorProcessor) static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space); OCIO::ConstProcessorRcPtr GetProcessor(); + void SetProsessor(OCIO::ConstProcessorRcPtr processor) { processor_ = processor; }; void ConvertFrame(FramePtr f); void ConvertFrame(Frame* f); diff --git a/app/shaders/ociogradingtransform.frag b/app/shaders/ociogradingtransform.frag new file mode 100644 index 000000000..ca1841dc2 --- /dev/null +++ b/app/shaders/ociogradingtransform.frag @@ -0,0 +1,13 @@ +uniform sampler2D tex_in; +varying vec2 ove_texcoord; + +// Program will replace this with OCIO's auto-generated shader code +%1 + +void main() { + vec4 col = texture2D(tex_in, ove_texcoord); + + col = OCIOGradingTransform(col); + + gl_FragColor = col; +} From 7f0fc1de900737fd6903788666a6b1875ac14c05 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 15 Apr 2022 14:03:06 -0700 Subject: [PATCH 07/96] implement color processor job Refactored code to use a color processor job --- app/common/ocioutils.cpp | 2 +- app/common/ocioutils.h | 2 +- app/node/color/CMakeLists.txt | 1 + app/node/color/colormanager/colormanager.cpp | 1 + app/node/color/colormanager/colormanager.h | 3 + .../displaytransform/displaytransform.cpp | 151 +++++++-------- .../color/displaytransform/displaytransform.h | 40 ++-- app/node/color/ociobase/CMakeLists.txt | 22 +++ app/node/color/ociobase/ociobase.cpp | 65 +++++++ app/node/color/ociobase/ociobase.h | 60 ++++++ .../ociogradingtransform.cpp | 117 ++++-------- .../ociogradingtransform.h | 31 ++- app/node/hashtraverser.cpp | 10 +- app/node/hashtraverser.h | 4 +- app/node/traverser.cpp | 17 +- app/node/traverser.h | 5 +- app/node/value.cpp | 3 + app/node/value.h | 9 + app/render/colorprocessor.cpp | 31 +-- app/render/colorprocessor.h | 16 +- app/render/job/colortransformjob.h | 54 ++++++ app/render/job/shaderjob.h | 37 ---- app/render/opengl/openglrenderer.cpp | 1 + app/render/renderer.cpp | 176 +++++++----------- app/render/renderer.h | 8 - app/render/renderprocessor.cpp | 19 +- app/render/renderprocessor.h | 4 +- app/shaders/displaytransform.frag | 13 -- app/shaders/ociogradingtransform.frag | 13 -- app/shaders/stub.frag | 13 ++ .../nodeparamviewwidgetbridge.cpp | 3 + 31 files changed, 518 insertions(+), 413 deletions(-) create mode 100644 app/node/color/ociobase/CMakeLists.txt create mode 100644 app/node/color/ociobase/ociobase.cpp create mode 100644 app/node/color/ociobase/ociobase.h create mode 100644 app/render/job/colortransformjob.h delete mode 100644 app/shaders/displaytransform.frag delete mode 100644 app/shaders/ociogradingtransform.frag create mode 100644 app/shaders/stub.frag diff --git a/app/common/ocioutils.cpp b/app/common/ocioutils.cpp index 950632c3e..cc8a0490a 100644 --- a/app/common/ocioutils.cpp +++ b/app/common/ocioutils.cpp @@ -44,7 +44,7 @@ OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format for return OCIO::BIT_DEPTH_UNKNOWN; } -OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(QVector4D vector) +OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(const QVector4D &vector) { OCIO::GradingRGBM rgbm; diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 511d7730b..545231b10 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -35,7 +35,7 @@ class OCIOUtils public: static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); - static OCIO::GradingRGBM QVec4ToRGBM(QVector4D vector); + static OCIO::GradingRGBM QVec4ToRGBM(const QVector4D &vector); }; } diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index 6f616da89..0cdea800e 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(colormanager) add_subdirectory(displaytransform) +add_subdirectory(ociobase) add_subdirectory(ociogradingtransform) set(OLIVE_SOURCES diff --git a/app/node/color/colormanager/colormanager.cpp b/app/node/color/colormanager/colormanager.cpp index 4f946a513..3a4bea28e 100644 --- a/app/node/color/colormanager/colormanager.cpp +++ b/app/node/color/colormanager/colormanager.cpp @@ -269,6 +269,7 @@ void ColorManager::InputValueChangedEvent(const QString &input, int element) try { SetConfig(OCIO::Config::CreateFromFile(GetConfigFilename().toUtf8())); + emit ConfigChanged(); } catch (OCIO::Exception&) {} } diff --git a/app/node/color/colormanager/colormanager.h b/app/node/color/colormanager/colormanager.h index 2dccc7270..26ea7cc90 100644 --- a/app/node/color/colormanager/colormanager.h +++ b/app/node/color/colormanager/colormanager.h @@ -124,6 +124,9 @@ public: virtual void Retranslate() override; +signals: + void ConfigChanged(); + protected: virtual void InputValueChangedEvent(const QString &input, int element) override; diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 19f8d4dc1..7e0bcdcd8 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -1,70 +1,42 @@ /*** + Olive - Non-Linear Video Editor Copyright (C) 2021 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 "displaytransform.h" -#include "node/project/project.h" -#include "render/colorprocessor.h" +#include "node/color/colormanager/colormanager.h" namespace olive { -const QString DisplayTransformNode::kTextureInput = QStringLiteral("tex_in"); const QString DisplayTransformNode::kDisplayInput = QStringLiteral("display_in"); const QString DisplayTransformNode::kViewInput = QStringLiteral("view_in"); const QString DisplayTransformNode::kDirectionInput = QStringLiteral("dir_in"); +#define super OCIOBaseNode + DisplayTransformNode::DisplayTransformNode() { - AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + AddInput(kDisplayInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kDisplayInput, NodeValue::kCombo, 0); + AddInput(kViewInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kViewInput, NodeValue::kCombo, 0); - - AddInput(kDirectionInput, NodeValue::kCombo, 0); - - Retranslate(); -} - -void DisplayTransformNode::GenerateProcessor() -{ - if (!project()) { - return; - } - if (view_.isEmpty()) { - Retranslate(); - } - - ColorTransform transform(display_, view_, ""); - - reference_to_display_ = ColorProcessor::Create(project()->color_manager(), - project()->color_manager()->GetReferenceColorSpace(), transform); - - // Create shader description - shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); - shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); - shader_desc_->setFunctionName("DisplayTransform"); - shader_desc_->setResourcePrefix("ocio_"); - - // Generate shader - reference_to_display_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); -} - -Node *DisplayTransformNode::copy() const -{ - return new DisplayTransformNode(); + AddInput(kDirectionInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); } QString DisplayTransformNode::Name() const @@ -74,7 +46,7 @@ QString DisplayTransformNode::Name() const QString DisplayTransformNode::id() const { - return QStringLiteral("org.olivevideoeditor.Olive.disaplaytransform"); + return QStringLiteral("org.olivevideoeditor.Olive.displaytransform"); } QVector DisplayTransformNode::Category() const @@ -89,66 +61,83 @@ QString DisplayTransformNode::Description() const void DisplayTransformNode::Retranslate() { + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); SetInputName(kDisplayInput, tr("Display")); SetInputName(kViewInput, tr("View")); - - if (project()) { - SetComboBoxStrings(kDisplayInput, project()->color_manager()->ListAvailableDisplays()); - display_ = project()->color_manager()->ListAvailableDisplays().at( - GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); - - SetComboBoxStrings(kViewInput, project()->color_manager()->ListAvailableViews(display_)); - view_ = project()->color_manager()->ListAvailableViews(display_).at( - GetSplitStandardValue(kViewInput).at(0).toString().toInt()); - } - SetInputName(kDirectionInput, tr("Direction")); SetComboBoxStrings(kDirectionInput, {tr("Forward"), tr("Inverse")}); } -void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element) { +void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element) +{ Q_UNUSED(element); - if (input == kDirectionInput) { + if (input == kDisplayInput || input == kDirectionInput || input == kViewInput) { + if (input == kDisplayInput) { + UpdateViews(); + } GenerateProcessor(); } - if (project()) { - if (input == kDisplayInput) { - display_ = project()->color_manager()->ListAvailableDisplays().at( - GetSplitStandardValue(kDisplayInput).at(0).toString().toInt()); - // If we change the display the view menu must be updated - Retranslate(); - GenerateProcessor(); - } - if (input == kViewInput) { - view_ = project()->color_manager()->ListAvailableViews(display_).at( - GetSplitStandardValue(kViewInput).at(0).toString().toInt()); - GenerateProcessor(); +} + +QString DisplayTransformNode::GetDisplay() const +{ + if (manager()) { + int index = GetStandardValue(kDisplayInput).toInt(); + if (index < manager()->ListAvailableDisplays().size()) { + return manager()->ListAvailableDisplays().at(index); } } - + return QString(); } -ShaderCode DisplayTransformNode::GetShaderCode(const QString &shader_id) const +QString DisplayTransformNode::GetView() const { - Q_UNUSED(shader_id) - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/displaytransform.frag")) - .arg(shader_desc_->getShaderText()); - return ShaderCode(shader_frag); + if (manager()) { + QString display = GetDisplay(); + if (!display.isEmpty()) { + int index = GetStandardValue(kViewInput).toInt(); + QStringList views = manager()->ListAvailableViews(display); + if (index < views.size()) { + return views.at(index); + } + } + } + return QString(); } -void DisplayTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +ColorProcessor::Direction DisplayTransformNode::GetDirection() const { - ShaderJob job; - job.InsertValue(value); - job.SetUseOCIO(true); - job.SetShaderDesc(shader_desc_); - job.SetColorProcessor(reference_to_display_); + return static_cast(GetStandardValue(kDirectionInput).toInt());; +} - // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { - table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); +void DisplayTransformNode::UpdateDisplays() +{ + if (manager()) { + SetComboBoxStrings(kDisplayInput, manager()->ListAvailableDisplays()); + } +} + +void DisplayTransformNode::UpdateViews() +{ + if (manager()) { + SetComboBoxStrings(kViewInput, manager()->ListAvailableViews(GetDisplay())); + } +} + +void DisplayTransformNode::ConfigChanged() +{ + UpdateDisplays(); + UpdateViews(); + GenerateProcessor(); +} + +void DisplayTransformNode::GenerateProcessor() +{ + if (manager()) { + ColorTransform transform(GetDisplay(), GetView(), QString()); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform, GetDirection())); } } diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index b50e73e29..9c8dff5ba 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -1,35 +1,39 @@ /*** + Olive - Non-Linear Video Editor Copyright (C) 2021 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 DISPLAYTRANSFORMNODE_H #define DISPLAYTRANSFORMNODE_H -#include "node/node.h" +#include "node/color/ociobase/ociobase.h" #include "render/colorprocessor.h" namespace olive { -class DisplayTransformNode : public Node { + +class DisplayTransformNode : public OCIOBaseNode +{ Q_OBJECT public: DisplayTransformNode(); NODE_DEFAULT_DESTRUCTOR(DisplayTransformNode) - - void GenerateProcessor(); - - virtual Node *copy() const override; + NODE_COPY_FUNCTION(DisplayTransformNode) virtual QString Name() const override; virtual QString id() const override; @@ -39,26 +43,26 @@ class DisplayTransformNode : public Node { virtual void Retranslate() override; virtual void InputValueChangedEvent(const QString &input, int element) override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; - virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + QString GetDisplay() const; + QString GetView() const; + ColorProcessor::Direction GetDirection() const; - ColorProcessorPtr GetColorProcessor() { return reference_to_display_; }; - OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; - - static const QString kTextureInput; static const QString kDisplayInput; static const QString kViewInput; static const QString kDirectionInput; - const QString shader_text_; +protected slots: + virtual void ConfigChanged() override; - ColorProcessorPtr reference_to_display_; - OCIO::GpuShaderDescRcPtr shader_desc_; +private: + void GenerateProcessor(); + + void UpdateDisplays(); + + void UpdateViews(); - QString display_; - QString view_; }; } // olive -#endif +#endif // DISPLAYTRANSFORMNODE_H diff --git a/app/node/color/ociobase/CMakeLists.txt b/app/node/color/ociobase/CMakeLists.txt new file mode 100644 index 000000000..fa00411a4 --- /dev/null +++ b/app/node/color/ociobase/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/color/ociobase/ociobase.cpp + node/color/ociobase/ociobase.h + PARENT_SCOPE +) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp new file mode 100644 index 000000000..db47c00ab --- /dev/null +++ b/app/node/color/ociobase/ociobase.cpp @@ -0,0 +1,65 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "ociobase.h" + +#include "node/color/colormanager/colormanager.h" +#include "node/project/project.h" + +namespace olive { + +const QString OCIOBaseNode::kTextureInput = QStringLiteral("tex_in"); + +OCIOBaseNode::OCIOBaseNode() : + manager_(nullptr), + processor_(nullptr) +{ + AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + connect(this, &Node::AddedToGraph, this, &OCIOBaseNode::ParentChanged); +} + +void OCIOBaseNode::ParentChanged(NodeGraph *graph) +{ + if (manager_) { + disconnect(manager_, &ColorManager::ConfigChanged, this, &OCIOBaseNode::ConfigChanged); + manager_ = nullptr; + } + + if (Project *p = dynamic_cast(graph)) { + manager_ = p->color_manager(); + connect(manager_, &ColorManager::ConfigChanged, this, &OCIOBaseNode::ConfigChanged); + ConfigChanged(); + } +} + +void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + if (!value[kTextureInput].data().isNull() && processor_) { + ColorTransformJob job; + + job.SetColorProcessor(processor_); + job.SetInputTexture(value[kTextureInput].data().value()); + + table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + } +} + +} diff --git a/app/node/color/ociobase/ociobase.h b/app/node/color/ociobase/ociobase.h new file mode 100644 index 000000000..a0b6fc0f2 --- /dev/null +++ b/app/node/color/ociobase/ociobase.h @@ -0,0 +1,60 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 OCIOBASENODE_H +#define OCIOBASENODE_H + +#include "node/node.h" +#include "render/job/colortransformjob.h" + +namespace olive { + +class OCIOBaseNode : public Node +{ + Q_OBJECT +public: + OCIOBaseNode(); + + virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + + static const QString kTextureInput; + +protected slots: + virtual void ConfigChanged() = 0; + +protected: + ColorManager *manager() const { return manager_; } + + ColorProcessorPtr processor() const { return processor_; } + void set_processor(ColorProcessorPtr p) { processor_ = p; } + +private: + ColorManager *manager_; + + ColorProcessorPtr processor_; + +private slots: + void ParentChanged(olive::NodeGraph *graph); + +}; + +} + +#endif // OCIOBASENODE_H diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.cpp b/app/node/color/ociogradingtransform/ociogradingtransform.cpp index 10b63da54..27a8f57f0 100644 --- a/app/node/color/ociogradingtransform/ociogradingtransform.cpp +++ b/app/node/color/ociogradingtransform/ociogradingtransform.cpp @@ -1,16 +1,21 @@ /*** + Olive - Non-Linear Video Editor Copyright (C) 2021 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 "ociogradingtransform.h" @@ -21,7 +26,6 @@ namespace olive { -const QString OCIOGradingTransformNode::kTextureInput = QStringLiteral("tex_in"); const QString OCIOGradingTransformNode::kTypeInput = QStringLiteral("type_in"); const QString OCIOGradingTransformNode::kBrightnessInput = QStringLiteral("brightness_in"); const QString OCIOGradingTransformNode::kContrastInput = QStringLiteral("contrast_in"); @@ -37,88 +41,39 @@ const QString OCIOGradingTransformNode::kPivotWhiteInput = QStringLiteral("pivot const QString OCIOGradingTransformNode::kClampBlackInput = QStringLiteral("clamp_black_in"); const QString OCIOGradingTransformNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); +#define super OCIOBaseNode + OCIOGradingTransformNode::OCIOGradingTransformNode() { - AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); - AddInput(kTypeInput, NodeValue::kCombo, 0); //AddInput(kBrightnessInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); - AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); //AddInput(kGammaInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); //AddInput(kLiftInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); //AddInput(kGainInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - AddInput(kSaturationInput, NodeValue::kFloat, 1.0); + AddInput(kSaturationInput, NodeValue::kFloat, 1.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); - AddInput(kPivotInput, NodeValue::kFloat, 0.203919098); + AddInput(kPivotInput, NodeValue::kFloat, 0.203919098, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); // AddInput(kPivotBlackInput, NodeValue::kFloat, 0.0); //AddInput(kPivotWhiteInput, NodeValue::kFloat, 1.0); - AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); + AddInput(kClampBlackInput, NodeValue::kFloat, 0.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0); - - GenerateProcessor(); -} - -void OCIOGradingTransformNode::GenerateProcessor() -{ - if (!project()) { - return; - } - - // Create shader description - shader_desc_ = OCIO::GpuShaderDesc::CreateShaderDesc(); - shader_desc_->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); - shader_desc_->setFunctionName("OCIOGradingTransform"); - shader_desc_->setResourcePrefix("ocio_"); - - OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); - //gp->makeDynamic(); - - OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; - //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); - gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); - gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); - //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); - //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); - gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); - gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); - gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); - gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); - //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); - //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); - try { - gp->setValue(gpdata); - - processor_ = std::make_shared(); - processor_->SetProsessor(project()->color_manager()->GetConfig()->getProcessor(gp)); - } catch (const OCIO::Exception &e) { - std::cerr << std::endl << e.what() << std::endl; - } - - processor_->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc_); -} - -Node *OCIOGradingTransformNode::copy() const -{ - return new OCIOGradingTransformNode(); + AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); } QString OCIOGradingTransformNode::Name() const @@ -143,6 +98,8 @@ QString OCIOGradingTransformNode::Description() const void OCIOGradingTransformNode::Retranslate() { + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); SetInputName(kTypeInput, tr("Type")); //SetInputName(kBrightnessInput, tr("Brightness")); @@ -165,29 +122,35 @@ void OCIOGradingTransformNode::Retranslate() void OCIOGradingTransformNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); - GenerateProcessor(); + ConfigChanged(); } -ShaderCode OCIOGradingTransformNode::GetShaderCode(const QString &shader_id) const +void OCIOGradingTransformNode::ConfigChanged() { - Q_UNUSED(shader_id) - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/ociogradingtransform.frag")) - .arg(shader_desc_->getShaderText()); - return ShaderCode(shader_frag); -} + OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); + //gp->makeDynamic(); -void OCIOGradingTransformNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const -{ - ShaderJob job; - job.InsertValue(value); - job.SetUseOCIO(true); - job.SetShaderDesc(shader_desc_); - job.SetColorProcessor(processor_); + OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; + //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); + gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); + gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); + //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); + //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); + gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); + gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); + gpdata.m_pivot = GetStandardValue(kPivotInput).value(); + gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); + gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); + //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); + //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); + try { + gp->setValue(gpdata); - // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { - table->Push(NodeValue::kShaderJob, QVariant::fromValue(job), this); + set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; } } diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.h b/app/node/color/ociogradingtransform/ociogradingtransform.h index 6de018d14..99f2db214 100644 --- a/app/node/color/ociogradingtransform/ociogradingtransform.h +++ b/app/node/color/ociogradingtransform/ociogradingtransform.h @@ -1,35 +1,39 @@ /*** + Olive - Non-Linear Video Editor Copyright (C) 2021 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 OCIOGRADINGTRANSFORMNODE_H #define OCIOGRADINGTRANSFORMNODE_H -#include "node/node.h" +#include "node/color/ociobase/ociobase.h" #include "render/colorprocessor.h" namespace olive { -class OCIOGradingTransformNode : public Node { + +class OCIOGradingTransformNode : public OCIOBaseNode +{ Q_OBJECT public: OCIOGradingTransformNode(); NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformNode) - - void GenerateProcessor(); - - virtual Node *copy() const override; + NODE_COPY_FUNCTION(OCIOGradingTransformNode) virtual QString Name() const override; virtual QString id() const override; @@ -39,13 +43,6 @@ class OCIOGradingTransformNode : public Node { virtual void Retranslate() override; virtual void InputValueChangedEvent(const QString &input, int element) override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; - virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; - - ColorProcessorPtr GetColorProcessor() { return processor_; }; - OCIO::GpuShaderDescRcPtr GetGPUShaderDesc() { return shader_desc_; }; - - static const QString kTextureInput; static const QString kTypeInput; static const QString kBrightnessInput; static const QString kContrastInput; @@ -61,13 +58,9 @@ class OCIOGradingTransformNode : public Node { static const QString kClampBlackInput; static const QString kClampWhiteInput; - const QString shader_text_; +protected slots: + virtual void ConfigChanged() override; - ColorProcessorPtr processor_; - OCIO::GpuShaderDescRcPtr shader_desc_; - - QString display_; - QString view_; }; } // olive diff --git a/app/node/hashtraverser.cpp b/app/node/hashtraverser.cpp index 155842242..cab012ad7 100644 --- a/app/node/hashtraverser.cpp +++ b/app/node/hashtraverser.cpp @@ -86,7 +86,7 @@ SampleBufferPtr HashTraverser::ProcessAudioFootage(const FootageJob &stream, con return buf; } -TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { HashGenerateJob(node, &job); @@ -104,6 +104,14 @@ TexturePtr HashTraverser::ProcessShader(const Node *node, const TimeRange &range return texture; } +TexturePtr HashTraverser::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + Hash(job.GetColorProcessor()->id()); + TexturePtr texture = super::ProcessColorTransform(node, job); + texture_ids_.insert(texture.get(), hash_.result()); + return texture; +} + SampleBufferPtr HashTraverser::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) { SampleBufferPtr buf = super::ProcessSamples(node, range, job); diff --git a/app/node/hashtraverser.h b/app/node/hashtraverser.h index 39957c9ed..a7bfe6b84 100644 --- a/app/node/hashtraverser.h +++ b/app/node/hashtraverser.h @@ -37,7 +37,9 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; + + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index d32941253..677f3ce99 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -292,7 +292,7 @@ SampleBufferPtr NodeTraverser::ProcessAudioFootage(const FootageJob& stream, con return SampleBuffer::Create(); } -TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(node) Q_UNUSED(range) @@ -304,6 +304,13 @@ TexturePtr NodeTraverser::ProcessShader(const Node *node, const TimeRange &range return CreateDummyTexture(tex_params); } +TexturePtr NodeTraverser::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + Q_UNUSED(node) + + return CreateDummyTexture(job.GetInputTexture()->params()); +} + SampleBufferPtr NodeTraverser::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) { Q_UNUSED(node) @@ -366,6 +373,7 @@ void NodeTraverser::PostProcessTable(const Node *node, const Node::ValueHint &hi QList shader_jobs_to_run; QList sample_jobs_to_run; QList generate_jobs_to_run; + QList color_transform_jobs_to_run; for (int i=0; i())), node, v.array(), v.tag()); } + // Run color transforms + foreach (const NodeValue& v, color_transform_jobs_to_run) { + output_params.Push(NodeValue::kTexture, QVariant::fromValue(ProcessColorTransform(node, v.data().value())), node, v.array(), v.tag()); + } + // Run generate jobs foreach (const NodeValue& v, generate_jobs_to_run) { output_params.Push(NodeValue::kTexture, QVariant::fromValue(ProcessFrameGeneration(node, v.data().value())), node, v.array(), v.tag()); diff --git a/app/node/traverser.h b/app/node/traverser.h index 3af7a300c..925e37552 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -27,6 +27,7 @@ #include "common/cancelableobject.h" #include "node/output/track/track.h" #include "render/job/footagejob.h" +#include "render/job/colortransformjob.h" #include "value.h" namespace olive { @@ -76,7 +77,9 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time); - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job); + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); + + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job); virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job); diff --git a/app/node/value.cpp b/app/node/value.cpp index d3fa7373b..3eed697a5 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -141,6 +141,7 @@ QByteArray NodeValue::ValueToBytes(NodeValue::Type type, const QVariant &value) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } @@ -358,6 +359,7 @@ QString NodeValue::GetPrettyDataTypeName(Type type) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } @@ -410,6 +412,7 @@ QString NodeValue::GetDataTypeName(Type type) case kShaderJob: case kSampleJob: case kGenerateJob: + case kColorTransformJob: case kDataTypeCount: break; } diff --git a/app/node/value.h b/app/node/value.h index 12fb91a33..e949bbca9 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -208,6 +208,15 @@ public: */ kGenerateJob, + /** + * Job type + * + * An internal type used to indicate to the renderer that an accelerated color transform job + * needs to take place. This value will usually be taken from a table and a kTexture value will + * be pushed to take its place. + */ + kColorTransformJob, + /** * End of list */ diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 6080aae54..b7349e4b2 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -25,11 +25,8 @@ #include "node/color/colormanager/colormanager.h" namespace olive { -ColorProcessor::ColorProcessor() -{ -} -ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform) +ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform, Direction direction) { QMutexLocker locker(config->mutex()); @@ -44,6 +41,7 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const display_transform->setSrc(input.toUtf8()); display_transform->setDisplay(output.toUtf8()); display_transform->setView(view.toUtf8()); + display_transform->setDirection(direction == kNormal ? OCIO::TRANSFORM_DIR_FORWARD : OCIO::TRANSFORM_DIR_INVERSE); OCIO_SET_C_LOCALE_FOR_SCOPE; @@ -73,7 +71,11 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const OCIO_SET_C_LOCALE_FOR_SCOPE; try { - processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); + if (direction == kNormal) { + processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); + } else { + processor_ = config->GetConfig()->getProcessor(output.toUtf8(), input.toUtf8()); + } } catch (OCIO::Exception &e) { qWarning() << "ColorProcessor exception:" << e.what(); } @@ -81,7 +83,12 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const } cpu_processor_ = processor_->getDefaultCPUProcessor(); - id_ = GenerateID(config, input, transform); +} + +ColorProcessor::ColorProcessor(OCIO::ConstProcessorRcPtr processor) +{ + processor_ = processor; + cpu_processor_ = processor_->getDefaultCPUProcessor(); } void ColorProcessor::ConvertFrame(Frame *f) @@ -115,18 +122,14 @@ Color ColorProcessor::ConvertColor(const Color& in) return Color(c[0], c[1], c[2], c[3]); } -QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform) +ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform, Direction direction) { - return QStringLiteral("%1:%2:%3:%4:%5").arg(config->GetConfigFilename(), - input, - transform.display(), - transform.view(), - transform.look()); + return std::make_shared(config, input, transform, direction); } -ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform) +ColorProcessorPtr ColorProcessor::Create(OCIO::ConstProcessorRcPtr processor) { - return std::make_shared(config, input, transform); + return std::make_shared(processor); } OCIO::ConstProcessorRcPtr ColorProcessor::GetProcessor() diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index 9a7c5552b..9d1c9130a 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -41,35 +41,31 @@ public: kInverse }; - ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space); - ColorProcessor(); + ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space, Direction direction = kNormal); + ColorProcessor(OCIO::ConstProcessorRcPtr processor); DISABLE_COPY_MOVE(ColorProcessor) - static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space); + static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space, Direction direction = kNormal); + static ColorProcessorPtr Create(OCIO::ConstProcessorRcPtr processor); OCIO::ConstProcessorRcPtr GetProcessor(); - void SetProsessor(OCIO::ConstProcessorRcPtr processor) { processor_ = processor; }; void ConvertFrame(FramePtr f); void ConvertFrame(Frame* f); Color ConvertColor(const Color &in); - const QString& id() const + const char *id() const { - return id_; + return processor_->getCacheID(); } - static QString GenerateID(ColorManager* config, const QString& input, const ColorTransform& dest_space); - private: OCIO::ConstProcessorRcPtr processor_; OCIO::ConstCPUProcessorRcPtr cpu_processor_; - QString id_; - }; using ColorProcessorChain = QVector; diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h new file mode 100644 index 000000000..cf653d27e --- /dev/null +++ b/app/render/job/colortransformjob.h @@ -0,0 +1,54 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 COLORTRANSFORMJOB_H +#define COLORTRANSFORMJOB_H + +#include "render/colorprocessor.h" +#include "render/texture.h" + +namespace olive { + +class ColorTransformJob { +public: + ColorTransformJob() + { + processor_ = nullptr; + input_texture_ = nullptr; + } + + TexturePtr GetInputTexture() const { return input_texture_; } + void SetInputTexture(TexturePtr tex) { input_texture_ = tex; } + + ColorProcessorPtr GetColorProcessor() const { return processor_; } + void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } + +private: + ColorProcessorPtr processor_; + + TexturePtr input_texture_; + +}; + +} + +Q_DECLARE_METATYPE(olive::ColorTransformJob) + +#endif // COLORTRANSFORMJOB_H diff --git a/app/render/job/shaderjob.h b/app/render/job/shaderjob.h index 335d442b5..53cd836d6 100644 --- a/app/render/job/shaderjob.h +++ b/app/render/job/shaderjob.h @@ -36,7 +36,6 @@ public: { iterations_ = 1; iterative_input_ = nullptr; - use_ocio_ = false; } const QString& GetShaderID() const @@ -90,36 +89,6 @@ public: interpolation_.insert(id, interp); } - bool UseOCIO() const - { - return use_ocio_; - } - - void SetUseOCIO(bool use_ocio) - { - use_ocio_ = use_ocio; - } - - ColorProcessorPtr ColorProcessor() - { - return color_processor_; - } - - void SetColorProcessor(ColorProcessorPtr processor) - { - color_processor_ = processor; - } - - OCIO::GpuShaderDescRcPtr ShaderDesc() - { - return shader_desc_; - } - - void SetShaderDesc(OCIO::GpuShaderDescRcPtr shader_desc) - { - shader_desc_ = shader_desc; - } - void SetVertexCoordinates(const QVector &vertex_coords) { vertex_overrides_ = vertex_coords; @@ -139,12 +108,6 @@ private: QHash interpolation_; - bool use_ocio_; - - ColorProcessorPtr color_processor_; - - OCIO::GpuShaderDescRcPtr shader_desc_; - QVector vertex_overrides_; }; diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index 8d9786973..f762c480e 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -523,6 +523,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video case NodeValue::kFootageJob: case NodeValue::kBezier: case NodeValue::kNone: + case NodeValue::kColorTransformJob: case NodeValue::kDataTypeCount: break; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 844624f38..b78df3df4 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -62,23 +62,6 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); } -void Renderer::ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, - OCIO::GpuShaderDescRcPtr shader_desc) { - ColorContext color_ctx; - if (!GetCustomColorContext(color_processor, &color_ctx, shader_desc)) { - return; - } - - foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { - job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); - job->SetInterpolation(l.name, l.interpolation); - } - foreach (const ColorContext::LUT& l, color_ctx.lut1d_textures) { - job->InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); - job->SetInterpolation(l.name, l.interpolation); - } -} - TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms) { color_cache_mutex_.lock(); @@ -120,96 +103,6 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetCustomColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext* ctx, - OCIO::GpuShaderDescRcPtr shader_desc) { - QMutexLocker locker(&color_cache_mutex_); - - ColorContext& color_ctx = *ctx; - - if (color_cache_.contains(color_processor->id())) { - color_ctx = color_cache_.value(color_processor->id()); - return true; - } else { - if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { - return true; - } else { - qCritical() << "Failed to allocate OCIO shader textures"; - return false; - } - } -} - -bool Renderer::SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, - ColorProcessorPtr color_processor) -{ - color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); - for (unsigned int i = 0; i < shader_desc->getNum3DTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int edge_len = 0; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); - - if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !edge_len) { - qCritical() << "3D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->get3DTextureValues(i, values); - if (!values) { - qCritical() << "3D LUT texture values are missing"; - return false; - } - - // Allocate 3D LUT - color_ctx.lut3d_textures[i].texture = CreateTexture( - VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), - Texture::k3D, values); - color_ctx.lut3d_textures[i].name = sampler_name; - color_ctx.lut3d_textures[i].interpolation = - (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; - } - - color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); - for (unsigned int i = 0; i < shader_desc->getNumTextures(); i++) { - const char* tex_name = nullptr; - const char* sampler_name = nullptr; - unsigned int width = 0, height = 0; - OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; - OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; - - shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); - - if (!tex_name || !*tex_name || !sampler_name || !*sampler_name || !width) { - qCritical() << "1D LUT texture data is corrupted"; - return false; - } - - const float* values = nullptr; - shader_desc->getTextureValues(i, values); - if (!values) { - qCritical() << "1D LUT texture values are missing"; - return false; - } - - // Allocate 1D LUT - color_ctx.lut1d_textures[i].texture = CreateTexture( - VideoParams(width, height, VideoParams::kFormatFloat32, - (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), - Texture::k2D, values); - color_ctx.lut1d_textures[i].name = sampler_name; - color_ctx.lut1d_textures[i].interpolation = - (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; - } - - color_cache_.insert(color_processor->id(), color_ctx); - - return true; - -} - bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) { QMutexLocker locker(&color_cache_mutex_); @@ -244,12 +137,71 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo return false; } - if (SetupColorContextTextures(color_ctx, shader_desc, color_processor)) { - return true; - } else { - qCritical() << "Failed to allocate OCIO shader textures"; - return false; + color_ctx.lut3d_textures.resize(shader_desc->getNum3DTextures()); + for (unsigned int i=0; igetNum3DTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int edge_len = 0; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->get3DTexture(i, tex_name, sampler_name, edge_len, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !edge_len) { + qCritical() << "3D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->get3DTextureValues(i, values); + if (!values) { + qCritical() << "3D LUT texture values are missing"; + return false; + } + + // Allocate 3D LUT + color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), + Texture::k3D, values); + color_ctx.lut3d_textures[i].name = sampler_name; + color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; } + + color_ctx.lut1d_textures.resize(shader_desc->getNumTextures()); + for (unsigned int i=0; igetNumTextures(); i++) { + const char* tex_name = nullptr; + const char* sampler_name = nullptr; + unsigned int width = 0, height = 0; + OCIO::GpuShaderDesc::TextureType channel = OCIO::GpuShaderDesc::TEXTURE_RGB_CHANNEL; + OCIO::Interpolation interpolation = OCIO::INTERP_LINEAR; + + shader_desc->getTexture(i, tex_name, sampler_name, width, height, channel, interpolation); + + if (!tex_name || !*tex_name + || !sampler_name || !*sampler_name + || !width) { + qCritical() << "1D LUT texture data is corrupted"; + return false; + } + + const float* values = nullptr; + shader_desc->getTextureValues(i, values); + if (!values) { + qCritical() << "1D LUT texture values are missing"; + return false; + } + + // Allocate 1D LUT + color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), + Texture::k2D, + values); + color_ctx.lut1d_textures[i].name = sampler_name; + color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; + } + + color_cache_.insert(color_processor->id(), color_ctx); + + return true; } } diff --git a/app/render/renderer.h b/app/render/renderer.h index ef41dfa93..977fc98ce 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -63,8 +63,6 @@ public: Blit(shader, job, nullptr, params, clear_destination); } - void ShaderJobInsertTextures(ColorProcessorPtr color_processor, ShaderJob* job, OCIO::GpuShaderDescRcPtr shader_desc); - enum AlphaAssociated { kAlphaNone, kAlphaUnassociated, @@ -130,12 +128,6 @@ private: bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); - bool GetCustomColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, - OCIO::GpuShaderDescRcPtr shader_desc); - - bool SetupColorContextTextures(ColorContext& color_ctx, OCIO::ConstGpuShaderDescRcPtr shader_desc, - ColorProcessorPtr color_processor); - void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, VideoParams params, bool clear_destination, diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 7017a7c11..f223824cb 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -496,7 +496,7 @@ SampleBufferPtr RenderProcessor::ProcessAudioFootage(const FootageJob &stream, c return super::ProcessAudioFootage(stream, input_time); } -TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, ShaderJob &job) +TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(range) @@ -507,9 +507,10 @@ TexturePtr RenderProcessor::ProcessShader(const Node *node, const TimeRange &ran QVariant shader = shader_cache_->value(full_shader_id); if (shader.isNull()) { - if (job.UseOCIO()) { - render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); - } + // FIXME: Reimplement as color job + //if (job.UseOCIO()) { + // render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); + //} // Since we have shader code, compile it now shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); @@ -565,6 +566,16 @@ SampleBufferPtr RenderProcessor::ProcessSamples(const Node *node, const TimeRang return output_buffer; } +TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorTransformJob &job) +{ + TexturePtr src = job.GetInputTexture(); + TexturePtr dest = render_ctx_->CreateTexture(src->params()); + + render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get()); + + return dest; +} + TexturePtr RenderProcessor::ProcessFrameGeneration(const Node *node, const GenerateJob &job) { FramePtr frame = Frame::Create(); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 7d655a986..a1ee8a747 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -48,10 +48,12 @@ protected: virtual SampleBufferPtr ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override; - virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, ShaderJob& job) override; + virtual TexturePtr ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; virtual SampleBufferPtr ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; + virtual TexturePtr ProcessColorTransform(const Node *node, const ColorTransformJob& job) override; + virtual TexturePtr ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; virtual bool CanCacheFrames() override; diff --git a/app/shaders/displaytransform.frag b/app/shaders/displaytransform.frag deleted file mode 100644 index d597f47d2..000000000 --- a/app/shaders/displaytransform.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex_in; -varying vec2 ove_texcoord; - -// Program will replace this with OCIO's auto-generated shader code -%1 - -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - - col = DisplayTransform(col); - - gl_FragColor = col; -} diff --git a/app/shaders/ociogradingtransform.frag b/app/shaders/ociogradingtransform.frag deleted file mode 100644 index ca1841dc2..000000000 --- a/app/shaders/ociogradingtransform.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex_in; -varying vec2 ove_texcoord; - -// Program will replace this with OCIO's auto-generated shader code -%1 - -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - - col = OCIOGradingTransform(col); - - gl_FragColor = col; -} diff --git a/app/shaders/stub.frag b/app/shaders/stub.frag new file mode 100644 index 000000000..ccc1b86dd --- /dev/null +++ b/app/shaders/stub.frag @@ -0,0 +1,13 @@ +uniform sampler2D tex_in; +in vec2 ove_texcoord; +out vec4 frag_color; + +%1 + +void main() { + vec4 col = texture2D(tex_in, ove_texcoord); + + col = %2(col); + + frag_color = col; +} diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 29c35657b..3413a2f2e 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -90,6 +90,7 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: @@ -244,6 +245,7 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: @@ -421,6 +423,7 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: + case NodeValue::kColorTransformJob: case NodeValue::kVideoParams: case NodeValue::kAudioParams: case NodeValue::kDataTypeCount: From 4d2f8f775c404ff3733f91cf21f52a6710239527 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 24 Apr 2022 18:50:06 +0100 Subject: [PATCH 08/96] Add ability to add custom shaders to ColorProcessorJobs --- app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/node/keying/CMakeLists.txt | 1 + app/node/keying/chromakey/CMakeLists.txt | 22 ++++++ app/node/keying/chromakey/chromakey.cpp | 89 ++++++++++++++++++++++++ app/node/keying/chromakey/chromakey.h | 53 ++++++++++++++ app/render/job/colortransformjob.h | 7 ++ app/render/renderer.cpp | 26 ++++--- app/render/renderer.h | 5 +- app/render/renderprocessor.cpp | 2 +- app/shaders/chromakey.frag | 34 +++++++++ 11 files changed, 232 insertions(+), 11 deletions(-) create mode 100644 app/node/keying/chromakey/CMakeLists.txt create mode 100644 app/node/keying/chromakey/chromakey.cpp create mode 100644 app/node/keying/chromakey/chromakey.h create mode 100644 app/shaders/chromakey.frag diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 02af0aded..0958d2d92 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -54,6 +54,7 @@ #include "math/trigonometry/trigonometry.h" #include "keying/colordifferencekey/colordifferencekey.h" #include "keying/despill/despill.h" +#include "keying/chromakey/chromakey.h" #include "output/track/track.h" #include "output/viewer/viewer.h" #include "project/folder/folder.h" @@ -283,6 +284,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new DisplayTransformNode(); case kOCIOGradingTransform: return new OCIOGradingTransformNode(); + case kChromaKey: + return new ChromaKeyNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index b57cdfe40..42658cfb2 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -72,6 +72,7 @@ public: kCornerPinDistort, kDisplayTransform, kOCIOGradingTransform, + kChromaKey, // Count value kInternalNodeCount diff --git a/app/node/keying/CMakeLists.txt b/app/node/keying/CMakeLists.txt index 2177a550a..4dbd437cd 100644 --- a/app/node/keying/CMakeLists.txt +++ b/app/node/keying/CMakeLists.txt @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(chromakey) add_subdirectory(colordifferencekey) add_subdirectory(despill) diff --git a/app/node/keying/chromakey/CMakeLists.txt b/app/node/keying/chromakey/CMakeLists.txt new file mode 100644 index 000000000..c2af2bba4 --- /dev/null +++ b/app/node/keying/chromakey/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/keying/chromakey/chromakey.h + node/keying/chromakey/chromakey.cpp + PARENT_SCOPE +) \ No newline at end of file diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp new file mode 100644 index 000000000..b57781fbc --- /dev/null +++ b/app/node/keying/chromakey/chromakey.cpp @@ -0,0 +1,89 @@ +/*** + 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 "chromakey.h" + +#include "node/color/colormanager/colormanager.h" +#include "render/colorprocessor.h" + +namespace olive { + +#define super OCIOBaseNode + +ChromaKeyNode::ChromaKeyNode() +{ +} + +QString ChromaKeyNode::Name() const +{ + return tr("Chroma Key"); +} + +QString ChromaKeyNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.chromakey"); +} + +QVector ChromaKeyNode::Category() const +{ + return {kCategoryKeying}; +} + +QString ChromaKeyNode::Description() const +{ + return tr("A simple color key based on the distance from the chroma of a selected color."); +} + +void ChromaKeyNode::Retranslate() +{ + super::Retranslate(); + SetInputName(kTextureInput, tr("Input")); + //SetInputName(kGarbageMatteInput, tr("Garbage Matte")); + //SetInputName(kCoreMatteInput, tr("Core Matte")); + //SetInputName(kColorInput, tr("Key Color")); + //SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")}); + //SetInputName(kShadowsInput, tr("Shadows")); + //SetInputName(kHighlightsInput, tr("Highlights")); + //SetInputName(kMaskOnlyInput, tr("Show Mask Only")); +} + +void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element); + GenerateProcessor(); +} + +void ChromaKeyNode::GenerateProcessor() +{ + if (manager()){ + ColorTransform transform("cie_xyz_d65_interchange"); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + } +} + +void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + if (!value[kTextureInput].data().isNull() && processor()) { + ColorTransformJob job; + + job.SetColorProcessor(processor()); + job.SetInputTexture(value[kTextureInput].data().value()); + job.SetShaderPath(QStringLiteral(":/shaders/chromakey.frag")); + + table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + } +} + +} // namespace olive \ No newline at end of file diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h new file mode 100644 index 000000000..c14272e02 --- /dev/null +++ b/app/node/keying/chromakey/chromakey.h @@ -0,0 +1,53 @@ +/*** + 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 CHROMAKEYNODE_H +#define CHROMAKEYNODE_H + +#include "node/color/ociobase/ociobase.h" + +namespace olive { + +class ChromaKeyNode : public OCIOBaseNode { + Q_OBJECT + public: + ChromaKeyNode(); + + NODE_DEFAULT_DESTRUCTOR(ChromaKeyNode) + NODE_COPY_FUNCTION(ChromaKeyNode) + + virtual QString Name() const override; + virtual QString id() const override; + virtual QVector Category() const override; + virtual QString Description() const override; + + virtual void Retranslate() override; + + virtual void InputValueChangedEvent(const QString& input, int element) override; + + virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; + + virtual void ConfigChanged() override {}; + +private: + void GenerateProcessor(); + + + +}; + +} // namespace olive + +#endif // CHROMAKEYNODE_H diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index cf653d27e..3bed475f8 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -21,6 +21,8 @@ #ifndef COLORTRANSFORMJOB_H #define COLORTRANSFORMJOB_H +#include + #include "render/colorprocessor.h" #include "render/texture.h" @@ -40,11 +42,16 @@ public: ColorProcessorPtr GetColorProcessor() const { return processor_; } void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } + QString GetShaderPath() const { return shader_path_; } + void SetShaderPath(const QString shader_path) { shader_path_ = shader_path; } + private: ColorProcessorPtr processor_; TexturePtr input_texture_; + QString shader_path_; + }; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index b78df3df4..6adab6348 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -57,6 +57,11 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix); } +void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) +{ + BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix, shader_path); +} + void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) { BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); @@ -103,7 +108,7 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx) +bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx, QString shader_path) { QMutexLocker locker(&color_cache_mutex_); @@ -123,11 +128,16 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo // Generate shader color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); - // Generate shader code using OCIO stub and our auto-generated name - QString shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")).arg( - shader_desc->getShaderText(), - ocio_func_name - ); + QString shader_frag; + if (shader_path.isEmpty()) { + // Generate shader code using OCIO stub and our auto-generated name + shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")) + .arg(shader_desc->getShaderText(), ocio_func_name); + } else { + // FIXME: Currently only supports a single function + shader_frag = FileFunctions::ReadFileAsString(shader_path) + .arg(shader_desc->getShaderText(), ocio_func_name); + } // Try to compile shader color_ctx.compiled_shader = CreateNativeShader(ShaderCode(shader_frag, @@ -208,10 +218,10 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture *destination, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, - const QMatrix4x4& crop_matrix) + const QMatrix4x4& crop_matrix, const QString shader_path) { ColorContext color_ctx; - if (!GetColorContext(color_processor, &color_ctx)) { + if (!GetColorContext(color_processor, &color_ctx, shader_path)) { return; } diff --git a/app/render/renderer.h b/app/render/renderer.h index 977fc98ce..58e306c4b 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -70,6 +70,7 @@ public: }; void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); + void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms); @@ -126,12 +127,12 @@ private: }; - bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); + bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, const QString shader_path); void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, VideoParams params, bool clear_destination, - const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix); + const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix, const QString shader_path = QString()); QHash color_cache_; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index f223824cb..55963a965 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -571,7 +571,7 @@ TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorT TexturePtr src = job.GetInputTexture(); TexturePtr dest = render_ctx_->CreateTexture(src->params()); - render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get()); + render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get(), job.GetShaderPath()); return dest; } diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag new file mode 100644 index 000000000..b4b35e524 --- /dev/null +++ b/app/shaders/chromakey.frag @@ -0,0 +1,34 @@ +uniform sampler2D tex_in; +in vec2 ove_texcoord; +out vec4 frag_color; + +// OCIO shader code +%1 + +// Assume D65 white point +float Xn = 95.0489; +float Yn = 100.0; +float Zn = 108.8840; +float delta = 0.20689655172; // 6/29 + +float func(float t) { + if (t > pow(delta, 3.0)){ + return pow(t, 1.0/3.0); + } else{ + return (t / (3.0 * pow(delta, 2))) + 4.0/29.0; + } +} + +void main() { + vec4 col = texture2D(tex_in, ove_texcoord); + vec4 new_col; + + new_col = %2(col); + + vec4 lab; + lab.r = 116.0 * func(col.g / Yn) - 16.0; + lab.g = 500.0 * (func(col.r / Xn) - func(col.g / Yn)); + lab.b = 200.0 * (func(col.g / Yn) - func(col.b / Zn)); + lab.w = 1.0; + frag_color = col; +} From 831fe7727559f7e16917520d582e92c90d79b009 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 24 Apr 2022 21:03:00 +0100 Subject: [PATCH 09/96] Cleanup and rename OCIO Linear Grading node --- app/node/color/CMakeLists.txt | 2 +- .../ociogradingtransform.cpp | 157 ------------------ .../CMakeLists.txt | 4 +- .../ociogradingtransformlinear.cpp | 125 ++++++++++++++ .../ociogradingtransformlinear.h} | 20 +-- app/node/factory.cpp | 6 +- app/node/factory.h | 2 +- app/render/renderer.cpp | 8 +- app/shaders/chromakey.frag | 36 ++-- 9 files changed, 169 insertions(+), 191 deletions(-) delete mode 100644 app/node/color/ociogradingtransform/ociogradingtransform.cpp rename app/node/color/{ociogradingtransform => ociogradingtransformlinear}/CMakeLists.txt (84%) create mode 100644 app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp rename app/node/color/{ociogradingtransform/ociogradingtransform.h => ociogradingtransformlinear/ociogradingtransformlinear.h} (74%) diff --git a/app/node/color/CMakeLists.txt b/app/node/color/CMakeLists.txt index 0cdea800e..046c499da 100644 --- a/app/node/color/CMakeLists.txt +++ b/app/node/color/CMakeLists.txt @@ -17,7 +17,7 @@ add_subdirectory(colormanager) add_subdirectory(displaytransform) add_subdirectory(ociobase) -add_subdirectory(ociogradingtransform) +add_subdirectory(ociogradingtransformlinear) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.cpp b/app/node/color/ociogradingtransform/ociogradingtransform.cpp deleted file mode 100644 index 27a8f57f0..000000000 --- a/app/node/color/ociogradingtransform/ociogradingtransform.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 "ociogradingtransform.h" - -#include "common/ocioutils.h" -#include "node/project/project.h" -#include "render/colorprocessor.h" - -namespace olive { - -const QString OCIOGradingTransformNode::kTypeInput = QStringLiteral("type_in"); -const QString OCIOGradingTransformNode::kBrightnessInput = QStringLiteral("brightness_in"); -const QString OCIOGradingTransformNode::kContrastInput = QStringLiteral("contrast_in"); -const QString OCIOGradingTransformNode::kGammaInput = QStringLiteral("gamma_in"); -const QString OCIOGradingTransformNode::kOffsetInput = QStringLiteral("offset_in"); -const QString OCIOGradingTransformNode::kExposureInput = QStringLiteral("exposure_in"); -const QString OCIOGradingTransformNode::kLiftInput = QStringLiteral("lift_in"); -const QString OCIOGradingTransformNode::kGainInput = QStringLiteral("gain_in"); -const QString OCIOGradingTransformNode::kSaturationInput = QStringLiteral("saturation_in"); -const QString OCIOGradingTransformNode::kPivotInput = QStringLiteral("pivot_in"); -const QString OCIOGradingTransformNode::kPivotBlackInput = QStringLiteral("pivot_black_in"); -const QString OCIOGradingTransformNode::kPivotWhiteInput = QStringLiteral("pivot_white_in"); -const QString OCIOGradingTransformNode::kClampBlackInput = QStringLiteral("clamp_black_in"); -const QString OCIOGradingTransformNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); - -#define super OCIOBaseNode - -OCIOGradingTransformNode::OCIOGradingTransformNode() -{ - AddInput(kTypeInput, NodeValue::kCombo, 0); - - //AddInput(kBrightnessInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); - - AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); - - //AddInput(kGammaInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - - AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - //AddInput(kLiftInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); - - //AddInput(kGainInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - - AddInput(kSaturationInput, NodeValue::kFloat, 1.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); - - AddInput(kPivotInput, NodeValue::kFloat, 0.203919098, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - // AddInput(kPivotBlackInput, NodeValue::kFloat, 0.0); - - //AddInput(kPivotWhiteInput, NodeValue::kFloat, 1.0); - - AddInput(kClampBlackInput, NodeValue::kFloat, 0.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); - - AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); -} - -QString OCIOGradingTransformNode::Name() const -{ - return tr("OCIO Grading Transform"); -} - -QString OCIOGradingTransformNode::id() const -{ - return QStringLiteral("org.olivevideoeditor.Olive.ociogradingtransform"); -} - -QVector OCIOGradingTransformNode::Category() const -{ - return {kCategoryColor}; -} - -QString OCIOGradingTransformNode::Description() const -{ - return tr("Simple color grading using OCIO"); -} - -void OCIOGradingTransformNode::Retranslate() -{ - super::Retranslate(); - - SetInputName(kTextureInput, tr("Input")); - SetInputName(kTypeInput, tr("Type")); - //SetInputName(kBrightnessInput, tr("Brightness")); - SetInputName(kContrastInput, tr("Contrast")); - //SetInputName(kGammaInput, tr("Gamma")); - SetInputName(kOffsetInput, tr("Offset")); - SetInputName(kExposureInput, tr("Exposure")); - //SetInputName(kLiftInput, tr("Lift")); - //SetInputName(kGainInput, tr("Gain")); - SetInputName(kSaturationInput, tr("Saturation")); - SetInputName(kPivotInput, tr("Pivot")); - //SetInputName(kPivotBlackInput, tr("Black Pivot")); - //SetInputName(kPivotWhiteInput, tr("White Pivot")); - SetInputName(kClampBlackInput, tr("Black Clamp")); - SetInputName(kClampWhiteInput, tr("White Clamp")); - - SetComboBoxStrings(kTypeInput, {"Linear"}); -} - -void OCIOGradingTransformNode::InputValueChangedEvent(const QString &input, int element) -{ - Q_UNUSED(element); - ConfigChanged(); -} - -void OCIOGradingTransformNode::ConfigChanged() -{ - OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - //auto gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); - //gp->makeDynamic(); - - OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; - //gpdata.m_lift = OCIOUtils::QVec4ToRGBM(GetStandardValue(kLiftInput).value()); - gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); - gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); - //gpdata.m_gamma = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGammaInput).value()); - //gpdata.m_gain = OCIOUtils::QVec4ToRGBM(GetStandardValue(kGainInput).value()); - gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); - gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); - gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); - gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); - //gpdata.m_pivotBlack = GetStandardValue(kPivotBlackInput).value(); - //gpdata.m_pivotWhite = GetStandardValue(kPivotWhiteInput).value(); - try { - gp->setValue(gpdata); - - set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); - } catch (const OCIO::Exception &e) { - std::cerr << std::endl << e.what() << std::endl; - } -} - -} diff --git a/app/node/color/ociogradingtransform/CMakeLists.txt b/app/node/color/ociogradingtransformlinear/CMakeLists.txt similarity index 84% rename from app/node/color/ociogradingtransform/CMakeLists.txt rename to app/node/color/ociogradingtransformlinear/CMakeLists.txt index ee382c689..05a3d4ae9 100644 --- a/app/node/color/ociogradingtransform/CMakeLists.txt +++ b/app/node/color/ociogradingtransformlinear/CMakeLists.txt @@ -16,7 +16,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - node/color/ociogradingtransform/ociogradingtransform.cpp - node/color/ociogradingtransform/ociogradingtransform.h + node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp + node/color/ociogradingtransformlinear/ociogradingtransformlinear.h PARENT_SCOPE ) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp new file mode 100644 index 000000000..2a9b263d5 --- /dev/null +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -0,0 +1,125 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "ociogradingtransformlinear.h" + +#include "common/ocioutils.h" +#include "node/project/project.h" +#include "render/colorprocessor.h" + +namespace olive { + +const QString OCIOGradingTransformLinearNode::kContrastInput = QStringLiteral("contrast_in"); +const QString OCIOGradingTransformLinearNode::kOffsetInput = QStringLiteral("offset_in"); +const QString OCIOGradingTransformLinearNode::kExposureInput = QStringLiteral("exposure_in"); +const QString OCIOGradingTransformLinearNode::kSaturationInput = QStringLiteral("saturation_in"); +const QString OCIOGradingTransformLinearNode::kPivotInput = QStringLiteral("pivot_in"); +const QString OCIOGradingTransformLinearNode::kClampBlackInput = QStringLiteral("clamp_black_in"); +const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); + +#define super OCIOBaseNode + +OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() +{ + AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); + + AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + + AddInput(kSaturationInput, NodeValue::kFloat, 1.0); + SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); + + AddInput(kPivotInput, NodeValue::kFloat, 0.203919098); + + AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); + + AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0); +} + +QString OCIOGradingTransformLinearNode::Name() const +{ + return tr("OCIO Linear Grading Transform"); +} + +QString OCIOGradingTransformLinearNode::id() const +{ + return QStringLiteral("org.olivevideoeditor.Olive.ociogradingtransformlinear"); +} + +QVector OCIOGradingTransformLinearNode::Category() const +{ + return {kCategoryColor}; +} + +QString OCIOGradingTransformLinearNode::Description() const +{ + return tr("Simple linearcolor grading using OCIO"); +} + +void OCIOGradingTransformLinearNode::Retranslate() +{ + super::Retranslate(); + + SetInputName(kTextureInput, tr("Input")); + SetInputName(kContrastInput, tr("Contrast")); + SetInputName(kOffsetInput, tr("Offset")); + SetInputName(kExposureInput, tr("Exposure")); + SetInputName(kSaturationInput, tr("Saturation")); + SetInputName(kPivotInput, tr("Pivot")); + SetInputName(kClampBlackInput, tr("Black Clamp")); + SetInputName(kClampWhiteInput, tr("White Clamp")); +} + +void OCIOGradingTransformLinearNode::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element); + GenerateProcessor(); +} + +void OCIOGradingTransformLinearNode::GenerateProcessor() +{ + OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); + + OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; + gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); + gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); + gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); + gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); + gpdata.m_pivot = GetStandardValue(kPivotInput).value(); + gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); + gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); + try { + gp->setValue(gpdata); + + set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; + } +} + +void OCIOGradingTransformLinearNode::ConfigChanged() +{ + GenerateProcessor(); +} + +} diff --git a/app/node/color/ociogradingtransform/ociogradingtransform.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h similarity index 74% rename from app/node/color/ociogradingtransform/ociogradingtransform.h rename to app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 99f2db214..883432a15 100644 --- a/app/node/color/ociogradingtransform/ociogradingtransform.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -18,22 +18,22 @@ ***/ -#ifndef OCIOGRADINGTRANSFORMNODE_H -#define OCIOGRADINGTRANSFORMNODE_H +#ifndef OCIOGRADINGTRANSFORMLINEARNODE_H +#define OCIOGRADINGTRANSFORMLINEARNODE_H #include "node/color/ociobase/ociobase.h" #include "render/colorprocessor.h" namespace olive { -class OCIOGradingTransformNode : public OCIOBaseNode +class OCIOGradingTransformLinearNode : public OCIOBaseNode { Q_OBJECT public: - OCIOGradingTransformNode(); + OCIOGradingTransformLinearNode(); - NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformNode) - NODE_COPY_FUNCTION(OCIOGradingTransformNode) + NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformLinearNode) + NODE_COPY_FUNCTION(OCIOGradingTransformLinearNode) virtual QString Name() const override; virtual QString id() const override; @@ -42,19 +42,13 @@ class OCIOGradingTransformNode : public OCIOBaseNode virtual void Retranslate() override; virtual void InputValueChangedEvent(const QString &input, int element) override; + void GenerateProcessor(); - static const QString kTypeInput; - static const QString kBrightnessInput; static const QString kContrastInput; - static const QString kGammaInput; static const QString kOffsetInput; static const QString kExposureInput; - static const QString kLiftInput; - static const QString kGainInput; static const QString kSaturationInput; static const QString kPivotInput; - static const QString kPivotBlackInput; - static const QString kPivotWhiteInput; static const QString kClampBlackInput; static const QString kClampWhiteInput; diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 0958d2d92..ab7632d7f 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -30,7 +30,7 @@ #include "block/transition/crossdissolve/crossdissolvetransition.h" #include "block/transition/diptocolor/diptocolortransition.h" #include "color/displaytransform/displaytransform.h" -#include "color/ociogradingtransform/ociogradingtransform.h" +#include "color/ociogradingtransformlinear/ociogradingtransformlinear.h" #include "distort/cornerpin/cornerpindistortnode.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" @@ -282,8 +282,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new CornerPinDistortNode(); case kDisplayTransform: return new DisplayTransformNode(); - case kOCIOGradingTransform: - return new OCIOGradingTransformNode(); + case kOCIOGradingTransformLinear: + return new OCIOGradingTransformLinearNode(); case kChromaKey: return new ChromaKeyNode(); diff --git a/app/node/factory.h b/app/node/factory.h index 42658cfb2..bb5878dab 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -71,7 +71,7 @@ public: kTimeOffsetNode, kCornerPinDistort, kDisplayTransform, - kOCIOGradingTransform, + kOCIOGradingTransformLinear, kChromaKey, // Count value diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 6adab6348..3eb7070e5 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -226,8 +226,12 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu } ShaderJob job; - - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); + if (shader_path.isEmpty()) { + job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); + } else { + // If we are using a custom shader in a node use "tex_in" for consistency + job.InsertValue(QStringLiteral("tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); + } job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix)); job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix.inverted())); job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, source_alpha_association)); diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index b4b35e524..c6dfbdb19 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -1,8 +1,12 @@ +// Main texture input uniform sampler2D tex_in; + + +// Main texture coordinate in vec2 ove_texcoord; out vec4 frag_color; -// OCIO shader code +// Program will replace this with OCIO's auto-generated shader code %1 // Assume D65 white point @@ -19,16 +23,24 @@ float func(float t) { } } -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - vec4 new_col; - - new_col = %2(col); - +vec4 CIExyz_to_Lab(vec4 CIE) { vec4 lab; - lab.r = 116.0 * func(col.g / Yn) - 16.0; - lab.g = 500.0 * (func(col.r / Xn) - func(col.g / Yn)); - lab.b = 200.0 * (func(col.g / Yn) - func(col.b / Zn)); - lab.w = 1.0; - frag_color = col; + lab.r = 116.0 * func(CIE.g / Yn) - 16.0; + lab.g = 500.0 * (func(CIE.r / Xn) - func(CIE.g / Yn)); + lab.b = 200.0 * (func(CIE.g / Yn) - func(CIE.b / Zn)); + lab.w = CIE.w; + + return lab; +} + + +void main() { + + vec4 col = texture(tex_in, ove_texcoord); + + // Perform color conversion + vec4 cie_xyz = %2(col); + vec4 lab = CIExyz_to_Lab(cie_xyz); + + frag_color = vec4(lab.r); } From 3c13e326202c513b8c1f7ca7cea28f24e4e5cb75 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Tue, 26 Apr 2022 13:13:28 -0700 Subject: [PATCH 10/96] further implement colortransformjob --- app/node/keying/chromakey/chromakey.cpp | 12 +++- app/node/keying/chromakey/chromakey.h | 1 + app/render/alphaassoc.h | 34 ++++++++++++ app/render/job/colortransformjob.h | 43 ++++++++++++-- app/render/renderer.cpp | 71 +++++++++--------------- app/render/renderer.h | 26 ++++----- app/render/renderprocessor.cpp | 37 ++++++++---- app/render/shadercode.h | 12 ++-- app/widget/scope/scopebase/scopebase.cpp | 8 ++- app/widget/viewer/viewerdisplay.cpp | 13 +++-- 10 files changed, 164 insertions(+), 93 deletions(-) create mode 100644 app/render/alphaassoc.h diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index b57781fbc..bf344f3ac 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -65,11 +65,16 @@ void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) GenerateProcessor(); } +ShaderCode ChromaKeyNode::GetShaderCode(const QString &) const +{ + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/chromakey.frag"))); +} + void ChromaKeyNode::GenerateProcessor() { if (manager()){ ColorTransform transform("cie_xyz_d65_interchange"); - set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); } } @@ -78,12 +83,13 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, if (!value[kTextureInput].data().isNull() && processor()) { ColorTransformJob job; + job.InsertValue(value); job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].data().value()); - job.SetShaderPath(QStringLiteral(":/shaders/chromakey.frag")); + job.SetNeedsCustomShader(this); table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); } } -} // namespace olive \ No newline at end of file +} // namespace olive diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index c14272e02..870601551 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -37,6 +37,7 @@ class ChromaKeyNode : public OCIOBaseNode { virtual void InputValueChangedEvent(const QString& input, int element) override; + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; virtual void ConfigChanged() override {}; diff --git a/app/render/alphaassoc.h b/app/render/alphaassoc.h new file mode 100644 index 000000000..22eb74835 --- /dev/null +++ b/app/render/alphaassoc.h @@ -0,0 +1,34 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 ALPHAASSOC_H +#define ALPHAASSOC_H + +namespace olive { + +enum AlphaAssociated { + kAlphaNone, + kAlphaUnassociated, + kAlphaAssociated +}; + +} + +#endif // ALPHAASSOC_H diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index 3bed475f8..dc7f7331e 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -21,19 +21,28 @@ #ifndef COLORTRANSFORMJOB_H #define COLORTRANSFORMJOB_H +#include #include +#include "render/job/acceleratedjob.h" +#include "render/alphaassoc.h" #include "render/colorprocessor.h" #include "render/texture.h" namespace olive { -class ColorTransformJob { +class Node; + +class ColorTransformJob : public AcceleratedJob +{ public: ColorTransformJob() { processor_ = nullptr; input_texture_ = nullptr; + custom_shader_src_ = nullptr; + input_alpha_association_ = kAlphaNone; + clear_destination_ = true; } TexturePtr GetInputTexture() const { return input_texture_; } @@ -42,15 +51,41 @@ public: ColorProcessorPtr GetColorProcessor() const { return processor_; } void SetColorProcessor(ColorProcessorPtr p) { processor_ = p; } - QString GetShaderPath() const { return shader_path_; } - void SetShaderPath(const QString shader_path) { shader_path_ = shader_path; } + const AlphaAssociated &GetInputAlphaAssociation() const { return input_alpha_association_; } + void SetInputAlphaAssociation(const AlphaAssociated &e) { input_alpha_association_ = e; } + + const Node *CustomShaderSource() const { return custom_shader_src_; } + const QString &CustomShaderID() const { return custom_shader_id_; } + void SetNeedsCustomShader(const Node *node, const QString &id = QString()) + { + custom_shader_src_ = node; + custom_shader_id_ = id; + } + + bool IsClearDestinationEnabled() const { return clear_destination_; } + void SetClearDestinationEnabled(bool e) { clear_destination_ = e; } + + const QMatrix4x4 &GetTransformMatrix() const { return matrix_; } + void SetTransformMatrix(const QMatrix4x4 &m) { matrix_ = m; } + + const QMatrix4x4 &GetCropMatrix() const { return crop_matrix_; } + void SetCropMatrix(const QMatrix4x4 &m) { crop_matrix_ = m; } private: ColorProcessorPtr processor_; TexturePtr input_texture_; - QString shader_path_; + const Node *custom_shader_src_; + QString custom_shader_id_; + + AlphaAssociated input_alpha_association_; + + bool clear_destination_; + + QMatrix4x4 matrix_; + + QMatrix4x4 crop_matrix_; }; diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 3eb7070e5..a4c0ae989 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -52,21 +52,6 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, return CreateTexture(params, Texture::k2D, data, linesize); } -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture *destination, bool clear_destination, const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix); -} - -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, destination, destination->params(), clear_destination, matrix, crop_matrix, shader_path); -} - -void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination, const QMatrix4x4& matrix, const QMatrix4x4 &crop_matrix) -{ - BlitColorManagedInternal(color_processor, source, source_alpha_association, nullptr, params, clear_destination, matrix, crop_matrix); -} - TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms) { color_cache_mutex_.lock(); @@ -108,14 +93,16 @@ TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const Vide return std::make_shared(this, v, params, type); } -bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx, QString shader_path) +bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::ColorContext *ctx) { QMutexLocker locker(&color_cache_mutex_); ColorContext& color_ctx = *ctx; - if (color_cache_.contains(color_processor->id())) { - color_ctx = color_cache_.value(color_processor->id()); + QString proc_id = color_job.GetColorProcessor()->id(); + + if (color_cache_.contains(proc_id)) { + color_ctx = color_cache_.value(proc_id); return true; } else { // Create shader description @@ -126,22 +113,21 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo shader_desc->setResourcePrefix("ocio_"); // Generate shader - color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); + color_job.GetColorProcessor()->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc); - QString shader_frag; - if (shader_path.isEmpty()) { - // Generate shader code using OCIO stub and our auto-generated name - shader_frag = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")) - .arg(shader_desc->getShaderText(), ocio_func_name); + ShaderCode code; + if (const Node *shader_src = color_job.CustomShaderSource()) { + // Use shader code from associated node + code = shader_src->GetShaderCode(color_job.CustomShaderID()); } else { - // FIXME: Currently only supports a single function - shader_frag = FileFunctions::ReadFileAsString(shader_path) - .arg(shader_desc->getShaderText(), ocio_func_name); + // Generate shader code using OCIO stub and our auto-generated name + code = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")); } + code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText(), ocio_func_name)); + // Try to compile shader - color_ctx.compiled_shader = CreateNativeShader(ShaderCode(shader_frag, - FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/default.vert")))); + color_ctx.compiled_shader = CreateNativeShader(code); if (color_ctx.compiled_shader.isNull()) { return false; @@ -209,32 +195,25 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; } - color_cache_.insert(color_processor->id(), color_ctx); + color_cache_.insert(proc_id, color_ctx); return true; } } -void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, - AlphaAssociated source_alpha_association, Texture *destination, - VideoParams params, bool clear_destination, const QMatrix4x4& matrix, - const QMatrix4x4& crop_matrix, const QString shader_path) +void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *destination, const VideoParams ¶ms) { ColorContext color_ctx; - if (!GetColorContext(color_processor, &color_ctx, shader_path)) { + if (!GetColorContext(color_job, &color_ctx)) { return; } ShaderJob job; - if (shader_path.isEmpty()) { - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); - } else { - // If we are using a custom shader in a node use "tex_in" for consistency - job.InsertValue(QStringLiteral("tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source))); - } - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix)); - job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix.inverted())); - job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, source_alpha_association)); + job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); + job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); + job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); + job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, color_job.GetInputAlphaAssociation())); + job.InsertValue(color_job.GetValues()); foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); @@ -246,9 +225,9 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu } if (destination) { - BlitToTexture(color_ctx.compiled_shader, job, destination, clear_destination); + BlitToTexture(color_ctx.compiled_shader, job, destination, color_job.IsClearDestinationEnabled()); } else { - Blit(color_ctx.compiled_shader, job, params, clear_destination); + Blit(color_ctx.compiled_shader, job, params, color_job.IsClearDestinationEnabled()); } } diff --git a/app/render/renderer.h b/app/render/renderer.h index 58e306c4b..e46ec7990 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -29,6 +29,7 @@ #include "common/timerange.h" #include "node/node.h" #include "render/colorprocessor.h" +#include "render/job/colortransformjob.h" #include "render/videoparams.h" #include "texture.h" @@ -63,15 +64,15 @@ public: Blit(shader, job, nullptr, params, clear_destination); } - enum AlphaAssociated { - kAlphaNone, - kAlphaUnassociated, - kAlphaAssociated - }; - - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, Texture* destination, QString shader_path, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); - void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, AlphaAssociated source_alpha_association, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4()); + void BlitColorManaged(const ColorTransformJob &color_job, Texture* destination, const VideoParams ¶ms); + void BlitColorManaged(const ColorTransformJob &job, Texture* destination) + { + BlitColorManaged(job, destination, destination->params()); + } + void BlitColorManaged(const ColorTransformJob &job, const VideoParams ¶ms) + { + BlitColorManaged(job, nullptr, params); + } TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms); @@ -127,12 +128,7 @@ private: }; - bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx, const QString shader_path); - - void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, - AlphaAssociated source_alpha_association, - Texture* destination, VideoParams params, bool clear_destination, - const QMatrix4x4 &matrix, const QMatrix4x4 &crop_matrix, const QString shader_path = QString()); + bool GetColorContext(const ColorTransformJob &color_job, ColorContext* ctx); QHash color_cache_; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 55963a965..5098ec8d9 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -99,9 +99,14 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time if (output_color_transform) { // Yes color transform, blit color managed - render_ctx_->BlitColorManaged(output_color_transform, texture, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, - blit_tex.get(), true, matrix); + ColorTransformJob job; + + job.SetColorProcessor(output_color_transform); + job.SetInputTexture(texture); + job.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + job.SetTransformMatrix(matrix); + + render_ctx_->BlitColorManaged(job, blit_tex.get()); } else { // No color transform, just blit ShaderJob job; @@ -452,19 +457,21 @@ TexturePtr RenderProcessor::ProcessVideoFootage(const FootageJob &stream, const using_colorspace, color_manager->GetReferenceColorSpace()); - Renderer::AlphaAssociated alpha_assoc; + ColorTransformJob job; + + job.SetColorProcessor(processor); + job.SetInputTexture(unmanaged_texture); + if (stream_data.channel_count() != VideoParams::kRGBAChannelCount || stream_data.colorspace() == color_manager->GetReferenceColorSpace()) { - alpha_assoc = Renderer::kAlphaNone; + job.SetInputAlphaAssociation(kAlphaNone); } else if (stream_data.premultiplied_alpha()) { - alpha_assoc = Renderer::kAlphaAssociated; + job.SetInputAlphaAssociation(kAlphaAssociated); } else { - alpha_assoc = Renderer::kAlphaUnassociated; + job.SetInputAlphaAssociation(kAlphaUnassociated); } - render_ctx_->BlitColorManaged(processor, unmanaged_texture, - alpha_assoc, - value.get()); + render_ctx_->BlitColorManaged(job, value.get()); return value; } @@ -571,7 +578,7 @@ TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorT TexturePtr src = job.GetInputTexture(); TexturePtr dest = render_ctx_->CreateTexture(src->params()); - render_ctx_->BlitColorManaged(job.GetColorProcessor(), src, Renderer::kAlphaAssociated, dest.get(), job.GetShaderPath()); + render_ctx_->BlitColorManaged(job, dest.get()); return dest; } @@ -600,7 +607,13 @@ TexturePtr RenderProcessor::ProcessFrameGeneration(const Node *node, const Gener TexturePtr dest = render_ctx_->CreateTexture(GetCacheVideoParams()); ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); ColorProcessorPtr cp = ColorProcessor::Create(color_manager, job.GetColorspace(), color_manager->GetReferenceColorSpace()); - render_ctx_->BlitColorManaged(cp, texture, Renderer::kAlphaAssociated, dest.get()); + ColorTransformJob ctj; + + ctj.SetColorProcessor(cp); + ctj.SetInputTexture(texture); + ctj.SetInputAlphaAssociation(kAlphaAssociated); + + render_ctx_->BlitColorManaged(ctj, dest.get()); texture = dest; } diff --git a/app/render/shadercode.h b/app/render/shadercode.h index c41422122..20c8b8079 100644 --- a/app/render/shadercode.h +++ b/app/render/shadercode.h @@ -33,15 +33,11 @@ public: { } - const QString& frag_code() const - { - return frag_code_; - } + const QString& frag_code() const { return frag_code_; } + void set_frag_code(const QString &f) { frag_code_ = f; } - const QString& vert_code() const - { - return vert_code_; - } + const QString& vert_code() const { return vert_code_; } + void set_vert_code(const QString &v) { vert_code_ = v; } private: QString frag_code_; diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 8e6074e74..2e152e052 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -74,7 +74,13 @@ void ScopeBase::OnPaint() if (!managed_tex_ || !managed_tex_up_to_date_ || managed_tex_->params() != texture_->params()) { managed_tex_ = renderer()->CreateTexture(texture_->params()); - renderer()->BlitColorManaged(color_service(), texture_, Renderer::kAlphaNone, managed_tex_.get()); + + ColorTransformJob job; + job.SetColorProcessor(color_service()); + job.SetInputTexture(texture_); + job.SetInputAlphaAssociation(kAlphaNone); + + renderer()->BlitColorManaged(job, managed_tex_.get()); } DrawScope(managed_tex_, pipeline_); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 7914763a9..a74d65d75 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -485,10 +485,15 @@ void ViewerDisplayWidget::OnPaint() texture_to_draw = deinterlace_texture_; } - renderer()->BlitColorManaged(color_service(), texture_to_draw, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, - device_params, false, - combined_matrix_flipped_, crop_matrix_); + ColorTransformJob ctj; + ctj.SetColorProcessor(color_service()); + ctj.SetInputTexture(texture_to_draw); + ctj.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + ctj.SetClearDestinationEnabled(false); + ctj.SetTransformMatrix(combined_matrix_flipped_); + ctj.SetCropMatrix(crop_matrix_); + + renderer()->BlitColorManaged(ctj, device_params); } } From f9f862268294ac132bd6c1bc40e4bc1683ec9696 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 27 Apr 2022 22:48:41 +0100 Subject: [PATCH 11/96] Add ability to set custom OCIO function names --- app/node/keying/chromakey/chromakey.cpp | 1 + app/render/job/colortransformjob.h | 5 +++++ app/render/renderer.cpp | 11 ++++++++--- app/shaders/chromakey.frag | 2 +- app/shaders/colormanage.frag | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index bf344f3ac..5c2ae1c7f 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -87,6 +87,7 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].data().value()); job.SetNeedsCustomShader(this); + job.SetFunctionName(QString("SceneLinearToCIEXYZ_d65")); table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); } diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index dc7f7331e..879f5c88c 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -71,6 +71,9 @@ public: const QMatrix4x4 &GetCropMatrix() const { return crop_matrix_; } void SetCropMatrix(const QMatrix4x4 &m) { crop_matrix_ = m; } + const QString &FunctionName() const { return function_name_; } + void SetFunctionName(const QString &function_name = QString()) { function_name_ = function_name; }; + private: ColorProcessorPtr processor_; @@ -87,6 +90,8 @@ private: QMatrix4x4 crop_matrix_; + QString function_name_; + }; } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index a4c0ae989..02cbb62a9 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -106,10 +106,15 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col return true; } else { // Create shader description - const char* ocio_func_name = "OCIODisplay"; + QString ocio_func_name; + if (color_job.FunctionName().isEmpty()) { + ocio_func_name = "OCIODisplay"; + } else { + ocio_func_name = color_job.FunctionName(); + } auto shader_desc = OCIO::GpuShaderDesc::CreateShaderDesc(); shader_desc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_3_0); - shader_desc->setFunctionName(ocio_func_name); + shader_desc->setFunctionName(ocio_func_name.toStdString().c_str()); shader_desc->setResourcePrefix("ocio_"); // Generate shader @@ -124,7 +129,7 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col code = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")); } - code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText(), ocio_func_name)); + code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText())); // Try to compile shader color_ctx.compiled_shader = CreateNativeShader(code); diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index c6dfbdb19..cc767d9be 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -39,7 +39,7 @@ void main() { vec4 col = texture(tex_in, ove_texcoord); // Perform color conversion - vec4 cie_xyz = %2(col); + vec4 cie_xyz = SceneLinearToCIEXYZ_d65(col); vec4 lab = CIExyz_to_Lab(cie_xyz); frag_color = vec4(lab.r); diff --git a/app/shaders/colormanage.frag b/app/shaders/colormanage.frag index e9461e71e..25efe5b50 100644 --- a/app/shaders/colormanage.frag +++ b/app/shaders/colormanage.frag @@ -44,7 +44,7 @@ void main() { } // Perform color conversion - col = %2(col); + col = OCIODisplay(col); // Associate or re-associate here if (ove_maintex_alpha == ALPHA_ASSOC) { From 2c31fdfc0eb555a2ee985c282e55582c632d491f Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 2 May 2022 20:47:18 +0100 Subject: [PATCH 12/96] Fix PR comments and generate mask --- app/node/keying/chromakey/chromakey.cpp | 13 ++++++++++--- app/node/keying/chromakey/chromakey.h | 3 +++ app/render/job/colortransformjob.h | 2 +- app/render/renderer.cpp | 10 +++++++--- app/shaders/chromakey.frag | 24 +++++++++++++++++++++++- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 5c2ae1c7f..7e430a123 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -22,8 +22,14 @@ namespace olive { #define super OCIOBaseNode +const QString ChromaKeyNode::kColorInput = QStringLiteral("color_key"); +const QString ChromaKeyNode::kMaskOnlyInput = QStringLiteral("mask_only_in"); + ChromaKeyNode::ChromaKeyNode() { + AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0.0f, 1.0f, 0.0f, 1.0f))); + + AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); } QString ChromaKeyNode::Name() const @@ -52,11 +58,11 @@ void ChromaKeyNode::Retranslate() SetInputName(kTextureInput, tr("Input")); //SetInputName(kGarbageMatteInput, tr("Garbage Matte")); //SetInputName(kCoreMatteInput, tr("Core Matte")); - //SetInputName(kColorInput, tr("Key Color")); + SetInputName(kColorInput, tr("Key Color")); //SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")}); //SetInputName(kShadowsInput, tr("Shadows")); //SetInputName(kHighlightsInput, tr("Highlights")); - //SetInputName(kMaskOnlyInput, tr("Show Mask Only")); + SetInputName(kMaskOnlyInput, tr("Show Mask Only")); } void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) @@ -84,10 +90,11 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, ColorTransformJob job; job.InsertValue(value); + job.SetInputAlphaAssociation(AlphaAssociated::kAlphaAssociated); job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].data().value()); job.SetNeedsCustomShader(this); - job.SetFunctionName(QString("SceneLinearToCIEXYZ_d65")); + job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); } diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 870601551..8b4c44e18 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -42,6 +42,9 @@ class ChromaKeyNode : public OCIOBaseNode { virtual void ConfigChanged() override {}; + static const QString kColorInput; + static const QString kMaskOnlyInput; + private: void GenerateProcessor(); diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index 879f5c88c..ec826fd66 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -71,7 +71,7 @@ public: const QMatrix4x4 &GetCropMatrix() const { return crop_matrix_; } void SetCropMatrix(const QMatrix4x4 &m) { crop_matrix_ = m; } - const QString &FunctionName() const { return function_name_; } + const QString &GetFunctionName() const { return function_name_; } void SetFunctionName(const QString &function_name = QString()) { function_name_ = function_name; }; private: diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 02cbb62a9..86f95a795 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -107,14 +107,14 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col } else { // Create shader description QString ocio_func_name; - if (color_job.FunctionName().isEmpty()) { + if (color_job.GetFunctionName().isEmpty()) { ocio_func_name = "OCIODisplay"; } else { - ocio_func_name = color_job.FunctionName(); + ocio_func_name = color_job.GetFunctionName(); } auto shader_desc = OCIO::GpuShaderDesc::CreateShaderDesc(); shader_desc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_ES_3_0); - shader_desc->setFunctionName(ocio_func_name.toStdString().c_str()); + shader_desc->setFunctionName(ocio_func_name.toUtf8()); shader_desc->setResourcePrefix("ocio_"); // Generate shader @@ -220,6 +220,10 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *des job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, color_job.GetInputAlphaAssociation())); job.InsertValue(color_job.GetValues()); + //if (color_job.GetInputAlphaAssociation() == AlphaAssociated::kAlphaAssociated) { + job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); + //} + foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); job.SetInterpolation(l.name, l.interpolation); diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index cc767d9be..070806c2e 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -1,5 +1,7 @@ // Main texture input uniform sampler2D tex_in; +uniform vec4 color_key; +uniform bool mask_only_in; // Main texture coordinate @@ -33,6 +35,14 @@ vec4 CIExyz_to_Lab(vec4 CIE) { return lab; } +float colorclose(vec4 col, vec4 key, float tola,float tolb) { + /*decides if a color is close to the specified hue*/ + float temp = sqrt(((key.g-col.g)*(key.g-col.g))+((key.b-col.b)*(key.b-col.b))); + if (temp < tola) {return (0.0);} + if (temp < tolb) {return ((temp-tola)/(tolb-tola));} + return (1.0); +} + void main() { @@ -42,5 +52,17 @@ void main() { vec4 cie_xyz = SceneLinearToCIEXYZ_d65(col); vec4 lab = CIExyz_to_Lab(cie_xyz); - frag_color = vec4(lab.r); + vec4 cie_xyz_key = SceneLinearToCIEXYZ_d65(color_key); + vec4 lab_key = CIExyz_to_Lab(cie_xyz_key); + + float mask = colorclose(lab, lab_key, 5.0, 25.0); + + col.rgb *= mask; + col.w = mask; + + if (!mask_only_in) { + frag_color = col; + } else { + frag_color = vec4(vec3(mask), 1.0); + } } From 4c8407a882e18857cb8614eb8565a84a81a3ca6c Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 2 May 2022 22:02:31 +0100 Subject: [PATCH 13/96] Add keying tolerance controls --- app/node/keying/chromakey/chromakey.cpp | 10 ++++++++++ app/node/keying/chromakey/chromakey.h | 2 ++ app/shaders/chromakey.frag | 4 +++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 7e430a123..4ec11aa5a 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -24,11 +24,19 @@ namespace olive { const QString ChromaKeyNode::kColorInput = QStringLiteral("color_key"); const QString ChromaKeyNode::kMaskOnlyInput = QStringLiteral("mask_only_in"); +const QString ChromaKeyNode::kUpperToleranceInput = QStringLiteral("upper_tolerence_in"); +const QString ChromaKeyNode::kLowerToleranceInput = QStringLiteral("lower_tolerence_in"); ChromaKeyNode::ChromaKeyNode() { AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0.0f, 1.0f, 0.0f, 1.0f))); + AddInput(kUpperToleranceInput, NodeValue::kFloat, 25.0); + SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), 0.0); + + AddInput(kLowerToleranceInput, NodeValue::kFloat, 5.0); + SetInputProperty(kLowerToleranceInput, QStringLiteral("min"), 0.0); + AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); } @@ -62,6 +70,8 @@ void ChromaKeyNode::Retranslate() //SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")}); //SetInputName(kShadowsInput, tr("Shadows")); //SetInputName(kHighlightsInput, tr("Highlights")); + SetInputName(kUpperToleranceInput, tr("Upper Tolerance")); + SetInputName(kLowerToleranceInput, tr("Lower Tolerance")); SetInputName(kMaskOnlyInput, tr("Show Mask Only")); } diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 8b4c44e18..84e4c2ca1 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -44,6 +44,8 @@ class ChromaKeyNode : public OCIOBaseNode { static const QString kColorInput; static const QString kMaskOnlyInput; + static const QString kUpperToleranceInput; + static const QString kLowerToleranceInput; private: void GenerateProcessor(); diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index 070806c2e..fbc4da00c 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -2,6 +2,8 @@ uniform sampler2D tex_in; uniform vec4 color_key; uniform bool mask_only_in; +uniform float upper_tolerence_in; +uniform float lower_tolerence_in; // Main texture coordinate @@ -55,7 +57,7 @@ void main() { vec4 cie_xyz_key = SceneLinearToCIEXYZ_d65(color_key); vec4 lab_key = CIExyz_to_Lab(cie_xyz_key); - float mask = colorclose(lab, lab_key, 5.0, 25.0); + float mask = colorclose(lab, lab_key, lower_tolerence_in, upper_tolerence_in); col.rgb *= mask; col.w = mask; From abc669fa8e3297489d7689b85071096d2316633e Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 2 May 2022 22:04:59 +0100 Subject: [PATCH 14/96] Attempt to fix build issue --- .../ociogradingtransformlinear/ociogradingtransformlinear.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 2a9b263d5..74098f5e7 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -20,6 +20,8 @@ #include "ociogradingtransformlinear.h" +#include + #include "common/ocioutils.h" #include "node/project/project.h" #include "render/colorprocessor.h" From 985131af5522a59ba0a551cd941693a42566d0cd Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 2 May 2022 15:16:27 -0700 Subject: [PATCH 15/96] pass colortransformjob alpha setting to shader --- app/node/keying/chromakey/chromakey.cpp | 2 +- app/render/job/colortransformjob.h | 4 ++-- app/render/renderer.cpp | 5 +---- app/render/renderprocessor.cpp | 6 +++++- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 4ec11aa5a..abfe25c0f 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -100,7 +100,7 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, ColorTransformJob job; job.InsertValue(value); - job.SetInputAlphaAssociation(AlphaAssociated::kAlphaAssociated); + job.SetAlphaChannelRequired(ColorTransformJob::kAlphaForceOn); job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].data().value()); job.SetNeedsCustomShader(this); diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index ec826fd66..bbc203226 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -24,7 +24,7 @@ #include #include -#include "render/job/acceleratedjob.h" +#include "render/job/generatejob.h" #include "render/alphaassoc.h" #include "render/colorprocessor.h" #include "render/texture.h" @@ -33,7 +33,7 @@ namespace olive { class Node; -class ColorTransformJob : public AcceleratedJob +class ColorTransformJob : public GenerateJob { public: ColorTransformJob() diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 86f95a795..66fb3853b 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -219,10 +219,7 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *des job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, color_job.GetInputAlphaAssociation())); job.InsertValue(color_job.GetValues()); - - //if (color_job.GetInputAlphaAssociation() == AlphaAssociated::kAlphaAssociated) { - job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - //} + job.SetAlphaChannelRequired(color_job.GetAlphaChannelRequired()); foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 5098ec8d9..d9db25303 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -576,7 +576,11 @@ SampleBufferPtr RenderProcessor::ProcessSamples(const Node *node, const TimeRang TexturePtr RenderProcessor::ProcessColorTransform(const Node *node, const ColorTransformJob &job) { TexturePtr src = job.GetInputTexture(); - TexturePtr dest = render_ctx_->CreateTexture(src->params()); + + VideoParams src_params = src->params(); + src_params.set_channel_count(GetChannelCountFromJob(job)); + + TexturePtr dest = render_ctx_->CreateTexture(src_params); render_ctx_->BlitColorManaged(job, dest.get()); From 5d0e90e6e4eac0689bca1238cfcdd0ee7756a382 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 3 May 2022 22:15:00 +0100 Subject: [PATCH 16/96] Set default connection --- app/node/keying/chromakey/chromakey.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index abfe25c0f..43ca49f88 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -38,6 +38,8 @@ ChromaKeyNode::ChromaKeyNode() SetInputProperty(kLowerToleranceInput, QStringLiteral("min"), 0.0); AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); + + SetEffectInput(kTextureInput); } QString ChromaKeyNode::Name() const From a508bd8cad685faa7fd97d776f9858ad091cd8e1 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 3 May 2022 22:50:59 +0100 Subject: [PATCH 17/96] Add mask controls to the chroma key node --- app/node/keying/chromakey/chromakey.cpp | 23 ++++++++--- app/node/keying/chromakey/chromakey.h | 4 ++ app/shaders/chromakey.frag | 55 ++++++++++++++++++++----- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 43ca49f88..9a399a386 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -26,6 +26,10 @@ const QString ChromaKeyNode::kColorInput = QStringLiteral("color_key"); const QString ChromaKeyNode::kMaskOnlyInput = QStringLiteral("mask_only_in"); const QString ChromaKeyNode::kUpperToleranceInput = QStringLiteral("upper_tolerence_in"); const QString ChromaKeyNode::kLowerToleranceInput = QStringLiteral("lower_tolerence_in"); +const QString ChromaKeyNode::kGarbageMatteInput = QStringLiteral("garbage_in"); +const QString ChromaKeyNode::kCoreMatteInput = QStringLiteral("core_in"); +const QString ChromaKeyNode::kShadowsInput = QStringLiteral("shadows_in"); +const QString ChromaKeyNode::kHighlightsInput = QStringLiteral("highlights_in"); ChromaKeyNode::ChromaKeyNode() { @@ -37,6 +41,16 @@ ChromaKeyNode::ChromaKeyNode() AddInput(kLowerToleranceInput, NodeValue::kFloat, 5.0); SetInputProperty(kLowerToleranceInput, QStringLiteral("min"), 0.0); + AddInput(kGarbageMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + AddInput(kCoreMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + AddInput(kHighlightsInput, NodeValue::kFloat, 100.0f); + SetInputProperty(kHighlightsInput, QStringLiteral("min"), 0.0); + + AddInput(kShadowsInput, NodeValue::kFloat, 100.0f); + SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0); + AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); SetEffectInput(kTextureInput); @@ -66,12 +80,11 @@ void ChromaKeyNode::Retranslate() { super::Retranslate(); SetInputName(kTextureInput, tr("Input")); - //SetInputName(kGarbageMatteInput, tr("Garbage Matte")); - //SetInputName(kCoreMatteInput, tr("Core Matte")); + SetInputName(kGarbageMatteInput, tr("Garbage Matte")); + SetInputName(kCoreMatteInput, tr("Core Matte")); SetInputName(kColorInput, tr("Key Color")); - //SetComboBoxStrings(kColorInput, {tr("Green"), tr("Blue")}); - //SetInputName(kShadowsInput, tr("Shadows")); - //SetInputName(kHighlightsInput, tr("Highlights")); + SetInputName(kShadowsInput, tr("Shadows")); + SetInputName(kHighlightsInput, tr("Highlights")); SetInputName(kUpperToleranceInput, tr("Upper Tolerance")); SetInputName(kLowerToleranceInput, tr("Lower Tolerance")); SetInputName(kMaskOnlyInput, tr("Show Mask Only")); diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 84e4c2ca1..3344ef019 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -46,6 +46,10 @@ class ChromaKeyNode : public OCIOBaseNode { static const QString kMaskOnlyInput; static const QString kUpperToleranceInput; static const QString kLowerToleranceInput; + static const QString kGarbageMatteInput; + static const QString kCoreMatteInput; + static const QString kShadowsInput; + static const QString kHighlightsInput; private: void GenerateProcessor(); diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index fbc4da00c..0b3fb132f 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -5,6 +5,14 @@ uniform bool mask_only_in; uniform float upper_tolerence_in; uniform float lower_tolerence_in; +uniform sampler2D garbage_in; +uniform sampler2D core_in; +uniform bool garbage_in_enabled; +uniform bool core_in_enabled; + +uniform float highlights_in; +uniform float shadows_in; + // Main texture coordinate in vec2 ove_texcoord; @@ -38,11 +46,11 @@ vec4 CIExyz_to_Lab(vec4 CIE) { } float colorclose(vec4 col, vec4 key, float tola,float tolb) { - /*decides if a color is close to the specified hue*/ - float temp = sqrt(((key.g-col.g)*(key.g-col.g))+((key.b-col.b)*(key.b-col.b))); - if (temp < tola) {return (0.0);} - if (temp < tolb) {return ((temp-tola)/(tolb-tola));} - return (1.0); + /*decides if a color is close to the specified hue*/ + float temp = sqrt(((key.g-col.g)*(key.g-col.g))+((key.b-col.b)*(key.b-col.b))); + if (temp < tola) {return (0.0);} + if (temp < tolb) {return ((temp-tola)/(tolb-tola));} + return (1.0); } @@ -50,8 +58,13 @@ void main() { vec4 col = texture(tex_in, ove_texcoord); + vec4 unassoc = col; + if (unassoc.a > 0) { + unassoc.rgb /= unassoc.a; + } + // Perform color conversion - vec4 cie_xyz = SceneLinearToCIEXYZ_d65(col); + vec4 cie_xyz = SceneLinearToCIEXYZ_d65(unassoc); vec4 lab = CIExyz_to_Lab(cie_xyz); vec4 cie_xyz_key = SceneLinearToCIEXYZ_d65(color_key); @@ -59,12 +72,34 @@ void main() { float mask = colorclose(lab, lab_key, lower_tolerence_in, upper_tolerence_in); + mask = clamp(mask, 0.0, 1.0); + + if (garbage_in_enabled) { + // Force anything we want to remove to be 0.0 + vec4 garbage = texture(garbage_in, ove_texcoord); + // Assumes garbage is achromatic + mask -= garbage.r; + mask = clamp(mask, 0.0, 1.0); + } + + if (core_in_enabled) { + // Force anything we want to keep to be 1.0 + vec3 core = texture(core_in, ove_texcoord).rgb; + // Assumes core is achromatic + mask += core.r; + mask = clamp(mask, 0.0, 1.0); + } + + // Crush blacks and push whites + mask = shadows_in * 0.01 * (highlights_in * 0.01 * mask - 1.0) + 1.0; + mask = clamp(mask, 0.0, 1.0); + col.rgb *= mask; col.w = mask; if (!mask_only_in) { - frag_color = col; - } else { - frag_color = vec4(vec3(mask), 1.0); - } + frag_color = col; + } else { + frag_color = vec4(vec3(mask), 1.0); + } } From 50ec381537f91c1b7c08a3c2aa05d3d7060b7307 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Tue, 3 May 2022 18:55:39 -0700 Subject: [PATCH 18/96] remove latent kColorTransformJob types --- app/node/color/ociobase/ociobase.cpp | 2 +- app/node/keying/chromakey/chromakey.cpp | 2 +- app/render/opengl/openglrenderer.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index db47c00ab..976ef35fb 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -58,7 +58,7 @@ void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, job.SetColorProcessor(processor_); job.SetInputTexture(value[kTextureInput].data().value()); - table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 9a399a386..c05c2cb8d 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -121,7 +121,7 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, job.SetNeedsCustomShader(this); job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); - table->Push(NodeValue::kColorTransformJob, QVariant::fromValue(job), this); + table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index b75826ec4..628ed8f15 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -520,7 +520,6 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video case NodeValue::kAudioParams: case NodeValue::kBezier: case NodeValue::kNone: - case NodeValue::kColorTransformJob: case NodeValue::kDataTypeCount: break; } From 91b761693bf42ab4416e402f13e7db1a5dc886b4 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 09:50:34 -0700 Subject: [PATCH 19/96] code: use config macro Macro is much easier to use and more readable --- app/audio/audiomanager.cpp | 2 +- app/audio/audiovisualwaveform.cpp | 2 +- app/config/config.h | 1 + app/core.cpp | 16 +++++----- app/dialog/about/about.cpp | 2 +- app/dialog/export/export.cpp | 2 +- .../tabs/preferencesappearancetab.cpp | 10 +++---- .../tabs/preferencesbehaviortab.cpp | 8 ++--- .../preferences/tabs/preferencesdisktab.cpp | 8 ++--- .../tabs/preferencesgeneraltab.cpp | 30 +++++++++---------- app/dialog/sequence/sequence.cpp | 16 +++++----- .../sequence/sequencedialogpresettab.cpp | 8 ++--- app/node/node.cpp | 6 ++-- app/node/output/viewer/viewer.cpp | 20 ++++++------- .../project/serializer/serializer210528.cpp | 2 +- .../project/serializer/serializer210907.cpp | 2 +- .../project/serializer/serializer211228.cpp | 2 +- app/panel/panelmanager.cpp | 2 +- app/render/diskmanager.cpp | 2 +- app/render/previewautocacher.cpp | 6 ++-- app/render/renderprocessor.cpp | 2 +- app/task/project/import/import.cpp | 2 +- app/timeline/timelinemarker.cpp | 2 +- app/ui/style/style.cpp | 2 +- app/widget/colorwheel/colorvalueswidget.cpp | 4 +-- .../handmovableview/handmovableview.cpp | 2 +- app/widget/scope/scopebase/scopebase.cpp | 2 +- app/widget/scope/waveform/waveform.cpp | 2 +- app/widget/slider/base/numericsliderbase.cpp | 2 +- app/widget/slider/base/sliderladder.cpp | 2 +- app/widget/timebased/timebasedwidget.cpp | 6 ++-- app/widget/timelinewidget/tool/import.cpp | 6 ++-- .../timelinewidget/undo/timelineundogeneral.h | 2 +- .../timelinewidget/view/timelineview.cpp | 6 ++-- app/widget/viewer/viewer.cpp | 12 ++++---- app/widget/viewer/viewerdisplay.cpp | 4 +-- app/window/mainwindow/mainmenu.cpp | 4 +-- app/window/mainwindow/mainwindow.cpp | 2 +- 38 files changed, 105 insertions(+), 106 deletions(-) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index 878944505..8fac9bd65 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -235,7 +235,7 @@ PaDeviceIndex AudioManager::FindConfigDeviceByName(bool is_output_device) { QString entry = is_output_device ? QStringLiteral("AudioOutput") : QStringLiteral("AudioInput"); - return FindDeviceByName(Config::Current()[entry].toString(), is_output_device); + return FindDeviceByName(OLIVE_CONFIG_STR(entry).toString(), is_output_device); } PaDeviceIndex AudioManager::FindDeviceByName(const QString &s, bool is_output_device) diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index af439bca0..dbc0cb973 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -426,7 +426,7 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con int start = qMax(rect.x(), -top_left.x()); int end = qMin(rect.right(), -top_left.x() + viewport.width()); - bool rectified = Config::Current()[QStringLiteral("RectifiedWaveforms")].toBool(); + bool rectified = OLIVE_CONFIG("RectifiedWaveforms").toBool(); for (int i=start;ihas_autorecovery_been_saved()) { QDir project_autorecovery_dir(QDir(FileFunctions::GetAutoRecoveryRoot()).filePath(p->GetUuid().toString())); @@ -986,7 +986,7 @@ void Core::SaveAutorecovery() realname_file.close(); } - int64_t max_recoveries_per_file = Config::Current()[QStringLiteral("AutorecoveryMaximum")].toLongLong(); + int64_t max_recoveries_per_file = OLIVE_CONFIG("AutorecoveryMaximum").toLongLong(); // Since we write an extra file, increment total allowed files by 1 max_recoveries_per_file++; @@ -1075,12 +1075,12 @@ Folder *Core::GetSelectedFolderInActiveProject() const Timecode::Display Core::GetTimecodeDisplay() const { - return static_cast(Config::Current()["TimecodeDisplay"].toInt()); + return static_cast(OLIVE_CONFIG("TimecodeDisplay").toInt()); } void Core::SetTimecodeDisplay(Timecode::Display d) { - Config::Current()["TimecodeDisplay"] = d; + OLIVE_CONFIG("TimecodeDisplay") = d; emit TimecodeDisplayChanged(d); } @@ -1202,7 +1202,7 @@ void Core::SetStartupLocale() } } - QString use_locale = Config::Current()[QStringLiteral("Language")].toString(); + QString use_locale = OLIVE_CONFIG("Language").toString(); if (use_locale.isEmpty()) { // No configured locale, auto-detect the system's locale @@ -1423,12 +1423,12 @@ QString GetRenderModePreferencePrefix(RenderMode::Mode mode, const QString &pref QVariant Core::GetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference) { - return Config::Current()[GetRenderModePreferencePrefix(mode, preference)]; + return OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)); } void Core::SetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference, const QVariant &value) { - Config::Current()[GetRenderModePreferencePrefix(mode, preference)] = value; + OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)) = value; } bool Core::LabelNodes(const QVector &nodes, MultiUndoCommand *parent) diff --git a/app/dialog/about/about.cpp b/app/dialog/about/about.cpp index e3500e217..066f8b537 100644 --- a/app/dialog/about/about.cpp +++ b/app/dialog/about/about.cpp @@ -132,7 +132,7 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) : void AboutDialog::accept() { if (dont_show_again_checkbox_ && dont_show_again_checkbox_->isChecked()) { - Config::Current()[QStringLiteral("ShowWelcomeDialog")] = false; + OLIVE_CONFIG("ShowWelcomeDialog") = false; } QDialog::accept(); diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 8723634e2..58813f7d5 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -208,7 +208,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->height_slider()->SetDefaultValue(vp.height()); video_tab_->SetSelectedFrameRate(vp.frame_rate()); video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(vp.pixel_aspect_ratio()); - video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()[QStringLiteral("OnlinePixelFormat")].toInt())); + video_tab_->pixel_format_field()->SetPixelFormat(static_cast(OLIVE_CONFIG("OnlinePixelFormat").toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing()); audio_tab_->sample_rate_combobox()->SetSampleRate(ap.sample_rate()); audio_tab_->sample_format_combobox()->SetAttemptToRestoreFormat(false); diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index 761ea18dd..63c5da053 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -74,7 +74,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() color_layout->addWidget(new QLabel(cat_name), i, 0); ColorCodingComboBox* ccc = new ColorCodingComboBox(); - ccc->SetColor(Config::Current()[QStringLiteral("CatColor%1").arg(i)].toInt()); + ccc->SetColor(OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(i)).toInt()); color_layout->addWidget(ccc, i, 1); color_btns_.append(ccc); } @@ -92,7 +92,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() marker_layout->addWidget(new QLabel("Default Marker Color"), 0, 0); marker_btn_ = new ColorCodingComboBox(); - marker_btn_->SetColor(Config::Current()[QStringLiteral("MarkerColor")].toInt()); + marker_btn_->SetColor(OLIVE_CONFIG("MarkerColor").toInt()); marker_layout->addWidget(marker_btn_, 0, 1); appearance_layout->addWidget(marker_group, row, 0, 1, 2); @@ -109,14 +109,14 @@ void PreferencesAppearanceTab::Accept(MultiUndoCommand *command) if (style_path != StyleManager::GetStyle()) { StyleManager::SetStyle(style_path); - Config::Current()[QStringLiteral("Style")] = style_path; + OLIVE_CONFIG("Style") = style_path; } for (int i=0; iGetSelectedColor(); + OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(i)) = color_btns_.at(i)->GetSelectedColor(); } - Config::Current()[QStringLiteral("MarkerColor")] = marker_btn_->GetSelectedColor(); + OLIVE_CONFIG("MarkerColor") = marker_btn_->GetSelectedColor(); } } diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp index 8d71b3df5..d16c7dce5 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp @@ -108,10 +108,8 @@ void PreferencesBehaviorTab::Accept(MultiUndoCommand *command) { Q_UNUSED(command) - QMap::const_iterator iterator; - - for (iterator=config_map_.begin();iterator!=config_map_.end();iterator++) { - Config::Current()[iterator.value()] = (iterator.key()->checkState(0) == Qt::Checked); + for (auto iterator=config_map_.begin();iterator!=config_map_.end();iterator++) { + OLIVE_CONFIG_STR(iterator.value()) = (iterator.key()->checkState(0) == Qt::Checked); } } @@ -119,7 +117,7 @@ QTreeWidgetItem* PreferencesBehaviorTab::AddItem(const QString &text, const QStr { QTreeWidgetItem* item = new QTreeWidgetItem({text}); item->setToolTip(0, tooltip); - item->setCheckState(0, Config::Current()[config_key].toBool() ? Qt::Checked : Qt::Unchecked); + item->setCheckState(0, OLIVE_CONFIG_STR(config_key).toBool() ? Qt::Checked : Qt::Unchecked); config_map_.insert(item, config_key); diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index f5258f34e..3d3ee3fa1 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -71,7 +71,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_ahead_slider_ = new FloatSlider(); cache_ahead_slider_->SetFormat(tr("%1 seconds")); cache_ahead_slider_->SetMinimum(0); - cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value().toDouble()); + cache_ahead_slider_->SetValue(OLIVE_CONFIG("DiskCacheAhead").value().toDouble()); cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1); cache_behavior_layout->addWidget(new QLabel(tr("Cache Behind:")), row, 2); @@ -79,7 +79,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_behind_slider_ = new FloatSlider(); cache_behind_slider_->SetMinimum(0); cache_behind_slider_->SetFormat(tr("%1 seconds")); - cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value().toDouble()); + cache_behind_slider_->SetValue(OLIVE_CONFIG("DiskCacheBehind").value().toDouble()); cache_behavior_layout->addWidget(cache_behind_slider_, row, 3); outer_layout->addStretch(); @@ -115,8 +115,8 @@ void PreferencesDiskTab::Accept(MultiUndoCommand *command) default_disk_cache_folder_->SetPath(disk_cache_location_->text()); } - Config::Current()["DiskCacheBehind"] = QVariant::fromValue(rational::fromDouble(cache_behind_slider_->GetValue())); - Config::Current()["DiskCacheAhead"] = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); + OLIVE_CONFIG("DiskCacheBehind") = QVariant::fromValue(rational::fromDouble(cache_behind_slider_->GetValue())); + OLIVE_CONFIG("DiskCacheAhead") = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); } } diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp index 3c869bb73..2e6425731 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -55,7 +55,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() AddLanguage(l); } - QString current_language = Config::Current()[QStringLiteral("Language")].toString(); + QString current_language = OLIVE_CONFIG("Language").toString(); if (current_language.isEmpty()) { // No configured language, use system language current_language = QLocale::system().name(); @@ -86,7 +86,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autoscroll_method_->addItem(tr("None"), AutoScroll::kNone); autoscroll_method_->addItem(tr("Page Scrolling"), AutoScroll::kPage); autoscroll_method_->addItem(tr("Smooth Scrolling"), AutoScroll::kSmooth); - autoscroll_method_->setCurrentIndex(Config::Current()["Autoscroll"].toInt()); + autoscroll_method_->setCurrentIndex(OLIVE_CONFIG("Autoscroll").toInt()); timeline_layout->addWidget(autoscroll_method_, row, 1); row++; @@ -94,7 +94,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() timeline_layout->addWidget(new QLabel(tr("Rectified Waveforms:")), row, 0); rectified_waveforms_ = new QCheckBox(); - rectified_waveforms_->setChecked(Config::Current()["RectifiedWaveforms"].toBool()); + rectified_waveforms_->setChecked(OLIVE_CONFIG("RectifiedWaveforms").toBool()); timeline_layout->addWidget(rectified_waveforms_, row, 1); row++; @@ -105,7 +105,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() default_still_length_->SetMinimum(rational(100, 1000)); default_still_length_->SetTimebase(rational(100, 1000)); default_still_length_->SetFormat(tr("%1 seconds")); - default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value()); + default_still_length_->SetValue(OLIVE_CONFIG("DefaultStillLength").value()); timeline_layout->addWidget(default_still_length_); } @@ -119,7 +119,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_layout->addWidget(new QLabel(tr("Enable Auto-Recovery:")), row, 0); autorecovery_enabled_ = new QCheckBox(); - autorecovery_enabled_->setChecked(Config::Current()[QStringLiteral("AutorecoveryEnabled")].toBool()); + autorecovery_enabled_->setChecked(OLIVE_CONFIG("AutorecoveryEnabled").toBool()); autorecovery_layout->addWidget(autorecovery_enabled_, row, 1); row++; @@ -130,7 +130,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_interval_->SetMinimum(1); autorecovery_interval_->SetMaximum(60); autorecovery_interval_->SetFormat(QT_TRANSLATE_N_NOOP("olive::SliderBase", "%n minute(s)"), true); - autorecovery_interval_->SetValue(Config::Current()[QStringLiteral("AutorecoveryInterval")].toLongLong()); + autorecovery_interval_->SetValue(OLIVE_CONFIG("AutorecoveryInterval").toLongLong()); autorecovery_layout->addWidget(autorecovery_interval_, row, 1); row++; @@ -140,7 +140,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_maximum_ = new IntegerSlider(); autorecovery_maximum_->SetMinimum(1); autorecovery_maximum_->SetMaximum(1000); - autorecovery_maximum_->SetValue(Config::Current()[QStringLiteral("AutorecoveryMaximum")].toLongLong()); + autorecovery_maximum_->SetValue(OLIVE_CONFIG("AutorecoveryMaximum").toLongLong()); autorecovery_layout->addWidget(autorecovery_maximum_, row, 1); row++; @@ -157,11 +157,11 @@ void PreferencesGeneralTab::Accept(MultiUndoCommand *command) { Q_UNUSED(command) - Config::Current()[QStringLiteral("RectifiedWaveforms")] = rectified_waveforms_->isChecked(); + OLIVE_CONFIG("RectifiedWaveforms") = rectified_waveforms_->isChecked(); - Config::Current()[QStringLiteral("Autoscroll")] = autoscroll_method_->currentData(); + OLIVE_CONFIG("Autoscroll") = autoscroll_method_->currentData(); - Config::Current()[QStringLiteral("DefaultStillLength")] = QVariant::fromValue(default_still_length_->GetValue()); + OLIVE_CONFIG("DefaultStillLength") = QVariant::fromValue(default_still_length_->GetValue()); QString set_language = language_combobox_->currentData().toString(); if (QLocale::system().name() == set_language) { @@ -170,14 +170,14 @@ void PreferencesGeneralTab::Accept(MultiUndoCommand *command) } // If the language has changed, set it now - if (Config::Current()[QStringLiteral("Language")].toString() != set_language) { - Config::Current()[QStringLiteral("Language")] = set_language; + if (OLIVE_CONFIG("Language").toString() != set_language) { + OLIVE_CONFIG("Language") = set_language; Core::instance()->SetLanguage(set_language.isEmpty() ? QLocale::system().name() : set_language); } - Config::Current()[QStringLiteral("AutorecoveryEnabled")] = autorecovery_enabled_->isChecked(); - Config::Current()[QStringLiteral("AutorecoveryInterval")] = QVariant::fromValue(autorecovery_interval_->GetValue()); - Config::Current()[QStringLiteral("AutorecoveryMaximum")] = QVariant::fromValue(autorecovery_maximum_->GetValue()); + OLIVE_CONFIG("AutorecoveryEnabled") = autorecovery_enabled_->isChecked(); + OLIVE_CONFIG("AutorecoveryInterval") = QVariant::fromValue(autorecovery_interval_->GetValue()); + OLIVE_CONFIG("AutorecoveryMaximum") = QVariant::fromValue(autorecovery_maximum_->GetValue()); Core::instance()->SetAutorecoveryInterval(autorecovery_interval_->GetValue()); } diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp index e7daa93e5..4305e1894 100644 --- a/app/dialog/sequence/sequence.cpp +++ b/app/dialog/sequence/sequence.cpp @@ -148,14 +148,14 @@ void SequenceDialog::SetAsDefaultClicked() tr("Are you sure you want to set the current parameters as defaults?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { // Maybe replace with Preset system - Config::Current()[QStringLiteral("DefaultSequenceWidth")] = parameter_tab_->GetSelectedVideoWidth(); - Config::Current()[QStringLiteral("DefaultSequenceHeight")] = parameter_tab_->GetSelectedVideoHeight(); - Config::Current()[QStringLiteral("DefaultSequencePixelAspect")] = QVariant::fromValue(parameter_tab_->GetSelectedVideoPixelAspect()); - Config::Current()[QStringLiteral("DefaultSequenceFrameRate")] = QVariant::fromValue(parameter_tab_->GetSelectedVideoFrameRate().flipped()); - Config::Current()[QStringLiteral("DefaultSequenceInterlacing")] = parameter_tab_->GetSelectedVideoInterlacingMode(); - Config::Current()[QStringLiteral("DefaultSequenceAudioFrequency")] = parameter_tab_->GetSelectedAudioSampleRate(); - Config::Current()[QStringLiteral("DefaultSequenceAudioLayout")] = QVariant::fromValue(parameter_tab_->GetSelectedAudioChannelLayout()); - Config::Current()[QStringLiteral("DefaultSequenceAutoCache")] = QVariant::fromValue(parameter_tab_->GetSelectedPreviewAutoCache()); + OLIVE_CONFIG("DefaultSequenceWidth") = parameter_tab_->GetSelectedVideoWidth(); + OLIVE_CONFIG("DefaultSequenceHeight") = parameter_tab_->GetSelectedVideoHeight(); + OLIVE_CONFIG("DefaultSequencePixelAspect") = QVariant::fromValue(parameter_tab_->GetSelectedVideoPixelAspect()); + OLIVE_CONFIG("DefaultSequenceFrameRate") = QVariant::fromValue(parameter_tab_->GetSelectedVideoFrameRate().flipped()); + OLIVE_CONFIG("DefaultSequenceInterlacing") = parameter_tab_->GetSelectedVideoInterlacingMode(); + OLIVE_CONFIG("DefaultSequenceAudioFrequency") = parameter_tab_->GetSelectedAudioSampleRate(); + OLIVE_CONFIG("DefaultSequenceAudioLayout") = QVariant::fromValue(parameter_tab_->GetSelectedAudioChannelLayout()); + OLIVE_CONFIG("DefaultSequenceAutoCache") = QVariant::fromValue(parameter_tab_->GetSelectedPreviewAutoCache()); } } diff --git a/app/dialog/sequence/sequencedialogpresettab.cpp b/app/dialog/sequence/sequencedialogpresettab.cpp index c3e471b9c..74c5a0595 100644 --- a/app/dialog/sequence/sequencedialogpresettab.cpp +++ b/app/dialog/sequence/sequencedialogpresettab.cpp @@ -100,8 +100,8 @@ QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name) QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider) { - const VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); - const bool default_autocache = Config::Current()[QStringLiteral("DefaultSequenceAutoCache")].toBool(); + const VideoParams::Format default_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); + const bool default_autocache = OLIVE_CONFIG("DefaultSequenceAutoCache").toBool(); QTreeWidgetItem* parent = CreateFolder(name); AddStandardItem(parent, std::make_shared(tr("%1 23.976 FPS").arg(name), width, @@ -163,8 +163,8 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider) { - const VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); - const bool default_autocache = Config::Current()[QStringLiteral("DefaultSequenceAutoCache")].toBool(); + const VideoParams::Format default_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); + const bool default_autocache = OLIVE_CONFIG("DefaultSequenceAutoCache").toBool(); QTreeWidgetItem* parent = CreateFolder(name); preset_tree_->addTopLevelItem(parent); AddStandardItem(parent, std::make_shared(tr("%1 Standard").arg(name), diff --git a/app/node/node.cpp b/app/node/node.cpp index 4a0c60b03..907287880 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -148,7 +148,7 @@ Color Node::color() const if (override_color_ >= 0) { c = override_color_; } else { - c = Config::Current()[QStringLiteral("CatColor%1").arg(this->Category().first())].toInt(); + c = OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(this->Category().first())).toInt(); } return ColorCoding::GetColor(c); @@ -171,7 +171,7 @@ QLinearGradient Node::gradient_color(qreal top, qreal bottom) const QBrush Node::brush(qreal top, qreal bottom) const { - if (Config::Current()[QStringLiteral("UseGradients")].toBool()) { + if (OLIVE_CONFIG("UseGradients").toBool()) { return gradient_color(top, bottom); } else { return color().toQColor(); @@ -1103,7 +1103,7 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command) { Node* copy; - if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + if (OLIVE_CONFIG("SplitClipsCopyNodes").toBool()) { copy = Node::CopyNodeAndDependencyGraphMinusItems(node, command); } else { copy = node->copy(); diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 3c01d17e2..0f5a35852 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -188,26 +188,26 @@ AudioParams ViewerOutput::GetFirstEnabledAudioStream() const void ViewerOutput::set_default_parameters() { - int width = Config::Current()["DefaultSequenceWidth"].toInt(); - int height = Config::Current()["DefaultSequenceHeight"].toInt(); + int width = OLIVE_CONFIG("DefaultSequenceWidth").toInt(); + int height = OLIVE_CONFIG("DefaultSequenceHeight").toInt(); SetVideoParams(VideoParams( width, height, - Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + OLIVE_CONFIG("DefaultSequenceFrameRate").value(), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount, - Config::Current()["DefaultSequencePixelAspect"].value(), - Config::Current()["DefaultSequenceInterlacing"].value(), + OLIVE_CONFIG("DefaultSequencePixelAspect").value(), + OLIVE_CONFIG("DefaultSequenceInterlacing").value(), VideoParams::generate_auto_divider(width, height) )); SetAudioParams(AudioParams( - Config::Current()["DefaultSequenceAudioFrequency"].toInt(), - Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), + OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(), + OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(), AudioParams::kInternalFormat )); - SetVideoAutoCacheEnabled(Config::Current()["DefaultSequenceAutoCache"].toBool()); + SetVideoAutoCacheEnabled(OLIVE_CONFIG("DefaultSequenceAutoCache").toBool()); } void ViewerOutput::ShiftVideoCache(const rational &from, const rational &to) @@ -499,7 +499,7 @@ void ViewerOutput::set_parameters_from_footage(const QVector foo SetVideoParams(VideoParams(s.width(), s.height(), using_timebase, - static_cast(Config::Current()[QStringLiteral("OfflinePixelFormat")].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount, s.pixel_aspect_ratio(), s.interlacing(), diff --git a/app/node/project/serializer/serializer210528.cpp b/app/node/project/serializer/serializer210528.cpp index baf53e442..47700b240 100644 --- a/app/node/project/serializer/serializer210528.cpp +++ b/app/node/project/serializer/serializer210528.cpp @@ -605,7 +605,7 @@ void ProjectSerializer210528::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/node/project/serializer/serializer210907.cpp b/app/node/project/serializer/serializer210907.cpp index 96b69f214..b65678a04 100644 --- a/app/node/project/serializer/serializer210907.cpp +++ b/app/node/project/serializer/serializer210907.cpp @@ -597,7 +597,7 @@ void ProjectSerializer210907::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/node/project/serializer/serializer211228.cpp b/app/node/project/serializer/serializer211228.cpp index 139fd2438..70ae3b494 100644 --- a/app/node/project/serializer/serializer211228.cpp +++ b/app/node/project/serializer/serializer211228.cpp @@ -647,7 +647,7 @@ void ProjectSerializer211228::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index e3959bfbf..edef10377 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -49,7 +49,7 @@ PanelWidget *PanelManager::CurrentlyFocused(bool enable_hover) const { // If hover focus is enabled, find the currently hovered panel and return it (if no panel is hovered, resort to // default behavior) - if (enable_hover && Config::Current()[QStringLiteral("HoverFocus")].toBool()) { + if (enable_hover && OLIVE_CONFIG("HoverFocus").toBool()) { PanelWidget* hovered = CurrentlyHovered(); if (hovered != nullptr) { diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index af67d6bfa..21b4b0413 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -196,7 +196,7 @@ DiskCacheFolder::DiskCacheFolder(const QString &path, QObject *parent) : { SetPath(path); - save_timer_.setInterval(Config::Current()[QStringLiteral("DiskCacheSaveInterval")].toInt()); + save_timer_.setInterval(OLIVE_CONFIG("DiskCacheSaveInterval").toInt()); connect(&save_timer_, &QTimer::timeout, this, &DiskCacheFolder::SaveDiskCacheIndex); save_timer_.start(); } diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index dcdb3d20a..c548b1f8f 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -48,7 +48,7 @@ PreviewAutoCacher::PreviewAutoCacher() : SetPlayhead(0); // Wait a certain amount of time before requeuing when we receive an invalidate signal - delayed_requeue_timer_.setInterval(Config::Current()[QStringLiteral("AutoCacheDelay")].toInt()); + delayed_requeue_timer_.setInterval(OLIVE_CONFIG("AutoCacheDelay").toInt()); delayed_requeue_timer_.setSingleShot(true); connect(&delayed_requeue_timer_, &QTimer::timeout, this, &PreviewAutoCacher::RequeueFrames); @@ -502,8 +502,8 @@ void PreviewAutoCacher::StartCachingAudioRange(const TimeRange &range) void PreviewAutoCacher::SetPlayhead(const rational &playhead) { - cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value(), - playhead + Config::Current()[QStringLiteral("DiskCacheAhead")].value()); + cache_range_ = TimeRange(playhead - OLIVE_CONFIG("DiskCacheBehind").value(), + playhead + OLIVE_CONFIG("DiskCacheAhead").value()); RequeueFrames(); } diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index cdb742d55..dc4556f8d 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -106,7 +106,7 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time if (output_color_transform) { // Yes color transform, blit color managed render_ctx_->BlitColorManaged(output_color_transform, texture, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, + OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, blit_tex.get(), true, matrix); } else { // No color transform, just blit diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index 352a8f175..900cc1d8b 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -203,7 +203,7 @@ void ProjectImportTask::ValidateImageSequence(Footage *footage, QFileInfoList& i // User has confirmed it is a still image, let's set it accordingly. video_stream.set_video_type(VideoParams::kVideoTypeImageSequence); - rational default_timebase = Config::Current()[QStringLiteral("DefaultSequenceFrameRate")].value(); + rational default_timebase = OLIVE_CONFIG("DefaultSequenceFrameRate").value(); video_stream.set_time_base(default_timebase); video_stream.set_frame_rate(default_timebase.flipped()); diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index 32eb98976..5fb5fb1fd 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -29,7 +29,7 @@ namespace olive { TimelineMarker::TimelineMarker(QObject *parent) : - color_(Config::Current()[QStringLiteral("MarkerColor")].toInt()) + color_(OLIVE_CONFIG("MarkerColor").toInt()) { setParent(parent); } diff --git a/app/ui/style/style.cpp b/app/ui/style/style.cpp index a63845984..af255fa38 100644 --- a/app/ui/style/style.cpp +++ b/app/ui/style/style.cpp @@ -136,7 +136,7 @@ void StyleManager::Init() available_themes_.insert(QStringLiteral("olive-dark"), QStringLiteral("Olive Dark")); available_themes_.insert(QStringLiteral("olive-light"), QStringLiteral("Olive Light")); - QString config_style = Config::Current()["Style"].toString(); + QString config_style = OLIVE_CONFIG("Style").toString(); if (config_style.isEmpty() || !available_themes_.contains(config_style)) { SetStyle(kDefaultStyle); diff --git a/app/widget/colorwheel/colorvalueswidget.cpp b/app/widget/colorwheel/colorvalueswidget.cpp index d65cf6b33..cb0218395 100644 --- a/app/widget/colorwheel/colorvalueswidget.cpp +++ b/app/widget/colorwheel/colorvalueswidget.cpp @@ -233,7 +233,7 @@ ColorValuesTab::ColorValuesTab(bool with_legacy_option, QWidget *parent) : if (with_legacy_option) { legacy_box_ = new QCheckBox(tr("Use legacy (8-bit) values")); - legacy_box_->setChecked(Config::Current()[QStringLiteral("UseLegacyColorInInputTab")].toBool()); + legacy_box_->setChecked(OLIVE_CONFIG("UseLegacyColorInInputTab").toBool()); connect(legacy_box_, &QCheckBox::clicked, this, &ColorValuesTab::LegacyChanged); layout->addWidget(legacy_box_, row, 0, 1, 2); row++; @@ -356,7 +356,7 @@ void ColorValuesTab::SliderChanged() void ColorValuesTab::LegacyChanged(bool legacy) { - Config::Current()[QStringLiteral("UseLegacyColorInInputTab")] = legacy; + OLIVE_CONFIG("UseLegacyColorInInputTab") = legacy; double legacy_multiplier = legacy ? kLegacyMultiplier : 1.0/kLegacyMultiplier; int decimal_places = legacy ? 0 : 5; diff --git a/app/widget/handmovableview/handmovableview.cpp b/app/widget/handmovableview/handmovableview.cpp index 5e0daa151..87086dcdc 100644 --- a/app/widget/handmovableview/handmovableview.cpp +++ b/app/widget/handmovableview/handmovableview.cpp @@ -32,7 +32,7 @@ namespace olive { HandMovableView::HandMovableView(QWidget* parent) : super(parent), dragging_hand_(false), - scroll_zooms_by_default_(Config::Current()[QStringLiteral("ScrollZooms")].toBool()) + scroll_zooms_by_default_(OLIVE_CONFIG("ScrollZooms").toBool()) { connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged); } diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 8e6074e74..94eb210cd 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -53,7 +53,7 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline) job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount)); } diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 1962be72f..7bd440751 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -73,7 +73,7 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount)); float waveform_dim_x = ceil((width() - 1.0) * waveform_scale); diff --git a/app/widget/slider/base/numericsliderbase.cpp b/app/widget/slider/base/numericsliderbase.cpp index 5dc4b7d6f..3e65d83ee 100644 --- a/app/widget/slider/base/numericsliderbase.cpp +++ b/app/widget/slider/base/numericsliderbase.cpp @@ -139,7 +139,7 @@ bool NumericSliderBase::IsDragging() const bool NumericSliderBase::UsingLadders() const { - return ladder_element_count_ > 0 && Config::Current()[QStringLiteral("UseSliderLadders")].toBool(); + return ladder_element_count_ > 0 && OLIVE_CONFIG("UseSliderLadders").toBool(); } QVariant NumericSliderBase::AdjustValue(const QVariant &value) const diff --git a/app/widget/slider/base/sliderladder.cpp b/app/widget/slider/base/sliderladder.cpp index b85ed4d95..c7a5ec7ad 100644 --- a/app/widget/slider/base/sliderladder.cpp +++ b/app/widget/slider/base/sliderladder.cpp @@ -48,7 +48,7 @@ SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QString setFrameShape(QFrame::Box); setLineWidth(1); - if (!Config::Current()[QStringLiteral("UseSliderLadders")].toBool()) { + if (!OLIVE_CONFIG("UseSliderLadders").toBool()) { nb_outer_values = 0; } diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 379dd8102..ae9ae8746 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -292,7 +292,7 @@ void TimeBasedWidget::SetTime(const rational &time) QMetaObject::invokeMethod(this, "CatchUpScrollToPlayhead", Qt::QueuedConnection); } else { // Otherwise, assume we jumped to this out of nowhere and must now autoscroll - switch (static_cast(Config::Current()["Autoscroll"].toInt())) { + switch (static_cast(OLIVE_CONFIG("Autoscroll").toInt())) { case AutoScroll::kNone: // Do nothing break; @@ -606,12 +606,12 @@ void TimeBasedWidget::SetMarker() color = closest->color(); } else { // Fallback to default color in preferences - color = Config::Current()[QStringLiteral("MarkerColor")].toInt(); + color = OLIVE_CONFIG("MarkerColor").toInt(); } TimelineMarker *marker = new TimelineMarker(color, TimeRange(GetTime(), GetTime())); - if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) { + if (OLIVE_CONFIG("SetNameWithMarker").toBool()) { MarkerPropertiesDialog mpd({marker}, timebase(), this); if (mpd.exec() != QDialog::Accepted) { delete marker; diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index fdcd49afc..ed81a6f8b 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -222,7 +222,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const DraggedFootageData if (footage_duration.isNull()) { // Fallback to still length if legngth was 0 - footage_duration = Config::Current()[QStringLiteral("DefaultStillLength")].value(); + footage_duration = OLIVE_CONFIG("DefaultStillLength").value(); } } @@ -285,7 +285,7 @@ void ImportTool::DropGhosts(bool insert) } else { // There's no active timeline here, ask the user what to do - DropWithoutSequenceBehavior behavior = static_cast(Config::Current()["DropWithoutSequenceBehavior"].toInt()); + DropWithoutSequenceBehavior behavior = static_cast(OLIVE_CONFIG("DropWithoutSequenceBehavior").toInt()); if (behavior == kDWSAsk) { QCheckBox* dont_ask_again_box = new QCheckBox(QCoreApplication::translate("ImportTool", "Don't ask me again")); @@ -312,7 +312,7 @@ void ImportTool::DropGhosts(bool insert) } if (behavior != kDWSDisable && dont_ask_again_box->isChecked()) { - Config::Current()["DropWithoutSequenceBehavior"] = behavior; + OLIVE_CONFIG("DropWithoutSequenceBehavior") = behavior; } } diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.h b/app/widget/timelinewidget/undo/timelineundogeneral.h index 40396f549..7c3df0a72 100644 --- a/app/widget/timelinewidget/undo/timelineundogeneral.h +++ b/app/widget/timelinewidget/undo/timelineundogeneral.h @@ -107,7 +107,7 @@ private: class TimelineAddTrackCommand : public UndoCommand { public: TimelineAddTrackCommand(TrackList *timeline) : - TimelineAddTrackCommand(timeline, Config::Current()[QStringLiteral("AutoMergeTracks")].toBool()) + TimelineAddTrackCommand(timeline, OLIVE_CONFIG("AutoMergeTracks").toBool()) { } diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 32f268c03..567d1d0f1 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -158,7 +158,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) QPoint angle_delta = event->angleDelta(); - if (Config::Current()[QStringLiteral("InvertTimelineScrollAxes")].toBool() // Check if config is set to invert timeline axes + if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool() // Check if config is set to invert timeline axes && event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though angle_delta = QPoint(angle_delta.y(), angle_delta.x()); } @@ -184,7 +184,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) Qt::Orientation orientation = event->orientation(); - if (Config::Current()["InvertTimelineScrollAxes"].toBool()) { + if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool()) { orientation = (orientation == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; } @@ -307,7 +307,7 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) Block *attached = Node::ValueToPtr(ghost->GetData(TimelineViewGhostItem::kAttachedBlock)); - if (attached && Config::Current()[QStringLiteral("ShowClipWhileDragging")].toBool()) { + if (attached && OLIVE_CONFIG("ShowClipWhileDragging").toBool()) { int adj_track = ghost->GetAdjustedTrack().index(); qreal track_top = GetTrackY(adj_track); qreal track_height = GetTrackHeight(adj_track); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index f8b25247a..80fe1a444 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -741,7 +741,7 @@ void ViewerWidget::PauseInternal() void ViewerWidget::PushScrubbedAudio() { - if (!IsPlaying() && GetConnectedNode() && Config::Current()[QStringLiteral("AudioScrubbing")].toBool()) { + if (!IsPlaying() && GetConnectedNode() && OLIVE_CONFIG("AudioScrubbing").toBool()) { // Get audio src device from renderer const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters(); @@ -1129,9 +1129,9 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) { QAction *stop_playback_on_last_frame = menu.addAction(tr("Stop Playback On Last Frame")); stop_playback_on_last_frame->setCheckable(true); - stop_playback_on_last_frame->setChecked(Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool()); + stop_playback_on_last_frame->setChecked(OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool()); connect(stop_playback_on_last_frame, &QAction::triggered, this, [](bool e){ - Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")] = e; + OLIVE_CONFIG("StopPlaybackOnLastFrame") = e; }); menu.addSeparator(); @@ -1180,7 +1180,7 @@ void ViewerWidget::Play(bool in_to_out_only) recording_filename_ = audio_path.filePath(QStringLiteral("%1.%2").arg( QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss"), - ExportFormat::GetExtension(static_cast(Config::Current()[QStringLiteral("AudioRecordingFormat")].toInt()))) + ExportFormat::GetExtension(static_cast(OLIVE_CONFIG("AudioRecordingFormat").toInt()))) ); AudioParams ap(OLIVE_CONFIG("AudioRecordingSampleRate").toInt(), OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong(), static_cast(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt())); @@ -1304,7 +1304,7 @@ void ViewerWidget::PlaybackTimerUpdate() // If we're stopping playback on the last frame rather than after it, subtract our max time // by one timebase unit - if (Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool()) { + if (OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool()) { max_time = qMax(min_time, max_time - timebase()); } @@ -1329,7 +1329,7 @@ void ViewerWidget::PlaybackTimerUpdate() // or restart playback end_of_line = true; - if (Config::Current()[QStringLiteral("Loop")].toBool() && !recording_) { + if (OLIVE_CONFIG("Loop").toBool() && !recording_) { // If we're looping, jump to the other side of the workarea and continue time_to_set = (tripped_time == min_time) ? max_time : min_time; diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 4a41a4c43..7ba11417c 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -428,7 +428,7 @@ void ViewerDisplayWidget::OnPaint() // Draw texture through color transform int device_width = width() * devicePixelRatioF(); int device_height = height() * devicePixelRatioF(); - VideoParams::Format device_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); + VideoParams::Format device_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount); if (push_mode_ == kPushBlank) { @@ -486,7 +486,7 @@ void ViewerDisplayWidget::OnPaint() } renderer()->BlitColorManaged(color_service(), texture_to_draw, - Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, + OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? Renderer::kAlphaAssociated : Renderer::kAlphaNone, device_params, false, combined_matrix_flipped_, crop_matrix_); } diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index c4ba08d5e..dec12a79e 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -381,7 +381,7 @@ void MainMenu::ToolsMenuAboutToShow() void MainMenu::PlaybackMenuAboutToShow() { - playback_loop_item_->setChecked(Config::Current()["Loop"].toBool()); + playback_loop_item_->setChecked(OLIVE_CONFIG("Loop").toBool()); } void MainMenu::SequenceMenuAboutToShow() @@ -506,7 +506,7 @@ void MainMenu::PlayInToOutTriggered() void MainMenu::LoopTriggered(bool enabled) { - Config::Current()["Loop"] = enabled; + OLIVE_CONFIG("Loop") = enabled; } void MainMenu::NextFrameTriggered() diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 6e02ffc07..8e247a76c 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -473,7 +473,7 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) void MainWindow::ShowWelcomeDialog() { - if (Config::Current()[QStringLiteral("ShowWelcomeDialog")].toBool()) { + if (OLIVE_CONFIG("ShowWelcomeDialog").toBool()) { AboutDialog ad(true, this); ad.exec(); } From d55d9c820f5c55bb273c02685b60fcfb12df21a8 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 11:01:17 -0700 Subject: [PATCH 20/96] code: use macros for default node functions Easier to maintain --- app/node/audio/pan/pan.cpp | 5 ----- app/node/audio/pan/pan.h | 4 +--- app/node/audio/volume/volume.cpp | 5 ----- app/node/audio/volume/volume.h | 4 +--- app/node/block/block.h | 2 -- app/node/block/clip/clip.cpp | 5 ----- app/node/block/clip/clip.h | 4 +--- app/node/block/gap/gap.cpp | 5 ----- app/node/block/gap/gap.h | 4 +--- app/node/block/subtitle/subtitle.cpp | 5 ----- app/node/block/subtitle/subtitle.h | 4 +--- .../transition/crossdissolve/crossdissolvetransition.cpp | 6 ------ .../transition/crossdissolve/crossdissolvetransition.h | 4 +--- .../block/transition/diptocolor/diptocolortransition.cpp | 5 ----- .../block/transition/diptocolor/diptocolortransition.h | 4 +--- app/node/block/transition/transition.h | 2 -- app/node/color/colormanager/colormanager.h | 7 ++----- app/node/distort/cornerpin/cornerpindistortnode.h | 7 +------ app/node/distort/crop/cropdistortnode.h | 7 +------ app/node/distort/flip/flipdistortnode.cpp | 5 ----- app/node/distort/flip/flipdistortnode.h | 4 +--- app/node/distort/transform/transformdistortnode.h | 7 +------ app/node/effect/opacity/opacityeffect.h | 4 +--- app/node/filter/blur/blur.cpp | 5 ----- app/node/filter/blur/blur.h | 4 +--- app/node/filter/mosaic/mosaicfilternode.h | 7 +------ app/node/filter/stroke/stroke.cpp | 5 ----- app/node/filter/stroke/stroke.h | 4 +--- app/node/generator/matrix/matrix.cpp | 5 ----- app/node/generator/matrix/matrix.h | 4 +--- app/node/generator/noise/noise.cpp | 5 ----- app/node/generator/noise/noise.h | 4 +--- app/node/generator/polygon/polygon.cpp | 5 ----- app/node/generator/polygon/polygon.h | 4 +--- app/node/generator/shape/generatorwithmerge.h | 2 -- app/node/generator/shape/shapenode.h | 3 +-- app/node/generator/shape/shapenodebase.h | 2 -- app/node/generator/solid/solid.cpp | 5 ----- app/node/generator/solid/solid.h | 4 +--- app/node/generator/text/textv1.h | 3 +-- app/node/generator/text/textv2.h | 3 +-- app/node/generator/text/textv3.h | 3 +-- app/node/group/group.h | 3 +-- app/node/input/time/timeinput.cpp | 5 ----- app/node/input/time/timeinput.h | 6 ++---- app/node/input/value/valuenode.h | 7 +------ app/node/keying/colordifferencekey/colordifferencekey.cpp | 5 ----- app/node/keying/colordifferencekey/colordifferencekey.h | 2 +- app/node/keying/despill/despill.cpp | 5 ----- app/node/keying/despill/despill.h | 8 ++++---- app/node/math/math/math.cpp | 5 ----- app/node/math/math/math.h | 4 +--- app/node/math/math/mathbase.h | 2 -- app/node/math/merge/merge.cpp | 5 ----- app/node/math/merge/merge.h | 4 +--- app/node/math/trigonometry/trigonometry.cpp | 5 ----- app/node/math/trigonometry/trigonometry.h | 4 +--- app/node/node.h | 4 ++++ app/node/output/track/track.cpp | 5 ----- app/node/output/track/track.h | 4 +--- app/node/output/viewer/viewer.cpp | 5 ----- app/node/output/viewer/viewer.h | 4 +--- app/node/project/folder/folder.h | 7 +------ app/node/project/footage/footage.h | 7 +------ app/node/project/projectsettings/projectsettings.h | 7 +------ app/node/project/sequence/sequence.h | 7 +------ app/node/time/timeoffset/timeoffsetnode.h | 3 +-- app/node/time/timeremap/timeremap.cpp | 5 ----- app/node/time/timeremap/timeremap.h | 4 +--- 69 files changed, 49 insertions(+), 269 deletions(-) diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index 482bf075f..c6311e67a 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -42,11 +42,6 @@ PanNode::PanNode() SetEffectInput(kSamplesInput); } -Node *PanNode::copy() const -{ - return new PanNode(); -} - QString PanNode::Name() const { return tr("Pan"); diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index 6f8fd9a89..075eafb02 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -31,9 +31,7 @@ class PanNode : public Node public: PanNode(); - NODE_DEFAULT_DESTRUCTOR(PanNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(PanNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 79feef607..e03d284b2 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -41,11 +41,6 @@ VolumeNode::VolumeNode() SetEffectInput(kSamplesInput); } -Node *VolumeNode::copy() const -{ - return new VolumeNode(); -} - QString VolumeNode::Name() const { return tr("Volume"); diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index a9fcc10d9..38ba243d8 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -31,9 +31,7 @@ class VolumeNode : public MathNodeBase public: VolumeNode(); - NODE_DEFAULT_DESTRUCTOR(VolumeNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(VolumeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/block.h b/app/node/block/block.h index a555cb065..33ddc00dd 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -37,8 +37,6 @@ class Block : public Node public: Block(); - NODE_DEFAULT_DESTRUCTOR(Block) - virtual QVector Category() const override; const rational& in() const diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index a7ce383b2..16720eafc 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -61,11 +61,6 @@ ClipBlock::ClipBlock() : SetEffectInput(kBufferIn); } -Node *ClipBlock::copy() const -{ - return new ClipBlock(); -} - QString ClipBlock::Name() const { if (track()) { diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 300f3408f..943c6ed15 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -37,9 +37,7 @@ class ClipBlock : public Block public: ClipBlock(); - NODE_DEFAULT_DESTRUCTOR(ClipBlock) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ClipBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/gap/gap.cpp b/app/node/block/gap/gap.cpp index d5ea6915c..60a066153 100644 --- a/app/node/block/gap/gap.cpp +++ b/app/node/block/gap/gap.cpp @@ -26,11 +26,6 @@ GapBlock::GapBlock() { } -Node *GapBlock::copy() const -{ - return new GapBlock(); -} - QString GapBlock::Name() const { return tr("Gap"); diff --git a/app/node/block/gap/gap.h b/app/node/block/gap/gap.h index c048e229e..5dfc01eb1 100644 --- a/app/node/block/gap/gap.h +++ b/app/node/block/gap/gap.h @@ -34,9 +34,7 @@ class GapBlock : public Block public: GapBlock(); - NODE_DEFAULT_DESTRUCTOR(GapBlock) - - virtual Node * copy() const override; + NODE_DEFAULT_FUNCTIONS(GapBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/subtitle/subtitle.cpp b/app/node/block/subtitle/subtitle.cpp index ef42559cd..8c60d8ee4 100644 --- a/app/node/block/subtitle/subtitle.cpp +++ b/app/node/block/subtitle/subtitle.cpp @@ -31,11 +31,6 @@ SubtitleBlock::SubtitleBlock() AddInput(kTextIn, NodeValue::kText, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); } -Node *SubtitleBlock::copy() const -{ - return new SubtitleBlock(); -} - QString SubtitleBlock::Name() const { return tr("Subtitle"); diff --git a/app/node/block/subtitle/subtitle.h b/app/node/block/subtitle/subtitle.h index c88a2bfc1..ed51c37d3 100644 --- a/app/node/block/subtitle/subtitle.h +++ b/app/node/block/subtitle/subtitle.h @@ -31,9 +31,7 @@ class SubtitleBlock : public ClipBlock public: SubtitleBlock(); - NODE_DEFAULT_DESTRUCTOR(SubtitleBlock) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(SubtitleBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index 8f9d33e62..bf50e7486 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -24,12 +24,6 @@ namespace olive { CrossDissolveTransition::CrossDissolveTransition() { - -} - -Node *CrossDissolveTransition::copy() const -{ - return new CrossDissolveTransition(); } QString CrossDissolveTransition::Name() const diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index aca4fd039..bd6f7ca9e 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -31,9 +31,7 @@ class CrossDissolveTransition : public TransitionBlock public: CrossDissolveTransition(); - NODE_DEFAULT_DESTRUCTOR(CrossDissolveTransition) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(CrossDissolveTransition) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 1c9691e13..5a64ed3de 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -29,11 +29,6 @@ DipToColorTransition::DipToColorTransition() AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0, 0, 0))); } -Node *DipToColorTransition::copy() const -{ - return new DipToColorTransition(); -} - QString DipToColorTransition::Name() const { return tr("Dip To Color"); diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index 00ff56550..66164d559 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -31,9 +31,7 @@ class DipToColorTransition : public TransitionBlock public: DipToColorTransition(); - NODE_DEFAULT_DESTRUCTOR(DipToColorTransition) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(DipToColorTransition) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 93577fcbc..e76888edd 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -33,8 +33,6 @@ class TransitionBlock : public Block public: TransitionBlock(); - NODE_DEFAULT_DESTRUCTOR(TransitionBlock) - virtual void Retranslate() override; rational in_offset() const; diff --git a/app/node/color/colormanager/colormanager.h b/app/node/color/colormanager/colormanager.h index 2dccc7270..06e0a8abd 100644 --- a/app/node/color/colormanager/colormanager.h +++ b/app/node/color/colormanager/colormanager.h @@ -38,6 +38,8 @@ class ColorManager : public Node public: ColorManager(); + NODE_DEFAULT_FUNCTIONS(ColorManager) + virtual QString Name() const override { return tr("Color Manager"); @@ -58,11 +60,6 @@ public: return tr("Color management configuration for project."); } - virtual Node* copy() const override - { - return new ColorManager(); - } - OCIO::ConstConfigRcPtr GetConfig() const; static OCIO::ConstConfigRcPtr CreateConfigFromFile(const QString& filename); diff --git a/app/node/distort/cornerpin/cornerpindistortnode.h b/app/node/distort/cornerpin/cornerpindistortnode.h index 86d80952f..8c5cae8cb 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.h +++ b/app/node/distort/cornerpin/cornerpindistortnode.h @@ -35,12 +35,7 @@ class CornerPinDistortNode : public Node public: CornerPinDistortNode(); - NODE_DEFAULT_DESTRUCTOR(CornerPinDistortNode) - - virtual Node* copy() const override - { - return new CornerPinDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(CornerPinDistortNode) virtual QString Name() const override { diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h index d2916a24d..402719281 100644 --- a/app/node/distort/crop/cropdistortnode.h +++ b/app/node/distort/crop/cropdistortnode.h @@ -36,12 +36,7 @@ class CropDistortNode : public Node public: CropDistortNode(); - NODE_DEFAULT_DESTRUCTOR(CropDistortNode) - - virtual Node* copy() const override - { - return new CropDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(CropDistortNode) virtual QString Name() const override { diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index 4589b4542..53fbcfb84 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -40,11 +40,6 @@ FlipDistortNode::FlipDistortNode() SetEffectInput(kTextureInput); } -Node* FlipDistortNode::copy() const -{ - return new FlipDistortNode(); -} - QString FlipDistortNode::Name() const { return tr("Flip"); diff --git a/app/node/distort/flip/flipdistortnode.h b/app/node/distort/flip/flipdistortnode.h index ba78023f1..3bb53bb0c 100644 --- a/app/node/distort/flip/flipdistortnode.h +++ b/app/node/distort/flip/flipdistortnode.h @@ -31,9 +31,7 @@ class FlipDistortNode : public Node public: FlipDistortNode(); - NODE_DEFAULT_DESTRUCTOR(FlipDistortNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(FlipDistortNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h index f584ff8e6..68e71d8a5 100644 --- a/app/node/distort/transform/transformdistortnode.h +++ b/app/node/distort/transform/transformdistortnode.h @@ -34,12 +34,7 @@ class TransformDistortNode : public MatrixGenerator public: TransformDistortNode(); - NODE_DEFAULT_DESTRUCTOR(TransformDistortNode) - - virtual Node* copy() const override - { - return new TransformDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(TransformDistortNode) virtual QString Name() const override { diff --git a/app/node/effect/opacity/opacityeffect.h b/app/node/effect/opacity/opacityeffect.h index d18af81cc..a7c8f7f0a 100644 --- a/app/node/effect/opacity/opacityeffect.h +++ b/app/node/effect/opacity/opacityeffect.h @@ -10,9 +10,7 @@ class OpacityEffect : public Node public: OpacityEffect(); - NODE_DEFAULT_DESTRUCTOR(OpacityEffect) - - NODE_COPY_FUNCTION(OpacityEffect) + NODE_DEFAULT_FUNCTIONS(OpacityEffect) virtual QString Name() const override { diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 0452c4fba..86d277ce1 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -50,11 +50,6 @@ BlurFilterNode::BlurFilterNode() SetEffectInput(kTextureInput); } -Node *BlurFilterNode::copy() const -{ - return new BlurFilterNode(); -} - QString BlurFilterNode::Name() const { return tr("Blur"); diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index 4b061040d..da70956a4 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -31,9 +31,7 @@ class BlurFilterNode : public Node public: BlurFilterNode(); - NODE_DEFAULT_DESTRUCTOR(BlurFilterNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(BlurFilterNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h index 726da5744..f1dea64e4 100644 --- a/app/node/filter/mosaic/mosaicfilternode.h +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -31,12 +31,7 @@ class MosaicFilterNode : public Node public: MosaicFilterNode(); - NODE_DEFAULT_DESTRUCTOR(MosaicFilterNode) - - virtual Node* copy() const override - { - return new MosaicFilterNode(); - } + NODE_DEFAULT_FUNCTIONS(MosaicFilterNode) virtual QString Name() const override { diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index d0360cc10..6f05f61fa 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -53,11 +53,6 @@ StrokeFilterNode::StrokeFilterNode() SetEffectInput(kTextureInput); } -Node *StrokeFilterNode::copy() const -{ - return new StrokeFilterNode(); -} - QString StrokeFilterNode::Name() const { return tr("Stroke"); diff --git a/app/node/filter/stroke/stroke.h b/app/node/filter/stroke/stroke.h index d70e7e7bc..d762b3923 100644 --- a/app/node/filter/stroke/stroke.h +++ b/app/node/filter/stroke/stroke.h @@ -31,9 +31,7 @@ class StrokeFilterNode : public Node public: StrokeFilterNode(); - NODE_DEFAULT_DESTRUCTOR(StrokeFilterNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(StrokeFilterNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index bbd5c9ba6..30cbf6065 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -51,11 +51,6 @@ MatrixGenerator::MatrixGenerator() AddInput(kAnchorInput, NodeValue::kVec2, QVector2D(0.0, 0.0)); } -Node *MatrixGenerator::copy() const -{ - return new MatrixGenerator(); -} - QString MatrixGenerator::Name() const { return tr("Orthographic Matrix"); diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 6ccb318a0..3466c703d 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -34,9 +34,7 @@ class MatrixGenerator : public Node public: MatrixGenerator(); - NODE_DEFAULT_DESTRUCTOR(MatrixGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MatrixGenerator) virtual QString Name() const override; virtual QString ShortName() const override; diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index 213910ad4..0d4e3c832 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -44,11 +44,6 @@ NoiseGeneratorNode::NoiseGeneratorNode() SetFlags(kVideoEffect); } -Node* NoiseGeneratorNode::copy() const -{ - return new NoiseGeneratorNode(); -} - QString NoiseGeneratorNode::Name() const { return tr("Noise"); diff --git a/app/node/generator/noise/noise.h b/app/node/generator/noise/noise.h index 36cbd7fe8..7b8ea005c 100644 --- a/app/node/generator/noise/noise.h +++ b/app/node/generator/noise/noise.h @@ -30,9 +30,7 @@ class NoiseGeneratorNode : public Node { public: NoiseGeneratorNode(); - NODE_DEFAULT_DESTRUCTOR(NoiseGeneratorNode) - - virtual Node *copy() const override; + NODE_DEFAULT_FUNCTIONS(NoiseGeneratorNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 40283689b..cb294b9ed 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -61,11 +61,6 @@ PolygonGenerator::PolygonGenerator() poly_gizmo_ = new PathGizmo(this); } -Node *PolygonGenerator::copy() const -{ - return new PolygonGenerator(); -} - QString PolygonGenerator::Name() const { return tr("Polygon"); diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index 2f2e4e467..0b2d98457 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -39,9 +39,7 @@ class PolygonGenerator : public GeneratorWithMerge public: PolygonGenerator(); - NODE_DEFAULT_DESTRUCTOR(PolygonGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(PolygonGenerator) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/shape/generatorwithmerge.h b/app/node/generator/shape/generatorwithmerge.h index 9345f2d64..af69e1ed4 100644 --- a/app/node/generator/shape/generatorwithmerge.h +++ b/app/node/generator/shape/generatorwithmerge.h @@ -31,8 +31,6 @@ class GeneratorWithMerge : public Node public: GeneratorWithMerge(); - NODE_DEFAULT_DESTRUCTOR(GeneratorWithMerge) - virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; diff --git a/app/node/generator/shape/shapenode.h b/app/node/generator/shape/shapenode.h index 2df95bed4..7ae7d5469 100644 --- a/app/node/generator/shape/shapenode.h +++ b/app/node/generator/shape/shapenode.h @@ -36,8 +36,7 @@ public: kEllipse }; - NODE_DEFAULT_DESTRUCTOR(ShapeNode) - NODE_COPY_FUNCTION(ShapeNode) + NODE_DEFAULT_FUNCTIONS(ShapeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/shape/shapenodebase.h b/app/node/generator/shape/shapenodebase.h index 451c32dea..4d9b01006 100644 --- a/app/node/generator/shape/shapenodebase.h +++ b/app/node/generator/shape/shapenodebase.h @@ -35,8 +35,6 @@ class ShapeNodeBase : public GeneratorWithMerge public: ShapeNodeBase(bool create_color_input = true); - NODE_DEFAULT_DESTRUCTOR(ShapeNodeBase) - virtual void Retranslate() override; virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index 713a096a7..0bfe93f9c 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -34,11 +34,6 @@ SolidGenerator::SolidGenerator() AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(1.0f, 0.0f, 0.0f, 1.0f))); } -Node *SolidGenerator::copy() const -{ - return new SolidGenerator(); -} - QString SolidGenerator::Name() const { return tr("Solid"); diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index 9e60090bc..55f5bdb50 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -31,9 +31,7 @@ class SolidGenerator : public Node public: SolidGenerator(); - NODE_DEFAULT_DESTRUCTOR(SolidGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(SolidGenerator) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv1.h b/app/node/generator/text/textv1.h index 868e22449..85e4f24cf 100644 --- a/app/node/generator/text/textv1.h +++ b/app/node/generator/text/textv1.h @@ -31,8 +31,7 @@ class TextGeneratorV1 : public Node public: TextGeneratorV1(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV1) - NODE_COPY_FUNCTION(TextGeneratorV1) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV1) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv2.h b/app/node/generator/text/textv2.h index d9fb17386..d98443dfc 100644 --- a/app/node/generator/text/textv2.h +++ b/app/node/generator/text/textv2.h @@ -31,8 +31,7 @@ class TextGeneratorV2 : public ShapeNodeBase public: TextGeneratorV2(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV2) - NODE_COPY_FUNCTION(TextGeneratorV2) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV2) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv3.h b/app/node/generator/text/textv3.h index 1fd9237c4..f2cd2d47c 100644 --- a/app/node/generator/text/textv3.h +++ b/app/node/generator/text/textv3.h @@ -32,8 +32,7 @@ class TextGeneratorV3 : public ShapeNodeBase public: TextGeneratorV3(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV3) - NODE_COPY_FUNCTION(TextGeneratorV3) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV3) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/group/group.h b/app/node/group/group.h index fe2151b26..d906c987e 100644 --- a/app/node/group/group.h +++ b/app/node/group/group.h @@ -31,8 +31,7 @@ class NodeGroup : public Node public: NodeGroup(); - NODE_DEFAULT_DESTRUCTOR(NodeGroup) - NODE_COPY_FUNCTION(NodeGroup) + NODE_DEFAULT_FUNCTIONS(NodeGroup) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index 96f80f385..b9e46c27a 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -28,11 +28,6 @@ TimeInput::TimeInput() { } -Node *TimeInput::copy() const -{ - return new TimeInput(); -} - QString TimeInput::Name() const { return tr("Time"); diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index c5afc75f4..c892e351c 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -27,13 +27,11 @@ namespace olive { class TimeInput : public Node { - Q_OBJECT + Q_OBJECT public: TimeInput(); - NODE_DEFAULT_DESTRUCTOR(TimeInput) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TimeInput) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/input/value/valuenode.h b/app/node/input/value/valuenode.h index 2d6d2ada8..8d2569786 100644 --- a/app/node/input/value/valuenode.h +++ b/app/node/input/value/valuenode.h @@ -31,12 +31,7 @@ class ValueNode : public Node public: ValueNode(); - NODE_DEFAULT_DESTRUCTOR(ValueNode) - - virtual Node* copy() const override - { - return new ValueNode(); - } + NODE_DEFAULT_FUNCTIONS(ValueNode) virtual QString Name() const override { diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index 39595e039..534d06a78 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -49,11 +49,6 @@ ColorDifferenceKeyNode::ColorDifferenceKeyNode() SetEffectInput(kTextureInput); } -Node *ColorDifferenceKeyNode::copy() const -{ - return new ColorDifferenceKeyNode(); -} - QString ColorDifferenceKeyNode::Name() const { return tr("Color Difference Key"); diff --git a/app/node/keying/colordifferencekey/colordifferencekey.h b/app/node/keying/colordifferencekey/colordifferencekey.h index 01ddaf718..3b4809256 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.h +++ b/app/node/keying/colordifferencekey/colordifferencekey.h @@ -24,7 +24,7 @@ class ColorDifferenceKeyNode : public Node { public: ColorDifferenceKeyNode(); - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ColorDifferenceKeyNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index e72124f31..17ea0a5ca 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -40,11 +40,6 @@ DespillNode::DespillNode() SetEffectInput(kTextureInput); } -Node* DespillNode::copy() const -{ - return new DespillNode(); -} - QString DespillNode::Name() const { return tr("Despill"); diff --git a/app/node/keying/despill/despill.h b/app/node/keying/despill/despill.h index c5aaed49d..098cb3132 100644 --- a/app/node/keying/despill/despill.h +++ b/app/node/keying/despill/despill.h @@ -25,7 +25,7 @@ class DespillNode : public Node { public: DespillNode(); - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(DespillNode) virtual QString Name() const override; virtual QString id() const override; @@ -36,13 +36,13 @@ class DespillNode : public Node { virtual ShaderCode GetShaderCode(const QString& shader_id) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; - + static const QString kTextureInput; static const QString kColorInput; static const QString kMethodInput; static const QString kPreserveLuminanceInput; - - + + }; } // namespace olive diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 932a963d1..123f768fa 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -42,11 +42,6 @@ MathNode::MathNode() SetInputProperty(kParamBIn, QStringLiteral("autotrim"), true); } -Node *MathNode::copy() const -{ - return new MathNode(); -} - QString MathNode::Name() const { return tr("Math"); diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index b87b09a19..6001db776 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -31,9 +31,7 @@ class MathNode : public MathNodeBase public: MathNode(); - NODE_DEFAULT_DESTRUCTOR(MathNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MathNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/math/math/mathbase.h b/app/node/math/math/mathbase.h index 6391c10d3..77f3fe336 100644 --- a/app/node/math/math/mathbase.h +++ b/app/node/math/math/mathbase.h @@ -30,8 +30,6 @@ class MathNodeBase : public Node public: MathNodeBase() = default; - NODE_DEFAULT_DESTRUCTOR(MathNodeBase) - enum Operation { kOpAdd, kOpSubtract, diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 1f1c9be42..5a911e8a2 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -38,11 +38,6 @@ MergeNode::MergeNode() SetFlags(kDontShowInParamView); } -Node *MergeNode::copy() const -{ - return new MergeNode(); -} - QString MergeNode::Name() const { return tr("Merge"); diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index fff8bbd5a..f73994a3f 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -31,9 +31,7 @@ class MergeNode : public Node public: MergeNode(); - NODE_DEFAULT_DESTRUCTOR(MergeNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MergeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index 5c6e16663..461ba538a 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -34,11 +34,6 @@ TrigonometryNode::TrigonometryNode() AddInput(kXIn, NodeValue::kFloat, 0.0); } -olive::Node *olive::TrigonometryNode::copy() const -{ - return new TrigonometryNode(); -} - QString TrigonometryNode::Name() const { return tr("Trigonometry"); diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index 1f1058f6b..a78f9ea59 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -31,9 +31,7 @@ class TrigonometryNode : public Node public: TrigonometryNode(); - NODE_DEFAULT_DESTRUCTOR(TrigonometryNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TrigonometryNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/node.h b/app/node/node.h index 98fcd8e27..f8ef73fa7 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -48,6 +48,10 @@ namespace olive { +#define NODE_DEFAULT_FUNCTIONS(x) \ + NODE_DEFAULT_DESTRUCTOR(x) \ + NODE_COPY_FUNCTION(x) + #define NODE_DEFAULT_DESTRUCTOR(x) \ virtual ~x() override {DisconnectAll();} diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index f4244804b..ce34c2240 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -66,11 +66,6 @@ const Track::Type& Track::type() const return track_type_; } -Node *Track::copy() const -{ - return new Track(); -} - QString Track::Name() const { if (track_type_ == Track::kVideo) { diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 72a1b6a78..237a70f15 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -45,13 +45,11 @@ public: Track(); - NODE_DEFAULT_DESTRUCTOR(Track) + NODE_DEFAULT_FUNCTIONS(Track) const Track::Type& type() const; void set_type(const Track::Type& track_type); - virtual Node* copy() const override; - virtual QString Name() const override; virtual QString id() const override; virtual QVector Category() const override; diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 0f5a35852..b1d9db487 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -72,11 +72,6 @@ ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_stream timeline_points_ = new TimelinePoints(this); } -Node *ViewerOutput::copy() const -{ - return new ViewerOutput(); -} - QString ViewerOutput::Name() const { return tr("Viewer"); diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index ee207c6ec..2edf2d344 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -46,9 +46,7 @@ class ViewerOutput : public Node public: ViewerOutput(bool create_buffer_inputs = true, bool create_default_streams = true); - NODE_DEFAULT_DESTRUCTOR(ViewerOutput) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ViewerOutput) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/project/folder/folder.h b/app/node/project/folder/folder.h index 12677e57b..7c779719d 100644 --- a/app/node/project/folder/folder.h +++ b/app/node/project/folder/folder.h @@ -37,12 +37,7 @@ class Folder : public Node public: Folder(); - NODE_DEFAULT_DESTRUCTOR(Folder) - - virtual Node* copy() const override - { - return new Folder(); - } + NODE_DEFAULT_FUNCTIONS(Folder) virtual QString Name() const override { diff --git a/app/node/project/footage/footage.h b/app/node/project/footage/footage.h index aed465106..77202dbe8 100644 --- a/app/node/project/footage/footage.h +++ b/app/node/project/footage/footage.h @@ -55,12 +55,7 @@ public: */ Footage(const QString& filename = QString()); - NODE_DEFAULT_DESTRUCTOR(Footage) - - virtual Node* copy() const override - { - return new Footage(); - } + NODE_DEFAULT_FUNCTIONS(Footage) virtual QString Name() const override { diff --git a/app/node/project/projectsettings/projectsettings.h b/app/node/project/projectsettings/projectsettings.h index ce1890847..35b9d578c 100644 --- a/app/node/project/projectsettings/projectsettings.h +++ b/app/node/project/projectsettings/projectsettings.h @@ -31,7 +31,7 @@ class ProjectSettingsNode : public Node public: ProjectSettingsNode(); - NODE_DEFAULT_DESTRUCTOR(ProjectSettingsNode) + NODE_DEFAULT_FUNCTIONS(ProjectSettingsNode) virtual QString Name() const override { @@ -53,11 +53,6 @@ public: return tr("Settings used throughout the project."); } - virtual Node* copy() const override - { - return new ProjectSettingsNode(); - } - enum CacheSetting { kCacheUseDefaultLocation, kCacheStoreAlongsideProject, diff --git a/app/node/project/sequence/sequence.h b/app/node/project/sequence/sequence.h index 62900b031..40cc9f4d6 100644 --- a/app/node/project/sequence/sequence.h +++ b/app/node/project/sequence/sequence.h @@ -36,12 +36,7 @@ class Sequence : public ViewerOutput public: Sequence(); - NODE_DEFAULT_DESTRUCTOR(Sequence) - - virtual Node* copy() const override - { - return new Sequence(); - } + NODE_DEFAULT_FUNCTIONS(Sequence) virtual QString Name() const override { diff --git a/app/node/time/timeoffset/timeoffsetnode.h b/app/node/time/timeoffset/timeoffsetnode.h index b44a1f1e0..961492245 100644 --- a/app/node/time/timeoffset/timeoffsetnode.h +++ b/app/node/time/timeoffset/timeoffsetnode.h @@ -30,8 +30,7 @@ class TimeOffsetNode : public Node public: TimeOffsetNode(); - NODE_DEFAULT_DESTRUCTOR(TimeOffsetNode) - NODE_COPY_FUNCTION(TimeOffsetNode) + NODE_DEFAULT_FUNCTIONS(TimeOffsetNode) virtual QString Name() const override { diff --git a/app/node/time/timeremap/timeremap.cpp b/app/node/time/timeremap/timeremap.cpp index ff2b1ff77..e903ad8eb 100644 --- a/app/node/time/timeremap/timeremap.cpp +++ b/app/node/time/timeremap/timeremap.cpp @@ -39,11 +39,6 @@ TimeRemapNode::TimeRemapNode() AddInput(kInputInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable)); } -Node *TimeRemapNode::copy() const -{ - return new TimeRemapNode(); -} - QString TimeRemapNode::Name() const { return tr("Time Remap"); diff --git a/app/node/time/timeremap/timeremap.h b/app/node/time/timeremap/timeremap.h index 6cdaf618a..a9a8cdb53 100644 --- a/app/node/time/timeremap/timeremap.h +++ b/app/node/time/timeremap/timeremap.h @@ -31,9 +31,7 @@ class TimeRemapNode : public Node public: TimeRemapNode(); - NODE_DEFAULT_DESTRUCTOR(TimeRemapNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TimeRemapNode) virtual QString Name() const override; virtual QString id() const override; From 494370cc49bf2ae01e05f2b9b15519c3178e5509 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 11:04:34 -0700 Subject: [PATCH 21/96] timeline: add rename action This used to be possible in properties, but then the properties action changed. Oops. --- app/widget/timelinewidget/timelinewidget.cpp | 16 ++++++++++++++++ app/widget/timelinewidget/timelinewidget.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index eba333b85..4f2a67647 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1079,6 +1079,9 @@ void TimelineWidget::ShowContextMenu() } } + QAction* rename_action = menu.addAction(tr("Rename")); + connect(rename_action, &QAction::triggered, this, &TimelineWidget::RenameSelectedBlocks); + QAction* properties_action = menu.addAction(tr("Properties")); connect(properties_action, &QAction::triggered, this, &TimelineWidget::ShowSpeedDurationDialogForSelectedClips); } @@ -1232,6 +1235,19 @@ void TimelineWidget::RevealInProject() emit RevealViewerInProject(item_to_reveal); } +void TimelineWidget::RenameSelectedBlocks() +{ + MultiUndoCommand *command = new MultiUndoCommand(); + QVector nodes(selected_blocks_.size()); + + for (int i=0; iLabelNodes(nodes); + Core::instance()->undo_stack()->pushIfHasChildren(command); +} + void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost) { ghost_items_.append(ghost); diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index a0b9afaaa..cd515b67f 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -414,6 +414,8 @@ private slots: void RevealInProject(); + void RenameSelectedBlocks(); + }; } From 2827758fae9e54301d6edc36780ce43362d53bba Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 4 May 2022 20:04:43 +0100 Subject: [PATCH 22/96] Cleanup --- app/node/keying/chromakey/chromakey.cpp | 8 ++++++-- app/shaders/chromakey.frag | 2 +- app/shaders/stub.frag | 13 ------------- 3 files changed, 7 insertions(+), 16 deletions(-) delete mode 100644 app/shaders/stub.frag diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index c05c2cb8d..5660c42a0 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -104,8 +104,12 @@ ShaderCode ChromaKeyNode::GetShaderCode(const QString &) const void ChromaKeyNode::GenerateProcessor() { if (manager()){ - ColorTransform transform("cie_xyz_d65_interchange"); - set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + try { + ColorTransform transform("cie_xyz_d65_interchange"); + set_processor(ColorProcessor::Create(manager(), manager()->GetReferenceColorSpace(), transform)); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; + } } } diff --git a/app/shaders/chromakey.frag b/app/shaders/chromakey.frag index 0b3fb132f..8c707e644 100644 --- a/app/shaders/chromakey.frag +++ b/app/shaders/chromakey.frag @@ -46,7 +46,7 @@ vec4 CIExyz_to_Lab(vec4 CIE) { } float colorclose(vec4 col, vec4 key, float tola,float tolb) { - /*decides if a color is close to the specified hue*/ + // Decides if a color is close to the specified hue float temp = sqrt(((key.g-col.g)*(key.g-col.g))+((key.b-col.b)*(key.b-col.b))); if (temp < tola) {return (0.0);} if (temp < tolb) {return ((temp-tola)/(tolb-tola));} diff --git a/app/shaders/stub.frag b/app/shaders/stub.frag deleted file mode 100644 index ccc1b86dd..000000000 --- a/app/shaders/stub.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D tex_in; -in vec2 ove_texcoord; -out vec4 frag_color; - -%1 - -void main() { - vec4 col = texture2D(tex_in, ove_texcoord); - - col = %2(col); - - frag_color = col; -} From 07519a952eb9ed47c3f9df3679b76e23c1249fe9 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 14:25:15 -0700 Subject: [PATCH 23/96] traverser: handle invalid audio params --- app/node/traverser.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/node/traverser.h b/app/node/traverser.h index 01a57ce29..63feed9ab 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -107,7 +107,11 @@ protected: SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, const rational &length) { - return CreateSampleBuffer(params, params.time_to_samples(length)); + if (params.is_valid()) { + return CreateSampleBuffer(params, params.time_to_samples(length)); + } else { + return SampleBuffer::Create(); + } } virtual bool CanCacheFrames() From 102ce9aa7ba0c08b0a61dd8ac6742e8f351abfea Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 14:59:51 -0700 Subject: [PATCH 24/96] nodeparamview/nodeview: connect selections and enable multi-select in npv --- app/node/node.h | 5 + app/panel/node/node.cpp | 3 +- app/panel/node/node.h | 8 +- app/panel/param/param.cpp | 12 +- app/panel/param/param.h | 10 +- app/widget/nodeparamview/nodeparamview.cpp | 225 ++++++++++++++---- app/widget/nodeparamview/nodeparamview.h | 17 +- .../nodeparamviewconnectedlabel.cpp | 2 +- .../nodeparamviewconnectedlabel.h | 2 +- app/widget/nodeparamview/nodeparamviewitem.h | 4 +- .../nodeparamview/nodeparamviewitembase.cpp | 8 + .../nodeparamview/nodeparamviewitembase.h | 4 + .../nodeparamviewitemtitlebar.cpp | 7 + .../nodeparamview/nodeparamviewitemtitlebar.h | 3 + app/widget/nodeview/nodeview.cpp | 36 ++- app/widget/nodeview/nodeview.h | 7 +- app/widget/nodeview/nodeviewundo.cpp | 28 ++- app/widget/nodeview/nodeviewundo.h | 6 +- app/window/mainwindow/mainwindow.cpp | 7 +- 19 files changed, 294 insertions(+), 100 deletions(-) diff --git a/app/node/node.h b/app/node/node.h index f8ef73fa7..4f45277d6 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -104,6 +104,11 @@ public: kAudioEffect = 0x4 }; + struct ContextPair { + Node *node; + Node *context; + }; + Node(); virtual ~Node() override; diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 5e694867b..d618c7d80 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -28,9 +28,10 @@ NodePanel::NodePanel(QWidget *parent) : node_widget_ = new NodeWidget(); connect(this, &NodePanel::visibilityChanged, node_widget_->view(), &NodeView::CenterOnItemsBoundingRect); - // Connect node view signals to this panel - MAY REMOVE connect(node_widget_->view(), &NodeView::NodesSelected, this, &NodePanel::NodesSelected); connect(node_widget_->view(), &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected); + connect(node_widget_->view(), &NodeView::NodeSelectionChanged, this, &NodePanel::NodeSelectionChanged); + connect(node_widget_->view(), &NodeView::NodeSelectionChangedWithContexts, this, &NodePanel::NodeSelectionChangedWithContexts); connect(node_widget_->view(), &NodeView::NodeGroupOpened, this, &NodePanel::NodeGroupOpened); connect(node_widget_->view(), &NodeView::NodeGroupClosed, this, &NodePanel::NodeGroupClosed); diff --git a/app/panel/node/node.h b/app/panel/node/node.h index b9a5ebf35..c8ebccaaa 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -105,10 +105,9 @@ public: } public slots: - void Select(const QVector& nodes, bool center_view_on_item) + void Select(const QVector &p) { - node_widget_->view()->Select(nodes, center_view_on_item); - this->raise(); + node_widget_->view()->Select(p, true); } signals: @@ -116,6 +115,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 8504a86b4..368a6abd2 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -28,24 +28,14 @@ ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) { NodeParamView* view = new NodeParamView(); - connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode); connect(view, &NodeParamView::FocusedNodeChanged, this, &ParamPanel::FocusedNodeChanged); + connect(view, &NodeParamView::SelectedNodesChanged, this, &ParamPanel::SelectedNodesChanged); connect(this, &ParamPanel::visibilityChanged, view, &NodeParamView::UpdateElementY); SetTimeBasedWidget(view); Retranslate(); } -void ParamPanel::SelectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->SelectNodes(nodes); -} - -void ParamPanel::DeselectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); -} - void ParamPanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 25b50a2db..9cfb881c0 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -49,8 +49,10 @@ public: } public slots: - void SelectNodes(const QVector& nodes); - void DeselectNodes(const QVector& nodes); + void SetSelectedNodes(const QVector &nodes) + { + GetParamView()->SetSelectedNodes(nodes, false); + } virtual void DeleteSelected() override; @@ -61,10 +63,10 @@ public slots: void SetContexts(const QVector &contexts); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void Retranslate() override; diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index f812c121e..2f97d8133 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -155,10 +155,11 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : SetScale(120); // Pickup on widget focus changes - connect(qApp, + // DISABLED - we now just handle this with item/titlebar clicking (see ToggleSelect) + /*connect(qApp, &QApplication::focusChanged, this, - &NodeParamView::FocusChanged); + &NodeParamView::FocusChanged);*/ } NodeParamView::~NodeParamView() @@ -297,12 +298,25 @@ void NodeParamView::ItemAboutToBeRemoved(NodeParamViewItem *item) } } - if (focused_node_ == item) { - focused_node_ = nullptr; - emit FocusedNodeChanged(nullptr); + QVector copy = selected_nodes_; + if (copy.removeOne(item)) { + SetSelectedNodes(copy); } } +void NodeParamView::ItemClicked() +{ + ToggleSelect(static_cast(sender())); +} + +void NodeParamView::SelectNodeFromConnectedLink(Node *node) +{ + NodeParamViewItem *item = static_cast(sender()); + + Node::ContextPair p = {node, item->GetContext()}; + SetSelectedNodes({p}); +} + void NodeParamView::SetContexts(const QVector &contexts) { // Setting contexts is expensive, so we queue it here to prevent multiple calls in a short timespan @@ -371,41 +385,138 @@ Node *NodeParamView::GetTimeTarget() const return time_target_; } +void ReconnectOutputsIfNotDeletingNode(MultiUndoCommand *c, NodeViewDeleteCommand *dc, Node *output, Node *deleting, Node *context) +{ + for (auto it=deleting->output_connections().cbegin(); it!=deleting->output_connections().cend(); it++) { + const NodeInput &proposed_reconnect = it->second; + + if (dc->ContainsNode(proposed_reconnect.node(), context)) { + // Uh-oh we're deleting this node too, instead connect to its outputs + ReconnectOutputsIfNotDeletingNode(c, dc, output, proposed_reconnect.node(), context); + } else { + c->add_child(new NodeEdgeAddCommand(output, it->second)); + } + } +} + void NodeParamView::DeleteSelected() { if (keyframe_view_ && keyframe_view_->hasFocus()) { keyframe_view_->DeleteSelected(); - } else if (focused_node_) { + } else if (!selected_nodes_.isEmpty()) { MultiUndoCommand *c = new MultiUndoCommand(); - Node *n = focused_node_->GetNode(); // Create command to delete node from context and/or graph NodeViewDeleteCommand *dc = new NodeViewDeleteCommand(); - dc->AddNode(n, focused_node_->GetContext()); c->add_child(dc); - // Copy any outputs that were connected - if (n->GetEffectInput().IsValid()) { - if (Node *out = n->GetEffectInput().GetConnectedOutput()) { - for (auto it=n->output_connections().cbegin(); it!=n->output_connections().cend(); it++) { - c->add_child(new NodeEdgeAddCommand(out, it->second)); - } - } + // Add all nodes + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + dc->AddNode(n, item->GetContext()); } + // Make reconnections where possible + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + + Node *node_being_deleted = n; + Node *connected_to_effect_input = n; + + while (true) { + if (node_being_deleted->GetEffectInput().IsValid()) { + if ((connected_to_effect_input = node_being_deleted->GetEffectInput().GetConnectedOutput())) { + if (dc->ContainsNode(connected_to_effect_input, item->GetContext())) { + // Node's getting deleted, recurse + node_being_deleted = connected_to_effect_input; + continue; + } + } + } + + break; + } + + if (connected_to_effect_input) { + ReconnectOutputsIfNotDeletingNode(c, dc, connected_to_effect_input, n, item->GetContext()); + } + } Core::instance()->undo_stack()->push(c); } } -void NodeParamView::SelectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool handle_focused_node, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + if (handle_focused_node) { + handle_focused_node = !focused_node_ || selected_nodes_.contains(focused_node_); + } + + foreach (NodeParamViewItem *n, selected_nodes_) { + n->SetHighlighted(false); + } + + selected_nodes_ = nodes; + + QVector p; + if (emit_signal) { + p.resize(selected_nodes_.size()); + } + + for (int i=0; iSetHighlighted(true); + + if (emit_signal) { + p[i] = {n->GetNode(), n->GetContext()}; + } + } + + if (handle_focused_node) { + focused_node_ = nullptr; + + foreach (NodeParamViewItem *n, selected_nodes_) { + if (n->GetNode()->HasGizmos()) { + focused_node_ = n; + break; + } + } + + Node *n = focused_node_ ? focused_node_->GetNode() : nullptr; + emit FocusedNodeChanged(n); + } + + if (emit_signal) { + emit SelectedNodesChanged(p); + } } -void NodeParamView::DeselectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + QVector items; + + foreach (const Node::ContextPair &n, nodes) { + for (auto it=context_items_.cbegin(); it!=context_items_.cend(); it++) { + NodeParamViewContext *ctx = *it; + + NodeParamViewItem *item = ctx->GetItem(n.node, n.context); + + if (item) { + items.append(item); + } + } + } + + SetSelectedNodes(items, true, emit_signal); + + if (!selected_nodes_.empty()) { + NodeParamViewItem *scrolled_to = selected_nodes_.front(); + param_scroll_area_->ensureWidgetVisible(scrolled_to, 0, 0); + + QPoint viewport_pos = scrolled_to->mapTo(param_scroll_area_, scrolled_to->geometry().topLeft()); + + param_scroll_area_->verticalScrollBar()->setValue(viewport_pos.y()); + } } void NodeParamView::UpdateItemTime(const rational &time) @@ -461,9 +572,10 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) NodeParamViewItem* item = new NodeParamViewItem(n, IsGroupMode() ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context); connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal); - connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode); + connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::SelectNodeFromConnectedLink); connect(item, &NodeParamViewItem::PinToggled, this, &NodeParamView::PinNode); connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::InputCheckBoxChanged); + connect(item, &NodeParamViewItem::Clicked, this, &NodeParamView::ItemClicked); item->SetContext(ctx); item->SetTimeTarget(GetTimeTarget()); @@ -474,9 +586,7 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) if (!focused_node_ && n->HasGizmos()) { // We'll focus this node now - item->SetHighlighted(true); - focused_node_ = item; - emit FocusedNodeChanged(n); + SetSelectedNodes({item}); } if (keyframe_view_) { @@ -561,6 +671,36 @@ NodeParamViewContext *NodeParamView::GetContextItemFromContext(Node *ctx) return context_items_.at(ctx_type); } +void NodeParamView::ToggleSelect(NodeParamViewItem *item) +{ + QVector new_sel; + + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel = selected_nodes_; + } + + if (selected_nodes_.contains(item)) { + // De-select this node + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel.removeOne(item); + SetSelectedNodes(new_sel, true); + } + } else { + new_sel.append(item); + SetSelectedNodes(new_sel, false); + + if (item->GetNode()->HasGizmos() || !new_sel.contains(focused_node_)) { + if (item->GetNode()->HasGizmos()) { + focused_node_ = item; + } else { + focused_node_ = nullptr; + } + + emit FocusedNodeChanged(focused_node_ ? focused_node_->GetNode() : nullptr); + } + } +} + void NodeParamView::UpdateGlobalScrollBar() { if (keyframe_view_) { @@ -584,7 +724,7 @@ void NodeParamView::PinNode(bool pin) } } -void NodeParamView::FocusChanged(QWidget* old, QWidget* now) +/*void NodeParamView::FocusChanged(QWidget* old, QWidget* now) { Q_UNUSED(old) @@ -592,39 +732,28 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now) while (parent) { if (NodeParamViewItem* item = dynamic_cast(parent)) { - if (item != focused_node_) { - // Found a NodeParamViewItem that isn't already focused, see if it belongs to us - bool ours = false; + // Found a NodeParamViewItem that isn't already focused, see if it belongs to us + bool ours = false; - do { - parent = parent->parent(); + do { + parent = parent->parent(); - if (parent == this) { - ours = true; - break; - } - } while (parent); - - if (ours) { - // This item is ours, - if (focused_node_) { - // De-focus current node - focused_node_->SetHighlighted(false); - } - - focused_node_ = item; - - item->SetHighlighted(true); - - emit FocusedNodeChanged(item->GetNode()); + if (parent == this) { + ours = true; + break; } + } while (parent); + + if (ours) { + //ToggleSelect(item); + Q_UNUSED(item) } break; } parent = parent->parent(); } -} +}*/ void NodeParamView::KeyframeViewDragged(int x, int y) { diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index f04072e52..3b90e22b7 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -61,8 +61,8 @@ public: keyframe_view_->DeselectAll(); } - void SelectNodes(const QVector &nodes); - void DeselectNodes(const QVector &nodes); + void SetSelectedNodes(const QVector &nodes, bool handle_focused_node = true, bool emit_signal = true); + void SetSelectedNodes(const QVector &nodes, bool emit_signal = true); const QVector &GetContexts() const { @@ -75,10 +75,10 @@ public slots: void UpdateElementY(); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -118,6 +118,8 @@ private: return contexts_.size() == 1 && dynamic_cast(contexts_.first()); } + void ToggleSelect(NodeParamViewItem *item); + KeyframeView* keyframe_view_; QVector context_items_; @@ -137,6 +139,7 @@ private: QVector active_nodes_; NodeParamViewItem* focused_node_; + QVector selected_nodes_; Node *time_target_; @@ -150,7 +153,7 @@ private slots: void PinNode(bool pin); - void FocusChanged(QWidget *old, QWidget *now); + //void FocusChanged(QWidget *old, QWidget *now); void KeyframeViewDragged(int x, int y); @@ -168,6 +171,10 @@ private slots: void ItemAboutToBeRemoved(NodeParamViewItem *item); + void ItemClicked(); + + void SelectNodeFromConnectedLink(Node *node); + }; } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp index 2810113a1..d55fbe103 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp @@ -135,7 +135,7 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu() void NodeParamViewConnectedLabel::ConnectionClicked() { if (connected_node_) { - emit RequestSelectNode({connected_node_}); + emit RequestSelectNode(connected_node_); } } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h index 621a697e1..3e4fc5f55 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h @@ -35,7 +35,7 @@ public: void SetTime(const rational &time); signals: - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *n); private slots: void InputConnected(Node *output, const NodeInput &input); diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 95ee238d8..3db8692a1 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -67,7 +67,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); @@ -214,7 +214,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); diff --git a/app/widget/nodeparamview/nodeparamviewitembase.cpp b/app/widget/nodeparamview/nodeparamviewitembase.cpp index f29d70702..645ee79f1 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.cpp +++ b/app/widget/nodeparamview/nodeparamviewitembase.cpp @@ -40,6 +40,7 @@ NodeParamViewItemBase::NodeParamViewItemBase(QWidget *parent) : // Connect title bar to this connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItemBase::SetExpanded); connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItemBase::PinToggled); + connect(title_bar_, &NodeParamViewItemTitleBar::Clicked, this, &NodeParamViewItemBase::Clicked); // Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar // size hints and will shrink as small as possible if the body is hidden) @@ -115,4 +116,11 @@ void NodeParamViewItemBase::moveEvent(QMoveEvent *event) emit Moved(); } +void NodeParamViewItemBase::mousePressEvent(QMouseEvent *e) +{ + super::mousePressEvent(e); + + emit Clicked(); +} + } diff --git a/app/widget/nodeparamview/nodeparamviewitembase.h b/app/widget/nodeparamview/nodeparamviewitembase.h index d5f570656..a728bb93f 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.h +++ b/app/widget/nodeparamview/nodeparamviewitembase.h @@ -60,6 +60,8 @@ signals: void Moved(); + void Clicked(); + protected: void SetBody(QWidget *body); @@ -74,6 +76,8 @@ protected: virtual void moveEvent(QMoveEvent *event) override; + virtual void mousePressEvent(QMouseEvent *e) override; + protected slots: virtual void Retranslate(){} diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp index 1d79ff4d9..efe3d2768 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp @@ -85,6 +85,13 @@ void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) } } +void NodeParamViewItemTitleBar::mousePressEvent(QMouseEvent *event) +{ + QWidget::mousePressEvent(event); + + emit Clicked(); +} + void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event) { QWidget::mouseDoubleClickEvent(event); diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h index 9bea7f06f..7024c9e82 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h @@ -79,9 +79,12 @@ signals: void EnabledCheckBoxClicked(bool e); + void Clicked(); + protected: virtual void paintEvent(QPaintEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseDoubleClickEvent(QMouseEvent *event) override; private: diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 07251995d..220a040bf 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -51,7 +51,8 @@ NodeView::NodeView(QWidget *parent) : create_edge_output_item_(nullptr), create_edge_input_item_(nullptr), overlay_view_(nullptr), - scale_(1.0) + scale_(1.0), + dont_emit_selection_signals_(false) { setScene(&scene_); SetDefaultDragMode(RubberBandDrag); @@ -171,9 +172,11 @@ void NodeView::DeselectAll() // Just emit all the nodes that are currently selected as no longer selected emit NodesDeselected(selected_nodes_); selected_nodes_.clear(); + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(QVector()); } -void NodeView::Select(const QVector &nodes, bool center_view_on_item) +void NodeView::Select(const QVector &nodes, bool center_view_on_item) { // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. @@ -184,18 +187,27 @@ void NodeView::Select(const QVector &nodes, bool center_view_on_item) scene_.DeselectAll(); - foreach (NodeViewContext *context, scene_.context_map()) { - context->Select(nodes); + foreach (const Node::ContextPair &p, nodes) { + NodeViewContext *ctx = scene_.context_map().value(p.context); + if (ctx) { + NodeViewItem *item = ctx->GetItemFromMap(p.node); + if (item) { + item->setSelected(true); + } + } } // Center on something if (center_view_on_item && !nodes.isEmpty()) { - QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first())); + QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first().node)); } ConnectSelectionChangedSignal(); + // Don't signal when this function was likely triggered from another widget's signal anyway + dont_emit_selection_signals_ = true; UpdateSelectionCache(); + dont_emit_selection_signals_ = false; } void NodeView::CopySelected(bool cut) @@ -734,13 +746,18 @@ void NodeView::UpdateSelectionCache() QVector selected; QVector deselected; + QVector sel_with_ctx(current_selection.size()); + // Determine which nodes are newly selected - foreach (NodeViewItem* i, current_selection) { + for (int j=0; jGetNode(); if (!selected_nodes_.contains(n)) { selected.append(n); selected_nodes_.append(n); } + + sel_with_ctx[j] = {n, i->GetContext()}; } // Determine which nodes are newly deselected @@ -773,6 +790,11 @@ void NodeView::UpdateSelectionCache() if (!selected.isEmpty()) { emit NodesSelected(selected); } + + if (!dont_emit_selection_signals_) { + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(sel_with_ctx); + } } void NodeView::ShowContextMenu(const QPoint &pos) @@ -1344,6 +1366,8 @@ void NodeView::ShowNodeProperties() overlay_view_->setFocus(); emit NodesDeselected(selected_nodes_); + emit NodeSelectionChanged(QVector()); + emit NodeSelectionChangedWithContexts(QVector()); overlay_view_->SelectAll(); emit NodeGroupOpened(group); diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 26894511e..d18d2d185 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -77,7 +77,7 @@ public: void SelectAll(); void DeselectAll(); - void Select(const QVector &nodes, bool center_view_on_item); + void Select(const QVector &nodes, bool center_view_on_item); void CopySelected(bool cut); void Paste(); @@ -117,6 +117,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); @@ -218,6 +221,8 @@ private: double scale_; + bool dont_emit_selection_signals_; + static const double kMinimumScale; private slots: diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 54106070f..2ed0ef28b 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -199,13 +199,12 @@ NodeViewDeleteCommand::NodeViewDeleteCommand() void NodeViewDeleteCommand::AddNode(Node *node, Node *context) { - foreach (const NodePair &pair, nodes_) { - if (pair.first == node && pair.second == context) { - return; - } + if (ContainsNode(node, context)) { + return; } - nodes_.append(NodePair({node, context})); + Node::ContextPair p = {node, context}; + nodes_.append(p); for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { if (context->ContextContainsNode(it->second)) { @@ -231,10 +230,21 @@ void NodeViewDeleteCommand::AddEdge(Node *output, const NodeInput &input) edges_.append({output, input}); } +bool NodeViewDeleteCommand::ContainsNode(Node *node, Node *context) +{ + foreach (const Node::ContextPair &pair, nodes_) { + if (pair.node == node && pair.context == context) { + return true; + } + } + + return false; +} + Project *NodeViewDeleteCommand::GetRelevantProject() const { if (!nodes_.isEmpty()) { - return nodes_.first().first->project(); + return nodes_.first().node->project(); } if (!edges_.isEmpty()) { @@ -250,11 +260,11 @@ void NodeViewDeleteCommand::redo() Node::DisconnectEdge(edge.first, edge.second); } - foreach (const NodePair &pair, nodes_) { + foreach (const Node::ContextPair &pair, nodes_) { RemovedNode rn; - rn.node = pair.first; - rn.context = pair.second; + rn.node = pair.node; + rn.context = pair.context; rn.pos = rn.context->GetNodePositionInContext(rn.node); rn.context->RemoveNodeFromContext(rn.node); diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 567198b5b..bb4588444 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -372,6 +372,8 @@ public: void AddEdge(Node *output, const NodeInput &input); + bool ContainsNode(Node *node, Node *context); + virtual Project * GetRelevantProject() const override; protected: @@ -380,9 +382,7 @@ protected: virtual void undo() override; private: - using NodePair = QPair; - - QVector nodes_; + QVector nodes_; QVector edges_; diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 8e247a76c..1bf868ffd 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -92,15 +92,12 @@ MainWindow::MainWindow(QWidget *parent) : scope_panel_ = new ScopePanel(this); // Make node-related connections - connect(node_panel_, &NodePanel::NodesSelected, param_panel_, &ParamPanel::SelectNodes); - connect(node_panel_, &NodePanel::NodesDeselected, param_panel_, &ParamPanel::DeselectNodes); + connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, param_panel_, &ParamPanel::SetSelectedNodes); connect(node_panel_, &NodePanel::NodeGroupOpened, this, &MainWindow::NodePanelGroupOpenedOrClosed); connect(node_panel_, &NodePanel::NodeGroupClosed, this, &MainWindow::NodePanelGroupOpenedOrClosed); - connect(param_panel_, &ParamPanel::RequestSelectNode, this, [this](const QVector& target){ - node_panel_->Select(target, true); - }); connect(param_panel_, &ParamPanel::FocusedNodeChanged, sequence_viewer_panel_, &ViewerPanel::SetGizmos); connect(param_panel_, &ParamPanel::FocusedNodeChanged, curve_panel_, &CurvePanel::SetNode); + connect(param_panel_, &ParamPanel::SelectedNodesChanged, node_panel_, &NodePanel::Select); // Connect time signals together connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime); From 8f7280dd0967630b7666e6449320841a8d393c0f Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 15:19:20 -0700 Subject: [PATCH 25/96] clip: add missing retranslate --- app/node/block/clip/clip.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 16720eafc..c48dee2a4 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -284,6 +284,7 @@ void ClipBlock::Retranslate() SetInputName(kMediaInInput, tr("Media In")); SetInputName(kSpeedInput, tr("Speed")); SetInputName(kReverseInput, tr("Reverse")); + SetInputName(kMaintainAudioPitchInput, tr("Maintain Audio Pitch")); } void ClipBlock::Hash(QCryptographicHash &hash, const NodeGlobals &globals, const VideoParams &video_params) const From ac7ff774e07ccb9ccd79ae0d059613b6d31c2a8e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Wed, 4 May 2022 15:19:34 -0700 Subject: [PATCH 26/96] subtitle: disable flag to not show in param view --- app/node/block/subtitle/subtitle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/node/block/subtitle/subtitle.cpp b/app/node/block/subtitle/subtitle.cpp index 8c60d8ee4..24b628178 100644 --- a/app/node/block/subtitle/subtitle.cpp +++ b/app/node/block/subtitle/subtitle.cpp @@ -29,6 +29,9 @@ const QString SubtitleBlock::kTextIn = QStringLiteral("text_in"); SubtitleBlock::SubtitleBlock() { AddInput(kTextIn, NodeValue::kText, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + + // Undo block flag that hides in param view + SetFlags(GetFlags() & ~kDontShowInParamView); } QString SubtitleBlock::Name() const From 37668aeddc050b69258a89d7800a63da3291f5ad Mon Sep 17 00:00:00 2001 From: Pablo Gil Date: Thu, 5 May 2022 11:03:41 +0200 Subject: [PATCH 27/96] Text edit icon --- .../olive-dark/png/text-edit.128.disabled.png | Bin 0 -> 1700 bytes app/ui/style/olive-dark/png/text-edit.128.png | Bin 0 -> 2253 bytes .../olive-dark/png/text-edit.16.disabled.png | Bin 0 -> 621 bytes app/ui/style/olive-dark/png/text-edit.16.png | Bin 0 -> 561 bytes .../olive-dark/png/text-edit.32.disabled.png | Bin 0 -> 761 bytes app/ui/style/olive-dark/png/text-edit.32.png | Bin 0 -> 738 bytes .../olive-dark/png/text-edit.64.disabled.png | Bin 0 -> 1049 bytes app/ui/style/olive-dark/png/text-edit.64.png | Bin 0 -> 1208 bytes app/ui/style/olive-dark/svg/text-edit.svg | 276 ++++++++++++++++++ .../png/text-edit.128.disabled.png | Bin 0 -> 1716 bytes .../style/olive-light/png/text-edit.128.png | Bin 0 -> 2284 bytes .../olive-light/png/text-edit.16.disabled.png | Bin 0 -> 614 bytes app/ui/style/olive-light/png/text-edit.16.png | Bin 0 -> 532 bytes .../olive-light/png/text-edit.32.disabled.png | Bin 0 -> 780 bytes app/ui/style/olive-light/png/text-edit.32.png | Bin 0 -> 800 bytes .../olive-light/png/text-edit.64.disabled.png | Bin 0 -> 1060 bytes app/ui/style/olive-light/png/text-edit.64.png | Bin 0 -> 1243 bytes app/ui/style/olive-light/svg/text-edit.svg | 276 ++++++++++++++++++ 18 files changed, 552 insertions(+) create mode 100644 app/ui/style/olive-dark/png/text-edit.128.disabled.png create mode 100644 app/ui/style/olive-dark/png/text-edit.128.png create mode 100644 app/ui/style/olive-dark/png/text-edit.16.disabled.png create mode 100644 app/ui/style/olive-dark/png/text-edit.16.png create mode 100644 app/ui/style/olive-dark/png/text-edit.32.disabled.png create mode 100644 app/ui/style/olive-dark/png/text-edit.32.png create mode 100644 app/ui/style/olive-dark/png/text-edit.64.disabled.png create mode 100644 app/ui/style/olive-dark/png/text-edit.64.png create mode 100644 app/ui/style/olive-dark/svg/text-edit.svg create mode 100644 app/ui/style/olive-light/png/text-edit.128.disabled.png create mode 100644 app/ui/style/olive-light/png/text-edit.128.png create mode 100644 app/ui/style/olive-light/png/text-edit.16.disabled.png create mode 100644 app/ui/style/olive-light/png/text-edit.16.png create mode 100644 app/ui/style/olive-light/png/text-edit.32.disabled.png create mode 100644 app/ui/style/olive-light/png/text-edit.32.png create mode 100644 app/ui/style/olive-light/png/text-edit.64.disabled.png create mode 100644 app/ui/style/olive-light/png/text-edit.64.png create mode 100644 app/ui/style/olive-light/svg/text-edit.svg diff --git a/app/ui/style/olive-dark/png/text-edit.128.disabled.png b/app/ui/style/olive-dark/png/text-edit.128.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ddaabbf360918dad9a64a599d23d72d676caca1f GIT binary patch literal 1700 zcmZ`(YgCh07QNp`!XtnakwowT3_<0ch$0xo1O-X$T1+kRpM6LI{sS zc{nPF1zNNgZ2`qGz|w>YR0VYuE3YbK5~WB5LkETkQ6{YUH9uypd(OW5?7i3dcgiBd zgDo*zFaQ9{(2ziy0g?4GMHxEVrgnTrGA)40isFVg4MtnO%9W=<`yY&4xYr}Nxb z>x-qMcD=eW3MW!56-8A2{wJ!gyf;4~iJKJ6Aye$}9!aiC^VGdl-GuSn)nEOfKXq?0 zrI?7m<55%^LRQ2Qed6suH6)4D)o>l+)53PNh-x&?A?9Wd>fmzBOc%1su8K!Ldzn-J9G+(7@5E`%%%FwP_P8^%e49vY_1@n%yF_f; z@cxUehAUrVupYS;Lg_Q}(fi0PTvI`CujpTr{m%69!q`rN^e++*emL^zbP~ZlHQ-on zGMpm!^Gb!(3que49Iv8&c=zv=EgRNO>TCM{3f-%bR99TS228&BYJkSdDIUY{1LG$Y09ebJjZK$qFr2uNvw8tT7dX!Gu6o4e@24QhuthLHsG3=U zL)~fBG)i=UBPdyN?P!XAV!WN8yS7wk-fH2iPNyv7bBk_&I}&^Seo6?l_l4boc=sz) zD}ZMER8shOfM%ayPjxl=?(RVB$cJYuz{-~2^|PYl!iVAYKWUXbsZXCd`iGJGV?+*J zr?>~GWZF5oLW;2c3sCm=n-o_nlwymq;ntV=`W^5}65Trye@^p0xurtsZgd-eRbr9q zA<;&m9q0m+G$+d6J&NAn+dS15lIxP$IVeZl$4FF4$)iFZYv2Oj#TL7_zp1S8)m2%O zqY63fF&9_^C+J+@5ufKhB_WWv{+6f1ZlhAS<`UvdYyUW6K2gpXl<+9kT&L4`aG3i685%~JRT_?os8eijW8NITy!Bg|A%Qbb7 z$ns-w`9{^Pyo{~9T&HTg-HEa7&ax`430mK8(Ip-n@#frR-rrufrd1zuGNmWvfzo&C z>BZ3p`{Gg|UeVjs^W^|wRsIzA)P!uxPww@W*?bbSw*G=3 zMP4V)W!TnrkhbKk-Kb<7qlPLzvPgxD)w4^Y%z7M%Da*nh?BI)+T;Z89MZt5p`l{S{ z@{sR##l;E5yK`nLALqd{Y@w}%-|Hi}K@cCREPk7binSS`JosdOIN?V1!d-G+K|44j zDZe-TrfSb`7wTJ(wT#jqdM!RR7Aq@WTzCI&{azVbX}^-gu5ELxTI?`fOlx6KoG>6; zn8p);ForPa{Q?h)gR z%lNxl*pf-|G)l(h#W3Yz9`3UL>vewT_deg>=X}oh`#Z1K`JPk{w6n5;wgLbE%C0Vs zo|2jNYi!*jIk(t`bx0=pSQmd10O;KKH9#3-b681mC)w!~*^7uHQ^Ml00EI#^#>Wsy z;bE~@V`6+{{)~;bM5OUcWS>BeBE|#mVew>qjGku#i9kI6rh}6wSw~7u65_+LKoprA zYi(i@PK=Hw#*mCDcmh5e8-Wk|WoPp1%EUV?CXyJ64=2WiFbp#R03vpEwD-PHF#Qli z*Z0$5vsixh4O{wXuOie3M+~4IKXbn4jI^;V>(0V_XN&wP^#m>L>yD~#lT0Vl%$1Jx zjM5xb`ft|ndX<}b^@59w@g)8ZRDJ6|j_zObTC(2t@sm)h=r-K+%*rCaY?!=ZTk>e! zr@@3Z9LX=MoXi7hIGvOncduRPS1F2UBcLMYY8Qi*<$K&1W>FME& zQQCL(2*VD2Rdsut-|n@PdD8tSgI4Ij^AMp)FAWg1!^CD0TQGQGNjt$(XWa8{Q}y-L=P5Hb}Ia-odx z@)yFEvdvfsCip~AYtN-(hWD^KLR8c{^?NX`{L=nei%E0T?NJb*@5(b^@@`eEsLhy- zvyNa&m9P+Fu=@i>_fuJ)eAQ>bMvIe()Sp>|7J)PY+JIpE>fNFk2{#=Vk*LQrpW=0w zgahxY*{j0^391DUss)PuM%LZ`6v)9Gwc-czb;FKY#|J$=!s@vKp~!U4dA628Fe21*{}&1HE{rdf0vU}q9pc} z!eOze6cog0DZs^UQcw~9Aq8WxgB0Yy$z}SU!zVu2E45+EoskBD_DEgW2H#{i6+!!? zCTz$VX@I&%>cKuxAuVL-sgE>EXwCl3ingWsN~I3!L7R^|U~VsU@7K$frXMJ)W*6|X zcnrTyC@nR5)Mr!b4CYJkeKImelr6@u9CLm5S%6_LE4+C5@+Ei#=GI=!C2Ey`^Vq0L4F7N`}&qmY2x;D z1Ezgd@3wC0aH9TbgrZCLf-P=+AMIIG`OI>4Y&G~4fuYa*pI{2pXrmn}qjaN1oH`+L z8YOq$cOBK#>!{X+a`~?GiNDvscRcA*cu`xMkW2T)-3r55w60dS*}VGrCW#xR-*mxd z9Zth=3Yu~k)7CFX2iGif@kz?F?gtK@E#gv+MT2G*c%!kr$XR zr0+k}6bG+ck+E~Ui|q@zl4yI~V%Vrw_B8H{U{q5jv8MfUN8$Cx9unp&H{bQJi3utq z-O7LN1;o$SS0%WSx?F2bn$)pHeF^|E4WB2>u{lH5hf*wtb??dTP}*_>puU~C>SORx zATF*3Aga4p!L;ARvs((D=eutG}{d<*(7#(Ev8PTnRCKXC`?}a*KAQMUQ+S11@n&q zQ)8cnAuSm*$-yg@xX&d?$_JB`5ik`YWY#~!AO7fK<1V)<;3$z#{gnH2qX&UR(irTx zg4YkRyA6A~BwzcT;W*nxRS+s8#$(YGBnCgjX8Y zf}tnxK~U&0K|XLPd2Qv#Xg_sPBP3qZ=yY~xu&W-AWTPtk2BtP5(i5K#OgHMp&p0t- z75|DGZS|uYMu;}JoKDA+3;Eq87}m~M{t&wsQWb4oy;?O;;EhAQdR^8A{D4nju2raei z+CE$KIMEEKf_A+d8XCI4vbJsvEF}HzT;exr<^|vyAGghSa)_Y6EO%#^EQr@s2@IFH z))Sy~QzAliOtW+OQSHw@!!+ZCq=uu~5nf=A8aW%~)0$0>{*0>!LLvmmoo~Yuu?Y!B zNLlDP^w*U_{kC5E#KFP+&3xhNT3^7$m)-x`Q0Bk45%`{PzF}>%a1BHkf|p>lDPa8p qw(nJBXJK+L!FsdZN}F!bysmZN4Krq40#fo90k}G$9V;D9|M?%d880&c literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.16.disabled.png b/app/ui/style/olive-dark/png/text-edit.16.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..552d6f37d54075908aa9110ef71387b2b357e5ac GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4O z;1OBOz`(o#gc;S3@UI05vX^-Jy0SlGW#wdKof>`_r0b5Si(`n!`Pz$Ty$(AF9QgP@ z@0#9}u8x%)o%cS+$eD}=1yQy;F=j>c5!F)tgw6e_exIWP1OH; zEbX0Td^6uHeJ=B@uWpzh{dQjrsCe7F9V=~5EIAo&AGvk@f39CY%G-WweoVJ5Tq>KA z)$VvWc8T7fnNW}ZS&X>oRb+4j?CW&-6^LGmey zC8<`)MX5lF!N|bKNY}s=h(Zi3tqcsU3{12Q46F9gP2NC6cYLll)3C8siEl#~=$>FX!w z=jP_;73-B}W@qN6rer39lG|=Q$@zJ4^ED;_wKI6S`njxgN@xNAtMS`G literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.16.png b/app/ui/style/olive-dark/png/text-edit.16.png new file mode 100644 index 0000000000000000000000000000000000000000..1cde2b02e72754c186eb3cfbc12983c3caa94fbe GIT binary patch literal 561 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9G08$g&*{RsbBprB-l zYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt&=TMUJH<8TmyFzKKO8nRyC9 zrN!C#W!q1mnF*9Ph8R*>l$^?tQBqQ1rLUiypPQSXSFBf_nVp%Nnv$6aGEN`F(+^3^ zOV5wbOwP}Xo3Al}fq^mJ)5S5wqIc>gdv9h#3APWpn zN;F<(?rVK;MNz%{Y=G7e_T^=o9Trwr7S`AO7X(-3#UOudOde#!6X%Rmn+JP;x^x0!_1I+^waz_Hy@O+ey-)U()j(~#Zx}rvMgUYW!I0*ja$Qv zKi|tRvAPnq-!*WHmrL}$-+kA9)z-YbuITsJfaiCh$Xc=Pqta>bw3gPLNqE*|Q}L{6 zkHm~$9-folFl+F$H8%ql9h)&p;L)^>XOBFa!&Yydv+Sj?vAp)uxE@1Q&8Maferv;K zcdPSWGP%pP!Nq0ywOhSwB!1MnDcwpj5p0L-0SY&c1DE^6RGZdzrQ*y{P1S) tdoIOytFOLt7qju)eK+m|>#|Rrz4K3RIK1z-IWVReJYD@<);T3K0RXTs?mqwk literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.32.disabled.png b/app/ui/style/olive-dark/png/text-edit.32.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe6f39e961b032a098ecf93425a8880e210c9cb GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5n0T@z@7-gj8hNq*aj42FY)wsWq-!X%E`z&HT*JA7h{H}i(`n#@wHPA`W6m<&PdZ8vk)g%FZ9*^L(RTu{JwhNML%rkacy_n?=R9)9%lnJM*mA zKZ!@&JW}0aSB}lS8OJ1@*~6eU^WK6FFP;4<9<%H%Uf>kcRd}M zki2sP=a)~blnw+2Tv->maKgh?Y?9WTr>^-rDoZz?N3Vr4m?vomxJd2hudl2;K!s${bshi6tCrrJYGBwh~u|4h6PVcgZdvktIk7rr; zL#)wyU*Lo0e1RVi?OFEyFmJT~=bE7G>#*<4-W?uk+HpHQwjV!j`(djCr%AUyVuDcaCkL*sU^W=4ScADLm%kSEyRM z8e9>_S1-AnZZ6}rgZsJr)2xO5Mn=K&_xp0>vv@PbrI^Ua>n?oVI6d+3>kIRLE&suA z!1hjFgWb{Nz-SODag8W(EG@~%FJkabEGo&&QwS<8&dx8}e)`Nzpu8$bJ|(dv)hf9t z6-Y4{85kMq8kho6h=HY*fuWUwskVWEm4QJ_!N&C{8glbfGSez?YtYr@6b5RL1lbUr zpH@mmtT}V`<;yxP?0f2QE5?fDnmv|Nr9EVesX?pZhl^| tUU_DAW^QUqW+F(rK8U9ul9-pCAD@|=pBFb@V**e+gQu&X%Q~loCIFVGAp8IT literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.32.png b/app/ui/style/olive-dark/png/text-edit.32.png new file mode 100644 index 0000000000000000000000000000000000000000..b41fbe7e41d9c7b98fabf02c2d9362aeb5bfab19 GIT binary patch literal 738 zcmV<80v-K{P)VJ>fSXD@eYYiTc3VQyz{Uuk1+ZeE`#kN^Mz5J^NqR9J=0mobaf zKorOS|A~bb;(Y+^g)0RQY%BzOTkR}%k|xcuy;z~xFJ?|(H6#yyzj^P?kO2QU7#fi0`EFU34*?*GqW7cG=-Z_Uh{#A) z_W?xyQAzU9TAK$K5Rp_>)3$dc4=M>0N?=o{>VBT*yFmo9EV~N;*4nA6zUWAcs<{|c zKtxiKZ$)Gb07;TamxM7!2NkIITvcsdg5n!vZsKfoPnteu=Wp7CC z`J5-#+LLBZuNE|S-Ujz4Vy~971_ydnU{l#IlG96IX!wN$Lcq5c2nF9tASC>c0-@m> z1ug^LDIg+=|B~svWVX48dI`+u^ZO)U@ic8Eb^rH?vl%Fg;;M7*7{K+K#E;c#^-NXo8DpOMXM@23;7YYv zE|(ALZ~#!%n|>gns_MV#Uk(L7Cr~ecOMEAJ5XbSSA>n{;K~WSt&bbr({(}L4pQ`$f zIv#Q*>R07*qoM6N<$g7FtUPXGV_ literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.64.disabled.png b/app/ui/style/olive-dark/png/text-edit.64.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..d00d93c28e4f7cc320b92944491dc00945b32588 GIT binary patch literal 1049 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5Sk?NMQuI$fPSveWmc;cGcfSNiyT^vI)?!BGqn|Ikkq~X4_ zv*xrF%~Exf)EXx2dd@YcwN+Yi;{yeq35y=M>R(XasO`BbY=>%QAgAlMrDw67Y3z>_Rrg|yRoMAKV<#H zvq*n(a5B@qj&EJ%ACJtH78H2=nd^*=TtnOZc^Tp>I-dteZ*JIqAl21u)5dRND*_An zbak2ToseG6WumX$E|HTh@WE}1`{9tpqM&sGO+}3rPtrw?$U2skFOF!KU$MvOWJH9! zb+b|9pFQgX7kt>3EyCF`ZSESUJRObQ$9{+J&@DE zIV1l2;@^RisZ6dlU0PZd$_(WP?e7OV^sEm$;jZ3Tv}cbKdt=s~HBPT11Nzw$V%{oh z<}ym|@tHY|>D7m|EFq7gIaVAs7Ypdk*H|ET-@}1@Ut@#Zo-GY}dzLiV?U~Zxx2L5c zu4ZjRUQKU9UCq)4&YIQ+$(of7nl&e-FXkk0>5F`jsYv6}7qCeBV)RaY%7J9{Jq`~Z zY33Xa-7QqHU3i~DL5s-$`mIKd`W!#_?)|IVWddYvs0;er$64c-kah6zlSR|z)^=9} zwVdaS*!{<}epk5VM=h2G^UwN-mOM1}{`f_%Iy7cx=25-FvTs!RHM0L`yel~AzUZ^^ zw-wW~E`D;*ocEfE>DBcqsy1Oae*{JpCVgOFo2r`sVRQ9Dsq>|bUr*oneZh9FZq7db ztB-{n`+3S+GY*;l-u3^jsp-lstp{q=H*At*sbKwgZRd;N*=&rbw*B}2aY`-h zd+py+ISd>xWNN>kI`Q3y;eps9{xk0c|3>Y*K@5dmdKI;Vst0L)>a`2YX_ literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-dark/png/text-edit.64.png b/app/ui/style/olive-dark/png/text-edit.64.png new file mode 100644 index 0000000000000000000000000000000000000000..a8c49e8f717b51de2d578b64b78751a1603f93a6 GIT binary patch literal 1208 zcmV;p1V{UcP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H102FjZ zSad;kbZBpK08L?XbZKrNQgw4{Z+5rK%$WcH05fz&Saefwb#h~60BCe{a5^t9V{dJ3 zZ*FrgcWG;BZDnL>VJ>fSXD@eYYiTc3VQyz{Uuk1+ZeE`#kN^M!=1D|BRCt{2n=y#w zR2awq-^=WtGkCVTg?0;GuUL4TjM#{c+gT_U%kefW47gw^2v;ZwdoU2PDF)@Rnr5vI zK{(~mLgZ?#??4ciZEj)lcJuxgZX}b*WRgiH``)nM zpec<;qw8@TzXAZB=RMxu-hNu9o$~;KAh@BF`UJo&5$ON`$#Vb?jWKt3cXxj;YVS0F zFbqEc@Off9M={ASeBb|ORt{$YL{T&#IVf|kh(ucJuX2wy+pTs~#eAY!5L9#BYDbHh z2LO`#;NalHY}`2jHT78#1UJ$F=KyG}haxguu(@}!V*DrP006Zi+!~EW*OM>S1Bjw% z5Jl0a*|^qvNHVvw7fD1q$%YBA96(a=Na{QYzVAniKrqHI`D`tKY_%_fP-QxhJYQQ| zdy;&&62PpbZWe@!HQ{0UKEXNw^Va#A5MpD@-E_bz0A)8hMG)rHgge=rBWnN@4EtPD zRSP4@;m*#^x7oNA_X0)cecvAfKp2KvM5YYS+T*9sPv@CxU%&hHRK|Rwst}?m8UX)J zjak>fQ~*`XC#nizo-Pf*BIXk{3E@%z)G?o^DG05v0!^3)0HxHmytpyu?<)Oibp$kJ zzNtJwivVmi53~fpR`Wm$0Bkl7EE$09=7A*waKSvVBml0M2bKW9CG$YT09-Q& z^FTuYTs03g0KjGQKurLyn+IwDSOxRIf&f;upz4= z^HuUJLxljwSW1i{NnsR!A$KTjloR7(A7jCn&u`coIMY|dwu`<{KL)7c_fYL_S?eUkk=Ru`|O zSZf~0nF1t*Q9N} zUjXi%o}S*@+uJ*BqH}F%0>E%Mye1;=mTgS(nTY(Xlseqp-29>6@1Hl{#pP-OK)2g{ zGmhgIiW-olh&%#txW2xAzwF=BY}Et+lDV&)T8$Z z`vbtM7on#l?~BNx*7}i%a5{zCnyPmD`}^HqulE+oXJ=<;zYGS0N-rH<=}K2}O8)?r WS-B=Hme?2o0000 + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Martin Ruskov + + + http://commons.wikimedia.org/wiki/Tango_icon + + + + + + + + + + + + + + + + + diff --git a/app/ui/style/olive-light/png/text-edit.128.disabled.png b/app/ui/style/olive-light/png/text-edit.128.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..b5c8837af645c4d179945eda7ce6cd6e8623f787 GIT binary patch literal 1716 zcmZ`(X;70{7Jd09pFkpnB_M$p4$NS)Dj?D<0)k>27Z68#(k?v&Xb^3o!!SsU33RCWH9w~6-FNETb56Zib*pYk zM0l_%hJXP8n1(PJQ3gcT%NT9Axx1R^20(KH!U6#3sKn}$VFM?!nNeW?oN_hz3IWg> zTF4v#SyTYtu>kOu0kBDMxi8YsAV9}LgBbucmy>7)W+GrFhyZXrvtFpmnZ;B?(?}c= z7GyLF!zL*7RK#>M05BRj(kMJn%R9v=dOiPo7J zl8S6O{;J!IiG7rD(7k_o&B+mbt6Md>SN;j@9NMS zI0C?7?UWz;I_|E>S-6!oes6CuY?bcO`cblg-q?3yME@({NM0ROsII}3;fZBWB3QLx zYYspXC7!tXjb&EEavX>oSoO#?xtVHuKCNo#ZTFQ?uW7fT0lv%gtCa3`+QiScc4RPg z#KT1Aa@zAnOYaK*3oJ7cM$azXCj}~zNo%{%q}PcP{)7Y+C~?jIN%)I$#VDa*gfqTp zA*c&Sz7ea6_g}pxfers*yt>zmebA*!UX|uH_9831$|!gwYt+2G3dFy5msK!pcm`P^UC|PdO}b&Su7<0=%6!j1}IrtevXA(B&|tIG)cVnAA>A zKff64V&XQ`r04X++M~odr}sI=qG0bXa-=@P1t~fZXcPorUU~<|iPlnnTtsXw?Rm<=yr~eXrt&AU>Ky7A(tE8?>yb z?J&aCl)|zzZ81oR1_R4V+V&$&no_jvTpI& zzA?1sO~{cJF=1K4^LE@ykaS36id&$ElGmo)7yY&1u=V(>q5?sN(-+Q23)Cv@(Jk%N z9)`j{)LQ)Y?%Rl`bLW<;OTb!ad(q>6)3gqd^nAPHsmW4xr?bQi_2{_TF6HD$%d%uvmYoJuynig|p8W31^7n)(++!pn-E$e<1l zs4HPP?d^ib+`Lu3)N7tCqru8Q*}nIvSPXq0&HQm!|N97HC9aM#{=gEnoR@P~e(bh; znRj;FMz%q&|0+1gMTu1J`8oP&@0e(9jS+_^E#_U_QvCWJ5)OoeydMPq!^ERynKz27 z@zh54=7fe{U)*l@S-o@4tfU!XZ~!70ARN%O4%frFEdw4_|9PYRpz#@Aet|u~3zatI zNZc^yqL ztvv_?W&Qz|3!-~>?@GJ6$-=x7e8Uku>|ENV2!kMnRhH?A0(+W0q5B~gqrQGEyb+Tl zG#V3(eIjoh{c_IFF!&5kUP{2_E0-qxI>N)g9LZzymA;5Xt*U!}c-y^O+oI~3U%LdA z+J2J@D6e{^X?#nRVT0nuK?lVFS>klQ5QHTQ#oSC{RF)`%f4uwA;~Im$d0kIQ7N`2M zg{cMrG%Ag@o$6^gF;pL4>P}y(hdY((OQmX!`t1KFz~iTI(@y^Xz_~=I!4R-pe<7Nm zCeBV4rh@G3>>b?93=un7kh+5}M3_uWyM{J001cC zuoy3C&)RGX^3rSD5fWe8ZI8tI#{j@jS2r6dbLv~LbWn$J%#Yzs4`DD#(ZK+d$wW~j z&c{$lk-;c>bZF6>-7cwU=cdRhmT`_A4V)xJGpG@8uh^LL^tdN{L4kDMTxJp*O$i3h zF&L3HXf%Z$9!`&lK{2W4so}xDP)VD1=*=gz4=Ey)ewIq1M+Dt5&H@01T{w)B&xPVI zw{YyhDOl&m4Bo&jtFd{v?w>6cb1z)Fy4gD_Zk#(E5huA zKoR*L_anQjj8il<+Of>#w>97GeR`Wym;3L2-lJVnW?KDkhLGuT`j!wyI6Erpv2I{nN(AIEbSWzsmlTj8-$uf~I+^I^#op$F+6M--_)G0uxYF37d!_j6^71m1 zI_(RJF7vt<=z`$`-EQ+qddoKpmMnLrGqXe3Va3^I4FO-`01sfOfNcIgb+)jptLtn) z&D%VjWeIrFu?ByJJiP)~>Cn1CksXthlPba`hifY#TD(J*MXkRO2Y$`QmVo`*iQ<;_ zTu11izg?MTrW#yQB!bdji5^w@AlD{W)_qBGr-8P~-b8>kVU?G6yu9|J@a%4@ZalmL zRf$I02h|St=p1(U1==15)Ob`>R9FImg>4JA`SHU`Yd=5PB@HNf6L!(k!U7894c#tc z!;B0KKiDU&{!m>D@&z5>OdNN_K!i&xK`1=vKy-q^OXn0F;nJOsy+3o-Qxu5>#c|tg zD=RC7=NkfqOHWHeK{}_Z-{jtZ^SQM&gGpc(u=iLL+{=S2geV1Llogx;tUj zvtX;>10rio3?~I{cMCH5@h)~W+1W#GfHU?YVrK$ba=C8NnRrcNW%a!B5tvhbulu0FOu(Gdz{5yUM+xp1l& zqy-mGGwbw0?AaWbKR8tqUVgFz>)!N|APQ~nniQbG^Gq{!1DbR ziPaK<{)vNe;Gu{l?Ry&6Zvycat!bF;FI-sMBH^(@2<6)bxa@GUrtP>=$h5Mzlgs+y zQvu@gDIF@POzTX*9^!A%EIf@G-+a9c=)Y!a+7sg94p2LCb1U;W8jb;VLeE!s%M*@*R+e1fl;cUNYEd)_Of^@EKe zTao?nAeq**RA%?c@qx?*&)&He-K7x)#+o!fw)5Y2d`sF1ACk?lPDQST+DUD2!NiFfRn0a2IEGEcLT^6G`A&ZHp_-sjC!7pTN8FA7!MY@LV zv#-^>5*7-eRX)f;jlQQ<6Acnc_9s+HAW9Uc8|uIc=NK9V#1VYm#3yGs*buOwyL;{c zEbVH3{E>eytWEOa^#sQ{zY*;Q2}b|Eq(Y1}%+Zpid+|S&}nXXpfhSN zvp-P^>}vpGVq#|Gnhw!)&C_hg%x{JIVND&?Ak5#>5v6O(U3oYp2&S!VlrI_1BDrBa zDhfi?67J_^_<(6NTAw>2l z5Bg~CTuK1c4eWokJPD|IA<;Ss3@7Ha2Z3NPSRBOZ z>p}AR*FHmX4P-d6z8yv!d`R%s>|5MFldgZsQfODl1ntk=2$G*uc`S)z$J$;Xkv=|% zYgr@RuubO3sr`+?cra>VZ^Ig5K>rV(E~3z!Jr*@IPO!on60}(>%9BLBWi)V593K@; z6%Tk`xBl?D{49C8po!iuUR}T(k+-@i+yGzpC*NIJrLnnShRv-rZt|%h%|1%H%fvnI zBBEdR7I16(&T+GuS)Pb~R0+PCpfYx#&0qc~rdp7gHWNR*s+8Ic9w8p? zAPxh!=}+Eg*4EZ;ICSdn!_9trJ3c<%-j!qI;PNuZL7oVR)!=7*ewmIHG_+7 zVn2rsg|Fj)t2?edkLk?#Y31!Wmx8MT1c^E6a0~;&y9-xPk!~jS>DD*ZKq1oO54-O- zQ#L?9RMo#Q34<0^nUA1yP-9ryAYuj0v3e$`H4|S7sh8-i4-J}Ft2gc#%IVO@ye3Vn z0=grO;qT9wn3(MLr}^SM@&VfcS}_|B=t>voHas4mjj zgBLqW&vx~u9X!R7mN@Q&)f2?(w_0Vr1Wg`dFxCO+?LwB2b9?2u$IItc^%5Y-d92h~ zZ#|o)i!0v;GxpdgJa@x%=yNi@@~7sdG!tl2EaloalZDVulHdGfrf|W z<%_r%Uea1AHz|XuZbI|_|MRzSgkHWCQ?mNXylGq3wKv>QdwC~qUZZ5%0`*S@{ESOx z=O@)aU+=cYd{=iq^HK(nPa761dT;Chv~ZQ$WHaHP`tz?9-~1R`=QaEF%iCEQD!g%V z*B9_t=v+RvwC%IJ^=+mV%=2t^UwLup_R&o%S3Ul7{lakphLq_pUze0@oXBJy|L?x{ z;pT$3=~KJUdN%5QmtZ+}>>rbHQPKTpX)Y{0R~uY^-rJWwA;UgEI@LeifA_rOX|t3+ za;y9cunNW}ZS&X>oRb+4j?CW&-6^LGmeyC8<`) zMX5lF!N|bKNY}s=h(Zi3tqcsU42-l546FqF7vrS4U!-m zg7ec#$`gxH8OqDc^)mCai<1)zQuXqS(r3T3kpe0*hA1j6N={|SC@Cqh($`PU&&|!x vE7mK|%+AbBP036IDc1+_^g|N!((~gplk@Z9=4(sbP0l+XkK1$^Dd literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-light/png/text-edit.16.png b/app/ui/style/olive-light/png/text-edit.16.png new file mode 100644 index 0000000000000000000000000000000000000000..d24c668ff79a8b6ca58f90d42ea8941641455aa0 GIT binary patch literal 532 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9G08$g&*{RsbBprB-l zYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt&=TMUJH<8TmyFzKKO8nRyC9 zrN!C#W!q1mnF*9Ph8R*>l$^?tQBqQ1rLUiypPQSXSFBf_nVp%Nnv$6aGEN`F(+^3^ zOV5wbOwP}Xo3Al}fq~J<)5S5wqW9<}L+`^5BJ3ajzgBf^_i)Rcbk92KM2vmI9V-|cx(ai9IJHF+o*gXOSrg*b+nKRr zUwY_420zy)mZvxEHu3$vE!WxQ)6W{YsbUcifn3i?H5qFYZ-3jH8tK0I<{M##e>n>e zqS6dq>#aAapH5$mP1R`jX!5Ezs$*?z|l1A+OMT|^Z3oS{@MRy&P?@r&wnyJ zsGN8H%;ZP9r-a)U9zK&F^*Szg4a0%LIl_XLEE`_$dbd01mDmA|zQ>7{|NnX%Kf1@? zrJ5n{kwx8&ic*GY?|~FQ?PgT*=NBbuJNHC{AX0I7K=D-?r&U}DSYSX17Kt@ Nc)I$ztaD0e0suki-&+6x literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-light/png/text-edit.32.disabled.png b/app/ui/style/olive-light/png/text-edit.32.disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ca6953d9399a08e76bd692f9506e7b23eeef933c GIT binary patch literal 780 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5n0T@z@7-gj8hNq*aj42FY)wsWq-!X%E`#YZR|Fmfq}8w)5S5w zx=my|+Na95_<;+r%#P3h=QABDd{dD4agiiv@3Er?%Q&L%%$>Qbbme{R&{FX~$sPI| zYzz&zoWHrgndS6O&k%<#XE*a6n8=?eJZaw&50T8P4VHVVC+qmzusl~>vUAOSBQ3SE zyn||0hQ^_>W*dcgBQsCk@=Or6WnQ+|iG$JQ_L^Uh6<&O7 z^IP0-alVigy8rGZLz~n4&%Y7e@#sFsosasgc0a_K?Eg$YApT$B!}0rTH_t7<|4do0 z`h#ra+?PyCJnSF7l&f)Hz&)WlzD7I3=O^QpeLuny{1`3v&w10AC-Xl3pw!-X--6;i zOdlh;Nw@ z))QtUV}E~(-3K#0CTSU#fBhA#1r_(!3eJ6-1dJJx64!_l$I_CF{2~V5#G;bSJcXdr z;_Upg?WfPo1j?&|BtbR==ckpFCl;kLl$V$5W#(lUCnpx9>g5-u&wghk1yp1V zQB+!#oXU_ont`Fkrha~2u=f`Iz=jX-E*O&m* O&fw|l=d#Wzp$P!ZVJ>fSXD@eYYiTc3VQyz{Uuk1+ZeE`#kN^MzPDw;TR9J=Om$7ft zKorKmcWDF+D88A-xg-lxM=B!GfdPrV{{jPuB?DEN5epK~#RHer%75n47}~#`+UDo@1D*!@Q;Ja283a_CWN>N0M^>KTI)|s zGZ2R1Z6U-KGgknBh<;gXceK_oMw&`laHUiiz&!xMTNXsLQLEK{W?9z5SaE3~gxCth zaIF*r&1Ul|03=Bg5z&)84Kr6pb5W=PrBv5i`>N4sY&#RX(@X$hpuibWN_CmJ>(ccg z2+n0$_Q4p_lTrdeXQXw*_$bS=Z-p2bgMS2Y3BbCP62_R=7!&&@nE9#J`VCM(2Yfg) zM_TLqQpzI$8vr_9Ct@ijh$v3e^x5e7Gu;C@@W`v(Vdia@?xty)I}4}ofDb34C{5GI zuNz}}K@fBRtm61MVq?tL@qJd#3TNgCxTooOnmBK-g^%E*wlAVNm4Tw+3mGT_KDU9g z;By%$6F$>G+3*t$ECUWqc^fLF?)sO^Eci6dJTcJ$rPOt1-aFoxq9jRX!t*rq#&`$F z-QPq+FUy8c7^v6lR{&gg>0#OM2?IiiO)q`eZnx`saAqz94tO)5lseDMhX5}ADH44F z@PL`G0l4MX3WEdQ+mM-W_;9zj3Se)P646eQB+rY2|78Hc=2R8%SqSlXFc=&Z2?yK} zD5U}b@#qi6#diR&t+o5Z;jjny6NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5Sk?NMQuI$fPSveV*YfQ>Gftn_Jx;Tbp+`k-8QY?6Gki=w7XAPK)cVE7FD5W_iJ3HRyvAf37vN-;<0N#>E&WSOZkqXTo9ZI7 zo17okx36IOwC&qx&VrKat-qL=?y}w5puiyD#It9%7wet$C&wh49(+IkQP6a4MY~m} zD%Xu|g6FgZ3uJeNl$ku{y2TRok>SFYX%G8LFJGA6xW-`D-L_{uESsktD9qa4AnCW2 z>rJS^`QyQt6dqVj+p4)S;hIuJre#D8xA+^TbqfaX&V<^P}4 zY?>Q-zPATG)fUNk!oR&-UT4A)_3+tu1e4zJKK?FWAs6sazDjR}Y;4UZwoGH0DUBsH zRbmpXn?C#$^{Vgt{&4bU;g!!dBbh5d>=Zf8`Qf2AXTc+Hjt`HxxeFe1bA5Qs&H3Vh zxWI+x^STST=Lb8;+f8rqtKnnZ`(rQDu8-9$UmhE?t~!v;5z_20x`Jzdk6WbyYo$x`Z_K5MlsIQ z`xT~8X!J`}?bwsYYu)mK5=5`$U0~R7=u4f^g@Bw)!L@e`UzuH8ykYs$EB}ti%j{=N zo^$cSC;#&kfGJj_#5JPCv9u&3zlgy%v8W_7Pa&wZI6J>=`{^??f%2*#`IN+xRIB8o zR3OD*WME{ZYhVgQAqJLK28LD!#@Yr3Rt5(43tFb4Xvob^$xN%nt-^^@~+bMy0x t^~y7|Gjmf@G7~|{^+7!Ski@+7{P@h|{JgmN8X#XXc)I$ztaD0e0sx1bs)GOk literal 0 HcmV?d00001 diff --git a/app/ui/style/olive-light/png/text-edit.64.png b/app/ui/style/olive-light/png/text-edit.64.png new file mode 100644 index 0000000000000000000000000000000000000000..855d94e20e52c09f6ce0ae9d28dc64c8d608789b GIT binary patch literal 1243 zcmV<11SI>3P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H102FjZ zSad;kbZBpK08L?XbZKrNQgw4{Z+5rK%$WcH05fz&Saefwb#h~60BCe{a5^t9V{dJ3 zZ*FrgcWG;BZDnL>VJ>fSXD@eYYiTc3VQyz{Uuk1+ZeE`#kN^M#2}wjjRCt{2n@?yX zRUF4ZZ;}uKt4R;7IpoiT7OH1gJnT~0(_ZaKFXBn|R@Q?D4_-X%MM3CE@gTbwPf|fx z4+}Lc?n;r0c+o;zI@2PERx+$mwn_Rtn9*c1GntvpOy4?5qJ$DwWK=y}c(v#wib=*=)W5ybY`Y`9Zh`JOn;64C80N@wsHn zOIEtBzYcs1ECbrmB@Ji^AzrIgDt~o4ogck&C<{Q>^$jWIyNnulN(0s^l}gdFtjBI| zP!hnv{6>f&SG^!82OxrZTUX2F@}HJv{WKi(n?7?VP1D{RG|hjd+zjY+Iy(ys3ji-i z7_I?T%d)<*1Iht_sUg&>)#}~T)6;WM0D!LR8|89&&Dp>P5S{|pLZ;NZ-R{?xW&I8r z2Qbv|T)TLu)7gy(;q%M`aOw7b5Fq$+=#@&P4>P?4d~S7K5W@6?_QAoy7xs(H0SIuP zj|@Qw(Fbl@mi31n%M^eR4>^7iJbQwa@_o}Zw})ey0pMj`O1Y_N+C#=og=&ma%1zTW zKXvBM1OPwtrfF{abo)RM>^yFtJ#zq)%-gRcLO=+yV;F|3d6@AJB0h*2wTIC_&hll{?#XLj+Fi++oB!GD{4XuM_-x!VO%ELpImEQ*Ho+l=9VSk`7K|-7yT~?lgJQ z&=`Pvz5XK5h?-Cc@vD^bwqY1QOjTJ*8Uvtd+N9>^rQd`Q_j + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Martin Ruskov + + + http://commons.wikimedia.org/wiki/Tango_icon + + + + + + + + + + + + + + + + + From a059216b07cc4b83707e86e760b0de38c3969d58 Mon Sep 17 00:00:00 2001 From: Pablo Gil Date: Thu, 5 May 2022 11:14:56 +0200 Subject: [PATCH 28/96] fix dark colors --- .../olive-dark/png/text-edit.128.disabled.png | Bin 1700 -> 1531 bytes app/ui/style/olive-dark/png/text-edit.128.png | Bin 2253 -> 1938 bytes .../olive-dark/png/text-edit.16.disabled.png | Bin 621 -> 556 bytes app/ui/style/olive-dark/png/text-edit.16.png | Bin 561 -> 385 bytes .../olive-dark/png/text-edit.32.disabled.png | Bin 761 -> 693 bytes app/ui/style/olive-dark/png/text-edit.32.png | Bin 738 -> 551 bytes .../olive-dark/png/text-edit.64.disabled.png | Bin 1049 -> 961 bytes app/ui/style/olive-dark/png/text-edit.64.png | Bin 1208 -> 966 bytes app/ui/style/olive-dark/svg/text-edit.svg | 4 ++-- .../png/text-edit.128.disabled.png | Bin 1716 -> 1678 bytes .../style/olive-light/png/text-edit.128.png | Bin 2284 -> 2269 bytes .../olive-light/png/text-edit.16.disabled.png | Bin 614 -> 603 bytes app/ui/style/olive-light/png/text-edit.16.png | Bin 532 -> 513 bytes .../olive-light/png/text-edit.32.disabled.png | Bin 780 -> 744 bytes app/ui/style/olive-light/png/text-edit.32.png | Bin 800 -> 753 bytes .../olive-light/png/text-edit.64.disabled.png | Bin 1060 -> 1048 bytes app/ui/style/olive-light/png/text-edit.64.png | Bin 1243 -> 1233 bytes app/ui/style/olive-light/svg/text-edit.svg | 4 ++-- 18 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/ui/style/olive-dark/png/text-edit.128.disabled.png b/app/ui/style/olive-dark/png/text-edit.128.disabled.png index ddaabbf360918dad9a64a599d23d72d676caca1f..f64c27582bdbd526e507a638ab2dd5fe752b0af9 100644 GIT binary patch delta 1208 zcmV;p1V{U%4f_j_jeiUlq(|(p000DPNkl*M48Ar?o0AhkOhtv0{%UpnS7VNVZ0Emf$f*s1;{Fw@HY6vUH zH39|#Xh270<$n$hp_8`}dA#2D31y==F(Kf{yiVk9g^_2#|6xyGk_C2sL2kJ$Y5{Yj zKA#F6SqLZ$dgTgCyF(5FO2_Ix06gAV}ImrQ#k>-`JIOYkERP>t`XK#CuQ z06lyM1q%EK1nA>iDHs4M{NMu2@NE=SMNk3e`2H0H6kvz%TR|`Z_V|7k1QOte?^8h# z0q*$z6n_Mm3;4lTT)XBYlCRNt2Kd7FRZqhLV#9A(Kz#U(3WyQEK>=~%Hzpuf{DuU? zi{FTVnDHAB5I2790%FInSwQ^wwF=;XU!wpX__Yb(f?tyWKKQi=;Dld;0ABds1#rXn zEPx-rR{z2_*Mc^!nY8R7QV57)bI@jq=#?xj1V29hi@Q&c5$2@zP14B;v_|UO#!rolhWRT zJ-%)R9AiCAd@TXAKELZmO89yia9oo9iQsDppbdOX7hfj>J{L-+>EKripk?e93KPPw z&VPX2!VwRP|9#6DzgobaOXcz7R|udF*en!w7WZT0j9--j<=_7x9ekw#k_qTh<>p0P z@YNZxncs41F8XQ(eDKu*dWz2!3OL~_1ke(8lxIp5@WNMRz_xPFZixbJ_$mQ9BY*`3 z{P3k)XwWLQw9fC-D#qdwpfwC6y+*|N(tlN9I*_aYmd67iy<EmR|UxS60*IMvIRm9F)}(bGAl4JIxsNtOYEPM0|p`w WF)}(bGAl4JIxsMR7E~jXGzM@#gB(Tx delta 1378 zcmV-o1)ci)3#1K@jeh|Lds(s&000FONklEpok)hDB=+ZvwZ=k;)snZtc>dbY>MOB^$UDN0)KiH-i&H&?f(+IRt*;JAC`t$)c`2aZ!d0Pei`$^!ve@c{tfo8BgQ0b0S>{%Q#sf(9HtgBrgDIiG2xlTYp zK)=<0mQ=3M5z2%F^jo-#JIM;Nb_726Rp_{Y`)Q9^1<~AgnbQL1XMH9W@CgY4@ky^( zf$DG=Q4o+c=NBnZ91iblbDO1(3J@)MjC6$23)jbhw0{+!en-G}^M5%gVA+CKvm=BL ze=TrMfXsSdBMW9hOp;>)WVbsqW&z^y%gMtcrv#|%_GB6k|6Kf$#32E~k$;ekq^bZ1 zor}d%XLg0f_}w#r-VRHI6>WAe9{;%>X9c9=CnKpS5aBx_U^%{?0x`Z50_5iC)h=;Lb%@Bv>#fFJmo1^9xW zQGh@AnFRQRpFx0M_{su&!&emGAHLE(Lj7(3@D&8SspFo1_yB8ihxID3pH$8U9V7Uv z^?#TPsSG&cY(MdRZG*O<)>o^?WJqPe)gC-qET!N208$yye}c`$QXg6$Kq>>Gy~S77 z`O*3S5*cu~!M==_`O^9T5*aZ2I^O(j=u7JZEX{zo0jobOLEwh)?YF*!fN4E`1Ruwr zzNL)6d<@vqsoZ`1B?9_iU^QMAmE-SYqkoLQECaR{r+*A)Er0M+1t4H@2WTWewJn41 z!WZAeNO>u7v&y#xA60+gzkkevZ)e4q7AYAJG{m2Yp53R0pCaIZLoMw@kpf!yDFW6v z)4GR90X6)zE+8=jh%2CnFWeM8STB7qw_(bL{Osif;B{%Og^8nvYhQd)0uHyMJ%8CM z5ZD+1%gI%_jW1jcMha7422d86L?>2!X^}Vv9B#mdiOOB>`}dKU0e21kM~V^Pw0mwF zZ+Rq;9x+~5uPBC(@COC_#0-aT6+M9?BeG1*T^1LLS000o+JwIvR+J@2+FsZX_BY$9oVQ}%&jcp)p0hv0$HHH}ed}kZRfPjNCR+VlU zn6NM!cK@-BVN5_tzWrw~f?@lU^>=ZZ6#!LmMTCtGvy*hh-uP*?Be~QA= z<&QJlmzkr0|89t=zzqJLg};o|t1P03B8n)Yh$4u@ziVldt}Bo9u#*V|LJu%8IxsgY kFfckWFw5_thLc(aA`dVzIxsgYFfckWFuJlBI+Ke9aEq&e$^ZZW diff --git a/app/ui/style/olive-dark/png/text-edit.128.png b/app/ui/style/olive-dark/png/text-edit.128.png index b943661f85e340f54d643b47bfee93a62ee3e5b0..a5da296faa0933064f1729859929aef312ba78f4 100644 GIT binary patch delta 1770 zcmXYtc~p~E8i&6xD*?kIFhJM}rJ!sIDEks2N|CU&WV8k(3KWn!s24s^Qwqf|@p7)RE{LX!!-#xcqt3-p_31P$m zq+{Wk)$=uh4P_La9;i35ob7we`d~1-HuZM@%@bZP?_w}`YgS;X+Ba_T;}!=EUGvp~ z5ZK%pZ}SIy3?@iW%qIDUj{8ZND~CIpFjMW9UN6fwHrAqRei*%I(X%zb6}Pq1ywKA9 z9_&do+MPHBcN|e|6E@;Tvw?)T(_hSQCOfG4gm*921yoYgLV969nVmVWbwtRYX9l~3 z)Abge=liiDFf)+COYmT3FjN~pB7!DDUh+AeCfQtU?cs{PD9F+sWx`;^I71Z;nwfxV zm}E1SNEkvHDbawn;LboN=fhpavRg# zMa2qZ=vv|;U_qqlg|Gf0{Ztl=HN;*O{Ve1({(Z+gih{d}urj|PP}MZ5E=`@(dKW6x6GGjh2UH81ovHRVMz@Qmzj1;DF^jWzHrGp8L8hzSjyGX5Cdn* zO*al5%}`mpAz^ZvU3#gy$$bm07tDF{gK^^?qK8)TZ>7w~M7`w=MY&bVHLJB}snF}q zFvT^j-0@)FLe)Gn>jU(l%|LQ}DS<0(t`q(tfHH2-& zR5WFJJ@C8m!$@OsrE(NnA=80}x)YTq<-Y@`ZQ71{^^#-vg1b3&_P}UCa?s!inF1%r z$U!iiBOiw$jC=)#G;%r&nwHLcTOkLu4S>X7+Ul(G^3@ov=c&Wmy(F~wOiR;D!oQ!R zVCW@5FwL-(aC@YKF}#KT9!YDGjjr5(76XfKmBX4+!ndICuStoQFVQUFCVMh0c^R+@ zOWGR=dy;z82x3oii+>W9l;~*ez2)0VJ}iMQgxbOuy8_tK7_bIgT3^DJ9>j03<+NGv zj@Es_V042lWjnPb1E9PC=f3oeNXa=~f+13#Ah66?ghtx3O{py)=peZ6OTu|R?{^{o zn#k}HDYgAe)N2J)MiHZ(@h+vy>>E1cRO&KhRWbmEj!>CTk$D|TOu!I$7q9<=wEsy! zeIh`KL|(x~_*~EzUY!gn|C>~<$f!-kW^#uV$ZGoX{Hvot(N|$Z2p1oG6S7uN#q>br zrG$^HCXX5X+*ZZo*c;2ko;91HWN*&Z*rYBGzp@4d)<-~<*tot&u|=oH`a{SQkh%~r zGs+^r4ylX!v5I%S4UEtJG-i!T$?@j%kPRQLE38lCN%{|KeHNGF}WwH&TjO_j(1PyffORRr|F z>h=}2w2sM5^@lf&c(X%~0LYMP^g)qfu}-LcvH(#}*tLk1IL-{<@wk!W$8;gZw6t*( zzBm8~+_7_#hhMQFhL`!$xn#3p-*~J@P2^V31qOhp$EPQLb+0Rs0?(5+?<=C@fG~u# zEog|gHpqUeyFPwOU1!}$W@8?w`pCNZg(hYsrnZlu)z0!ztivz+|wQ|4yg> zRBs_ilIxo|;Q8hMepDrU{wF&hq<_L$!yU8t?gN@H=#1+DJGx6Z#A$NP#a2%I@5&mL z7ib!lPruD56=TKq=9dl*bq4$IX7nCqcfG?Fms7pqdZ(0`2D;)W4ctCt$@PDnsi!tx zDsWiZd>g$n{yB^`Ql4cG@}v>J@N|kF99gQKWP7SyR+06#nuW@3D*pmSknHR3e3-WU yQ?+{xcNdX@-9~kRh53>qgI2e~_pbk+(%U;AzU*x{rLqD9c2B_ZU{bR$jrCt*DmV`S delta 2088 zcmXYydpOhWAIHBNS`INvI!u%)tuWgX@)+WAs5T{*AsrZ!-;zACwl+_vC6z;IBGXEe zQ_1RyZ2UY~*pf+_!>HAGxEQ7!=J4!izx(?9@wz_u=YHRx_kCa2ePXy!ZBoPq_97ltI)#+hxn>SgqX z;xLqkG1%29V|W^N->BXAl9h4!ysxj_aBL>jWaZyp2fpMsX1$Y0DOe+1Gih{eZdzK} ze{RXG_~Bqsojt!lT3T8$oC~6_@jj@IJ6A4s8x~UY+hf+mlgSoVoC~=r>jCDF7HLr> z7K`t8c6JJXP!SAh7TlSX?tHv_VT-Ztfenqqo+g%A8JB-kHj{QEC5VyZmlY{l*AXpO z0L&IxqtIX=1;DB&>$WOO0oy7bZ}H3;Z!IACvvWZ%7W{mzfIiWhgl5%15F+2K@0T6q zgr^cJV9CLo9L$0@Psgzzjivh2#F$ZZV*d~4>o%i*)M87i`K?fY2e06jN9LcM55a0 zRfj-y*N)LYAi}WO(OfIT=#XE3mw^!Oz&9t{^_Y+1seW}+U#iK^fYg`-Yh)8^bs&E| zs+qG|kkEZqTR30T9)p?i$kv0ha$a4+s}By}yW%hac^un~@0jw561=W9hdr3$=zYwX zr@5h%OMRh~J;cJp+*hahjr5(mhxw66xRncIX$&W z@NwGlm~t9jJc4ldZjts>B2owS8y^%E6YI65#JYq5<0@;@|PQotCk zM=2FgXn{I59vwb4wq(dX(t=^CUI3$XaMre5yNhGvvOA8Uht%q_kgt4e5=j@%&y)lf zFYb!V&_n7(u)ph`KR%O<;v+fW{e?}P7mL`3`%RF_!mg3u!bxQpw~jjwW3abmAOP+s zw&sX$md_cFp$7T8@FfOO5IgXJ`|OS<+Ch0nPl2UIZ)IY4Mj=iKG6fht^1;h@3jd?# z`hCho>b{I8u@*Cmo_F*r!F+#yl2JZ{>WCG*);4?qpP-*w>nkz6bW*@v7SOH7fc4fF>*h-8GxF5%kzJlvofeyaI^RY;D_i{;FFB zys?T1#JtrzeOV>&^e(= zgl*QS2&})+wU+M4*jBEwGV>%z($0cSX~CLOPm{3a{kCB| zH1ge+EKUER+Q#n07ezl}S1UBG<7Gk1r9NP(X6yG*aM9rKQ-QDX>l!SOG#qFwNzb#k$80myuW@?yH-9m3I zxXSBH#D5j#`R%l~$3~_*hfF+&5Q2jZ!+F$Mu1n&uxf}Kq5yY{1mNX#{_POjxb?mpe ztFz8v#WjHXX6$m1^+&m?s0x4>ZJGx&_T=p+27}{y^x@MWoK$7zS12;tTSON$TxuAo zz!fVIr;fVf4BV$KoD|wm)?OJI8JUJTojG#Q53>A>^klP`MhZlGo{VRdp zWGVF%>(^2z5{+iC1qt;0R}Z2#*>tw6U;gzcNp90dAap5!rV_;H+6c=(X-_Ec=JuS1(lBmvauDC zo{^=<^ps~kqdfDoW8R!I`hO+Jng~prNad19*yeR`DzBp$Pv@^cBfauC0N64Y%(Mh5 zkVYC>ONO&^ecgYpRIN z{1pSvfLTr7SOk-4&W5YNo>;WrYLp0H$(=41FCggR~<90 zfB0uYEpRkazR%|tEF~%_X;)$vZUXmpt^nTL#T?q+yR|{8m|u_(FTCjZ$2EEKdvl!h z5JGChZBQ(Lm8h&$%hTeQPwwvgvDRP6iD~AFAl3xQJkA3d>C;o}&Dlcj4mR?-FJS$^nYZJj zA;Tv3Bd<)$%D1ZcO@k?`Be#{B z^nPxe3k=>_er28SUp-y1)3|VJ`MZsM@;@1NY;|{(wM^MGxth_5-_Xd)$Uxh`z{JnQwh{ z!~E#C`(i-V+ve?9X?tSH$#DC~t@HnL{rXYf_EYm?x^3Z7*_5ny$HTEp^!_A2^vX7# zwOW>qH(uREYc1by37!=Z4?NsHP1)a4Zo2(e|CjcBw)N9<&nLe(t$rl!Y?JhCqh{k8 zphrbYTq8;xOG`5Hix_+-doddE8yH#{m}naqSQ!}nV&5e_xtmc5S*$yXY5C+mj0FHE C;Dq}C diff --git a/app/ui/style/olive-dark/png/text-edit.16.png b/app/ui/style/olive-dark/png/text-edit.16.png index 1cde2b02e72754c186eb3cfbc12983c3caa94fbe..c3485002531413717c12a17bb2601fd202b58ee0 100644 GIT binary patch delta 205 zcmV;;05bov1c3vPyng_%NklvMdMaTFB!Ss#$fW-)7O-g00000NkvXX Hu0mjf5b;{k delta 382 zcmV-^0fGL31F-~9m5bdCJ zDCudwh2Yd7CwI+ID)4i-Lr+{7araO$eB2f*Wx%{ z8?Os_aFQe^MARdqUbES(0{~^k#+Vf;;otd z27`kz4Ex5Il6Mf|mWbx!NrP6awVbBu6EhzxrCy9NB`M`KfKIJen~Nt6(lp%$utY?s z*4mA%82ElhBHCqU0N7;a4Q4)9O5Od30U&5J8jIfh^+KWW?7i;_A?~Zy>PHqlNxR)% c$OWeI35}o2u*1IlHvj+t07*qoM6N<$g0<(kT>t<8 diff --git a/app/ui/style/olive-dark/png/text-edit.32.disabled.png b/app/ui/style/olive-dark/png/text-edit.32.disabled.png index ffe6f39e961b032a098ecf93425a8880e210c9cb..336da94d040e0967f1a8de68d16ff055dbc7b50a 100644 GIT binary patch delta 363 zcmV-x0hIpv1+@i`jeiUkJx;w90003bNkl~+zM^RU|7)^C?f&LKAm37iG_pBLpbn1!N-4Ejpq{(I zu#g&(6WaGWGYB*TDJe$#w}=*~=TUQzdZZvy5PEk(QFUdSD1Sk~*ML(GQU*mSn}|~g zcqOGea-fz1f{25H9tRjIqV`~ngVeNu(=19b#X&t8P)Xa*5)(eD{2_?Ne-Xsvdj%GJ zkHCii5Loevz>bgZfjT=r5a<=T9sd?6a|0004KNkl7XBFG3k({I7SzU_*2MrHFzX>MOwA#N#%UNJ!xqq+;^zy1Az)?`tu2G?o z;i?81I|<6xO+h0YgUJeoWSyCVpv*q(-fIflwn?Foq0<;wcrOF!N0NZ#=35_j;8Nny z%XI=8*`||VmEB~OSu{b1X7ag9cHzBj`-FVr=yI_7v z4M6702R#Z--LeCO0Pn2=2d&GwpyiY8EGPXEz)|xC`e;i{Pe zvPt}1L^a@T?@HQt6Bjim6qAjlJa}yV(nLkBD6b#|yc?|Z3Qbm5?>F$=&vt4$QT1oU zfd{#vCK`bUnyWyw(lmUeW(*(0$M8Q5-)$4VCh4s$xJkP4!Uv7Qz4%g4e7#Y)1C9bf zPtrna_|H@A&K1ZIQ$J8%fB0^5Gp@p&)0flc77Ml0ad%+6!M0j7fWR*mkJ!7Sg4 z2?y_hqq&e@z|B7#p41V9< SPJ@a70000#8eE{u+D+Ld1EChR7?JRbZ zCe5+ESe_gU3%l_JC6%_x)3$dc4=M>0 zN?=o{>VBT*yFmo9EV~N;*4nA6zUWAcs<{|cKtxiKZ$)Gb07;TamxM7!2NkIITvcsd zg53L8wD-{-YFm=iT{%6ykxeyh(KBu0TH%uP=D1&)tcn<*=%;J4c>MC_ldI^ zD2n2$bM6?x^_s+w)oS%jRqq*Np898l!2#e(wOB5f59)9LP}Q4$Afc-2zv*8N1wSWH zFMmsXCwUOZ@uwl-fNw!j6g$qj6a4;z0f3*X`i|t0we~AX9U2b!3M>{28e{gdgTInSji=@LXP-MG}Dqd_`gO1bE2hy??quOZhAlWdXBf6{=>g z9)T8xOvWk#GLyNbuxPx|a18J&Hl7O*iYzy4fqCeOs1YbLKewW=Zs-VMA6dW|c)8ON zK85YSnIW1$ZQO?yq{xm)0^ZL~9!SUU#iSHPz`?I9l$#5W*H`AMIE*j~T)bI=mHD}6 zM6As6@#%vnqklRcKyqvFSyPY9z{Vde;Kzp)s^uVoW_)*r0|dhOt_p)kK|8+kc8MB+ zF8EH0!vx~t2MNT)4-klp?=27;-%}tyzL$UozK4JgzO#T9zN3I1zLS6^zJq`+zEwaQ z-y)!o4+^Bf2L#gK8wFC~8~%voV=BB?Kr%k1!g~Z{#DCXxcwYoQ@H!p7CLo4l{puzK zz8-ZICB`H#zAu>UN&_RVkNlP3d04>2-2GBPVLFgh?W@k{KVlXwFn4>2-2 TGBPVLFgh?WfEH9Elc@u6j_WIj delta 722 zcmV;@0xkW)2blWab6oB6wLn)T1gBpI4CV-H- z=L(#Kg&QHU;2XPL;xaKhx51BMg?Y%;RW&xqJJ-wQ)2?&i1vzi@x+}Q z5fJ0^3d}qnfQFx*Xcwr7=Tlp=fV;qDMK-dr_7Y={Y%U-zT?Q5j_dMSO}XDtIFRcfmj3 zQ9z8ZQpiUqfpWaOLI;6rysSd&Sx}D$U|j7XDQy86yiA#v0_yOs1XSW%2&lz37Eq0E zD4-tSNI(a^fq)*ow16(Wq<}uWlz>jWgn(Xrt$=QPjemfCe5HU1e1(7+e5rsbe90Tp zY+wp66!08)W(qG5IAZiN?iZB6V<)^o;NmH4#Z|i!c()V2AaH~f|9`bIfiDR74&MHL zx-@|=2(W%q{f-HIPGD-m!{nlu9<7UbQiRV5SiAf+f4WyW@hSwMpUq4abm22g@$?>h zRa}{A#eXit9qc6!C~N#E?r_ORqVps6sF!Nd@<1t`>jDDm*OVnZR@wMbSaD+T00xyM zZ}78wp&HM10rkt@P3Q*Bew@A!)#DR^j|_K(Xu>u7y8rDpHL0|Pzllf}n*(AYD2Qb{4TpBSZ+1AQD>(ts)54DMY#Bv$#F8*_-`$ySJIm%?E+p?99vj zzI*d#Z*KxYlPx>y3DhM?r-2L6%RMvOFEXz621vRDJOZu((|=KO7uW)p&FpK|_*NSr z=??Ie1MsAJzzZ{bl@_D521x1vor2w0&FrP?LMsg@2|tk2gcJ2lsX2`Z53nTZZnCj; z22|9OsA&FI>kKfn6<}q=;ZyW?jDvWUXLLlWuoSw$+~7XJ`wWoOk@Ps(9%X{Fvgc@; zgBzyQ{nHD@-+yIEB&)cYtx5tIGAJ+f;1_Q*z>(rhDVeZJxth=gehglCX+XyMPBWoQ zVcd#;PVmlv0>!P02|Zvr-r$u1B`SNC30Z~lS@Oe?HwI+Dr$J@a1XuqRGka5QmSa-1 z)qQvTbYgv$Qu;V|fJFaM?iZR-5%^f&vLvF$dY3VbX^EhaR+ z3uIOMXd5f4nUwZFUihtjMJzBe1H$|0Y1P7_~zp@ssJD01AKrF@BzO0IE^a6 zPcZ!bNrs=7^leh%XC-YPSNI|iMehOU5^bd(V5+_cp|vaXh>WBu`X?^W#+o_O2# z;4?hrXMeyvhv5M}7Y*(^Jmed&=xCcO61WZUkYRwNQ@~Bfr5nom_N6WGkevayfRicL zoZrnuyWk<)09X3QHDp5D;2~ufkaQl{OuL@Y2jCNM1z2!g_ZA+~&j~J4{1oW|ZgB7% z9vlWpGT?T_xIN&xnZ2$UXY6uiz-3}bNk`C6;D4c+eW?(mF}V!LD}HJE1*`#UX7+pZ zDK)D@>s-N+u?Tv3r%__MBW`VcB#i(f?*q{%-Yi8n@X=tyHOt?;eeSb7Fe-9l61qD^rKXzak V2M|g<*Yp4Y002ovPDHLkV1m>v0^v0)GIW=RMxu-hNu9o$~;K zAh@BF`UJo&5$ON`$#Vb?jWKt3cXxj;YVS0FFbqEc@Off9M={ASeBb|ORt{$YL{T&# zIVf|kh(ucJuX2wy+pTs~#eAY!5L9#BYDbHh2LO`#;NalHY}`2jHT78#1UJ$F=KyG} zhaxguu(@}!Vt@Q6=Kuh;A>0~`M%R-s)&q#5Xb?rwr`fpHdPp+2vKL82I?09!upB^A z@JQ-B2)^$}i$E~OF!^jPfNZrdf>32TkUU>oTYHjxw-UgtrEV64iZ$V3`aZ!r0Q1)Q znh;`R%-wXrDgb3SIYkiW)Py_Pn-<3Spiu4ZtGi6Ez9p zQUKI3pQtGat*-)2mSW1i{NnsR!A$KTjloR7(A7 zjDLAUMEX+~ux!p}mHVE3r_R;}?n=kfew_0&uv#zJ9;# z-_vZ>1OSq`ubo`ziHIDE$ah-n$4l;4YnlLXa&q!huh;tnz^fObrzG!-$f4Hyk%(|Q zh1;5{cKiGL-CnQv7RhI4XJ@|*27^j39bM^4S8_`K0F_y}CM}lO7ytkO07*qoLQ4Xw diff --git a/app/ui/style/olive-dark/svg/text-edit.svg b/app/ui/style/olive-dark/svg/text-edit.svg index 1bab2a334..a63d30511 100644 --- a/app/ui/style/olive-dark/svg/text-edit.svg +++ b/app/ui/style/olive-dark/svg/text-edit.svg @@ -264,12 +264,12 @@ transform="translate(0,16)"> diff --git a/app/ui/style/olive-light/png/text-edit.128.disabled.png b/app/ui/style/olive-light/png/text-edit.128.disabled.png index b5c8837af645c4d179945eda7ce6cd6e8623f787..725316db95d43d6a1f0699813c304bc2b3115370 100644 GIT binary patch delta 1356 zcmV-S1+)6J4UP?vjeiUi)GZhw000F2Nkl&x&*uXV#@k8GIRpHv3`rh(OaOX`s2W_Y4@SaY~{{_Q=!0|DK=@P8EQEP?|8?q^qnsnr5H zV(@~n_iYq6LIDUz>zJK`6Z;XzIjRKygOvhW4QL8vFhZs3_&==^&}zV`@P|u$ z1w;i%;m0ZA{>fSdqjd;q|5`Dy%Xxy?}vnHPJP|{SMd4osZtuk0dhy zAk{>0s=oj7`X+0TB{#h)7#tMk6`G0u|r0N2k_pcW33>CmV<ZJSesjImHiHCk@o!)pi6pDw#{IG0Xp8_pzB}L|$tbvS2T{WtA|MW* zizK6fgMV*`fF%6X3b^=22oS+fr630100E--iV6@Warl{EA0UJOe~-@)xj%&8`%3#m znPz}IzI+xKEI3iz_!|^J1Ak)zsNio%03G~|2%v<&0Rgn|wF{tzuUP;+e60c~;%gK@6JMJEs`#1& z(8bpxfHJ-Y0krW`3!sjlQUHDYR03?kPa(h#d}RT);42ES2VY5mP524|?8288U>m-q z0Dt@NrLGZbpV)^lA)sA@rhWLr0=kE+8+q{+aeP4m4JYhIt`_9+1qJLh*}k3lLITeA z@z_>;ApwPE#N!Gr!50wFIe?12_yPjLPisv>d+-wld@Vq2xdj0&!Ux!iKRm6iDq>Uj z1%$(N{NyR{G0ouS<0lB{e8AFb8x~ie$A3l{KS4nFalQOyz#8`8CryFq2~dxIvJ*x8 z*n5ULC3eC&lyF}T9sJk~2@zpCcfs%MP<12yksae)JSTtVxfv8Vq~=yR6|9 z1+>brn{H5i4tlP@FT9u#Q5leG4*(e6&aMYx)?ms4z80oc)xi+JpI==+tM)fSz)MZ> zp$Z{-czgMjHBf2+G8MpUJc1W`SAX-YVKfLhF9s!qYlIUVstO$tO1mi>i z_s;Ngk~M&C0j10yX!UaMPF)}(aIV&(QIxsMO!@q`;69ys=F)}(aIV&(Q OIxsK{o(DRUL1t|kX4uEZSjmFAfwKi z|NnFLtgcYNU6-mwd_!rU{jj?VZIdQxXp`Fe(-3J6*OezB%^(64DN>}!Cl1N_1*jwW zw(nO-1pwcy<>e#bClb)xw+=`P%WGIGy!HPcKYjuMr#q`7(tp8dj$6;3EORZOUnk$8 z#K80LVsyvqp#%nJZ~$juF`r_QR>N~2aw%ZY#Xd&`6KFK7`F-vL47zy4{p1>5fuRC~ z@RY_I*MCGn9DY&-bbKuY@Zcv=z{1x+0586z0zwue27czB4-mos?~1P&c|HVJBdPPD zOe;VfU%U!579fMKUO{F8Wbsui$VfmEe6$M~2MTiRp z@KyDbvH;!iQx>2feyRd=#7|Lxp7^N=&=o%=0e|}9ry@XS{1gP}jlXpPy5nzIfd2Sf z6<`AX76q7rzcm4-;BQHQIrv)iLXq6srZTn zn2WDOfXVm@1elGVSb*vH2?dyspGZI+@Dm8g2fnm`yx>a;$Pd1hfIQ(#2*?+{uz+zq#yKl%V%70}y-gK%peMjwEy0<31t=}^(=i}jO< z0RKy{h0O9Y`Wym&l&~Fo;fnCHAAJr1%YSz88Dx3+3f$2hKYj}Qnxu36@nZy>{Die& z8&-qg$7V8qi~v7!{IQ!K{1^ckEua(q%}zY{I=u01hVeT?y&5^B{3z!4a&)`nV}(%x zq{F!GE4>O#!e>;#ndP4_CkUkq%)(~~__;;m-U1^On1;`o0Q%J@)yzEdQj}M_Q(8&@2tCXK<_r|vw+JT7B7MKQ~{c%Tp zBG-VEJ=jyxxz2O{|3p@R*AeX|Dr7vm${J5j0D-n}KfxegjBc`qlN2zhVubz z3qXkpKpw&I9eb5Ei~<2i)$k!0Gq2!~+3-c^8m$r#Q05 zQ@J}gW~CPq5VHW1XK>21^Eb#%0s_brbq#of8!{Ujx5^6&@UE>+s0w^?2S3hm&if|} z%}VGzpx-8IXMtovoSmEBJh4tqO2mOkZ`V42eemF+>|89xyDU-v_kS| zznq`S#uHOE(K%v>Hor=f$*9F|kNxiJ{^N7Kuh0E@zwi6Hug@3c7_zt%RQJL=2c4~$ zt@OWif~b=RiVy9d+I^+IzZ74wy!JZrbxic0M>k-#L*zRPSXGG$38Yj@HiBTKXxJD(Yf58VP>cpG@jU>w zv$d7|HJWbfzc4rS;LIJkj(k{k076mEjK7hF3232U33-5t!b`0 zeiU>8>u1@3i2Ks|S142K4q!8MvYiMyr;eMRNJY~8+d>-8$Cjy&=2>QjSxQ7P?#Z3>Y;rFrvk@yiHhu>$F&OmUM@&puD=W1sK2=k0EQ1_bCZwR ziKoC*GGjU=8Fd$afvJaI2-@10=C`HJj28XEx^pPORuymzd%U2UKhtLI8~*MT4Y7%) zC}M5Pfw}ub6s_m|e;9d$jgE|DP)0wS;?Qv;0nd<>Z_T}^^M#0c1YV0WEK7w#X&3_5+-6g1NZ*PAqqlT-P zI2ZOkBx3*vp|1PEgS`t)86(^$L#kEr!mQCoe0E6ne_8vwR>96Z^f2z zn#Td12a%!G&Bv4Pm2CfCy{iq#mzKoF_%= zOaUNmK>y%*SWTJ69pG8HlVLFoNV=II%~nBm5v3lm;t7|sTGYH~bKl>HiHFNZ=X?m) zbG6YyQV&l?#3T$pCPxPBIBWv>6t@D;*W7&>IBf@B0Ik)2{~&?hwgyqE|K1QK%4VY} ztCqz$U?kHIBbdk1|A%Tg#eIq~4=E-QjXuDfslLt>HS{uPFtM9{8HD zKN{AXEcb<*w%LMUh5DwxZ@&OP9eaFvxRDxG$T}=jX9Z zepu2pz-b43ITna6q1DvX1PVr>Z@WNE-sbYl3rb#=E?$2hv<)Ay+WV7Ra%GC2mD-qfae8 zYm#1eEteF&fF6$5j}X-lB1@U2%O{4@7g+;oK1U$%u5~IrC*8hpkvqg0s6i4tTTi!Tk=d3QppmKvjXd)*Z z!3N%p_^<0|?Z2H)R0v={d}2CnHC8i5`j`;2zvKO^@CJEUpYm1y@uL{OkjfqBt_Nn% z{5%i%L6=gpDKS!?08hoEa85R6ji$p5*Ut@3mgx6O&mBXJ$PwBj>Jd@cB5K}mP9Yx% ziBz|g@pX!zC@Zihx)jWbk!~x_RC&_$#hEqYbZ|YsMM1xFXA8%Yp^6H|RQcKI{Im6ers zwsv-_p^=4uo%rOIMJ9h_bVtlZA4nG$#b4xZ;hdF<28`KZo!|px%2&7JpAbn?Jo=zP zf^^jbFV3Ga?hKRYL&QftYY|<7a0C+8LgEJj;z{0b?iA_VJq@GKcxo z_ysJ$jS#)$=}wU~$%a}g|9L~bIT1PRKvJDMr|lM<(J3?oL zt~BE*$s4^BQA{3gR{Y0?(v?LvgoXkttay($pefhFE)(RD-nL4*q}lZeCTb X$T6RKQDe#)s$o|=%vnWr{c+Db{ZNv4_KA%63dr!9_rmrkciWR&MR zay*sfNaV1xLUJsRl_hI3PjyaKM%w1#x8HVO_aFClU+?$(b>G+Zxjr9}!9NB$kHIY@ zf>+?V($6?@YdCWklZtTo;n@;lB_8~3j zFnUBOVKWSlF8r_)(^q4YZe-X=WGUX%ee(<)Xw6Uz-Tt)Aq^iQM_U~*l%kRWZu|4&) zNZRk(u9z#t;QcorP;FCp8z}((CAN9>_oB!PAut?#3-ARvYikhZC;wz5d3GpHH0)4*oY37O>MN2MQvRJthoaoYA$EINLGZXLwghh0xcNw$A zJv}|AgX`WDkX*{3llVIFDf+Y$z?w4pAZNQKCnxp9OSmh_2xI=9>XP<<(}sV}C6+;h zI%%@D&U`%lk6$iLvob6%Y@k6hUrHZT2Vzzxm8+C6trI}U5K`Q+;9i(Ky0r4+qb({z+3V=@F3!$y zpg?%5goCuUvU=~Cw)|axC6of$#g!bw6JX*cWvD$FvMWBt@`ZQ0sd(wPuI)c^SJOAp zib|R5+^egr#s6sv7B4+1i-edSt9_k+_w}dt@@y7JWfgI@ITzh2KpAu>A|}I)MJX@&$pHm zuQy=u`lMoM^85I7zq|5g!`R=~3$4yEGZKn_*b zCd@}g$sook*)*%c0>YWi^ZA`yBj*=_IQE_CB|)5n)4{Z09ezNTPsix+{_r-a@XS71 znkBI}XalWQPPI6^n+X;EH_haZ;nf>JvU7VTVf}L-Hm^i{pcoeZbq$18>;;Y7Cv+pG zHwAe4tnNJ)EUTO{je=Adp9_~3@h zsgK<+bWnA|p?O9ZQFG9x&uUE1{uQlGxn-kUr*``V{(4;Pw$}5uWX{&(YE=a$H^Us)Y5JkUE}pd@7G*d z{JBy6xc3%n-E{OlHuj8m$Xi!zmt!%)DF(Chz;}+{$Dxs*#Fs2pThKk`pZM%By5Vt2|?syWeEPB}$R&Ldn6! zJcmqQGSD42cWo$DW!TXKBqSuvXtnHNm^o#-jXT|p3?ka$5ir)TS?KZ=MNa_<13{XY zSQpAibHaQHepN-0h?Khp*?~|7gAt-Ne$^|SGus9>H8n|x1&zj|%L^4E_*fz73ha!m z5#8|rbmNF8HmdY~Rf9~(?HksQNn=_dQ99{c5ue?lj-AJIT1 zN8%uui1f=X{ZuLU?}|flfvI>o-MrO(`rYxBZ&{%qoV?4afPtmw_qIpDb8oD`t>|^I(bUFHByHqAm0~owxN|1U;)09Vqk#q4nZFjQJ*W3j z&g3Myp9>57aF5xx5_a7knOIu$7x8 zY32$CV7DweE&?0?nu{i{mwG<~|LC3Z-*yg=BejXf`3gI+vIzpY$maCp!}x0|PY zwKE__gW*{|k~_SMSE2rJ8$hQ`8hbH7z^flT!^>sm_@jsH%gD7migTA`(GNuQ#HF{>ot^2STg61ua0P`;Vqg_CLkL26zWijWB7-$v=^sk%yI zmg@}!Bto@*_xN@reGT$m-{3QgI^vAI_5iL0w?Sr(pp_0>>{CI#qwGRNqug{=IAZH+ z(7aKY*JVL?1%^%Q17>5*G4D><+S+bC$)J$@3IX?FMk$93n5jy19hpo{^KG>2($#{a z%3}-V6NT@V4fwr;M1GPeHuqovWA`z(YT)rC*hlE)ul1YEQ;hiNkt7^2(1R(X=MQM{ z4pq+Uo2S6Q0(Qo1fVo@CdF8i}>}{SY&wL48I16s}m)@y)m7N8&Ao#JsJ_lr`L;d~x kE?HFp>N%~R)|Q9U*459XLw3zn_-=Kf<2!^Z)<= diff --git a/app/ui/style/olive-light/png/text-edit.16.disabled.png b/app/ui/style/olive-light/png/text-edit.16.disabled.png index 7bb7cc722b82ef5b355674997e45e73881bd7456..edaaf4c9d80c749595e662afc3f07d82d39c4ae6 100644 GIT binary patch delta 272 zcmV+r0q_3i1lt6VjeiUgIwN@u0002WNklxrL?4aFp&hJ z;=%v_Pg)9TtfCi9E!xvUll4#$$~K+b%<~7)7o5gtJI#Bw62GM*e2=RW}bl=W}qkXFb@Hwn{Q%&=dVVrH@b^&1El~+ z^01>JOSX^lp{gd6HWT?TpVo8P@m+pOo9pS@YG@=4US8Lr4}W+p)5@iW^B+6g0;mI? zJiFBB!rR5NsjB1r*U-lh0A!a$^`vyMkpeqk{@+W(gK+IrID-SR+IxsRTFfckWFqzknA(OfRA`dVzIxsRTFfckWFzAXmos;VU EaK*QZ#sB~S diff --git a/app/ui/style/olive-light/png/text-edit.16.png b/app/ui/style/olive-light/png/text-edit.16.png index d24c668ff79a8b6ca58f90d42ea8941641455aa0..083099b6d645308101a1479633545735a360ac9b 100644 GIT binary patch delta 333 zcmV-T0kZy-1c3yQy?-xBL_t(Ijm43%N&`U^b>Ev%9zAXWxj8{3109Ox5hd*|9Dn(A^_`NJ?Q!}rg>3^bH6CN;*St9Q^4 zz5-^ztk>&ZHZri*?s)G5@4Z^qwJ|2GWgsG>vMgs|7*2ul`hQHWz& delta 352 zcmV-m0iXVX1e64jy?;VUL_t(Ijm6S2OT$1E2k`&vB}IowMro4XJ6gzGKY){qi>Nq= z)NddKzlC!*XC0i{MGz;8YZuo*p#jYYsE%p!TvF{~noR!TIF94@?%r`g%@|`sV@$YO zt2$U~eI+785xH<(H(M+g(?(U??RIyFr~!bAacztVD-~eo!GChOd{jz}iD)k+Sm88H`$>{~Xsuz}_Pu3UN3+@N69E2fp}=QKsmmlu zK7t@<0XWF>e6+%)Co}VFr_%`lAP9n%*7~L0ZVxuK{J;2|nJ1p-`2gT~p3lsa;w{P( zhM~jEZ(8eKU0JLEz;T=t5jg~~>$>i{QtB4KD30S{Isg4g$Hlx)M0)^k;y8ZTcy$1l y@B7;#(j%fN5sjP8=2H|!Usdo=n0c!fSj#t0GjVAX+{NGk00005l1*L4!gcw&3l!1t*1$%7vd$z9Y;LIVRpx;s{RLk+(Nr6F^%nFEQI+_DC zLb%Sz+%1JpYE231jOAzjRzP47Lq27)o3Wx&?1p0fImMP2;oNpVf;rRlph4b`M2*t zcfIx#paFfckWFx#}W cGLvfpA`dY#Ix#paFfckWFskVcj+2}MaEu|x2LJ#7 delta 451 zcmV;!0X+Wb1&juejeh|G3o}Na0004dNklW|ZaAEPH83~QX#ldz6Til(Qx^=1FD^+zD{9}kOusks_w9nbEg9OXDNmM|z z&9e=_kq>SYlD?!!6lv9fIlOz5EKfWH=OLuItlu&!CU$PYCVzS{GgVzSu@VhgY0BD3 zU=uw9roBQ40YuxZ`r{zz@rDW0SjxJrJB8-ilS2y~u0?hmD-q$$RCQU$BF(CR(SNYT za{xQn1+ZD|jPht4mtvK7=dziFOqj+^`7+!I#;XrF*hE9nVpYH0k}*8Xzt8LuxZ>Xk z-0?33KKK^`KY#p_z!(1@@WR}<|8h9@Ew7j=>nukKjG;fd`F-Qkb7TzD_BhV z0o1ZtkaDPKCJWUyWDTH zzAN2u2*3tJ+MWLL*gmWqSGX6nm{yEdJRCpYv_9}QE)W7690dN4cm;5H-mMXx?P8Pm t0YVQjF*-0ZD=;uRFff_dk0Fys0wNDEF*-0ZD=;uRFfizfH=UDs0&w1L(L?|M diff --git a/app/ui/style/olive-light/png/text-edit.32.png b/app/ui/style/olive-light/png/text-edit.32.png index 62569222e6a8fbbcfd3fc36c19908d19805f563e..772eb2ebf7985d5ced0e8151999a87c1e95f4ca5 100644 GIT binary patch delta 575 zcmV-F0>J&C2Jr=uy?-A`L_t(oh2@sNixWW)XKQ<%h*&8oE2I=G!etV)vYB9^SKK~}+m&^b+>f{u3tu&}@9loy zzL^~s{&7fXK%>!EF~(d2NYnK7Xf*n?Fo8IZZvyM8S_2S~J%3_`Yign3*4hqm z8!&~-23V`t>p#8sJxa+%#(JaCSP3E!$MHn~=Uf+fIITuiYx%yYRKQx>QPmf59B*V2 zPiIL03Ki~wY|T5_bhTcupY-0p_uluSC<18bwIZ^Yrs@6hc>JvrffD>9a28mNq6qJO z;=NCb5+d?wIDZ_zf(klNf_I&BccLiT1=fIep%b}8;+%V&-~U$vQ{Y{ItnIl(aXAw2 zeNueJ+yb-Ud1Ml8V43~pNWAx7%g>qXD>w{ZsA(5!l5!2qaTFf|eqha90#(D0B@hCB zWPwodBMF3rA1V+UexSf2;4tGHu-4vM1RSPxz*>7nM1QtaRYJpIvI8O_8yWn0X!wLc zv)R0$s^_!mhtTi|0ad-8k45BOtJOLe5)OquV68pH{#!2<@?U_vs(ML8Zd45iIFS#G zF;~+xT`J|5fh`e1L{wEbopVpBg8v~zX7eflBuNqx(UUw4Ggn4)QK$i> zRM%Sjs?lg{I}^LpOaNe@z!^|Vb(y*A()Az+&ShEl!5Gt%QUX9{q;sJ6=cIjc+@CgG# zh)pkj*lxG$d2nVf1P*vJpp-h#%!dFj{wWfD0q}sCuK~E_)(V3I-rJCwZ}@PxwhCZx zloHWSl4m5(i-P}U0Kn!{74TUI@pv#8925x$+z}|H0s!&o55~oJ0I#jJ`@`X|2lo|Q zbgTe?wU&esKZxi8GrtG0U#(W(_51y!GN8H9YPD*v6aQEI2JRWanij|!4*&oF07*qo IM6N<$f;BfEQvd(} diff --git a/app/ui/style/olive-light/png/text-edit.64.disabled.png b/app/ui/style/olive-light/png/text-edit.64.disabled.png index 01fd090f9408ef82491d8908f6c1d3c2cfd65da4..b066cd6c048a84cf4db158847e89c586f1cec715 100644 GIT binary patch delta 721 zcmV;?0xtce2$%?vjeiUi)GZhw0007qNklT8jo&k6>wgHlV&i)kM1npqd|(d;eTA1A_J>qc*|M@92?H0 z4F_ojG65xit?=OeSXT|Y2;`PtuT2~QZ)q_&R5mlCzR(hAaCVE*t1K%+qBzRy)) z7!CbEqk#0W!+$GqxxhxQx2|as;P6xM6O<|)r|##ty9NOs?@lSG=As(fDHfGathr9^67f48eyjhsPXD3XcWl97gwnKI^KpCM@N*8Q!xjM;0q~M z6VQjRB%l*tK|n9Qw194WNdf)%QUVnC5&|^%!U9zIf`0;Z_(B4d_yPj7_^kre_$>nT z_*{WH@HqnY;FSV(;T1cg{_DE%Qh|X9=XK#F0=9vJWcx;rmk2ap;gkCCSpfzoj}@;D zd`7@AA)dc<7q1(ijlfY-lYG_Cj~4{qHlP#N(du{kt`vCTX!h(Fo~JIk;}i{ET!JIM z5l`bNP=DdMNAa6h^e%gVV;(Hw5G@)!Kyy zg#aTe`bI$58U2Den_u4%az%mA+q=a!0EBG8<{lpil1){TncGIwLfrF*B&qhl{Ke%r z2-2F*z$RFgh?WeZ#+olY;{y4>2-2F*z$RFgh?W44wx%le7bH Dp?XZ- delta 733 zcmV<30wVpG2&4#*jeh|Hd^C0m0007$Nkli-b~NJ( z+5}SZ0MN9S;g5CG(3gR%FuL7_<_rY0mcVgpw}2T=wF>N2Fwe(R(jeeEmbEFdVAdj7 zX*pPY3m5DHu0xmcDi7uv3SZd;qRN*Q)DMD=2F#B@+IVpVbuEM+t^r1YoqeCFAPBv1 z!6=}7?Z^sJEq{>b2kRD#KpamaBaBcf`;ghoysplzK19|Yd z6w3+l;Y$f{;!6nd;tLCK;|mJ#;|mGsz!wnEgU>CX3xA(eKp#GrfKGf40loOW0=n^g z1oY!G1**Vj2vmbl6{rfIaw6)ys0yzX=vbmt6<#6W7~<8YEpp(+L3o8g{Tz=sQ}=V= z`v>871q3~RXa!Z^cLZE(vwl*Z;<@p=890rmSNzrB$0r2NYSfA@>~32gDpx)aJ|Xb* zM7q9+D}V59ybOWu14t_9!b`8>*XHt_Vnl!$j$ubPuqA&T^=)%?rW|2!;Q)<1R=gxY zr`baV!S}{sj!2;0gqexIqnWJVto7fCFU#@po*y3xyfGFh%6>wK>zCi(Q-L|l z2rR7KpEY8Ri8;Mm0iG`URv>XQ`XwgD71VCf0I$cWBxJNGi+A%YP>i4i3%$K&e!Ey}iBt zE=)V+1yrlmvzn&eVCGc-gG2p$N zGYsRc5aLCDF@I?K%woQ&R;y?G3(Cy^Aw;uWE(5^%7|k_J(@qH??s)~}1OO9DIK8m2 zaBF{m{}50>fN7fRhGDD@ZeTqL?*Uwh*rn#W?l0|j`!68p0{S*Q-(6e?u@y%GGvCR* z0H57HNCFUkIdtac=Dy4I5(v1|jgk<0PavX3tJV71`+uA}0U@sQu_X{uS4w%k-EP0} zYPk{+;U*_Y!pJ>=h`zOLd$Yfm8vz0EbpVer3>9@_tlPHz<6!5x5D)}!+jczwDy)RM zZQFIfzddyU-qy`J~ePid3Yei z5-1c3pU)~hFkZk30N45pM6@|8@W2=WrfFUTurN^mEo|p`hX=;bfHj}mCt*5P0Uii= zGPJU?@`3BRH}T&K$X={*PhV7l2Lc4l&(E&`xIE(U$VX5r!2`idz;F8h8)p8}vaGNA zYk#W210(JO78e&!ODQ*fZhVG2AbJR(3E(_4U-CI6xA4I5`UU`WyWKT}yi4ps`+);F zhX?!x5P;7n>6D1N%zV?f?OT)dlSPIE)M~YlrIcslc1T2jNGY#7j`M7?p=FaH0n8k@ z`32-p0JmM&y}h@$cQDzovdfWmzO=Md?0cjaMaBJ0000{8j& zUhPRQ;z{;a)`JHRUOenYLFh^GAiEb&QbAY`3pFh6N|B0q(L!4~(;|pgGOSRxN%}mP z(PT0+nVHN?=EZ(*`Ayz0zwd|lely8?flK|rC1zbfTv}aSeShZc?5qJ$DwWK=y}c(v z#wib=*=)W5ybY`Y`9Zh`JOn;64C80N@wsHnOIEtBzYcs1ECbrmB@Ji^AzrIgDt~o4 zogck&C<{Q>^$jWIyNnulN(0s^l}gdFtjBI|P!hnv{6>f&SG^!82OxrZTUX2F@}HJv z{WKi(n?7?VO@Gtg8#K*-rQ8hYbUHf=3kv`*M;NXFRm-xzvIEKifT&) zPym3g>l@{AdCl3t1`wVC*FvV$y4~*AmSz1883!=b@Laoir_%CQQ;y07Nx! zD^3Whe}5gG*8Gr)Zb2#K(=hd<+5_S;A0x!{0A$fTqy!+V<{fs+fla0H|ahVg{g^d595!ism6E0IHgY7yzhj9;O7Kx_Ouaz&x0ThydorJVXF6 zPv#*cfO#_yA$}2RG#YQsn|TO00~(FSbs@xO&VTo-ZXN;vsMTtvTrT$jsE!O2V)N+e zXlnCe^Te%*OCX=mzsa1MhsgkPQpz_RvF&*=4-)|Bx_%vaZa5~T{61*%tec0)Ghp2r z5JJ2ZB(VzS!DnY^adGiVp-{NPe+Q6lwI=Pp_;q`~jmlZb6Ts5a(mHU{q<={>wINprP%FuzXP5PIQ|^?7T9XF zS`XUob}#M%lh()#=yto;m~37OA$EbSVzGGN{(G8X7zve_tei{0_1MWk$3loLP1C+S zJUld$EGkWn0OfDJRbh og~Fr#{rymfjxKenODUzl0Tbx9LY8d83IG5A07*qoM6N<$f?(SJ;s5{u diff --git a/app/ui/style/olive-light/svg/text-edit.svg b/app/ui/style/olive-light/svg/text-edit.svg index 24835a975..fcc472610 100644 --- a/app/ui/style/olive-light/svg/text-edit.svg +++ b/app/ui/style/olive-light/svg/text-edit.svg @@ -264,12 +264,12 @@ transform="translate(0,16)"> From fd692e69107f667b8a9e009104b0afc4144caf16 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 09:39:52 -0700 Subject: [PATCH 29/96] rendertask: always wait for watchers to finish I don't know why this wasn't written to do this before, perhaps I thought waiting for the thread would achieve this goal. Anyway, in my testing, this ensures render jobs are complete before the task returns. Fixes #1899 Fixes #1900 --- app/task/render/render.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index f3cd07d5c..bb7c99a17 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -266,9 +266,14 @@ bool RenderTask::Render(ColorManager* manager, if (IsCancelled() || !result) { // Cancel every watcher we created foreach (RenderTicketWatcher* watcher, running_watchers_) { + watcher->Cancel(); disconnect(watcher, &RenderTicketWatcher::Finished, this, &RenderTask::TicketDone); RenderManager::instance()->RemoveTicket(watcher->GetTicket()); } + + foreach (RenderTicketWatcher* watcher, running_watchers_) { + watcher->WaitForFinished(); + } } watcher_thread.quit(); From 591d02bdd6735d01c9c2230a6d5140a798c1df94 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 11:47:53 -0700 Subject: [PATCH 30/96] audiomanager: fix crash and return error text if applicable --- app/audio/audiomanager.cpp | 13 ++++++++++--- app/audio/audiomanager.h | 2 +- app/codec/ffmpeg/ffmpegencoder.cpp | 2 +- app/widget/viewer/viewer.cpp | 5 +++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index 8fac9bd65..f22319f42 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -189,7 +189,7 @@ void AudioManager::HardReset() Pa_Initialize(); } -bool AudioManager::StartRecording(const EncodingParams ¶ms) +bool AudioManager::StartRecording(const EncodingParams ¶ms, QString *error_str) { if (input_device_ == paNoDevice) { return false; @@ -203,12 +203,19 @@ bool AudioManager::StartRecording(const EncodingParams ¶ms) PaStreamParameters p = GetPortAudioParams(params.audio_params(), input_device_); - if (Pa_OpenStream(&input_stream_, &p, nullptr, params.audio_params().sample_rate(), paFramesPerBufferUnspecified, paNoFlag, InputCallback, input_encoder_) == paNoError) { - if (Pa_StartStream(input_stream_) == paNoError) { + PaError r = Pa_OpenStream(&input_stream_, &p, nullptr, params.audio_params().sample_rate(), paFramesPerBufferUnspecified, paNoFlag, InputCallback, input_encoder_); + if (r == paNoError) { + //const PaStreamInfo* info = Pa_GetStreamInfo(input_stream_); + r = Pa_StartStream(input_stream_); + if (r == paNoError) { return true; } } + if (error_str) { + *error_str = Pa_GetErrorText(r); + } + StopRecording(); return false; } diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index bf71e2223..c9400316c 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -74,7 +74,7 @@ public: void HardReset(); - bool StartRecording(const EncodingParams ¶ms); + bool StartRecording(const EncodingParams ¶ms, QString *error_str = nullptr); void StopRecording(); diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 19db89732..8a0462e2d 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -285,7 +285,7 @@ bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio) } } - result = WriteAudioData(audio->audio_params(), const_cast(input_data), input_sample_count); + result = WriteAudioData(audio ? audio->audio_params() : params().audio_params(), const_cast(input_data), input_sample_count); if (input_data) { av_freep(&input_data[0]); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 80fe1a444..d404fb5ed 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1190,12 +1190,13 @@ void ViewerWidget::Play(bool in_to_out_only) encode_param.SetFilename(recording_filename_); encode_param.set_audio_bit_rate(OLIVE_CONFIG("AudioRecordingBitRate").toInt() * 1000); - if (AudioManager::instance()->StartRecording(encode_param)) { + QString error; + if (AudioManager::instance()->StartRecording(encode_param, &error)) { recording_ = true; controls_->SetPauseButtonRecordingState(true); recording_callback_->EnableRecordingOverlay(TimelineCoordinate(recording_range_.in(), recording_track_)); } else { - QMessageBox::critical(this, tr("Audio Recording"), tr("Failed to start audio recording")); + QMessageBox::critical(this, tr("Audio Recording"), tr("Failed to start audio recording: %1").arg(error)); return; } } From 8ba1b231a3b7a9e552c670123f8ab8507b206e21 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 14:40:56 -0700 Subject: [PATCH 31/96] packaging: add macos mic permission description --- app/packaging/macos/MacOSXBundleInfo.plist.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/packaging/macos/MacOSXBundleInfo.plist.in b/app/packaging/macos/MacOSXBundleInfo.plist.in index 286f53ae2..4b8ea9a1a 100644 --- a/app/packaging/macos/MacOSXBundleInfo.plist.in +++ b/app/packaging/macos/MacOSXBundleInfo.plist.in @@ -28,5 +28,7 @@ ${MACOSX_BUNDLE_COPYRIGHT} NSPrincipalClass NSApplication + NSMicrophoneUsageDescription + This app requires microphone access to record audio tracks. From 9ec42c792adaf93c9daf893dc9055e967caf927e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 15:28:32 -0700 Subject: [PATCH 32/96] audio: merged all processors into single versatile object --- app/audio/CMakeLists.txt | 8 +- app/audio/audiomanager.cpp | 1 - app/audio/audiomanager.h | 1 + app/audio/audioprocessor.cpp | 302 ++++++++++++++++++ .../{tempoprocessor.h => audioprocessor.h} | 50 ++- app/audio/packedprocessor.cpp | 101 ------ app/audio/packedprocessor.h | 60 ---- app/audio/planarprocessor.cpp | 104 ------ app/audio/planarprocessor.h | 62 ---- app/audio/tempoprocessor.cpp | 269 ---------------- app/render/audioparams.h | 20 ++ app/render/renderprocessor.cpp | 46 +-- app/widget/viewer/viewer.cpp | 79 +++-- app/widget/viewer/viewer.h | 9 +- 14 files changed, 426 insertions(+), 686 deletions(-) create mode 100644 app/audio/audioprocessor.cpp rename app/audio/{tempoprocessor.h => audioprocessor.h} (66%) delete mode 100644 app/audio/packedprocessor.cpp delete mode 100644 app/audio/packedprocessor.h delete mode 100644 app/audio/planarprocessor.cpp delete mode 100644 app/audio/planarprocessor.h delete mode 100644 app/audio/tempoprocessor.cpp diff --git a/app/audio/CMakeLists.txt b/app/audio/CMakeLists.txt index 5d190af1f..08273c9af 100644 --- a/app/audio/CMakeLists.txt +++ b/app/audio/CMakeLists.txt @@ -18,13 +18,9 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} audio/audiomanager.cpp audio/audiomanager.h + audio/audioprocessor.cpp + audio/audioprocessor.h audio/audiovisualwaveform.cpp audio/audiovisualwaveform.h - audio/packedprocessor.cpp - audio/packedprocessor.h - audio/planarprocessor.cpp - audio/planarprocessor.h - audio/tempoprocessor.cpp - audio/tempoprocessor.h PARENT_SCOPE ) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index f22319f42..fe791b3d5 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -26,7 +26,6 @@ #include -#include "audio/packedprocessor.h" #include "config/config.h" namespace olive { diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index c9400316c..20d1be75b 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -104,6 +104,7 @@ private: PaDeviceIndex input_device_; PaStream *input_stream_; + FFmpegEncoder *input_encoder_; }; diff --git a/app/audio/audioprocessor.cpp b/app/audio/audioprocessor.cpp new file mode 100644 index 000000000..b9c95bb6d --- /dev/null +++ b/app/audio/audioprocessor.cpp @@ -0,0 +1,302 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "audioprocessor.h" + +extern "C" { +#include +#include +} + +#include "common/ffmpegutils.h" + +namespace olive { + +AudioProcessor::AudioProcessor() +{ + filter_graph_ = nullptr; + in_frame_ = nullptr; + out_frame_ = nullptr; +} + +AudioProcessor::~AudioProcessor() +{ + Close(); +} + +bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double tempo) +{ + if (filter_graph_) { + qWarning() << "Tried to open a processor that was already open"; + return false; + } + + filter_graph_ = avfilter_graph_alloc(); + if (!filter_graph_) { + qCritical() << "Failed to allocate filter graph"; + return false; + } + + from_fmt_ = FFmpegUtils::GetFFmpegSampleFormat(from.format()); + to_fmt_ = FFmpegUtils::GetFFmpegSampleFormat(to.format()); + + // Set up audio buffer args + char filter_args[200]; + snprintf(filter_args, 200, "time_base=%d/%d:sample_rate=%d:sample_fmt=%d:channel_layout=0x%" PRIx64, + 1, + from.sample_rate(), + from.sample_rate(), + from_fmt_, + from.channel_layout()); + + int r; + + // Create buffersrc (input) + r = avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("abuffer"), "in", filter_args, nullptr, filter_graph_); + if (r < 0) { + qCritical() << "Failed to create buffersrc:" << r; + Close(); + return false; + } + + // Store "previous" filter for linking + AVFilterContext *previous_filter = buffersrc_ctx_; + + // Create tempo + bool create_tempo; + if ((create_tempo = !qFuzzyCompare(tempo, 1.0))) { + // Create audio tempo filters: FFmpeg's atempo can only be set between 0.5 and 2.0. If the requested speed is outside + // those boundaries, we need to daisychain more than one together. + double base = (tempo > 1.0) ? 2.0 : 0.5; + double speed_log = log(tempo) / log(base); + + // This is the number of how many 0.5 or 2.0 tempos we need to daisychain + int whole = qFloor(speed_log); + + // Set speed_log to the remainder + speed_log -= whole; + + for (int i=0;i<=whole;i++) { + double filter_tempo = (i == whole) ? qPow(base, speed_log) : base; + + if (qFuzzyCompare(filter_tempo, 1.0)) { + // This filter would do nothing + continue; + } + + previous_filter = CreateTempoFilter(filter_graph_, + previous_filter, + filter_tempo); + + if (!previous_filter) { + qCritical() << "Failed to create audio tempo filter"; + Close(); + return false; + } + } + } + + // Create conversion filter + if (from.sample_rate() != to.sample_rate() || from.channel_layout() != to.channel_layout() || from.format() != to.format() + || (to.FormatIsPlanar() && create_tempo)) { // Tempo processor automatically converts to packed, + // so if the desired output is planar, it'll need + // to be converted + snprintf(filter_args, 200, "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%" PRIx64, + av_get_sample_fmt_name(to_fmt_), + to.sample_rate(), + to.channel_layout()); + + AVFilterContext *c; + r = avfilter_graph_create_filter(&c, avfilter_get_by_name("aformat"), "fmt", filter_args, nullptr, filter_graph_); + if (r < 0) { + qCritical() << "Failed to create format conversion filter:" << r << filter_args; + Close(); + return false; + } + + r = avfilter_link(previous_filter, 0, c, 0); + if (r < 0) { + qCritical() << "Failed to link filters:" << r; + Close(); + return false; + } + + previous_filter = c; + } + + // Create buffersink (output) + r = avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("abuffersink"), "out", nullptr, nullptr, filter_graph_); + if (r < 0) { + qCritical() << "Failed to create buffersink:" << r; + Close(); + return false; + } + + r = avfilter_link(previous_filter, 0, buffersink_ctx_, 0); + if (r < 0) { + qCritical() << "Failed to link filters:" << r; + Close(); + return false; + } + + r = avfilter_graph_config(filter_graph_, nullptr); + if (r < 0) { + qCritical() << "Failed to configure graph:" << r; + Close(); + return false; + } + + in_frame_ = av_frame_alloc(); + if (in_frame_) { + in_frame_->sample_rate = from.sample_rate(); + in_frame_->format = from_fmt_; + in_frame_->channel_layout = from.channel_layout(); + in_frame_->channels = from.channel_count(); + in_frame_->pts = 0; + } else { + qCritical() << "Failed to allocate input frame"; + Close(); + return false; + } + + out_frame_ = av_frame_alloc(); + if (!out_frame_) { + qCritical() << "Failed to allocate output frame"; + Close(); + return false; + } + + from_ = from; + to_ = to; + + return true; +} + +void AudioProcessor::Close() +{ + if (filter_graph_) { + avfilter_graph_free(&filter_graph_); + filter_graph_ = nullptr; + buffersrc_ctx_ = nullptr; + buffersink_ctx_ = nullptr; + } + + if (in_frame_) { + av_frame_free(&in_frame_); + in_frame_ = nullptr; + } + + if (out_frame_) { + av_frame_free(&out_frame_); + out_frame_ = nullptr; + } +} + +int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffer *output) +{ + if (!IsOpen()) { + qCritical() << "Tried to convert on closed processor"; + return -1; + } + + int r = 0; + + if (in && nb_in_samples) { + // Set frame parameters + in_frame_->nb_samples = nb_in_samples; + for (int i=0; idata[i] = reinterpret_cast(in[i]); + in_frame_->linesize[i] = from_.samples_to_bytes(nb_in_samples); + } + + r = av_buffersrc_add_frame_flags(buffersrc_ctx_, in_frame_, AV_BUFFERSRC_FLAG_KEEP_REF); + if (r < 0) { + qCritical() << "Failed to add frame to buffersrc:" << r; + return r; + } + } + + if (output) { + int nb_channels = to_.channel_count(); + + if (to_.FormatIsPacked()) { + nb_channels = 1; + } + + AudioProcessor::Buffer &result = *output; + result.resize(nb_channels); + + int byte_offset = 0; + + while (true) { + av_frame_unref(out_frame_); + r = av_buffersink_get_frame(buffersink_ctx_, out_frame_); + if (r < 0) { + if (r == AVERROR(EAGAIN)) { + r = 0; + } else { + // Handle unexpected error + qCritical() << "Failed to pull from buffersink:" << r; + } + break; + } + + int nb_bytes = out_frame_->nb_samples * to_.bytes_per_sample_per_channel(); + if (to_.FormatIsPacked()) { + nb_bytes *= to_.channel_count(); + } + + for (int i=0; idata[i], nb_bytes); + } + byte_offset += nb_bytes; + } + av_frame_unref(out_frame_); + } + + return r; +} + +void AudioProcessor::Flush() +{ + int r = av_buffersrc_add_frame_flags(buffersrc_ctx_, nullptr, AV_BUFFERSRC_FLAG_KEEP_REF); + if (r < 0) { + qCritical() << "Failed to flush:" << r; + } +} + +AVFilterContext *AudioProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilterContext* link, const double &tempo) +{ + // Set up tempo param, which is taken as a C string + char speed_param[20]; + snprintf(speed_param, 20, "%f", tempo); + + AVFilterContext* tempo_ctx = nullptr; + + if (avfilter_graph_create_filter(&tempo_ctx, avfilter_get_by_name("atempo"), "atempo", speed_param, nullptr, graph) >= 0 + && avfilter_link(link, 0, tempo_ctx, 0) == 0) { + return tempo_ctx; + } + + return nullptr; +} + +} diff --git a/app/audio/tempoprocessor.h b/app/audio/audioprocessor.h similarity index 66% rename from app/audio/tempoprocessor.h rename to app/audio/audioprocessor.h index c56eafc5d..534cca9b1 100644 --- a/app/audio/tempoprocessor.h +++ b/app/audio/audioprocessor.h @@ -18,14 +18,8 @@ ***/ -#ifndef TEMPOPROCESSOR_H -#define TEMPOPROCESSOR_H - -#ifdef __MINGW32__ -#ifndef __USE_MINGW_ANSI_STDIO -#define __USE_MINGW_ANSI_STDIO -#endif -#endif +#ifndef AUDIOPROCESSOR_H +#define AUDIOPROCESSOR_H #include @@ -37,29 +31,26 @@ extern "C" { namespace olive { -class TempoProcessor +class AudioProcessor { public: - TempoProcessor(); + AudioProcessor(); - ~TempoProcessor(); + ~AudioProcessor(); - DISABLE_COPY_MOVE(TempoProcessor) + DISABLE_COPY_MOVE(AudioProcessor) - bool IsOpen() const; - - const double& GetSpeed() const; - - bool Open(const AudioParams& params, const double &speed); - - void Push(const QByteArray &packed); - - void Flush(); - - QByteArray Pull(); + bool Open(const AudioParams &from, const AudioParams &to, double tempo = 1.0); void Close(); + bool IsOpen() const { return filter_graph_; } + + using Buffer = QVector; + int Convert(float **in, int nb_in_samples, AudioProcessor::Buffer *output); + + void Flush(); + private: static AVFilterContext* CreateTempoFilter(AVFilterGraph *graph, AVFilterContext *link, const double& tempo); @@ -69,17 +60,18 @@ private: AVFilterContext* buffersink_ctx_; - AudioParams params_; + AudioParams from_; + AVSampleFormat from_fmt_; - int64_t timestamp_; + AudioParams to_; + AVSampleFormat to_fmt_; - double speed_; + AVFrame *in_frame_; - bool open_; + AVFrame *out_frame_; - bool flushed_; }; } -#endif // TEMPOPROCESSOR_H +#endif // AUDIOPROCESSOR_H diff --git a/app/audio/packedprocessor.cpp b/app/audio/packedprocessor.cpp deleted file mode 100644 index 91fd25a5c..000000000 --- a/app/audio/packedprocessor.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 "packedprocessor.h" - -#include "common/ffmpegutils.h" - -namespace olive { - -PackedProcessor::PackedProcessor() : - swr_ctx_(nullptr) -{ -} - -PackedProcessor::~PackedProcessor() -{ - Close(); -} - -bool PackedProcessor::Open(const AudioParams ¶ms) -{ - if (IsOpen()) { - return true; - } - - swr_ctx_ = swr_alloc_set_opts(nullptr, - params.channel_layout(), - FFmpegUtils::GetFFmpegSampleFormat(AudioParams::GetPackedEquivalent(params.format())), - params.sample_rate(), - params.channel_layout(), - FFmpegUtils::GetFFmpegSampleFormat(params.format()), - params.sample_rate(), - 0, - nullptr); - - if (!swr_ctx_) { - qCritical() << "Failed to allocate resample context"; - return false; - } - - if (swr_init(swr_ctx_) < 0) { - qCritical() << "Failed to init resample context"; - swr_free(&swr_ctx_); - return false; - } - - return true; -} - -QByteArray PackedProcessor::Convert(SampleBufferPtr planar) -{ - if (!IsOpen()) { - qCritical() << "Tried to convert while closed"; - return QByteArray(); - } - - int nb_samples = planar->sample_count(); - if (nb_samples == 0) { - return QByteArray(); - } - - QByteArray output(planar->audio_params().samples_to_bytes(nb_samples), Qt::Uninitialized); - uint8_t *output_data = reinterpret_cast(output.data()); - - int ret = swr_convert(swr_ctx_, &output_data, nb_samples, - const_cast(reinterpret_cast(planar->to_raw_ptrs())), - nb_samples); - if (ret < 0) { - char buf[200]; - av_strerror(ret, buf, 200); - qDebug() << "Packed processor failed with error:" << buf << ret; - } - - return output; -} - -void PackedProcessor::Close() -{ - if (swr_ctx_) { - swr_free(&swr_ctx_); - } -} - -} diff --git a/app/audio/packedprocessor.h b/app/audio/packedprocessor.h deleted file mode 100644 index 8b1bb59c5..000000000 --- a/app/audio/packedprocessor.h +++ /dev/null @@ -1,60 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 PACKEDPROCESSOR_H -#define PACKEDPROCESSOR_H - -extern "C" { -#include -} - -#include "codec/samplebuffer.h" -#include "render/audioparams.h" - -namespace olive { - -class PackedProcessor -{ -public: - PackedProcessor(); - - ~PackedProcessor(); - - DISABLE_COPY_MOVE(PackedProcessor) - - bool Open(const AudioParams ¶ms); - - QByteArray Convert(SampleBufferPtr planar); - - void Close(); - - bool IsOpen() const - { - return swr_ctx_; - } - -private: - SwrContext *swr_ctx_; - -}; - -} - -#endif // PACKEDPROCESSOR_H diff --git a/app/audio/planarprocessor.cpp b/app/audio/planarprocessor.cpp deleted file mode 100644 index 0d5222b76..000000000 --- a/app/audio/planarprocessor.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 "planarprocessor.h" - -#include "common/ffmpegutils.h" - -namespace olive { - -PlanarProcessor::PlanarProcessor() : - swr_ctx_(nullptr) -{ -} - -PlanarProcessor::~PlanarProcessor() -{ - Close(); -} - -bool PlanarProcessor::Open(const AudioParams ¶ms) -{ - if (IsOpen()) { - return true; - } - - swr_ctx_ = swr_alloc_set_opts(nullptr, - params.channel_layout(), - FFmpegUtils::GetFFmpegSampleFormat(AudioParams::GetPlanarEquivalent(params.format())), - params.sample_rate(), - params.channel_layout(), - FFmpegUtils::GetFFmpegSampleFormat(params.format()), - params.sample_rate(), - 0, - nullptr); - - if (!swr_ctx_) { - qCritical() << "Failed to allocate resample context"; - return false; - } - - if (swr_init(swr_ctx_) < 0) { - qCritical() << "Failed to init resample context"; - swr_free(&swr_ctx_); - return false; - } - - params_ = params; - - return true; -} - -SampleBufferPtr PlanarProcessor::Convert(const QByteArray &packed) -{ - if (!IsOpen()) { - qCritical() << "Tried to convert while closed"; - return nullptr; - } - - if (packed.isEmpty()) { - return nullptr; - } - - int nb_samples_per_channel = params_.bytes_to_samples(packed.size()); - - SampleBufferPtr output = SampleBuffer::CreateAllocated(params_, nb_samples_per_channel); - - const uint8_t *input = reinterpret_cast(packed.constData()); - int ret = swr_convert(swr_ctx_, - reinterpret_cast(output->to_raw_ptrs()), nb_samples_per_channel, - &input, nb_samples_per_channel); - if (ret < 0) { - char buf[200]; - av_strerror(ret, buf, 200); - qDebug() << "Planar processor failed with error:" << buf << ret; - } - - return output; -} - -void PlanarProcessor::Close() -{ - if (swr_ctx_) { - swr_free(&swr_ctx_); - } -} - -} diff --git a/app/audio/planarprocessor.h b/app/audio/planarprocessor.h deleted file mode 100644 index ad5167a95..000000000 --- a/app/audio/planarprocessor.h +++ /dev/null @@ -1,62 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 PLANARPROCESSOR_H -#define PLANARPROCESSOR_H - -extern "C" { -#include -} - -#include "codec/samplebuffer.h" -#include "render/audioparams.h" - -namespace olive { - -class PlanarProcessor -{ -public: - PlanarProcessor(); - - ~PlanarProcessor(); - - DISABLE_COPY_MOVE(PlanarProcessor) - - bool Open(const AudioParams ¶ms); - - SampleBufferPtr Convert(const QByteArray &packed); - - void Close(); - - bool IsOpen() const - { - return swr_ctx_; - } - -private: - SwrContext *swr_ctx_; - - AudioParams params_; - -}; - -} - -#endif // PLANARPROCESSOR_H diff --git a/app/audio/tempoprocessor.cpp b/app/audio/tempoprocessor.cpp deleted file mode 100644 index f22946227..000000000 --- a/app/audio/tempoprocessor.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2021 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 "tempoprocessor.h" - -extern "C" { -#include -#include -#include -} - -#include - -#include "common/ffmpegutils.h" - -namespace olive { - -TempoProcessor::TempoProcessor() : - filter_graph_(nullptr), - buffersrc_ctx_(nullptr), - buffersink_ctx_(nullptr), - open_(false) -{ -} - -TempoProcessor::~TempoProcessor() -{ - Close(); -} - -bool TempoProcessor::IsOpen() const -{ - return open_; -} - -const double &TempoProcessor::GetSpeed() const -{ - return speed_; -} - -bool TempoProcessor::Open(const AudioParams ¶ms, const double& speed) -{ - if (open_) { - return true; - } - - params_ = params; - speed_ = speed; - - // Create AVFilterGraph instance - filter_graph_ = avfilter_graph_alloc(); - if (!filter_graph_) { - qCritical() << "Failed to create AVFilterGraph"; - Close(); - return false; - } - - // Set up audio buffer args - char filter_args[200]; - snprintf(filter_args, 200, "time_base=%d/%d:sample_rate=%d:sample_fmt=%d:channel_layout=0x%" PRIx64, - 1, - params_.sample_rate(), - params_.sample_rate(), - FFmpegUtils::GetFFmpegSampleFormat(params_.format()), - params.channel_layout()); - - // Create buffer and buffersink - if (avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("abuffer"), "in", filter_args, nullptr, filter_graph_) < 0) { - qCritical() << "Failed to create audio buffer source"; - Close(); - return false; - } - - if (avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("abuffersink"), "out", nullptr, nullptr, filter_graph_) < 0) { - qCritical() << "Failed to create audio buffer sink"; - Close(); - return false; - } - - // Create audio tempo filters: FFmpeg's atempo can only be set between 0.5 and 2.0. If the requested speed is outside - // those boundaries, we need to daisychain more than one together. - double base = (speed_ > 1.0) ? 2.0 : 0.5; - double speed_log = log(speed_) / log(base); - - // This is the number of how many 0.5 or 2.0 tempos we need to daisychain - int whole = qFloor(speed_log); - - // Set speed_log to the remainder - speed_log -= whole; - - AVFilterContext* previous_filter = buffersrc_ctx_; - - for (int i=0;i<=whole;i++) { - double filter_tempo = (i == whole) ? qPow(base, speed_log) : base; - - if (qFuzzyCompare(filter_tempo, 1.0)) { - // This filter would do nothing - continue; - } - - previous_filter = CreateTempoFilter(filter_graph_, - previous_filter, - filter_tempo); - - if (!previous_filter) { - qCritical() << "Failed to create audio tempo filter"; - Close(); - return false; - } - } - - // Link the last filter to the buffersink - if (avfilter_link(previous_filter, 0, buffersink_ctx_, 0) != 0) { - qCritical() << "Failed to link final filter and buffer sink"; - Close(); - return false; - } - - // Config graph - if (avfilter_graph_config(filter_graph_, nullptr) < 0) { - qCritical() << "Failed to configure filter graph"; - Close(); - return false; - } - - timestamp_ = 0; - - open_ = true; - - flushed_ = false; - - return true; -} - -void TempoProcessor::Push(const QByteArray &packed) -{ - if (!IsOpen()) { - qWarning() << "Tried to push to closed TempoProcessor"; - return; - } - - if (flushed_) { - qWarning() << "Tried to push to flushed TempoProcessor"; - return; - } - - AVFrame* src_frame = av_frame_alloc(); - - if (!src_frame) { - qCritical() << "Failed to allocate source frame"; - return; - } - - // Allocate a buffer for the number of samples we got - src_frame->sample_rate = params_.sample_rate(); - src_frame->format = FFmpegUtils::GetFFmpegSampleFormat(params_.format()); - src_frame->channel_layout = params_.channel_layout(); - src_frame->nb_samples = params_.bytes_to_samples(packed.size()); - src_frame->pts = timestamp_; - timestamp_ += src_frame->nb_samples; - - if (av_frame_get_buffer(src_frame, 0) < 0) { - qCritical() << "Failed to allocate buffer for source frame"; - av_frame_free(&src_frame); - return; - } - - // Copy buffer from data array to frame - memcpy(src_frame->data[0], packed, packed.size()); - - int ret = av_buffersrc_add_frame_flags(buffersrc_ctx_, src_frame, AV_BUFFERSRC_FLAG_KEEP_REF); - - if (ret < 0) { - qCritical() << "Failed to feed buffer source" << ret; - } - - if (src_frame) { - av_frame_free(&src_frame); - } -} - -void TempoProcessor::Flush() -{ - if (!flushed_) { - int ret = av_buffersrc_add_frame_flags(buffersrc_ctx_, nullptr, AV_BUFFERSRC_FLAG_KEEP_REF); - if (ret < 0) { - qCritical() << "Failed to feed buffer source" << ret; - } - flushed_ = true; - } -} - -QByteArray TempoProcessor::Pull() -{ - QByteArray b; - AVFrame *processed_frame = av_frame_alloc(); - - // Try to pull samples from the buffersink - int ret = av_buffersink_get_frame(buffersink_ctx_, processed_frame); - - if (ret < 0) { - // We couldn't pull for some reason, if the error was EAGAIN, we just need to send more samples. Otherwise the - // error might be fatal... - if (ret != AVERROR(EAGAIN)) { - qCritical() << "Failed to pull from buffersink" << ret; - } - - av_frame_free(&processed_frame); - return b; - } - - b.resize(params_.samples_to_bytes(processed_frame->nb_samples)); - - // Copy the bytes - memcpy(b.data(), processed_frame->data[0], b.size()); - - // If the index has reached the limit of this processed frame, we can dispose of the frame now - av_frame_free(&processed_frame); - - return b; -} - -void TempoProcessor::Close() -{ - open_ = false; - - if (filter_graph_) { - avfilter_graph_free(&filter_graph_); - filter_graph_ = nullptr; - } - - buffersrc_ctx_ = nullptr; - buffersink_ctx_ = nullptr; -} - -AVFilterContext *TempoProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilterContext* link, const double &tempo) -{ - // Set up tempo param, which is taken as a C string - char speed_param[20]; - snprintf(speed_param, 20, "%f", tempo); - - AVFilterContext* tempo_ctx = nullptr; - - if (avfilter_graph_create_filter(&tempo_ctx, avfilter_get_by_name("atempo"), "atempo", speed_param, nullptr, graph) >= 0 - && avfilter_link(link, 0, tempo_ctx, 0) == 0) { - return tempo_ctx; - } - - return nullptr; -} - -} diff --git a/app/render/audioparams.h b/app/render/audioparams.h index 9213fd872..cb4c591b7 100644 --- a/app/render/audioparams.h +++ b/app/render/audioparams.h @@ -186,6 +186,26 @@ public: duration_ = duration; } + static bool FormatIsPacked(Format f) + { + return f >= kPackedStart && f < kPackedEnd; + } + + bool FormatIsPacked() const + { + return FormatIsPacked(format_); + } + + static bool FormatIsPlanar(Format f) + { + return f >= kPlanarStart && f < kPlanarEnd; + } + + bool FormatIsPlanar() const + { + return FormatIsPlanar(format_); + } + qint64 time_to_bytes(const double& time) const; qint64 time_to_bytes(const rational& time) const; qint64 time_to_bytes_per_channel(const double& time) const; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index dc4556f8d..7e3876f8d 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -25,9 +25,7 @@ #include #include -#include "audio/packedprocessor.h" -#include "audio/planarprocessor.h" -#include "audio/tempoprocessor.h" +#include "audio/audioprocessor.h" #include "node/block/clip/clip.h" #include "node/block/transition/transition.h" #include "node/project/project.h" @@ -300,14 +298,10 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim samples_from_this_block->silence(); } else if (!qFuzzyCompare(speed_value, 1.0)) { if (clip_cast->maintain_audio_pitch()) { - PackedProcessor packer; - packer.Open(samples_from_this_block->audio_params()); + AudioProcessor processor; - QByteArray packed = packer.Convert(samples_from_this_block); - - if (!packed.isEmpty()) { - TempoProcessor tp; - tp.Open(samples_from_this_block->audio_params(), speed_value); + if (processor.Open(samples_from_this_block->audio_params(), samples_from_this_block->audio_params(), speed_value)) { + AudioProcessor::Buffer out; // FIXME: This is not the best way to do this, the TempoProcessor works best // when it's given a continuous stream of audio, which is challenging @@ -315,15 +309,31 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim // well on export (assuming audio is all generated at once on export), but // users may hear clicks and pops in the audio during preview due to this // approach. - tp.Push(packed); - tp.Flush(); - packed = tp.Pull(); - tp.Close(); + int r = processor.Convert(samples_from_this_block->to_raw_ptrs(), samples_from_this_block->sample_count(), nullptr); - if (!packed.isEmpty()) { - PlanarProcessor planar; - planar.Open(samples_from_this_block->audio_params()); - samples_from_this_block = planar.Convert(packed); + if (r < 0) { + qCritical() << "Failed to change tempo of audio:" << r; + } else { + processor.Flush(); + + processor.Convert(nullptr, 0, &out); + + if (!out.empty()) { + int nb_samples = out.front().size() * samples_from_this_block->audio_params().bytes_per_sample_per_channel(); + + if (nb_samples) { + SampleBufferPtr new_samples = SampleBuffer::Create(); + new_samples->set_audio_params(samples_from_this_block->audio_params()); + new_samples->set_sample_count(nb_samples); + new_samples->allocate(); + + for (int i=0; idata(i), out[i].data(), out[i].size()); + } + + samples_from_this_block = new_samples; + } + } } } } else { diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index d404fb5ed..012e7650e 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -210,8 +210,7 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n) last_length_ = 0; LengthChangedSlot(n->GetLength()); - AudioParams ap = n->GetAudioParams(); - packed_processor_.Open(ap); + UpdateAudioProcessor(); ColorManager* color_manager = n->project()->color_manager(); @@ -245,7 +244,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n) disconnect(n->video_frame_cache(), &FrameHashCache::Shifted, this, &ViewerWidget::ViewerShiftedRange); disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack); - packed_processor_.Close(); + CloseAudioProcessor(); SetDisplayImage(QVariant()); @@ -456,6 +455,21 @@ void ViewerWidget::DisarmRecording() record_armed_ = false; } +void ViewerWidget::UpdateAudioProcessor() +{ + audio_processor_.Close(); + + AudioParams ap = GetConnectedNode()->GetAudioParams(); + AudioParams packed = ap; + packed.set_format(AudioParams::GetPackedEquivalent(ap.format())); + audio_processor_.Open(ap, packed, (playback_speed_ == 0) ? 1 : std::abs(playback_speed_)); +} + +void ViewerWidget::CloseAudioProcessor() +{ + audio_processor_.Close(); +} + void ViewerWidget::QueueNextAudioBuffer() { rational queue_end = audio_playback_queue_time_ + (kAudioPlaybackInterval * playback_speed_); @@ -493,23 +507,23 @@ void ViewerWidget::ReceivedAudioBufferForPlayback() } // Convert to packed data for audio output - QByteArray pack = packed_processor_.Convert(samples); - - // If the tempo must be adjusted, adjust now - if (tempo_processor_.IsOpen()) { - tempo_processor_.Push(pack); - pack = tempo_processor_.Pull(); - } + AudioProcessor::Buffer buf; + int r = audio_processor_.Convert(samples->to_raw_ptrs(), samples->sample_count(), &buf); // TempoProcessor may have emptied the array - if (!pack.isEmpty()) { - if (prequeuing_audio_) { - // Add to prequeued audio buffer - prequeued_audio_.append(pack); - } else { - // Push directly to audio manager - AudioManager::instance()->PushToOutput(GetConnectedNode()->GetAudioParams(), pack); + if (r >= 0) { + if (!buf.empty()) { + const QByteArray &pack = buf.at(0); + if (prequeuing_audio_) { + // Add to prequeued audio buffer + prequeued_audio_.append(pack); + } else { + // Push directly to audio manager + AudioManager::instance()->PushToOutput(GetConnectedNode()->GetAudioParams(), pack); + } } + } else { + qCritical() << "Failed to process audio for playback:" << r; } } } @@ -540,10 +554,19 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing() samples->transform_volume_for_sample(samples->sample_count() - i - 1, amt); }*/ - QByteArray packed = packed_processor_.Convert(samples); - AudioManager::instance()->ClearBufferedOutput(); - AudioManager::instance()->PushToOutput(samples->audio_params(), packed); - AudioMonitor::PushBytesOnAll(packed); + AudioProcessor::Buffer buf; + int r = audio_processor_.Convert(samples->to_raw_ptrs(), samples->sample_count(), &buf); + + if (r >= 0) { + if (!buf.empty()) { + const QByteArray &packed = buf.at(0); + AudioManager::instance()->ClearBufferedOutput(); + AudioManager::instance()->PushToOutput(samples->audio_params(), packed); + AudioMonitor::PushBytesOnAll(packed); + } + } else { + qCritical() << "Failed to process audio for scrubbing:" << r; + } } } } @@ -675,9 +698,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) AudioManager::instance()->SetOutputNotifyInterval(ap.time_to_bytes(kAudioPlaybackInterval)); connect(AudioManager::instance(), &AudioManager::OutputNotify, this, &ViewerWidget::QueueNextAudioBuffer); - if (std::abs(playback_speed_) > 1) { - tempo_processor_.Open(GetConnectedNode()->GetAudioParams(), std::abs(playback_speed_)); - } + UpdateAudioProcessor(); static const int prequeue_count = 2; prequeuing_audio_ = prequeue_count; // Queue two buffers ahead of time @@ -721,9 +742,7 @@ void ViewerWidget::PauseInternal() disconnect(AudioManager::instance(), &AudioManager::OutputNotify, this, &ViewerWidget::QueueNextAudioBuffer); qDeleteAll(audio_playback_queue_); audio_playback_queue_.clear(); - if (tempo_processor_.IsOpen()) { - tempo_processor_.Close(); - } + UpdateAudioProcessor(); foreach (ViewerWidget* viewer, instances_) { viewer->auto_cacher_.SetAudioPaused(false); @@ -1434,11 +1453,7 @@ void ViewerWidget::UpdateRendererVideoParameters() void ViewerWidget::UpdateRendererAudioParameters() { - packed_processor_.Close(); - - AudioParams ap = GetConnectedNode()->GetAudioParams(); - - packed_processor_.Open(ap); + UpdateAudioProcessor(); } void ViewerWidget::SetZoomFromMenu(QAction *action) diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 4bf043af1..be515ff4d 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -28,8 +28,7 @@ #include #include -#include "audio/packedprocessor.h" -#include "audio/tempoprocessor.h" +#include "audio/audioprocessor.h" #include "audiowaveformview.h" #include "common/rational.h" #include "node/output/viewer/viewer.h" @@ -212,6 +211,9 @@ private: void DisarmRecording(); + void UpdateAudioProcessor(); + void CloseAudioProcessor(); + QStackedWidget* stack_; ViewerSizer* sizer_; @@ -255,8 +257,7 @@ private: std::list audio_playback_queue_; rational audio_playback_queue_time_; - PackedProcessor packed_processor_; - TempoProcessor tempo_processor_; + AudioProcessor audio_processor_; QByteArray prequeued_audio_; static const rational kAudioPlaybackInterval; From d727ab535319c57d23b3ca15dfe50c00fdc920c0 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 15:30:34 -0700 Subject: [PATCH 33/96] viewer: fixed audio reverse playback regression --- app/widget/viewer/viewer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 012e7650e..5218e6698 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -476,7 +476,8 @@ void ViewerWidget::QueueNextAudioBuffer() // Clamp queue end by zero and the audio length queue_end = clamp(queue_end, rational(0), GetConnectedNode()->GetAudioLength()); - if (queue_end <= audio_playback_queue_time_) { + if ((playback_speed_ > 0 && queue_end <= audio_playback_queue_time_) + || (playback_speed_ < 0 && queue_end >= audio_playback_queue_time_)) { // This will queue nothing, so stop the loop here if (prequeuing_audio_) { DecrementPrequeuedAudio(); From 5bed4396ea9d11d677b09a29f2eb83dc8dc09f45 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 16:32:17 -0700 Subject: [PATCH 34/96] use audioprocessor to match device's output --- app/audio/audiomanager.cpp | 15 +++++-- app/audio/audiomanager.h | 5 ++- app/audio/audioprocessor.h | 3 ++ app/config/config.cpp | 4 ++ .../preferences/tabs/preferencesaudiotab.cpp | 40 +++++++++++++++++++ .../preferences/tabs/preferencesaudiotab.h | 4 ++ .../standardcombos/sampleformatcombobox.h | 18 +++++++++ app/widget/viewer/viewer.cpp | 28 +++++++++---- app/widget/viewer/viewer.h | 3 +- 9 files changed, 107 insertions(+), 13 deletions(-) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index fe791b3d5..3817f285a 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -80,10 +80,11 @@ int InputCallback(const void *input, void *output, unsigned long frameCount, con return paContinue; } -void AudioManager::PushToOutput(const AudioParams ¶ms, const QByteArray &samples) +bool AudioManager::PushToOutput(const AudioParams ¶ms, const QByteArray &samples, QString *error) { if (output_device_ == paNoDevice) { - return; + if (error) *error = tr("No output device is set"); + return false; } if (output_params_ != params || output_stream_ == nullptr) { @@ -93,7 +94,13 @@ void AudioManager::PushToOutput(const AudioParams ¶ms, const QByteArray &sam PaStreamParameters p = GetPortAudioParams(params, output_device_); - Pa_OpenStream(&output_stream_, nullptr, &p, output_params_.sample_rate(), paFramesPerBufferUnspecified, paNoFlag, OutputCallback, output_buffer_); + PaError r = Pa_OpenStream(&output_stream_, nullptr, &p, output_params_.sample_rate(), paFramesPerBufferUnspecified, paNoFlag, OutputCallback, output_buffer_); + if (r != paNoError) { + // Unhandled error + //qCritical() << "Failed to open output stream:" << Pa_GetErrorText(r); + if (error) *error = Pa_GetErrorText(r); + return false; + } output_buffer_->set_bytes_per_frame(output_params_.samples_to_bytes(1)); } @@ -103,6 +110,8 @@ void AudioManager::PushToOutput(const AudioParams ¶ms, const QByteArray &sam if (!Pa_IsStreamActive(output_stream_)) { Pa_StartStream(output_stream_); } + + return true; } void AudioManager::ClearBufferedOutput() diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index 20d1be75b..2916d29d2 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -27,6 +27,7 @@ #include #include "audiovisualwaveform.h" +#include "audio/audioprocessor.h" #include "common/define.h" #include "codec/ffmpeg/ffmpegencoder.h" #include "render/audioparams.h" @@ -52,7 +53,7 @@ public: void SetOutputNotifyInterval(int n); - void PushToOutput(const AudioParams ¶ms, const QByteArray& samples); + bool PushToOutput(const AudioParams ¶ms, const QByteArray& samples, QString *error = nullptr); void ClearBufferedOutput(); @@ -86,6 +87,8 @@ public: signals: void OutputNotify(); + void OutputParamsChanged(); + private: AudioManager(); diff --git a/app/audio/audioprocessor.h b/app/audio/audioprocessor.h index 534cca9b1..38826c707 100644 --- a/app/audio/audioprocessor.h +++ b/app/audio/audioprocessor.h @@ -51,6 +51,9 @@ public: void Flush(); + const AudioParams &from() const { return from_; } + const AudioParams &to() const { return to_; } + private: static AVFilterContext* CreateTempoFilter(AVFilterGraph *graph, AVFilterContext *link, const double& tempo); diff --git a/app/config/config.cpp b/app/config/config.cpp index d114b0a10..0aaaa6253 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -121,6 +121,10 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("AudioOutput"), NodeValue::kText, QString()); SetEntryInternal(QStringLiteral("AudioInput"), NodeValue::kText, QString()); + SetEntryInternal(QStringLiteral("AudioOutputSampleRate"), NodeValue::kInt, 48000); + SetEntryInternal(QStringLiteral("AudioOutputChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO); + SetEntryInternal(QStringLiteral("AudioOutputSampleFormat"), NodeValue::kInt, AudioParams::kFormatSigned16Packed); + SetEntryInternal(QStringLiteral("AudioRecordingFormat"), NodeValue::kInt, ExportFormat::kFormatWAV); SetEntryInternal(QStringLiteral("AudioRecordingCodec"), NodeValue::kInt, ExportCodec::kCodecPCM); SetEntryInternal(QStringLiteral("AudioRecordingSampleRate"), NodeValue::kInt, 48000); diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index c8760ae8a..7d2edc892 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -69,6 +69,40 @@ PreferencesAudioTab::PreferencesAudioTab() audio_output_devices_ = new QComboBox(); output_layout->addWidget(audio_output_devices_, row, 1); + + row++; + + { + int output_row = 0; + + QGroupBox *output_param_group = new QGroupBox(tr("Advanced")); + output_layout->addWidget(output_param_group, row, 0, 1, 2); + + QGridLayout *output_param_layout = new QGridLayout(output_param_group); + + output_param_layout->addWidget(new QLabel(tr("Sample Rate:")), output_row, 0); + + output_rate_combo_ = new SampleRateComboBox(); + output_rate_combo_->SetSampleRate(OLIVE_CONFIG("AudioOutputSampleRate").toInt()); + output_param_layout->addWidget(output_rate_combo_, output_row, 1); + + output_row++; + + output_param_layout->addWidget(new QLabel(tr("Channel Layout:")), output_row, 0); + + output_ch_layout_combo_ = new ChannelLayoutComboBox(); + output_ch_layout_combo_->SetChannelLayout(OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong()); + output_param_layout->addWidget(output_ch_layout_combo_, output_row, 1); + + output_row++; + + output_param_layout->addWidget(new QLabel(tr("Sample Format:")), output_row, 0); + + output_fmt_combo_ = new SampleFormatComboBox(); + output_fmt_combo_->SetPackedFormats(); + output_fmt_combo_->SetSampleFormat(static_cast(OLIVE_CONFIG("AudioOutputSampleFormat").toInt())); + output_param_layout->addWidget(output_fmt_combo_, output_row, 1); + } } row = 0; @@ -146,12 +180,18 @@ void PreferencesAudioTab::Accept(MultiUndoCommand *command) AudioManager::instance()->SetOutputDevice(output_device); AudioManager::instance()->SetInputDevice(input_device); + OLIVE_CONFIG("AudioOutputSampleRate") = output_rate_combo_->GetSampleRate(); + OLIVE_CONFIG("AudioOutputChannelLayout") = QVariant::fromValue(output_ch_layout_combo_->GetChannelLayout()); + OLIVE_CONFIG("AudioOutputSampleFormat") = output_fmt_combo_->GetSampleFormat(); + OLIVE_CONFIG("AudioRecordingFormat") = record_format_combo_->GetFormat(); OLIVE_CONFIG("AudioRecordingCodec") = record_options_->GetCodec(); OLIVE_CONFIG("AudioRecordingSampleRate") = record_options_->sample_rate_combobox()->GetSampleRate(); OLIVE_CONFIG("AudioRecordingChannelLayout") = QVariant::fromValue(record_options_->channel_layout_combobox()->GetChannelLayout()); OLIVE_CONFIG("AudioRecordingBitRate") = QVariant::fromValue(record_options_->bit_rate_slider()->GetValue()); OLIVE_CONFIG("AudioRecordingSampleFormat") = record_options_->sample_format_combobox()->GetSampleFormat(); + + emit AudioManager::instance()->OutputParamsChanged(); } void PreferencesAudioTab::RefreshBackends() diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index 8fccd4276..550b6fa9e 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -61,6 +61,10 @@ private: */ QPushButton* refresh_devices_btn_; + SampleRateComboBox *output_rate_combo_; + ChannelLayoutComboBox *output_ch_layout_combo_; + SampleFormatComboBox *output_fmt_combo_; + ExportFormatComboBox *record_format_combo_; ExportAudioTab *record_options_; diff --git a/app/widget/standardcombos/sampleformatcombobox.h b/app/widget/standardcombos/sampleformatcombobox.h index a48e9016a..d52a20709 100644 --- a/app/widget/standardcombos/sampleformatcombobox.h +++ b/app/widget/standardcombos/sampleformatcombobox.h @@ -57,6 +57,24 @@ public: } } + void SetPackedFormats() + { + AudioParams::Format tmp = AudioParams::kFormatInvalid; + + if (attempt_to_restore_format_) { + tmp = GetSampleFormat(); + } + + clear(); + for (int i=AudioParams::kPackedStart; i(i)); + } + + if (attempt_to_restore_format_) { + SetSampleFormat(tmp); + } + } + AudioParams::Format GetSampleFormat() const { return static_cast(this->currentData().toInt()); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 5218e6698..3cac18a5e 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -141,6 +141,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(Core::instance(), &Core::ColorPickerEnabled, this, &ViewerWidget::SetSignalCursorColorEnabled); connect(this, &ViewerWidget::CursorColor, Core::instance(), &Core::ColorPickerColorEmitted); + connect(AudioManager::instance(), &AudioManager::OutputParamsChanged, this, &ViewerWidget::UpdateAudioProcessor); } ViewerWidget::~ViewerWidget() @@ -457,12 +458,16 @@ void ViewerWidget::DisarmRecording() void ViewerWidget::UpdateAudioProcessor() { - audio_processor_.Close(); + if (GetConnectedNode()) { + audio_processor_.Close(); - AudioParams ap = GetConnectedNode()->GetAudioParams(); - AudioParams packed = ap; - packed.set_format(AudioParams::GetPackedEquivalent(ap.format())); - audio_processor_.Open(ap, packed, (playback_speed_ == 0) ? 1 : std::abs(playback_speed_)); + AudioParams ap = GetConnectedNode()->GetAudioParams(); + AudioParams packed(OLIVE_CONFIG("AudioOutputSampleRate").toInt(), + OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong(), + static_cast(OLIVE_CONFIG("AudioOutputSampleFormat").toInt())); + + audio_processor_.Open(ap, packed, (playback_speed_ == 0) ? 1 : std::abs(playback_speed_)); + } } void ViewerWidget::CloseAudioProcessor() @@ -520,7 +525,7 @@ void ViewerWidget::ReceivedAudioBufferForPlayback() prequeued_audio_.append(pack); } else { // Push directly to audio manager - AudioManager::instance()->PushToOutput(GetConnectedNode()->GetAudioParams(), pack); + AudioManager::instance()->PushToOutput(audio_processor_.to(), pack); } } } else { @@ -560,9 +565,12 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing() if (r >= 0) { if (!buf.empty()) { + QString error; const QByteArray &packed = buf.at(0); AudioManager::instance()->ClearBufferedOutput(); - AudioManager::instance()->PushToOutput(samples->audio_params(), packed); + if (!AudioManager::instance()->PushToOutput(audio_processor_.to(), packed, &error)) { + Core::instance()->ShowStatusBarMessage(tr("Audio scrubbing failed: %1").arg(error)); + } AudioMonitor::PushBytesOnAll(packed); } } else { @@ -872,7 +880,11 @@ void ViewerWidget::FinishPlayPreprocess() // Start audio waveform playback if (!prequeued_audio_.isEmpty()) { - AudioManager::instance()->PushToOutput(GetConnectedNode()->GetAudioParams(), prequeued_audio_); + QString error; + if (!AudioManager::instance()->PushToOutput(audio_processor_.to(), prequeued_audio_, &error)) { + QMessageBox::critical(this, tr("Audio Error"), tr("Failed to start audio: %1\n\n" + "Please check your audio preferences and try again.").arg(error)); + } prequeued_audio_.clear(); AudioMonitor::StartWaveformOnAll(&GetConnectedNode()->audio_playback_cache()->visual(), diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index be515ff4d..ba7f7be56 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -211,7 +211,6 @@ private: void DisarmRecording(); - void UpdateAudioProcessor(); void CloseAudioProcessor(); QStackedWidget* stack_; @@ -319,6 +318,8 @@ private slots: void ForceRequeueFromCurrentTime(); + void UpdateAudioProcessor(); + }; } From 5920af9901194400ade450b93cf972b85252f3a8 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 16:49:15 -0700 Subject: [PATCH 35/96] fixed issue with audio failing to resolve Regression, particularly evident in footage viewer --- app/render/renderprocessor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 7e3876f8d..ce1db8b41 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -191,7 +191,11 @@ void RenderProcessor::Run() table = GenerateTable(texture_output, viewer->GetValueHintForInput(ViewerOutput::kSamplesInput),time); } - QVariant sample_variant = table.Get(NodeValue::kSamples); + NodeValue sample_val = table.GetWithMeta(NodeValue::kSamples); + + ResolveJobs(sample_val, time); + + QVariant sample_variant = sample_val.data(); SampleBufferPtr samples = sample_variant.value(); if (samples && ticket_->property("enablewaveforms").toBool()) { AudioVisualWaveform vis; From 6286b7091ce9694684158b3db609724873a295f8 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 17:29:40 -0700 Subject: [PATCH 36/96] sliders: implement color coding for clarity --- .../ociogradingtransformlinear.cpp | 11 +++++++ .../ociogradingtransformlinear.h | 3 ++ .../nodeparamviewwidgetbridge.cpp | 17 ++++++++++ app/widget/slider/base/sliderbase.h | 5 +++ app/widget/slider/base/sliderlabel.cpp | 32 ++++++++++++++++++- app/widget/slider/base/sliderlabel.h | 8 +++++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 74098f5e7..536dd62fc 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -42,10 +42,13 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() { AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); + SetVec4InputColors(kContrastInput); AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + SetVec4InputColors(kOffsetInput); AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + SetVec4InputColors(kExposureInput); AddInput(kSaturationInput, NodeValue::kFloat, 1.0); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); @@ -124,4 +127,12 @@ void OCIOGradingTransformLinearNode::ConfigChanged() GenerateProcessor(); } +void OCIOGradingTransformLinearNode::SetVec4InputColors(const QString &input) +{ + SetInputProperty(input, QStringLiteral("color0"), QColor(255, 0, 0).name()); + SetInputProperty(input, QStringLiteral("color1"), QColor(0, 255, 0).name()); + SetInputProperty(input, QStringLiteral("color2"), QColor(0, 0, 255).name()); + SetInputProperty(input, QStringLiteral("color3"), QColor(192, 192, 192).name()); +} + } diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 883432a15..11e65ed85 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -55,6 +55,9 @@ class OCIOGradingTransformLinearNode : public OCIOBaseNode protected slots: virtual void ConfigChanged() override; +private: + void SetVec4InputColors(const QString &input); + }; } // olive diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index e030d1b15..0a5f091d8 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -654,6 +654,23 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } UpdateWidgetValues(); + } else if (key.startsWith(QStringLiteral("color"))) { + QColor c(value.toString()); + + int tracks = NodeValue::get_number_of_keyframe_tracks(data_type); + + if (key.size() == 5) { + // Set for all tracks + for (int i=0; i(widgets_.at(i))->SetColor(c); + } + } else { + bool ok; + int element = key.mid(5).toInt(&ok); + if (ok && element >= 0 && element < tracks) { + static_cast(widgets_.at(element))->SetColor(c); + } + } } } diff --git a/app/widget/slider/base/sliderbase.h b/app/widget/slider/base/sliderbase.h index 64d4ed2f4..4663525d9 100644 --- a/app/widget/slider/base/sliderbase.h +++ b/app/widget/slider/base/sliderbase.h @@ -55,6 +55,11 @@ public: UpdateLabel(); } + void SetColor(const QColor &c) + { + label_->SetColor(c); + } + public slots: void ShowEditor(); diff --git a/app/widget/slider/base/sliderlabel.cpp b/app/widget/slider/base/sliderlabel.cpp index b5c851515..4271bd1e5 100644 --- a/app/widget/slider/base/sliderlabel.cpp +++ b/app/widget/slider/base/sliderlabel.cpp @@ -27,7 +27,8 @@ namespace olive { SliderLabel::SliderLabel(QWidget *parent) : - QLabel(parent) + QLabel(parent), + override_color_enabled_(false) { QPalette p = palette(); @@ -52,6 +53,26 @@ SliderLabel::SliderLabel(QWidget *parent) : setContextMenuPolicy(Qt::CustomContextMenu); } +void SliderLabel::SetColor(const QColor &c) +{ + // Prevent infinite loop in changeEvent when we set the stylesheet + override_color_enabled_ = false; + override_color_ = c; + + // Different colors will look different depending on the theme (light/dark mode). We abstract + // that away here so that other classes can simply choose a color and we will handle making it + // more legible based on the background + QColor adjusted; + if (palette().window().color().lightness() < 128) { + adjusted = override_color_.lighter(150); + } else { + adjusted = override_color_.darker(150); + } + + setStyleSheet(QStringLiteral("color: %1").arg(adjusted.name())); + override_color_enabled_ = true; +} + void SliderLabel::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { @@ -81,4 +102,13 @@ void SliderLabel::focusInEvent(QFocusEvent *event) } } +void SliderLabel::changeEvent(QEvent *event) +{ + QWidget::changeEvent(event); + + if (override_color_enabled_ && event->type() == QEvent::StyleChange) { + SetColor(override_color_); + } +} + } diff --git a/app/widget/slider/base/sliderlabel.h b/app/widget/slider/base/sliderlabel.h index 747ad44ce..948b0d77a 100644 --- a/app/widget/slider/base/sliderlabel.h +++ b/app/widget/slider/base/sliderlabel.h @@ -33,6 +33,8 @@ class SliderLabel : public QLabel public: SliderLabel(QWidget* parent); + void SetColor(const QColor &c); + protected: virtual void mousePressEvent(QMouseEvent *e) override; @@ -40,6 +42,8 @@ protected: virtual void focusInEvent(QFocusEvent *event) override; + virtual void changeEvent(QEvent *event) override; + signals: void LabelPressed(); @@ -51,6 +55,10 @@ signals: void ChangeSliderType(); +private: + bool override_color_enabled_; + QColor override_color_; + }; } From 07751434857f80cc264da40c0c00780ae44e008e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Thu, 5 May 2022 17:30:54 -0700 Subject: [PATCH 37/96] nodes: slightly improve descriptions --- app/node/color/displaytransform/displaytransform.cpp | 2 +- .../ociogradingtransformlinear/ociogradingtransformlinear.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/node/color/displaytransform/displaytransform.cpp b/app/node/color/displaytransform/displaytransform.cpp index 7e0bcdcd8..5152d6614 100644 --- a/app/node/color/displaytransform/displaytransform.cpp +++ b/app/node/color/displaytransform/displaytransform.cpp @@ -56,7 +56,7 @@ QVector DisplayTransformNode::Category() const QString DisplayTransformNode::Description() const { - return tr("Converts an image to/from display space"); + return tr("Converts an image to or from a display color space."); } void DisplayTransformNode::Retranslate() diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 536dd62fc..e721a1d0e 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -77,7 +77,7 @@ QVector OCIOGradingTransformLinearNode::Category() const QString OCIOGradingTransformLinearNode::Description() const { - return tr("Simple linearcolor grading using OCIO"); + return tr("Simple linear color grading using OpenColorIO."); } void OCIOGradingTransformLinearNode::Retranslate() From bd6f0257e52f03c16128cc081930990469620cda Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 6 May 2022 09:01:03 -0700 Subject: [PATCH 38/96] viewer: use output params to calculate notify interval --- app/widget/viewer/viewer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 3cac18a5e..4fbb94846 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -704,11 +704,11 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) AudioParams ap = GetConnectedNode()->GetAudioParams(); if (ap.is_valid()) { - AudioManager::instance()->SetOutputNotifyInterval(ap.time_to_bytes(kAudioPlaybackInterval)); - connect(AudioManager::instance(), &AudioManager::OutputNotify, this, &ViewerWidget::QueueNextAudioBuffer); - UpdateAudioProcessor(); + AudioManager::instance()->SetOutputNotifyInterval(audio_processor_.to().time_to_bytes(kAudioPlaybackInterval)); + connect(AudioManager::instance(), &AudioManager::OutputNotify, this, &ViewerWidget::QueueNextAudioBuffer); + static const int prequeue_count = 2; prequeuing_audio_ = prequeue_count; // Queue two buffers ahead of time audio_playback_queue_time_ = GetTime(); From ef046d5ed6b8d32ba347e1e7addf8774a80c9ff1 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 6 May 2022 09:12:22 -0700 Subject: [PATCH 39/96] mathbase: don't push sample job if no samples are found Not sure what this code was supposed to do, but this doesn't look right at all --- app/node/math/math/mathbase.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 51ef80060..00c0b7ce4 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -416,8 +416,6 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt } else { output->Push(NodeValue::kSamples, QVariant::fromValue(job), this); } - } else { - output->Push(NodeValue::kSamples, QVariant::fromValue(job), this); } break; } From 180be5fe46193de24df316c7ae78b8b4ca5910a5 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Fri, 6 May 2022 09:36:06 -0700 Subject: [PATCH 40/96] audiomonitor: use samplebuffer directly Pushing bytes was broken and pretty much pointless anyway, this should be faster and easier to use too --- app/widget/audiomonitor/audiomonitor.cpp | 65 ++++++++---------------- app/widget/audiomonitor/audiomonitor.h | 13 +++-- app/widget/viewer/viewer.cpp | 2 +- 3 files changed, 27 insertions(+), 53 deletions(-) diff --git a/app/widget/audiomonitor/audiomonitor.cpp b/app/widget/audiomonitor/audiomonitor.cpp index 6a196e095..10777ba00 100644 --- a/app/widget/audiomonitor/audiomonitor.cpp +++ b/app/widget/audiomonitor/audiomonitor.cpp @@ -37,7 +37,6 @@ QVector AudioMonitor::instances_; AudioMonitor::AudioMonitor(QWidget *parent) : QOpenGLWidget(parent), - file_(nullptr), waveform_(nullptr), cached_channels_(0) { @@ -70,15 +69,13 @@ void AudioMonitor::SetParams(const AudioParams ¶ms) void AudioMonitor::Stop() { - delete file_; - file_ = nullptr; waveform_ = nullptr; // We don't stop the update loop here so that the monitor can show a smooth fade out. The update // loop will stop itself since file_ and waveform_ are null. } -void AudioMonitor::PushBytes(const QByteArray &d) +void AudioMonitor::PushSampleBuffer(SampleBufferPtr d) { if (!params_.channel_count()) { return; @@ -86,9 +83,12 @@ void AudioMonitor::PushBytes(const QByteArray &d) QVector v(params_.channel_count(), 0); - BytesToSampleSummary(d, v); + AudioVisualWaveform::Sample summed = AudioVisualWaveform::SumSamples(d, 0, d->sample_count()); - PushValue(v); + AudioVisualWaveformSampleToInternalValues(summed, v); + + // Fill values because they get averaged out for smoothing + values_.fill(v); SetUpdateLoop(true); } @@ -236,13 +236,7 @@ void AudioMonitor::paintGL() delta_time *= abs_speed; } - if (file_) { - UpdateValuesFromFile(v, delta_time); - - if (file_->atEnd()) { - Stop(); - } - } else if (waveform_) { + if (waveform_) { UpdateValuesFromWaveform(v, delta_time); if (waveform_time_ >= waveform_->length()) { @@ -304,30 +298,6 @@ void AudioMonitor::mousePressEvent(QMouseEvent *) update(); } -void AudioMonitor::UpdateValuesFromFile(QVector& v, qint64 delta_time) -{ - // Convert ms to float seconds and determine how many bytes that is - qint64 bytes_to_read = params_.time_to_bytes(static_cast(delta_time) * 0.001); - - if (playback_speed_ < 0) { - // If reversing, jump back by the amount of bytes we're going to read - bytes_to_read = qMin(bytes_to_read, file_->pos()); - - file_->seek(file_->pos() - bytes_to_read); - } - - // Read bytes in from file - QByteArray b = file_->read(bytes_to_read); - - if (playback_speed_ < 0) { - // If reversing, head back to where we were before the read so that the next read starts - // from where we left off - file_->seek(file_->pos() - bytes_to_read); - } - - BytesToSampleSummary(b, v); -} - void AudioMonitor::UpdateValuesFromWaveform(QVector &v, qint64 delta_time) { // Delta time is provided in milliseconds, so we convert to seconds in rational @@ -335,18 +305,23 @@ void AudioMonitor::UpdateValuesFromWaveform(QVector &v, qint64 delta_tim AudioVisualWaveform::Sample sum = waveform_->GetSummaryFromTime(waveform_time_, length); - for (int i=0; i v.at(output_index)) { - v[output_index] = max; - } - } + AudioVisualWaveformSampleToInternalValues(sum, v); waveform_time_ += length; } +void AudioMonitor::AudioVisualWaveformSampleToInternalValues(const AudioVisualWaveform::Sample &in, QVector &out) +{ + for (int i=0; i out.at(output_index)) { + out[output_index] = max; + } + } +} + void AudioMonitor::PushValue(const QVector &v) { int lim = values_.size()-1; diff --git a/app/widget/audiomonitor/audiomonitor.h b/app/widget/audiomonitor/audiomonitor.h index e9bdf05b3..f532aa206 100644 --- a/app/widget/audiomonitor/audiomonitor.h +++ b/app/widget/audiomonitor/audiomonitor.h @@ -42,7 +42,7 @@ public: bool IsPlaying() const { - return file_ || waveform_; + return waveform_; } static void StartWaveformOnAll(const AudioVisualWaveform *waveform, const rational& start, int playback_speed) @@ -59,10 +59,10 @@ public: } } - static void PushBytesOnAll(const QByteArray &d) + static void PushSampleBufferOnAll(SampleBufferPtr d) { foreach (AudioMonitor *m, instances_) { - m->PushBytes(d); + m->PushSampleBuffer(d); } } @@ -71,7 +71,7 @@ public slots: void Stop(); - void PushBytes(const QByteArray& d); + void PushSampleBuffer(SampleBufferPtr samples); void StartWaveform(const AudioVisualWaveform *waveform, const rational& start, int playback_speed); @@ -83,10 +83,10 @@ protected: private: void SetUpdateLoop(bool e); - void UpdateValuesFromFile(QVector &v, qint64 delta_time); - void UpdateValuesFromWaveform(QVector &v, qint64 delta_time); + void AudioVisualWaveformSampleToInternalValues(const AudioVisualWaveform::Sample &in, QVector &out); + void PushValue(const QVector& v); void BytesToSampleSummary(const QByteArray& bytes, QVector& v); @@ -95,7 +95,6 @@ private: AudioParams params_; - QIODevice* file_; qint64 last_time_; const AudioVisualWaveform* waveform_; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 4fbb94846..b5720f927 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -571,7 +571,7 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing() if (!AudioManager::instance()->PushToOutput(audio_processor_.to(), packed, &error)) { Core::instance()->ShowStatusBarMessage(tr("Audio scrubbing failed: %1").arg(error)); } - AudioMonitor::PushBytesOnAll(packed); + AudioMonitor::PushSampleBufferOnAll(samples); } } else { qCritical() << "Failed to process audio for scrubbing:" << r; From 7c23ad0b5166fa84bd4f21255b704921dff72681 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Fri, 6 May 2022 18:51:35 +0100 Subject: [PATCH 41/96] Set default input for the ociobase node --- app/node/color/ociobase/ociobase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index 976ef35fb..e59f19343 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -33,6 +33,8 @@ OCIOBaseNode::OCIOBaseNode() : { AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + SetEffectInput(kTextureInput); + connect(this, &Node::AddedToGraph, this, &OCIOBaseNode::ParentChanged); } From dabd6d5d3db64362677ce221b8761237bf0053a1 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 09:37:20 -0700 Subject: [PATCH 42/96] chromakey: regen processor on config change --- app/node/keying/chromakey/chromakey.cpp | 7 +++++-- app/node/keying/chromakey/chromakey.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 5660c42a0..6ada34aca 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -52,8 +52,6 @@ ChromaKeyNode::ChromaKeyNode() SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0); AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); - - SetEffectInput(kTextureInput); } QString ChromaKeyNode::Name() const @@ -129,4 +127,9 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, } } +void ChromaKeyNode::ConfigChanged() +{ + GenerateProcessor(); +} + } // namespace olive diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 3344ef019..a9ac4ffa0 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -40,7 +40,7 @@ class ChromaKeyNode : public OCIOBaseNode { virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; - virtual void ConfigChanged() override {}; + virtual void ConfigChanged() override; static const QString kColorInput; static const QString kMaskOnlyInput; From 21000c3aa7b137694067eeb2d1b34fdc8f7d332e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 09:39:08 -0700 Subject: [PATCH 43/96] nodetraverser: always push primary input last if applicable --- app/node/node.cpp | 3 +-- app/node/node.h | 11 +++++++---- app/node/traverser.cpp | 10 +++++++++- app/node/value.h | 5 +++++ app/node/valuedatabase.h | 5 +++++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/node/node.cpp b/app/node/node.cpp index 907287880..62580f280 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -50,8 +50,7 @@ Node::Node() : folder_(nullptr), operation_stack_(0), cache_result_(false), - flags_(kNone), - effect_element_(-1) + flags_(kNone) { AddInput(kEnabledInput, NodeValue::kBoolean, true); } diff --git a/app/node/node.h b/app/node/node.h index 4f45277d6..dccd13f9c 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -552,7 +552,12 @@ public: NodeInput GetEffectInput() { - return effect_input_.isEmpty() ? NodeInput() : NodeInput(this, effect_input_, effect_element_); + return effect_input_.isEmpty() ? NodeInput() : NodeInput(this, effect_input_); + } + + const QString &GetEffectInputID() const + { + return effect_input_; } class ValueHint { @@ -1047,10 +1052,9 @@ protected: virtual void childEvent(QChildEvent *event) override; - void SetEffectInput(const QString &input, int element = -1) + void SetEffectInput(const QString &input) { effect_input_ = input; - effect_element_ = element; } void SetToolTip(const QString& s) @@ -1369,7 +1373,6 @@ private: QVector gizmos_; QString effect_input_; - int effect_element_; private slots: /** diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 103702fa3..7b8958f4e 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -269,7 +269,15 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const Node::ValueHint return table; } else { - return database.Merge(); + // If this node has an effect input, ensure that is pushed last + NodeValueTable primary; + if (!n->GetEffectInputID().isEmpty()) { + primary = database.Take(n->GetEffectInputID()); + } + + NodeValueTable m = database.Merge(); + m.Push(primary); + return m; } } diff --git a/app/node/value.h b/app/node/value.h index d894a7d35..886b4f470 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -340,6 +340,11 @@ public: values_.append(value); } + void Push(const NodeValueTable& value) + { + values_.append(value.values_); + } + void Push(NodeValue::Type type, const QVariant& data, const Node *from, bool array = false, const QString& tag = QString()) { Push(NodeValue(type, data, from, array, tag)); diff --git a/app/node/valuedatabase.h b/app/node/valuedatabase.h index 725ed1e62..80574b371 100644 --- a/app/node/valuedatabase.h +++ b/app/node/valuedatabase.h @@ -41,6 +41,11 @@ public: tables_.insert(key, value); } + NodeValueTable Take(const QString &key) + { + return tables_.take(key); + } + NodeValueTable Merge() const; using Tables = QHash; From 677ed38ff9d576f67db8e54c40734c66f37e472e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 09:46:13 -0700 Subject: [PATCH 44/96] nodeview: ignore enabled input when dropping --- app/widget/nodeview/nodeview.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 220a040bf..69af099fa 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -571,6 +571,11 @@ void NodeView::mouseMoveEvent(QMouseEvent *event) } else { // Otherwise, we may have to iterate to find a valid one for (const QString& input : attached_node->inputs()) { + if (input == Node::kEnabledInput) { + // Ignore enabled input + continue; + } + NodeInput i(attached_node, input); if (attached_node->IsInputConnectable(input)) { From b51cae04752558397fd0376c5941e324f20782ff Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 10:28:48 -0700 Subject: [PATCH 45/96] viewer: prepend main widget to tab focus order Fixes UI papercut where maximizing a panel (with `) would auto-focus the time slider, meaning pressing ` again wouldn't immediately un-maximize --- app/widget/viewer/viewer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index b5720f927..92b92eead 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -98,6 +98,11 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove); sizer_->SetWidget(display_widget_); + // Make the display widget the first tabbable widget. While the viewer display cannot actually + // be interacted with by tabbing, it prevents the actual first tabbable widget (the playhead + // slider in `controls_`) from getting auto-focused any time the panel is maximized (with `) + display_widget_->setFocusPolicy(Qt::TabFocus); + // Create waveform view when audio is connected and video isn't waveform_view_ = new AudioWaveformView(); ConnectTimelineView(waveform_view_, true); From a213ae8944e3d3af528f857f076f960451d95f3c Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 10:55:50 -0700 Subject: [PATCH 46/96] nodeparamviewwidgetbridge: make disable property more versatile --- app/node/generator/matrix/matrix.cpp | 2 +- .../nodeparamviewwidgetbridge.cpp | 31 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 30cbf6065..475aca566 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -183,7 +183,7 @@ void MatrixGenerator::InputValueChangedEvent(const QString &input, int element) Q_UNUSED(element) if (input == kUniformScaleInput) { - SetInputProperty(kScaleInput, QStringLiteral("disabley"), GetStandardValue(kUniformScaleInput).toBool()); + SetInputProperty(kScaleInput, QStringLiteral("disable1"), GetStandardValue(kUniformScaleInput).toBool()); } } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 0a5f091d8..b17335fff 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -553,17 +553,24 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } } - // Parameters for vectors only - if (NodeValue::type_is_vector(data_type)) { - if (key == QStringLiteral("disablex")) { - static_cast(widgets_.at(0))->setEnabled(!value.toBool()); - } else if (key == QStringLiteral("disabley")) { - static_cast(widgets_.at(1))->setEnabled(!value.toBool()); - } else if (widgets_.size() > 2 && key == QStringLiteral("disablez")) { - static_cast(widgets_.at(2))->setEnabled(!value.toBool()); - } else if (widgets_.size() > 3 && key == QStringLiteral("disablew")) { - static_cast(widgets_.at(3))->setEnabled(!value.toBool()); + if (key.startsWith(QStringLiteral("disable"))) { + + bool dis = value.toBool(); + + if (key.size() == 7) { + for (int i=0; isetEnabled(!dis); + } + } else { + bool ok; + int element = key.mid(7).toInt(&ok); + int tracks = NodeValue::get_number_of_keyframe_tracks(data_type); + + if (ok && element >= 0 && element < tracks) { + widgets_.at(element)->setEnabled(!dis); + } } + } // Parameters for integers, floats, and vectors @@ -645,6 +652,7 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & break; } } else if (key == QStringLiteral("offset")) { + int tracks = NodeValue::get_number_of_keyframe_tracks(data_type); QVector offsets = NodeValue::split_normal_value_into_track_values(data_type, value); @@ -654,7 +662,9 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } UpdateWidgetValues(); + } else if (key.startsWith(QStringLiteral("color"))) { + QColor c(value.toString()); int tracks = NodeValue::get_number_of_keyframe_tracks(data_type); @@ -671,6 +681,7 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & static_cast(widgets_.at(element))->SetColor(c); } } + } } From 9a9b1bbe2d75994573e915fff5fc892222d506bb Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 11:05:23 -0700 Subject: [PATCH 47/96] nodeparamviewwidgetbridge: merge enabled and disable properties --- .../nodeparamviewwidgetbridge.cpp | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index b17335fff..8d7084756 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -547,27 +547,25 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & NodeValue::Type data_type = GetDataType(); // Parameters for all types - if (key == QStringLiteral("enabled")) { - foreach (QWidget* w, widgets_) { - w->setEnabled(value.toBool()); + bool key_is_disable = key.startsWith(QStringLiteral("disable")); + if (key_is_disable || key.startsWith(QStringLiteral("enabled"))) { + + bool e = value.toBool(); + if (key_is_disable) { + e = !e; } - } - if (key.startsWith(QStringLiteral("disable"))) { - - bool dis = value.toBool(); - - if (key.size() == 7) { + if (key.size() == 7) { // just the word "disable" or "enabled" for (int i=0; isetEnabled(!dis); + widgets_.at(i)->setEnabled(e); } - } else { + } else { // set specific track/widget bool ok; - int element = key.mid(7).toInt(&ok); + int element = key.midRef(7).toInt(&ok); int tracks = NodeValue::get_number_of_keyframe_tracks(data_type); if (ok && element >= 0 && element < tracks) { - widgets_.at(element)->setEnabled(!dis); + widgets_.at(element)->setEnabled(e); } } @@ -676,7 +674,7 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } } else { bool ok; - int element = key.mid(5).toInt(&ok); + int element = key.midRef(5).toInt(&ok); if (ok && element >= 0 && element < tracks) { static_cast(widgets_.at(element))->SetColor(c); } From d08c46aaab23c095dc17a01fe13f285688f7f68a Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 19:33:47 +0100 Subject: [PATCH 48/96] Add disable options for black and white clamp Also sets sensible pivot default and add a config check around GenerateProcessor app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h --- .../ociogradingtransformlinear.cpp | 61 +++++++++++++------ .../ociogradingtransformlinear.h | 2 + 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index e721a1d0e..548e405ff 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -33,7 +33,9 @@ const QString OCIOGradingTransformLinearNode::kOffsetInput = QStringLiteral("off const QString OCIOGradingTransformLinearNode::kExposureInput = QStringLiteral("exposure_in"); const QString OCIOGradingTransformLinearNode::kSaturationInput = QStringLiteral("saturation_in"); const QString OCIOGradingTransformLinearNode::kPivotInput = QStringLiteral("pivot_in"); +const QString OCIOGradingTransformLinearNode::kClampBlackDisableInput = QStringLiteral("clamp_black_disable"); const QString OCIOGradingTransformLinearNode::kClampBlackInput = QStringLiteral("clamp_black_in"); +const QString OCIOGradingTransformLinearNode::kClampWhiteDisableInput = QStringLiteral("clamp_white_disable"); const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); #define super OCIOBaseNode @@ -53,11 +55,17 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() AddInput(kSaturationInput, NodeValue::kFloat, 1.0); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); - AddInput(kPivotInput, NodeValue::kFloat, 0.203919098); + AddInput(kPivotInput, NodeValue::kFloat, 0.18); + + AddInput(kClampBlackDisableInput, NodeValue::kBoolean, true); AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); + SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); - AddInput(kClampWhiteInput, NodeValue::kFloat, 200.0); + AddInput(kClampWhiteDisableInput, NodeValue::kBoolean, true); + + AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); + SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); } QString OCIOGradingTransformLinearNode::Name() const @@ -90,35 +98,54 @@ void OCIOGradingTransformLinearNode::Retranslate() SetInputName(kExposureInput, tr("Exposure")); SetInputName(kSaturationInput, tr("Saturation")); SetInputName(kPivotInput, tr("Pivot")); + SetInputName(kClampBlackDisableInput, tr("Disable Black Clamp")); SetInputName(kClampBlackInput, tr("Black Clamp")); + SetInputName(kClampWhiteDisableInput, tr("Disable White Clamp")); SetInputName(kClampWhiteInput, tr("White Clamp")); } void OCIOGradingTransformLinearNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); + if (input == kClampWhiteDisableInput) { + SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); + } + if (input == kClampBlackDisableInput) { + SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); + } + GenerateProcessor(); } void OCIOGradingTransformLinearNode::GenerateProcessor() { - OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); - gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); + if (manager()) { + OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); - OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; - gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); - gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); - gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); - gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); - gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); - gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); - try { - gp->setValue(gpdata); + OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; + gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); + gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); + gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); + gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); + gpdata.m_pivot = GetStandardValue(kPivotInput).value(); + if (GetStandardValue(kClampBlackDisableInput).toBool()) { + gpdata.NoClampBlack(); + } else { + gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); + } + if (GetStandardValue(kClampWhiteDisableInput).toBool()) { + gpdata.NoClampWhite(); + } else { + gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); + } + try { + gp->setValue(gpdata); - set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); - } catch (const OCIO::Exception &e) { - std::cerr << std::endl << e.what() << std::endl; + set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); + } catch (const OCIO::Exception &e) { + std::cerr << std::endl << e.what() << std::endl; + } } } diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 11e65ed85..507b502f1 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -49,7 +49,9 @@ class OCIOGradingTransformLinearNode : public OCIOBaseNode static const QString kExposureInput; static const QString kSaturationInput; static const QString kPivotInput; + static const QString kClampBlackDisableInput; static const QString kClampBlackInput; + static const QString kClampWhiteDisableInput; static const QString kClampWhiteInput; protected slots: From e4b7d33af13705c26feb6ac26f4e8779d59e6216 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 19:37:12 +0100 Subject: [PATCH 49/96] Add new nodes to Video Effects list --- app/node/color/ociobase/ociobase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index e59f19343..22e03f3ba 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -36,6 +36,8 @@ OCIOBaseNode::OCIOBaseNode() : SetEffectInput(kTextureInput); connect(this, &Node::AddedToGraph, this, &OCIOBaseNode::ParentChanged); + + SetFlags(kVideoEffect); } void OCIOBaseNode::ParentChanged(NodeGraph *graph) From 63ac71b84cbb5ffc0af3907decc638295ba0399b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 12:34:05 -0700 Subject: [PATCH 50/96] numericsliderbase: fixed bug where multiplier was applied twice --- app/widget/slider/base/numericsliderbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/widget/slider/base/numericsliderbase.cpp b/app/widget/slider/base/numericsliderbase.cpp index 3e65d83ee..81b3951ac 100644 --- a/app/widget/slider/base/numericsliderbase.cpp +++ b/app/widget/slider/base/numericsliderbase.cpp @@ -69,7 +69,7 @@ void NumericSliderBase::LadderDragged(int value, double multiplier) { dragged_ = true; - dragged_diff_ += value * drag_multiplier_ * multiplier; + dragged_diff_ += value * multiplier; // Store current value to try and prevent any unnecessary signalling if the value doesn't change QVariant pre_set_value = GetValueInternal(); From 67516a5d45380b9d9f8c42b513400c07e47bf2ab Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 12:34:42 -0700 Subject: [PATCH 51/96] ociogradingtransformlinear: add base for easier dragging --- .../ociogradingtransformlinear.cpp | 13 ++++++++++--- .../nodeparamview/nodeparamviewwidgetbridge.cpp | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 548e405ff..1d648d6b7 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -44,28 +44,35 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() { AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); + SetInputProperty(kContrastInput, QStringLiteral("base"), 0.01); SetVec4InputColors(kContrastInput); AddInput(kOffsetInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + SetInputProperty(kOffsetInput, QStringLiteral("base"), 0.01); SetVec4InputColors(kOffsetInput); AddInput(kExposureInput, NodeValue::kVec4, QVector4D{0.0, 0.0, 0.0, 0.0}); + SetInputProperty(kExposureInput, QStringLiteral("base"), 0.01); SetVec4InputColors(kExposureInput); AddInput(kSaturationInput, NodeValue::kFloat, 1.0); + SetInputProperty(kSaturationInput, QStringLiteral("base"), 0.01); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); - AddInput(kPivotInput, NodeValue::kFloat, 0.18); + AddInput(kPivotInput, NodeValue::kFloat, 0.18); // Default listed in OCIO::GradingPrimary + SetInputProperty(kPivotInput, QStringLiteral("base"), 0.01); - AddInput(kClampBlackDisableInput, NodeValue::kBoolean, true); + AddInput(kClampBlackEnableInput, NodeValue::kBoolean, false); AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); + SetInputProperty(kClampBlackInput, QStringLiteral("base"), 0.01); - AddInput(kClampWhiteDisableInput, NodeValue::kBoolean, true); + AddInput(kClampWhiteEnableInput, NodeValue::kBoolean, false); AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); + SetInputProperty(kClampWhiteInput, QStringLiteral("base"), 0.01); } QString OCIOGradingTransformLinearNode::Name() const diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 8d7084756..0307b29ac 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -680,6 +680,13 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } } + } else if (key == QStringLiteral("base")) { + + double d = value.toDouble(); + for (int i=0; i(widgets_.at(i))->SetDragMultiplier(d); + } + } } From ceffff3f824ae1c5a493de13df215ab4529d74c7 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 12:36:06 -0700 Subject: [PATCH 52/96] ociogradingtransformlinear: fix potential merge conflict --- .../ociogradingtransformlinear/ociogradingtransformlinear.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 1d648d6b7..f20012b47 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -62,13 +62,13 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() AddInput(kPivotInput, NodeValue::kFloat, 0.18); // Default listed in OCIO::GradingPrimary SetInputProperty(kPivotInput, QStringLiteral("base"), 0.01); - AddInput(kClampBlackEnableInput, NodeValue::kBoolean, false); + AddInput(kClampBlackDisableInput, NodeValue::kBoolean, false); AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); SetInputProperty(kClampBlackInput, QStringLiteral("base"), 0.01); - AddInput(kClampWhiteEnableInput, NodeValue::kBoolean, false); + AddInput(kClampBlackDisableInput, NodeValue::kBoolean, false); AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); From 0403ad8fcee32830668463676e7c5508f78e3972 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 12:37:24 -0700 Subject: [PATCH 53/96] ociogradingtransformlinear: fix other potential merge conflict --- .../ociogradingtransformlinear/ociogradingtransformlinear.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index f20012b47..6bb640d7f 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -68,7 +68,7 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); SetInputProperty(kClampBlackInput, QStringLiteral("base"), 0.01); - AddInput(kClampBlackDisableInput, NodeValue::kBoolean, false); + AddInput(kClampWhiteDisableInput, NodeValue::kBoolean, false); AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); From f46f8e50dcb42825215fa1e215a5b5309b8bb5f1 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 21:26:34 +0100 Subject: [PATCH 54/96] Swap clamp disables for enables --- .../ociogradingtransformlinear.cpp | 28 +++++++++---------- .../ociogradingtransformlinear.h | 4 +-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 6bb640d7f..647e59739 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -33,9 +33,9 @@ const QString OCIOGradingTransformLinearNode::kOffsetInput = QStringLiteral("off const QString OCIOGradingTransformLinearNode::kExposureInput = QStringLiteral("exposure_in"); const QString OCIOGradingTransformLinearNode::kSaturationInput = QStringLiteral("saturation_in"); const QString OCIOGradingTransformLinearNode::kPivotInput = QStringLiteral("pivot_in"); -const QString OCIOGradingTransformLinearNode::kClampBlackDisableInput = QStringLiteral("clamp_black_disable"); +const QString OCIOGradingTransformLinearNode::kClampBlackEnableInput = QStringLiteral("clamp_black_enable_in"); const QString OCIOGradingTransformLinearNode::kClampBlackInput = QStringLiteral("clamp_black_in"); -const QString OCIOGradingTransformLinearNode::kClampWhiteDisableInput = QStringLiteral("clamp_white_disable"); +const QString OCIOGradingTransformLinearNode::kClampWhiteEnableInput = QStringLiteral("clamp_white_enable_in"); const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); #define super OCIOBaseNode @@ -62,16 +62,16 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() AddInput(kPivotInput, NodeValue::kFloat, 0.18); // Default listed in OCIO::GradingPrimary SetInputProperty(kPivotInput, QStringLiteral("base"), 0.01); - AddInput(kClampBlackDisableInput, NodeValue::kBoolean, false); + AddInput(kClampBlackEnableInput, NodeValue::kBoolean, false); AddInput(kClampBlackInput, NodeValue::kFloat, 0.0); - SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); + SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool()); SetInputProperty(kClampBlackInput, QStringLiteral("base"), 0.01); - AddInput(kClampWhiteDisableInput, NodeValue::kBoolean, false); + AddInput(kClampWhiteEnableInput, NodeValue::kBoolean, false); AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); - SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); + SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool()); SetInputProperty(kClampWhiteInput, QStringLiteral("base"), 0.01); } @@ -105,20 +105,20 @@ void OCIOGradingTransformLinearNode::Retranslate() SetInputName(kExposureInput, tr("Exposure")); SetInputName(kSaturationInput, tr("Saturation")); SetInputName(kPivotInput, tr("Pivot")); - SetInputName(kClampBlackDisableInput, tr("Disable Black Clamp")); + SetInputName(kClampBlackEnableInput, tr("Enable Black Clamp")); SetInputName(kClampBlackInput, tr("Black Clamp")); - SetInputName(kClampWhiteDisableInput, tr("Disable White Clamp")); + SetInputName(kClampWhiteEnableInput, tr("Enable White Clamp")); SetInputName(kClampWhiteInput, tr("White Clamp")); } void OCIOGradingTransformLinearNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); - if (input == kClampWhiteDisableInput) { - SetInputProperty(kClampWhiteInput, QStringLiteral("disable"), GetStandardValue(kClampWhiteDisableInput).toBool()); + if (input == kClampWhiteEnableInput) { + SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool()); } - if (input == kClampBlackDisableInput) { - SetInputProperty(kClampBlackInput, QStringLiteral("disable"), GetStandardValue(kClampBlackDisableInput).toBool()); + if (input == kClampBlackEnableInput) { + SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool()); } GenerateProcessor(); @@ -136,12 +136,12 @@ void OCIOGradingTransformLinearNode::GenerateProcessor() gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - if (GetStandardValue(kClampBlackDisableInput).toBool()) { + if (!GetStandardValue(kClampBlackEnableInput).toBool()) { gpdata.NoClampBlack(); } else { gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); } - if (GetStandardValue(kClampWhiteDisableInput).toBool()) { + if (!GetStandardValue(kClampWhiteEnableInput).toBool()) { gpdata.NoClampWhite(); } else { gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 507b502f1..3026f8803 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -49,9 +49,9 @@ class OCIOGradingTransformLinearNode : public OCIOBaseNode static const QString kExposureInput; static const QString kSaturationInput; static const QString kPivotInput; - static const QString kClampBlackDisableInput; + static const QString kClampBlackEnableInput; static const QString kClampBlackInput; - static const QString kClampWhiteDisableInput; + static const QString kClampWhiteEnableInput; static const QString kClampWhiteInput; protected slots: From 09d30c6aee1c5395b01077e32d1e1cfccff2f9bc Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 13:28:46 -0700 Subject: [PATCH 55/96] colortransformjob: allow overriding ID --- app/render/job/colortransformjob.h | 12 ++++++++++++ app/render/renderer.cpp | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/render/job/colortransformjob.h b/app/render/job/colortransformjob.h index bbc203226..18f48a7cb 100644 --- a/app/render/job/colortransformjob.h +++ b/app/render/job/colortransformjob.h @@ -45,6 +45,17 @@ public: clear_destination_ = true; } + QString id() const + { + if (id_.isEmpty()) { + return processor_->id(); + } else { + return id_; + } + } + + void SetOverrideID(const QString &id) { id_ = id; } + TexturePtr GetInputTexture() const { return input_texture_; } void SetInputTexture(TexturePtr tex) { input_texture_ = tex; } @@ -76,6 +87,7 @@ public: private: ColorProcessorPtr processor_; + QString id_; TexturePtr input_texture_; diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 66fb3853b..8d8b16a25 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -99,7 +99,7 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col ColorContext& color_ctx = *ctx; - QString proc_id = color_job.GetColorProcessor()->id(); + QString proc_id = color_job.id(); if (color_cache_.contains(proc_id)) { color_ctx = color_cache_.value(proc_id); From 601d08ce6432df12d33d120b2884de9ecc95ffca Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 13:36:44 -0700 Subject: [PATCH 56/96] node: change class sent to GetShaderCode --- .../crossdissolve/crossdissolvetransition.cpp | 4 ++-- .../crossdissolve/crossdissolvetransition.h | 2 +- .../transition/diptocolor/diptocolortransition.cpp | 4 ++-- .../transition/diptocolor/diptocolortransition.h | 2 +- app/node/distort/cornerpin/cornerpindistortnode.cpp | 4 ++-- app/node/distort/cornerpin/cornerpindistortnode.h | 2 +- app/node/distort/crop/cropdistortnode.cpp | 4 ++-- app/node/distort/crop/cropdistortnode.h | 2 +- app/node/distort/flip/flipdistortnode.cpp | 4 ++-- app/node/distort/flip/flipdistortnode.h | 2 +- app/node/distort/transform/transformdistortnode.cpp | 4 ++-- app/node/distort/transform/transformdistortnode.h | 2 +- app/node/effect/opacity/opacityeffect.cpp | 4 ++-- app/node/effect/opacity/opacityeffect.h | 2 +- app/node/filter/blur/blur.cpp | 4 ++-- app/node/filter/blur/blur.h | 2 +- app/node/filter/mosaic/mosaicfilternode.cpp | 4 ++-- app/node/filter/mosaic/mosaicfilternode.h | 2 +- app/node/filter/stroke/stroke.cpp | 4 ++-- app/node/filter/stroke/stroke.h | 2 +- app/node/generator/noise/noise.cpp | 2 +- app/node/generator/noise/noise.h | 2 +- app/node/generator/shape/generatorwithmerge.cpp | 4 ++-- app/node/generator/shape/generatorwithmerge.h | 2 +- app/node/generator/shape/shapenode.cpp | 6 +++--- app/node/generator/shape/shapenode.h | 2 +- app/node/generator/solid/solid.cpp | 4 ++-- app/node/generator/solid/solid.h | 2 +- .../colordifferencekey/colordifferencekey.cpp | 4 ++-- .../keying/colordifferencekey/colordifferencekey.h | 2 +- app/node/keying/despill/despill.cpp | 4 ++-- app/node/keying/despill/despill.h | 2 +- app/node/math/math/math.cpp | 4 ++-- app/node/math/math/math.h | 2 +- app/node/math/merge/merge.cpp | 4 ++-- app/node/math/merge/merge.h | 2 +- app/node/node.cpp | 4 +--- app/node/node.h | 13 ++++++++++++- 38 files changed, 67 insertions(+), 58 deletions(-) diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index bf50e7486..bc7466785 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -46,9 +46,9 @@ QString CrossDissolveTransition::Description() const return tr("Smoothly transition between two clips."); } -ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) const +ShaderCode CrossDissolveTransition::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); } diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index bd6f7ca9e..b1787dbf2 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -40,7 +40,7 @@ public: //virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; protected: virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const override; diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 5a64ed3de..dd49ea8b3 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -49,9 +49,9 @@ QString DipToColorTransition::Description() const return tr("Transition between clips by dipping to a color."); } -ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const +ShaderCode DipToColorTransition::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); } diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index 66164d559..b32918555 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -38,7 +38,7 @@ public: virtual QVector Category() const override; virtual QString Description() const override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; static const QString kColorInput; diff --git a/app/node/distort/cornerpin/cornerpindistortnode.cpp b/app/node/distort/cornerpin/cornerpindistortnode.cpp index 57129bf3f..aa3d0e97d 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.cpp +++ b/app/node/distort/cornerpin/cornerpindistortnode.cpp @@ -108,9 +108,9 @@ void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g } } -ShaderCode CornerPinDistortNode::GetShaderCode(const QString &shader_id) const +ShaderCode CornerPinDistortNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/cornerpin.frag")), FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/cornerpin.vert"))); diff --git a/app/node/distort/cornerpin/cornerpindistortnode.h b/app/node/distort/cornerpin/cornerpindistortnode.h index 8c5cae8cb..41a82ca88 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.h +++ b/app/node/distort/cornerpin/cornerpindistortnode.h @@ -61,7 +61,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp index 5fc6dd56a..847a4a139 100644 --- a/app/node/distort/crop/cropdistortnode.cpp +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -94,9 +94,9 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global } } -ShaderCode CropDistortNode::GetShaderCode(const QString &shader_id) const +ShaderCode CropDistortNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/crop.frag"))); } diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h index 402719281..697f5540a 100644 --- a/app/node/distort/crop/cropdistortnode.h +++ b/app/node/distort/crop/cropdistortnode.h @@ -62,7 +62,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index 53fbcfb84..10b90e0ac 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -69,9 +69,9 @@ void FlipDistortNode::Retranslate() SetInputName(kVerticalInput, tr("Vertical")); } -ShaderCode FlipDistortNode::GetShaderCode(const QString& shader_id) const +ShaderCode FlipDistortNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/flip.frag")); } diff --git a/app/node/distort/flip/flipdistortnode.h b/app/node/distort/flip/flipdistortnode.h index 3bb53bb0c..2d607ffd3 100644 --- a/app/node/distort/flip/flipdistortnode.h +++ b/app/node/distort/flip/flipdistortnode.h @@ -40,7 +40,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; static const QString kTextureInput; diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index 1b5cad90f..9987e1526 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -119,9 +119,9 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g } } -ShaderCode TransformDistortNode::GetShaderCode(const QString &shader_id) const +ShaderCode TransformDistortNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id); + Q_UNUSED(request); // Returns default frag and vert shader return ShaderCode(); diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h index 68e71d8a5..9738c7e68 100644 --- a/app/node/distort/transform/transformdistortnode.h +++ b/app/node/distort/transform/transformdistortnode.h @@ -65,7 +65,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; enum AutoScaleType { kAutoScaleNone, diff --git a/app/node/effect/opacity/opacityeffect.cpp b/app/node/effect/opacity/opacityeffect.cpp index 6027c2ab3..4fe76014f 100644 --- a/app/node/effect/opacity/opacityeffect.cpp +++ b/app/node/effect/opacity/opacityeffect.cpp @@ -37,9 +37,9 @@ void OpacityEffect::Retranslate() SetInputName(kValueInput, tr("Opacity")); } -ShaderCode OpacityEffect::GetShaderCode(const QString &shader_id) const +ShaderCode OpacityEffect::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/opacity.frag")); } diff --git a/app/node/effect/opacity/opacityeffect.h b/app/node/effect/opacity/opacityeffect.h index a7c8f7f0a..36e284274 100644 --- a/app/node/effect/opacity/opacityeffect.h +++ b/app/node/effect/opacity/opacityeffect.h @@ -34,7 +34,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; static const QString kTextureInput; diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 86d277ce1..123443aea 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -83,9 +83,9 @@ void BlurFilterNode::Retranslate() SetInputName(kRepeatEdgePixelsInput, tr("Repeat Edge Pixels")); } -ShaderCode BlurFilterNode::GetShaderCode(const QString &shader_id) const +ShaderCode BlurFilterNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/blur.frag")); } diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index da70956a4..5e85dc079 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -40,7 +40,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; static const QString kTextureInput; diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp index c198868c5..4e77a524d 100644 --- a/app/node/filter/mosaic/mosaicfilternode.cpp +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -73,9 +73,9 @@ void MosaicFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa } } -ShaderCode MosaicFilterNode::GetShaderCode(const QString &shader_id) const +ShaderCode MosaicFilterNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/mosaic.frag")); } diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h index f1dea64e4..fed3f3168 100644 --- a/app/node/filter/mosaic/mosaicfilternode.h +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -56,7 +56,7 @@ public: virtual void Retranslate() override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; static const QString kTextureInput; static const QString kHorizInput; diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index 6f05f61fa..5a8ac7da7 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -101,9 +101,9 @@ void StrokeFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa } } -ShaderCode StrokeFilterNode::GetShaderCode(const QString &shader_id) const +ShaderCode StrokeFilterNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/stroke.frag")); } diff --git a/app/node/filter/stroke/stroke.h b/app/node/filter/stroke/stroke.h index d762b3923..48a442ace 100644 --- a/app/node/filter/stroke/stroke.h +++ b/app/node/filter/stroke/stroke.h @@ -41,7 +41,7 @@ public: virtual void Retranslate() override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; static const QString kTextureInput; static const QString kColorInput; diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index 0d4e3c832..09dfaabd3 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -73,7 +73,7 @@ void NoiseGeneratorNode::Retranslate() SetInputName(kColorInput, tr("Color")); } -ShaderCode NoiseGeneratorNode::GetShaderCode(const QString& shader_id) const +ShaderCode NoiseGeneratorNode::GetShaderCode(const ShaderRequest &request) const { return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/noise.frag")); } diff --git a/app/node/generator/noise/noise.h b/app/node/generator/noise/noise.h index 7b8ea005c..73a3a0c0b 100644 --- a/app/node/generator/noise/noise.h +++ b/app/node/generator/noise/noise.h @@ -39,7 +39,7 @@ class NoiseGeneratorNode : public Node { virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; static const QString kBaseIn; diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp index 363ba4d12..fac36b0ff 100644 --- a/app/node/generator/shape/generatorwithmerge.cpp +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -42,9 +42,9 @@ void GeneratorWithMerge::Retranslate() SetInputName(kBaseInput, tr("Base")); } -ShaderCode GeneratorWithMerge::GetShaderCode(const QString &shader_id) const +ShaderCode GeneratorWithMerge::GetShaderCode(const ShaderRequest &request) const { - if (shader_id == QStringLiteral("mrg")) { + if (request.id == QStringLiteral("mrg")) { return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag")); } diff --git a/app/node/generator/shape/generatorwithmerge.h b/app/node/generator/shape/generatorwithmerge.h index af69e1ed4..de3e3bc04 100644 --- a/app/node/generator/shape/generatorwithmerge.h +++ b/app/node/generator/shape/generatorwithmerge.h @@ -33,7 +33,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; static const QString kBaseInput; diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp index 34db8dfcb..9f77939ad 100644 --- a/app/node/generator/shape/shapenode.cpp +++ b/app/node/generator/shape/shapenode.cpp @@ -61,12 +61,12 @@ void ShapeNode::Retranslate() SetComboBoxStrings(kTypeInput, {tr("Rectangle"), tr("Ellipse")}); } -ShaderCode ShapeNode::GetShaderCode(const QString &shader_id) const +ShaderCode ShapeNode::GetShaderCode(const ShaderRequest &request) const { - if (shader_id == QStringLiteral("shape")) { + if (request.id == QStringLiteral("shape")) { return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/shape.frag"))); } else { - return super::GetShaderCode(shader_id); + return super::GetShaderCode(request); } } diff --git a/app/node/generator/shape/shapenode.h b/app/node/generator/shape/shapenode.h index 7ae7d5469..5b69209a7 100644 --- a/app/node/generator/shape/shapenode.h +++ b/app/node/generator/shape/shapenode.h @@ -45,7 +45,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; static QString kTypeInput; diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index 0bfe93f9c..d06076666 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -68,9 +68,9 @@ void SolidGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } -ShaderCode SolidGenerator::GetShaderCode(const QString &shader_id) const +ShaderCode SolidGenerator::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/solid.frag")); } diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index 55f5bdb50..4b40a7fc4 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -41,7 +41,7 @@ public: virtual void Retranslate() override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; static const QString kColorInput; diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index 534d06a78..6039c1c03 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -83,9 +83,9 @@ void ColorDifferenceKeyNode::Retranslate() SetInputName(kMaskOnlyInput, tr("Show Mask Only")); } -ShaderCode ColorDifferenceKeyNode::GetShaderCode(const QString &shader_id) const +ShaderCode ColorDifferenceKeyNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/colordifferencekey.frag")); } diff --git a/app/node/keying/colordifferencekey/colordifferencekey.h b/app/node/keying/colordifferencekey/colordifferencekey.h index 3b4809256..31cb106a6 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.h +++ b/app/node/keying/colordifferencekey/colordifferencekey.h @@ -33,7 +33,7 @@ class ColorDifferenceKeyNode : public Node { virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; static const QString kTextureInput; diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index 17ea0a5ca..364e04a1f 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -75,8 +75,8 @@ void DespillNode::Retranslate() SetInputName(kPreserveLuminanceInput, tr("Preserve Luminance")); } -ShaderCode DespillNode::GetShaderCode(const QString& shader_id) const { - Q_UNUSED(shader_id) +ShaderCode DespillNode::GetShaderCode(const ShaderRequest &request) const { + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/despill.frag")); } diff --git a/app/node/keying/despill/despill.h b/app/node/keying/despill/despill.h index 098cb3132..936402427 100644 --- a/app/node/keying/despill/despill.h +++ b/app/node/keying/despill/despill.h @@ -34,7 +34,7 @@ class DespillNode : public Node { virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString& shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; static const QString kTextureInput; diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 123f768fa..babe0b9a5 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -80,9 +80,9 @@ void MathNode::Retranslate() SetComboBoxStrings(kMethodIn, operations); } -ShaderCode MathNode::GetShaderCode(const QString &shader_id) const +ShaderCode MathNode::GetShaderCode(const ShaderRequest &request) const { - return GetShaderCodeInternal(shader_id, kParamAIn, kParamBIn); + return GetShaderCodeInternal(request.id, kParamAIn, kParamBIn); } void MathNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 6001db776..60c910140 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -40,7 +40,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; Operation GetOperation() const { diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 5a911e8a2..335cb9e74 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -67,9 +67,9 @@ void MergeNode::Retranslate() SetInputName(kBlendIn, tr("Blend")); } -ShaderCode MergeNode::GetShaderCode(const QString &shader_id) const +ShaderCode MergeNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) + Q_UNUSED(request) return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag")); } diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index f73994a3f..814b2a93b 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -40,7 +40,7 @@ public: virtual void Retranslate() override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; static const QString kBaseIn; diff --git a/app/node/node.cpp b/app/node/node.cpp index 907287880..a510bbbe4 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1520,10 +1520,8 @@ QVector Node::GetImmediateDependencies() const return GetDependenciesInternal(false, false); } -ShaderCode Node::GetShaderCode(const QString &shader_id) const +ShaderCode Node::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(shader_id) - return ShaderCode(QString(), QString()); } diff --git a/app/node/node.h b/app/node/node.h index 4f45277d6..f0df101f8 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -660,10 +660,21 @@ public: */ QVector GetImmediateDependencies() const; + struct ShaderRequest + { + ShaderRequest(const QString &shader_id) + { + id = shader_id; + } + + QString id; + QString stub; + }; + /** * @brief Generate hardware accelerated code for this Node */ - virtual ShaderCode GetShaderCode(const QString& shader_id) const; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const; /** * @brief If Value() pushes a ShaderJob, this is the function that will process them. From 6d84df828871b6791b0e597981e92ad4001ac33e Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 21:47:52 +0100 Subject: [PATCH 57/96] Add tooltip property to node parameters. --- .../ociogradingtransformlinear.cpp | 3 ++- app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 647e59739..309c1e199 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -77,7 +77,7 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() QString OCIOGradingTransformLinearNode::Name() const { - return tr("OCIO Linear Grading Transform"); + return tr("OCIO Color Grading (Linear)"); } QString OCIOGradingTransformLinearNode::id() const @@ -103,6 +103,7 @@ void OCIOGradingTransformLinearNode::Retranslate() SetInputName(kContrastInput, tr("Contrast")); SetInputName(kOffsetInput, tr("Offset")); SetInputName(kExposureInput, tr("Exposure")); + SetInputProperty(kExposureInput, QStringLiteral("tooltip"), tr("Exposure increments in stops.")); SetInputName(kSaturationInput, tr("Saturation")); SetInputName(kPivotInput, tr("Pivot")); SetInputName(kClampBlackEnableInput, tr("Enable Black Clamp")); diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 0307b29ac..c25848f03 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -571,6 +571,12 @@ void NodeParamViewWidgetBridge::SetProperty(const QString &key, const QVariant & } + if (key == QStringLiteral("tooltip")) { + for (int i = 0; i < widgets_.size(); i++) { + widgets_.at(i)->setToolTip(value.toString()); + } + } + // Parameters for integers, floats, and vectors if (NodeValue::type_is_numeric(data_type) || NodeValue::type_is_vector(data_type)) { if (key == QStringLiteral("min")) { From b4bf57ad5096593f70e6eaed7d4fae67e935c071 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 13:55:05 -0700 Subject: [PATCH 58/96] update chroma key GetShaderCode sig --- app/node/keying/chromakey/chromakey.cpp | 5 +++-- app/node/keying/chromakey/chromakey.h | 2 +- app/node/node.h | 6 ++++++ app/render/renderer.cpp | 5 ++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 6ada34aca..7915d00fa 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -94,9 +94,9 @@ void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) GenerateProcessor(); } -ShaderCode ChromaKeyNode::GetShaderCode(const QString &) const +ShaderCode ChromaKeyNode::GetShaderCode(const ShaderRequest &request) const { - return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/chromakey.frag"))); + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/chromakey.frag")).arg(request.stub)); } void ChromaKeyNode::GenerateProcessor() @@ -122,6 +122,7 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, job.SetInputTexture(value[kTextureInput].data().value()); job.SetNeedsCustomShader(this); job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); + job.SetOverrideID(id()); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index a9ac4ffa0..9feadb736 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -37,7 +37,7 @@ class ChromaKeyNode : public OCIOBaseNode { virtual void InputValueChangedEvent(const QString& input, int element) override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; virtual void ConfigChanged() override; diff --git a/app/node/node.h b/app/node/node.h index 72c171249..6125dc01c 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -672,6 +672,12 @@ public: id = shader_id; } + ShaderRequest(const QString &shader_id, const QString &shader_stub) + { + id = shader_id; + stub = shader_stub; + } + QString id; QString stub; }; diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 8d8b16a25..2d75ae47f 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -123,14 +123,13 @@ bool Renderer::GetColorContext(const ColorTransformJob &color_job, Renderer::Col ShaderCode code; if (const Node *shader_src = color_job.CustomShaderSource()) { // Use shader code from associated node - code = shader_src->GetShaderCode(color_job.CustomShaderID()); + code = shader_src->GetShaderCode({color_job.CustomShaderID(), shader_desc->getShaderText()}); } else { // Generate shader code using OCIO stub and our auto-generated name code = FileFunctions::ReadFileAsString(QStringLiteral(":shaders/colormanage.frag")); + code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText())); } - code.set_frag_code(code.frag_code().arg(shader_desc->getShaderText())); - // Try to compile shader color_ctx.compiled_shader = CreateNativeShader(code); From 2ef4f9440be271f9749f623c59ad313f22ca24aa Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 22:30:15 +0100 Subject: [PATCH 59/96] Set contrast to OCIO specified minimum --- .../ociogradingtransformlinear/ociogradingtransformlinear.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 309c1e199..8899fd8d7 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -43,7 +43,7 @@ const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral( OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() { AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); - SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.001f, 0.001f, 0.001f, 0.001f}); + SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.01f, 0.01f, 0.01f, 0.01f}); SetInputProperty(kContrastInput, QStringLiteral("base"), 0.01); SetVec4InputColors(kContrastInput); From b5d7be9e47ffb387c0e91163ed05d6b3f3aae78e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 15:37:19 -0700 Subject: [PATCH 60/96] nodevalue: add convenience function for retrieving internal value --- app/node/value.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/node/value.h b/app/node/value.h index 886b4f470..e16fc1055 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -203,6 +203,12 @@ public: return type_; } + template + T value() const + { + return data_.value(); + } + const QVariant& data() const { return data_; From 862e462b2035e03ce7de1f3aabc532c940018af2 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 15:38:05 -0700 Subject: [PATCH 61/96] chromakey: add base properties --- app/node/keying/chromakey/chromakey.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 7915d00fa..8b63a9c9b 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -37,9 +37,11 @@ ChromaKeyNode::ChromaKeyNode() AddInput(kUpperToleranceInput, NodeValue::kFloat, 25.0); SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), 0.0); + SetInputProperty(kUpperToleranceInput, QStringLiteral("base"), 0.1); AddInput(kLowerToleranceInput, NodeValue::kFloat, 5.0); SetInputProperty(kLowerToleranceInput, QStringLiteral("min"), 0.0); + SetInputProperty(kLowerToleranceInput, QStringLiteral("base"), 0.1); AddInput(kGarbageMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); @@ -47,9 +49,11 @@ ChromaKeyNode::ChromaKeyNode() AddInput(kHighlightsInput, NodeValue::kFloat, 100.0f); SetInputProperty(kHighlightsInput, QStringLiteral("min"), 0.0); + SetInputProperty(kHighlightsInput, QStringLiteral("base"), 0.1); AddInput(kShadowsInput, NodeValue::kFloat, 100.0f); SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0); + SetInputProperty(kShadowsInput, QStringLiteral("base"), 0.1); AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); } @@ -122,7 +126,6 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, job.SetInputTexture(value[kTextureInput].data().value()); job.SetNeedsCustomShader(this); job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); - job.SetOverrideID(id()); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } From ab9114947d41ed24310c759dc081ed7ecba88c4b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 15:38:20 -0700 Subject: [PATCH 62/96] ociogradingtransformlinear: update for dynamic processor --- .../ociogradingtransformlinear.cpp | 72 ++++++++++++------- .../ociogradingtransformlinear.h | 2 + 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 309c1e199..0a98c66d8 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -25,18 +25,19 @@ #include "common/ocioutils.h" #include "node/project/project.h" #include "render/colorprocessor.h" +#include "widget/slider/floatslider.h" namespace olive { -const QString OCIOGradingTransformLinearNode::kContrastInput = QStringLiteral("contrast_in"); -const QString OCIOGradingTransformLinearNode::kOffsetInput = QStringLiteral("offset_in"); -const QString OCIOGradingTransformLinearNode::kExposureInput = QStringLiteral("exposure_in"); -const QString OCIOGradingTransformLinearNode::kSaturationInput = QStringLiteral("saturation_in"); -const QString OCIOGradingTransformLinearNode::kPivotInput = QStringLiteral("pivot_in"); +const QString OCIOGradingTransformLinearNode::kContrastInput = QStringLiteral("ocio_grading_primary_contrast"); +const QString OCIOGradingTransformLinearNode::kOffsetInput = QStringLiteral("ocio_grading_primary_offset"); +const QString OCIOGradingTransformLinearNode::kExposureInput = QStringLiteral("ocio_grading_primary_exposure"); +const QString OCIOGradingTransformLinearNode::kSaturationInput = QStringLiteral("ocio_grading_primary_saturation"); +const QString OCIOGradingTransformLinearNode::kPivotInput = QStringLiteral("ocio_grading_primary_pivot"); const QString OCIOGradingTransformLinearNode::kClampBlackEnableInput = QStringLiteral("clamp_black_enable_in"); -const QString OCIOGradingTransformLinearNode::kClampBlackInput = QStringLiteral("clamp_black_in"); +const QString OCIOGradingTransformLinearNode::kClampBlackInput = QStringLiteral("ocio_grading_primary_clampBlack"); const QString OCIOGradingTransformLinearNode::kClampWhiteEnableInput = QStringLiteral("clamp_white_enable_in"); -const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("clamp_white_in"); +const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("ocio_grading_primary_clampWhite"); #define super OCIOBaseNode @@ -56,7 +57,7 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() SetVec4InputColors(kExposureInput); AddInput(kSaturationInput, NodeValue::kFloat, 1.0); - SetInputProperty(kSaturationInput, QStringLiteral("base"), 0.01); + SetInputProperty(kSaturationInput, QStringLiteral("view"), FloatSlider::kPercentage); SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0); AddInput(kPivotInput, NodeValue::kFloat, 0.18); // Default listed in OCIO::GradingPrimary @@ -129,27 +130,10 @@ void OCIOGradingTransformLinearNode::GenerateProcessor() { if (manager()) { OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN); + gp->makeDynamic(); gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD); - OCIO::GradingPrimary gpdata{OCIO::GRADING_LIN}; - gpdata.m_contrast = OCIOUtils::QVec4ToRGBM(GetStandardValue(kContrastInput).value()); - gpdata.m_exposure = OCIOUtils::QVec4ToRGBM(GetStandardValue(kExposureInput).value()); - gpdata.m_offset = OCIOUtils::QVec4ToRGBM(GetStandardValue(kOffsetInput).value()); - gpdata.m_saturation = GetStandardValue(kSaturationInput).value(); - gpdata.m_pivot = GetStandardValue(kPivotInput).value(); - if (!GetStandardValue(kClampBlackEnableInput).toBool()) { - gpdata.NoClampBlack(); - } else { - gpdata.m_clampBlack = GetStandardValue(kClampBlackInput).value(); - } - if (!GetStandardValue(kClampWhiteEnableInput).toBool()) { - gpdata.NoClampWhite(); - } else { - gpdata.m_clampWhite = GetStandardValue(kClampWhiteInput).value(); - } try { - gp->setValue(gpdata); - set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp))); } catch (const OCIO::Exception &e) { std::cerr << std::endl << e.what() << std::endl; @@ -157,6 +141,42 @@ void OCIOGradingTransformLinearNode::GenerateProcessor() } } +void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + if (!value[kTextureInput].data().isNull() && processor()) { + ColorTransformJob job; + + job.SetColorProcessor(processor()); + job.SetInputTexture(value[kTextureInput].data().value()); + + job.InsertValue(value); + + // Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU. + // Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API. + // Therefore, this code has been duplicated from OCIO here: + // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157 + QVector4D offset = value[kOffsetInput].value(); + offset[0] = offset[3] + offset[0]; + offset[1] = offset[3] + offset[1]; + offset[2] = offset[3] + offset[2]; + job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, offset.toVector3D())); + + QVector4D exposure = value[kExposureInput].value(); + exposure[0] = std::pow(2.0f, static_cast(exposure[3] + exposure[0])); + exposure[1] = std::pow(2.0f, static_cast(exposure[3] + exposure[1])); + exposure[2] = std::pow(2.0f, static_cast(exposure[3] + exposure[2])); + job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, exposure.toVector3D())); + + QVector4D contrast = value[kContrastInput].value(); + contrast[0] = static_cast(contrast[3] * contrast[0]); + contrast[1] = static_cast(contrast[3] * contrast[1]); + contrast[2] = static_cast(contrast[3] * contrast[2]); + job.InsertValue(kContrastInput, NodeValue(NodeValue::kVec3, contrast.toVector3D())); + + table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + } +} + void OCIOGradingTransformLinearNode::ConfigChanged() { GenerateProcessor(); diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index 3026f8803..fac1a8f78 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -44,6 +44,8 @@ class OCIOGradingTransformLinearNode : public OCIOBaseNode virtual void InputValueChangedEvent(const QString &input, int element) override; void GenerateProcessor(); + virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + static const QString kContrastInput; static const QString kOffsetInput; static const QString kExposureInput; From 471064df04e36595fdae03e51b6cdb55d2545b5b Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 23:40:25 +0100 Subject: [PATCH 63/96] Ensure white clamp is always greater than black clamp --- .../ociogradingtransformlinear.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 8899fd8d7..c02027f43 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -43,6 +43,7 @@ const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral( OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() { AddInput(kContrastInput, NodeValue::kVec4, QVector4D{1.0, 1.0, 1.0, 1.0}); + // Minimum based on OCIO::GradingPrimary::validate SetInputProperty(kContrastInput, QStringLiteral("min"), QVector4D{0.01f, 0.01f, 0.01f, 0.01f}); SetInputProperty(kContrastInput, QStringLiteral("base"), 0.01); SetVec4InputColors(kContrastInput); @@ -73,6 +74,7 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool()); SetInputProperty(kClampWhiteInput, QStringLiteral("base"), 0.01); + SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); } QString OCIOGradingTransformLinearNode::Name() const @@ -121,6 +123,10 @@ void OCIOGradingTransformLinearNode::InputValueChangedEvent(const QString &input if (input == kClampBlackEnableInput) { SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool()); } + if (input == kClampBlackInput) { + // Ensure the white clamp is always greater than the black clamp as per OCIO::GradingPrimary::validate + SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); + } GenerateProcessor(); } From f652676008b9a052560e88fe859eabde1342d137 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 15:50:56 -0700 Subject: [PATCH 64/96] remove fixme --- app/render/renderprocessor.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 5f6c2084d..d9cce652d 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -523,11 +523,6 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, co QVariant shader = shader_cache_->value(full_shader_id); if (shader.isNull()) { - // FIXME: Reimplement as color job - //if (job.UseOCIO()) { - // render_ctx_->ShaderJobInsertTextures(job.ColorProcessor(), &job, job.ShaderDesc()); - //} - // Since we have shader code, compile it now shader = render_ctx_->CreateNativeShader(node->GetShaderCode(job.GetShaderID())); From 0f824d180c72480d1f17da20a7b52467fe0eff2a Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 8 May 2022 00:13:17 +0100 Subject: [PATCH 65/96] Chromakey: ensure upper tolerence is always greater than lower tolerence --- app/node/keying/chromakey/chromakey.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 8b63a9c9b..7cd573e0d 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -35,14 +35,14 @@ ChromaKeyNode::ChromaKeyNode() { AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0.0f, 1.0f, 0.0f, 1.0f))); - AddInput(kUpperToleranceInput, NodeValue::kFloat, 25.0); - SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), 0.0); - SetInputProperty(kUpperToleranceInput, QStringLiteral("base"), 0.1); - AddInput(kLowerToleranceInput, NodeValue::kFloat, 5.0); SetInputProperty(kLowerToleranceInput, QStringLiteral("min"), 0.0); SetInputProperty(kLowerToleranceInput, QStringLiteral("base"), 0.1); + AddInput(kUpperToleranceInput, NodeValue::kFloat, 25.0); + SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); + SetInputProperty(kUpperToleranceInput, QStringLiteral("base"), 0.1); + AddInput(kGarbageMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); AddInput(kCoreMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); @@ -95,6 +95,10 @@ void ChromaKeyNode::Retranslate() void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); + if (input == kLowerToleranceInput) { + SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); + } + GenerateProcessor(); } From fca5f65899f8c2ed5d23cdd57cb7040c8e84c695 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 7 May 2022 16:27:10 -0700 Subject: [PATCH 66/96] renderer: fix divider regression --- app/node/project/footage/footage.cpp | 7 +------ app/node/traverser.cpp | 17 +++++++++++++++++ app/render/renderprocessor.cpp | 11 +---------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/node/project/footage/footage.cpp b/app/node/project/footage/footage.cpp index d3c82304f..59d520d96 100644 --- a/app/node/project/footage/footage.cpp +++ b/app/node/project/footage/footage.cpp @@ -118,12 +118,7 @@ void Footage::InputValueChangedEvent(const QString &input, int element) decoder_ = footage_info.decoder(); for (int i=0; i 1 + && VideoParams::GetScaledDimension(job_params.width(), job_params.divider()-1) < render_params.effective_width() + && VideoParams::GetScaledDimension(job_params.height(), job_params.divider()-1) < render_params.effective_height()) { + job_params.set_divider(job_params.divider() - 1); + } + job.set_video_params(job_params); + if (footage_time.isNaN()) { // Push dummy texture tex = CreateDummyTexture(job.video_params()); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index ce1db8b41..f58b7ea3c 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -402,19 +402,10 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ // Check the still frame cache. On large frames such as high resolution still images, uploading // and color managing them for every frame is a waste of time, so we implement a small cache here // to optimize such a situation - const VideoParams& render_params = GetCacheVideoParams(); VideoParams stream_data = stream.video_params(); ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); - // See if we can make this divider larger (i.e. if the fooage is smaller) - int footage_divider = render_params.divider(); - while (footage_divider > 1 - && VideoParams::GetScaledDimension(stream_data.width(), footage_divider-1) < render_params.effective_width() - && VideoParams::GetScaledDimension(stream_data.height(), footage_divider-1) < render_params.effective_height()) { - footage_divider--; - } - QString using_colorspace = stream_data.colorspace(); if (using_colorspace.isEmpty()) { @@ -449,7 +440,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ if (decoder) { Decoder::RetrieveVideoParams p; - p.divider = footage_divider; + p.divider = stream.video_params().divider(); p.src_interlacing = stream_data.interlacing(); p.dst_interlacing = GetCacheVideoParams().interlacing(); From 8b951371bb181826638daebb7716f99178fbcd30 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 11:48:54 -0700 Subject: [PATCH 67/96] ocioutils: remove unused function We could have kept this, but since I want to reorganize the sliders it might result in confusion in the codebase --- app/common/ocioutils.cpp | 12 ------------ app/common/ocioutils.h | 1 - 2 files changed, 13 deletions(-) diff --git a/app/common/ocioutils.cpp b/app/common/ocioutils.cpp index cc8a0490a..b296f0305 100644 --- a/app/common/ocioutils.cpp +++ b/app/common/ocioutils.cpp @@ -44,16 +44,4 @@ OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format for return OCIO::BIT_DEPTH_UNKNOWN; } -OCIO::GradingRGBM OCIOUtils::QVec4ToRGBM(const QVector4D &vector) -{ - OCIO::GradingRGBM rgbm; - - rgbm.m_red = vector.x(); - rgbm.m_green = vector.y(); - rgbm.m_blue = vector.z(); - rgbm.m_master = vector.w(); - - return rgbm; -} - } diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 545231b10..38df3f773 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -35,7 +35,6 @@ class OCIOUtils public: static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); - static OCIO::GradingRGBM QVec4ToRGBM(const QVector4D &vector); }; } From 75a327593605146a5f87bac121984bce69c01450 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 11:49:49 -0700 Subject: [PATCH 68/96] ociogradingtransformlinear: reorder sliders Most people will probably want master controls, so it makes sense to have them first, particularly since we aren't using GradingRGBMs anymore --- .../ociogradingtransformlinear.cpp | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index ce229a6cc..72674af85 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -157,27 +157,40 @@ void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const Node job.InsertValue(value); + const int MASTER_CHANNEL = 0; + const int RED_CHANNEL = 1; + const int GREEN_CHANNEL = 2; + const int BLUE_CHANNEL = 3; + // Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU. // Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API. // Therefore, this code has been duplicated from OCIO here: // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157 QVector4D offset = value[kOffsetInput].value(); - offset[0] = offset[3] + offset[0]; - offset[1] = offset[3] + offset[1]; - offset[2] = offset[3] + offset[2]; - job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, offset.toVector3D())); + offset[RED_CHANNEL] += offset[MASTER_CHANNEL]; + offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL]; + offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL]; + job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); QVector4D exposure = value[kExposureInput].value(); - exposure[0] = std::pow(2.0f, static_cast(exposure[3] + exposure[0])); - exposure[1] = std::pow(2.0f, static_cast(exposure[3] + exposure[1])); - exposure[2] = std::pow(2.0f, static_cast(exposure[3] + exposure[2])); - job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, exposure.toVector3D())); + exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]); + exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]); + exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]); + job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); QVector4D contrast = value[kContrastInput].value(); - contrast[0] = static_cast(contrast[3] * contrast[0]); - contrast[1] = static_cast(contrast[3] * contrast[1]); - contrast[2] = static_cast(contrast[3] * contrast[2]); - job.InsertValue(kContrastInput, NodeValue(NodeValue::kVec3, contrast.toVector3D())); + contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL]; + contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL]; + contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL]; + job.InsertValue(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); + + if (!value[kClampBlackEnableInput].data().toBool()) { + job.InsertValue(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); + } + + if (!value[kClampWhiteEnableInput].data().toBool()) { + job.InsertValue(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); + } table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } @@ -190,10 +203,10 @@ void OCIOGradingTransformLinearNode::ConfigChanged() void OCIOGradingTransformLinearNode::SetVec4InputColors(const QString &input) { - SetInputProperty(input, QStringLiteral("color0"), QColor(255, 0, 0).name()); - SetInputProperty(input, QStringLiteral("color1"), QColor(0, 255, 0).name()); - SetInputProperty(input, QStringLiteral("color2"), QColor(0, 0, 255).name()); - SetInputProperty(input, QStringLiteral("color3"), QColor(192, 192, 192).name()); + SetInputProperty(input, QStringLiteral("color0"), QColor(192, 192, 192).name()); + SetInputProperty(input, QStringLiteral("color1"), QColor(255, 0, 0).name()); + SetInputProperty(input, QStringLiteral("color2"), QColor(0, 255, 0).name()); + SetInputProperty(input, QStringLiteral("color3"), QColor(0, 0, 255).name()); } } From accdbe8dfb4d4715a8b75a4600dec2c7c4db3d63 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 11:50:40 -0700 Subject: [PATCH 69/96] ociogradingtransformlinear: disable limits Unfortunately I realized these will break if the input they are using are keyframed or connected in any way. At some point we may implement something to get around that, but currently there is nothing so they are temporarily disabled --- .../ociogradingtransformlinear.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 72674af85..7a8bc1c74 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -75,7 +75,11 @@ OCIOGradingTransformLinearNode::OCIOGradingTransformLinearNode() AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0); SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool()); SetInputProperty(kClampWhiteInput, QStringLiteral("base"), 0.01); - SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); + + // FIXME: Temporarily disabled. This will break if "clamp black" is keyframed or connected to + // something and there's currently no solution to remedy that. If there is in the future, + // we can look into re-enabling this. + //SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); } QString OCIOGradingTransformLinearNode::Name() const @@ -118,15 +122,17 @@ void OCIOGradingTransformLinearNode::Retranslate() void OCIOGradingTransformLinearNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); + if (input == kClampWhiteEnableInput) { SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool()); - } - if (input == kClampBlackEnableInput) { + } else if (input == kClampBlackEnableInput) { SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool()); - } - if (input == kClampBlackInput) { + } else if (input == kClampBlackInput) { // Ensure the white clamp is always greater than the black clamp as per OCIO::GradingPrimary::validate - SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); + // FIXME: Temporarily disabled. This will break if "clamp black" is keyframed or connected to + // something and there's currently no solution to remedy that. If there is in the future, + // we can look into re-enabling this. + //SetInputProperty(kClampWhiteInput, QStringLiteral("min"), GetStandardValue(kClampBlackInput).toDouble() + 0.000001); } GenerateProcessor(); From 71a7b3d12864598bb287b4a8c06bcfac56fa9062 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 11:56:52 -0700 Subject: [PATCH 70/96] chromakey: temporarily disable limits --- app/node/keying/chromakey/chromakey.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 7cd573e0d..18910e886 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -40,9 +40,13 @@ ChromaKeyNode::ChromaKeyNode() SetInputProperty(kLowerToleranceInput, QStringLiteral("base"), 0.1); AddInput(kUpperToleranceInput, NodeValue::kFloat, 25.0); - SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); SetInputProperty(kUpperToleranceInput, QStringLiteral("base"), 0.1); + // FIXME: Temporarily disabled. This will break if "lower tolerance" is keyframed or connected to + // something and there's currently no solution to remedy that. If there is in the future, + // we can look into re-enabling this. + //SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); + AddInput(kGarbageMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); AddInput(kCoreMatteInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); @@ -96,7 +100,10 @@ void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element) { Q_UNUSED(element); if (input == kLowerToleranceInput) { - SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); + // FIXME: Temporarily disabled. This will break if "lower tolerance" is keyframed or connected to + // something and there's currently no solution to remedy that. If there is in the future, + // we can look into re-enabling this. + //SetInputProperty(kUpperToleranceInput, QStringLiteral("min"), GetStandardValue(kLowerToleranceInput).toDouble()); } GenerateProcessor(); From 30c22690c196bd3888a2c7ff02160b9feae12be8 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 11:56:57 -0700 Subject: [PATCH 71/96] code: minor cleanup --- app/common/ocioutils.h | 3 --- app/node/color/displaytransform/displaytransform.h | 3 +-- .../ociogradingtransformlinear/ociogradingtransformlinear.h | 3 +-- app/node/keying/chromakey/chromakey.h | 3 +-- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index 38df3f773..6fa294de7 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -24,8 +24,6 @@ #include namespace OCIO = OCIO_NAMESPACE; -#include - #include "render/videoparams.h" namespace olive { @@ -34,7 +32,6 @@ class OCIOUtils { public: static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); - }; } diff --git a/app/node/color/displaytransform/displaytransform.h b/app/node/color/displaytransform/displaytransform.h index 9c8dff5ba..ac6be6bef 100644 --- a/app/node/color/displaytransform/displaytransform.h +++ b/app/node/color/displaytransform/displaytransform.h @@ -32,8 +32,7 @@ class DisplayTransformNode : public OCIOBaseNode public: DisplayTransformNode(); - NODE_DEFAULT_DESTRUCTOR(DisplayTransformNode) - NODE_COPY_FUNCTION(DisplayTransformNode) + NODE_DEFAULT_FUNCTIONS(DisplayTransformNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h index fac1a8f78..8e5d59cca 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.h @@ -32,8 +32,7 @@ class OCIOGradingTransformLinearNode : public OCIOBaseNode public: OCIOGradingTransformLinearNode(); - NODE_DEFAULT_DESTRUCTOR(OCIOGradingTransformLinearNode) - NODE_COPY_FUNCTION(OCIOGradingTransformLinearNode) + NODE_DEFAULT_FUNCTIONS(OCIOGradingTransformLinearNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/keying/chromakey/chromakey.h b/app/node/keying/chromakey/chromakey.h index 9feadb736..653d31c87 100644 --- a/app/node/keying/chromakey/chromakey.h +++ b/app/node/keying/chromakey/chromakey.h @@ -25,8 +25,7 @@ class ChromaKeyNode : public OCIOBaseNode { public: ChromaKeyNode(); - NODE_DEFAULT_DESTRUCTOR(ChromaKeyNode) - NODE_COPY_FUNCTION(ChromaKeyNode) + NODE_DEFAULT_FUNCTIONS(ChromaKeyNode) virtual QString Name() const override; virtual QString id() const override; From f424c341251f7a03eeef480160f0e95fc1ead995 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 12:13:19 -0700 Subject: [PATCH 72/96] matrixgenerator: update property --- app/node/generator/matrix/matrix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 475aca566..0d5184335 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -44,7 +44,7 @@ MatrixGenerator::MatrixGenerator() AddInput(kScaleInput, NodeValue::kVec2, QVector2D(1.0f, 1.0f)); SetInputProperty(kScaleInput, QStringLiteral("min"), QVector2D(0, 0)); SetInputProperty(kScaleInput, QStringLiteral("view"), FloatSlider::kPercentage); - SetInputProperty(kScaleInput, QStringLiteral("disabley"), true); + SetInputProperty(kScaleInput, QStringLiteral("disable1"), true); AddInput(kUniformScaleInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); From dc1b79c49524c091e26c6b70a7fd48556ff7bbff Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 14:45:04 -0700 Subject: [PATCH 73/96] block: set flags --- app/node/block/block.cpp | 2 ++ app/node/block/subtitle/subtitle.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 68ee09863..c505a80a2 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -45,6 +45,8 @@ Block::Block() : SetInputProperty(kLengthInput, QStringLiteral("viewlock"), true); IgnoreHashingFrom(kLengthInput); + SetInputFlags(kEnabledInput, InputFlags(GetInputFlags(kEnabledInput) | kInputFlagNotConnectable | kInputFlagNotKeyframable)); + SetFlags(kDontShowInParamView); } diff --git a/app/node/block/subtitle/subtitle.cpp b/app/node/block/subtitle/subtitle.cpp index 24b628178..6231fc7d2 100644 --- a/app/node/block/subtitle/subtitle.cpp +++ b/app/node/block/subtitle/subtitle.cpp @@ -30,6 +30,13 @@ SubtitleBlock::SubtitleBlock() { AddInput(kTextIn, NodeValue::kText, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + SetInputFlags(kBufferIn, InputFlags(GetInputFlags(kBufferIn) | kInputFlagHidden)); + SetInputFlags(kLengthInput, InputFlags(GetInputFlags(kLengthInput) | kInputFlagHidden)); + SetInputFlags(kMediaInInput, InputFlags(GetInputFlags(kMediaInInput) | kInputFlagHidden)); + SetInputFlags(kSpeedInput, InputFlags(GetInputFlags(kSpeedInput) | kInputFlagHidden)); + SetInputFlags(kReverseInput, InputFlags(GetInputFlags(kReverseInput) | kInputFlagHidden)); + SetInputFlags(kMaintainAudioPitchInput, InputFlags(GetInputFlags(kMaintainAudioPitchInput) | kInputFlagHidden)); + // Undo block flag that hides in param view SetFlags(GetFlags() & ~kDontShowInParamView); } From 197f94f8d6632ad2eb4a432b154fd45e72a0d861 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 14:45:24 -0700 Subject: [PATCH 74/96] rendertask: ignore disabled subtitle blocks --- app/task/render/render.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index bb7c99a17..56e9975a2 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -165,9 +165,11 @@ bool RenderTask::Render(ColorManager* manager, Block *this_block = this_track->Blocks().at(block_indexes.at(tracks_to_push.at(i))); if (const SubtitleBlock *sub = dynamic_cast(this_block)) { - if (!EncodeSubtitle(sub)) { - result = false; - break; + if (sub->is_enabled()) { + if (!EncodeSubtitle(sub)) { + result = false; + break; + } } } From bdb917c591c89cf6e0998f39ac00a1ce7fc25f1e Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 14:45:43 -0700 Subject: [PATCH 75/96] subtitles: implemented very basic renderer --- app/common/qtutils.cpp | 36 ++++++++++++ app/common/qtutils.h | 2 + app/node/project/sequence/sequence.cpp | 9 +++ app/node/project/sequence/sequence.h | 4 ++ app/widget/viewer/viewer.cpp | 8 +++ app/widget/viewer/viewerdisplay.cpp | 79 +++++++++++++++++++++++++- app/widget/viewer/viewerdisplay.h | 12 +++- 7 files changed, 146 insertions(+), 4 deletions(-) diff --git a/app/common/qtutils.cpp b/app/common/qtutils.cpp index f4f363880..560566029 100644 --- a/app/common/qtutils.cpp +++ b/app/common/qtutils.cpp @@ -79,4 +79,40 @@ QString QtUtils::GetFormattedDateTime(const QDateTime &dt) return dt.toString(Qt::TextDate); } +QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width) +{ + QStringList list; + + QStringList lines = s.split('\n'); + + // Iterate every line + for (int i=0; i 1 && QFontMetricsWidth(fm, this_line) >= bounding_width) { + for (int j=this_line.size()-1; j>=0; j--) { + if (this_line.at(j).isSpace()) { + QString chopped = this_line.left(j); + if (QFontMetricsWidth(fm, chopped) < bounding_width) { + list.append(chopped); + + int k = j+1; + while (k < this_line.size() && this_line.at(k).isSpace()) { + k++; + } + this_line.remove(0, k); + break; + } + } + } + } + + if (!this_line.isEmpty()) { + list.append(this_line); + } + } + + return list; +} + } diff --git a/app/common/qtutils.h b/app/common/qtutils.h index 45321c76b..2c5f6b652 100644 --- a/app/common/qtutils.h +++ b/app/common/qtutils.h @@ -62,6 +62,8 @@ public: static QString GetFormattedDateTime(const QDateTime &dt); + static QStringList WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width); + }; } diff --git a/app/node/project/sequence/sequence.cpp b/app/node/project/sequence/sequence.cpp index 0cb443188..8829089dd 100644 --- a/app/node/project/sequence/sequence.cpp +++ b/app/node/project/sequence/sequence.cpp @@ -118,6 +118,15 @@ void Sequence::Retranslate() } } +void Sequence::InvalidateCache(const TimeRange &range, const QString &from, int element, InvalidateCacheOptions options) +{ + if (from == kTrackInputFormat.arg(Track::kSubtitle)) { + emit SubtitlesChanged(range); + } + + super::InvalidateCache(range, from, element, options); +} + rational Sequence::VerifyLengthInternal(Track::Type type) const { if (!track_lists_.isEmpty()) { diff --git a/app/node/project/sequence/sequence.h b/app/node/project/sequence/sequence.h index 40cc9f4d6..d07a89c4f 100644 --- a/app/node/project/sequence/sequence.h +++ b/app/node/project/sequence/sequence.h @@ -84,6 +84,8 @@ public: virtual void Retranslate() override; + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override; + static const QString kTrackInputFormat; virtual bool IsItem() const override @@ -102,6 +104,8 @@ signals: void TrackAdded(Track* track); void TrackRemoved(Track* track); + void SubtitlesChanged(const TimeRange &range); + private: QVector track_lists_; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 92b92eead..1568f3237 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -275,6 +275,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n) void ViewerWidget::ConnectedNodeChangeEvent(ViewerOutput *n) { auto_cacher_.SetViewerNode(n); + display_widget_->SetSubtitleTracks(dynamic_cast(n)); } void ViewerWidget::ScaleChangedEvent(const double &s) @@ -1189,6 +1190,13 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) connect(show_fps_action, &QAction::triggered, display_widget_, &ViewerDisplayWidget::SetShowFPS); } + if (context_menu_widget_ == display_widget_) { + QAction* show_subtitles_action = menu.addAction(tr("Show Subtitles")); + show_subtitles_action->setCheckable(true); + show_subtitles_action->setChecked(display_widget_->GetShowSubtitles()); + connect(show_subtitles_action, &QAction::triggered, display_widget_, &ViewerDisplayWidget::SetShowSubtitles); + } + menu.exec(static_cast(sender())->mapToGlobal(pos)); } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 2d6d0513e..6000e7f0d 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -37,8 +37,10 @@ #include "common/define.h" #include "common/functiontimer.h" #include "common/html.h" +#include "common/qtutils.h" #include "config/config.h" #include "core.h" +#include "node/block/subtitle/subtitle.h" #include "node/gizmo/path.h" #include "node/gizmo/point.h" #include "node/gizmo/polygon.h" @@ -59,6 +61,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : gizmos_(nullptr), current_gizmo_(nullptr), gizmo_drag_started_(false), + show_subtitles_(true), + subtitle_tracks_(nullptr), hand_dragging_(false), deinterlace_(false), show_fps_(false), @@ -189,6 +193,21 @@ void ViewerDisplayWidget::SetTime(const rational &time) } } +void ViewerDisplayWidget::SetSubtitleTracks(Sequence *list) +{ + if (subtitle_tracks_) { + disconnect(subtitle_tracks_, &Sequence::SubtitlesChanged, this, &ViewerDisplayWidget::SubtitlesChanged); + } + + subtitle_tracks_ = list; + + if (subtitle_tracks_) { + connect(subtitle_tracks_, &Sequence::SubtitlesChanged, this, &ViewerDisplayWidget::SubtitlesChanged); + } + + update(); +} + QPointF ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(const QPointF &pos) { /* @@ -582,6 +601,53 @@ void ViewerDisplayWidget::OnPaint() } } } + + // Extraordinarily basic subtitle renderer. Hoping to swap this out with libass at some point. + if (show_subtitles_ && subtitle_tracks_) { + const QVector &subtitle_tracklist = subtitle_tracks_->track_list(Track::kSubtitle)->GetTracks(); + + if (!subtitle_tracklist.empty()) { + QPainter p(inner_widget()); + + QTransform transform = GenerateWorldTransform(); + QRect bounding_box = transform.mapRect(rect()); + + bounding_box.adjust(bounding_box.width()/10, bounding_box.height()/10, -bounding_box.width()/10, -bounding_box.height()/10); + + QFont f = p.font(); + int font_sz = bounding_box.height() / 18; + f.setStyleHint(QFont::SansSerif); + f.setFamily(f.defaultFamily()); + f.setPointSize(font_sz); + f.setWeight(QFont::Bold); + p.setFont(f); + p.setPen(Qt::white); + + QPainterPath path; + + int text_line = 1; + + for (int j=subtitle_tracklist.size()-1; j>=0; j--) { + Track *sub_track = subtitle_tracklist.at(j); + if (!sub_track->IsMuted()) { + if (SubtitleBlock *sub = dynamic_cast(sub_track->BlockAtTime(time_))) { + // Split into lines + QStringList list = QtUtils::WordWrapString(sub->GetText(), p.fontMetrics(), bounding_box.width()); + + for (int i=list.size()-1; i>=0; i--) { + int w = QtUtils::QFontMetricsWidth(p.fontMetrics(), list.at(i)); + path.addText(bounding_box.x() + bounding_box.width()/2 - w/2, bounding_box.y() + bounding_box.height() - p.fontMetrics().height() * text_line + p.fontMetrics().ascent(), p.font(), list.at(i)); + text_line++; + } + } + } + } + + p.setPen(QPen(Qt::black, font_sz / 16)); + p.setBrush(Qt::white); + p.drawPath(path); + } + } } void ViewerDisplayWidget::OnDestroy() @@ -618,12 +684,12 @@ QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y y / gizmo_params_.height()); } -void ViewerDisplayWidget::DrawTextWithCrudeShadow(QPainter *painter, const QRect &rect, const QString &text) +void ViewerDisplayWidget::DrawTextWithCrudeShadow(QPainter *painter, const QRect &rect, const QString &text, const QTextOption &opt) { painter->setPen(Qt::black); - painter->drawText(rect.adjusted(1, 1, 0, 0), text); + painter->drawText(rect.adjusted(1, 1, 0, 0), text, opt); painter->setPen(Qt::white); - painter->drawText(rect, text); + painter->drawText(rect, text, opt); } rational ViewerDisplayWidget::GetGizmoTime() @@ -807,4 +873,11 @@ void ViewerDisplayWidget::TextEditChanged() gizmo->UpdateInputHtml(html, GetGizmoTime()); } +void ViewerDisplayWidget::SubtitlesChanged(const TimeRange &r) +{ + if (time_ >= r.in() && time_ < r.out()) { + update(); + } +} + } diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 718fd3070..1ccc5b3d1 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -26,6 +26,7 @@ #include "node/color/colormanager/colormanager.h" #include "node/node.h" +#include "node/output/track/tracklist.h" #include "render/color.h" #include "tool/tool.h" #include "viewerplaybacktimer.h" @@ -72,6 +73,7 @@ public: void SetGizmos(Node* node); void SetVideoParams(const VideoParams ¶ms); void SetTime(const rational& time); + void SetSubtitleTracks(Sequence *list); void SetShowWidgetBackground(bool e) { @@ -97,6 +99,9 @@ public: return show_fps_; } + bool GetShowSubtitles() const { return show_subtitles_; } + void SetShowSubtitles(bool e) { show_subtitles_ = e; update(); } + void IncrementSkippedFrames(); void IncrementFrameCount() @@ -239,7 +244,7 @@ private: QPointF GetTexturePosition(const QSize& size); QPointF GetTexturePosition(const double& x, const double& y); - static void DrawTextWithCrudeShadow(QPainter* painter, const QRect& rect, const QString& text); + static void DrawTextWithCrudeShadow(QPainter* painter, const QRect& rect, const QString& text, const QTextOption &opt = QTextOption()); rational GetGizmoTime(); @@ -312,6 +317,9 @@ private: NodeGizmo *current_gizmo_; bool gizmo_drag_started_; + bool show_subtitles_; + Sequence *subtitle_tracks_; + rational time_; /** @@ -365,6 +373,8 @@ private slots: void TextEditChanged(); + void SubtitlesChanged(const TimeRange &r); + }; } From f910117a5880dbad1b50f00d0d800361d0ca5234 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 16:53:04 -0700 Subject: [PATCH 76/96] blur: implement radial and directional blur methods --- app/node/filter/blur/blur.cpp | 119 ++++++++++++++++-- app/node/filter/blur/blur.h | 30 +++++ app/node/gizmo/gizmo.cpp | 3 +- app/node/gizmo/gizmo.h | 5 + app/node/node.cpp | 1 + app/node/node.h | 2 + app/shaders/blur.frag | 90 ++++++++++--- .../nodeparamview/nodeparamviewitem.cpp | 30 ++++- app/widget/nodeparamview/nodeparamviewitem.h | 8 ++ app/widget/viewer/viewerdisplay.cpp | 34 ++--- 10 files changed, 270 insertions(+), 52 deletions(-) diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 123443aea..de9bcbaf9 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -29,25 +29,50 @@ const QString BlurFilterNode::kHorizInput = QStringLiteral("horiz_in"); const QString BlurFilterNode::kVertInput = QStringLiteral("vert_in"); const QString BlurFilterNode::kRepeatEdgePixelsInput = QStringLiteral("repeat_edge_pixels_in"); +const QString BlurFilterNode::kDirectionalDegreesInput = QStringLiteral("directional_degrees_in"); + +const QString BlurFilterNode::kRadialCenterInput = QStringLiteral("radial_center_in"); + #define super Node BlurFilterNode::BlurFilterNode() { AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); - AddInput(kMethodInput, NodeValue::kCombo, 1); // Default to gaussian + Method default_method = kGaussian; + + AddInput(kMethodInput, NodeValue::kCombo, default_method, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable)); AddInput(kRadiusInput, NodeValue::kFloat, 10.0); SetInputProperty(kRadiusInput, QStringLiteral("min"), 0.0); - AddInput(kHorizInput, NodeValue::kBoolean, true); + { + // Box and gaussian only + AddInput(kHorizInput, NodeValue::kBoolean, true); + AddInput(kVertInput, NodeValue::kBoolean, true); + } - AddInput(kVertInput, NodeValue::kBoolean, true); + { + // Directional only + AddInput(kDirectionalDegreesInput, NodeValue::kFloat, 0.0); + } + + { + // Radial only + AddInput(kRadialCenterInput, NodeValue::kVec2, QVector2D(0, 0)); + } + + UpdateInputs(default_method); AddInput(kRepeatEdgePixelsInput, NodeValue::kBoolean, true); SetFlags(kVideoEffect); SetEffectInput(kTextureInput); + + radial_center_gizmo_ = AddDraggableGizmo(); + radial_center_gizmo_->SetShape(PointGizmo::kAnchorPoint); + radial_center_gizmo_->AddInput(NodeKeyframeTrackReference(NodeInput(this, kRadialCenterInput), 0)); + radial_center_gizmo_->AddInput(NodeKeyframeTrackReference(NodeInput(this, kRadialCenterInput), 1)); } QString BlurFilterNode::Name() const @@ -76,11 +101,14 @@ void BlurFilterNode::Retranslate() SetInputName(kTextureInput, tr("Input")); SetInputName(kMethodInput, tr("Method")); - SetComboBoxStrings(kMethodInput, { tr("Box"), tr("Gaussian") }); + SetComboBoxStrings(kMethodInput, { tr("Box"), tr("Gaussian"), tr("Directional"), tr("Radial") }); SetInputName(kRadiusInput, tr("Radius")); SetInputName(kHorizInput, tr("Horizontal")); SetInputName(kVertInput, tr("Vertical")); SetInputName(kRepeatEdgePixelsInput, tr("Repeat Edge Pixels")); + + SetInputName(kDirectionalDegreesInput, tr("Direction")); + SetInputName(kRadialCenterInput, tr("Center")); } ShaderCode BlurFilterNode::GetShaderCode(const ShaderRequest &request) const @@ -96,25 +124,47 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals job.InsertValue(value); job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + Method method = static_cast(job.GetValue(kMethodInput).data().toInt()); + // If there's no texture, no need to run an operation if (!job.GetValue(kTextureInput).data().isNull()) { - // Check if radius > 0, and both "horiz" and/or "vert" are enabled - if ((job.GetValue(kHorizInput).data().toBool() || job.GetValue(kVertInput).data().toBool()) - && job.GetValue(kRadiusInput).data().toDouble() > 0.0) { + bool can_push_job = true; - // Set iteration count to 2 if we're blurring both horizontally and vertically - if (job.GetValue(kHorizInput).data().toBool() && job.GetValue(kVertInput).data().toBool()) { - job.SetIterations(2, kTextureInput); + // Check if radius is > 0 + if (job.GetValue(kRadiusInput).data().toDouble() > 0.0) { + // Method-specific considerations + switch (method) { + case kBox: + case kGaussian: + { + bool horiz = job.GetValue(kHorizInput).data().toBool(); + bool vert = job.GetValue(kVertInput).data().toBool(); + + if (!horiz && !vert) { + // Disable job if horiz and vert are unchecked + can_push_job = false; + } else if (horiz && vert) { + // Set iteration count to 2 if we're blurring both horizontally and vertically + job.SetIterations(2, kTextureInput); + } + break; } + case kDirectional: + case kRadial: + break; + } + } else { + can_push_job = false; + } + if (can_push_job) { // If we're not repeating pixels, expect an alpha channel to appear if (!job.GetValue(kRepeatEdgePixelsInput).data().toBool()) { job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); } table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); - } else { // If we're not performing the blur job, just push the texture table->Push(job.GetValue(kTextureInput)); @@ -123,4 +173,51 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals } } +void BlurFilterNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) +{ + if (row[kMethodInput].data().toInt() == kRadial) { + const QVector2D &sequence_res = globals.resolution(); + QVector2D sequence_half_res = sequence_res * 0.5; + + radial_center_gizmo_->SetVisible(true); + radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].value().toPointF()); + + SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res); + } else{ + radial_center_gizmo_->SetVisible(false); + } +} + +void BlurFilterNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) +{ + DraggableGizmo *gizmo = static_cast(sender()); + + if (gizmo == radial_center_gizmo_) { + + NodeInputDragger &x_drag = gizmo->GetDraggers()[0]; + NodeInputDragger &y_drag = gizmo->GetDraggers()[1]; + + x_drag.Drag(x_drag.GetStartValue().toDouble() + x); + y_drag.Drag(y_drag.GetStartValue().toDouble() + y); + + } +} + +void BlurFilterNode::InputValueChangedEvent(const QString &input, int element) +{ + if (input == kMethodInput) { + UpdateInputs(GetMethod()); + } + + super::InputValueChangedEvent(input, element); +} + +void BlurFilterNode::UpdateInputs(Method method) +{ + SetInputFlags(kHorizInput, (method == kBox || method == kGaussian) ? InputFlags() : InputFlags(kInputFlagHidden)); + SetInputFlags(kVertInput, (method == kBox || method == kGaussian) ? InputFlags() : InputFlags(kInputFlagHidden)); + SetInputFlags(kDirectionalDegreesInput, (method == kDirectional) ? InputFlags() : InputFlags(kInputFlagHidden)); + SetInputFlags(kRadialCenterInput, (method == kRadial) ? InputFlags() : InputFlags(kInputFlagHidden)); +} + } diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index 5e85dc079..9355dd4c6 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -21,6 +21,7 @@ #ifndef BLURFILTERNODE_H #define BLURFILTERNODE_H +#include "node/gizmo/point.h" #include "node/node.h" namespace olive { @@ -31,6 +32,13 @@ class BlurFilterNode : public Node public: BlurFilterNode(); + enum Method { + kBox, + kGaussian, + kDirectional, + kRadial + }; + NODE_DEFAULT_FUNCTIONS(BlurFilterNode) virtual QString Name() const override; @@ -43,6 +51,13 @@ public: virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; + Method GetMethod() const + { + return static_cast(GetStandardValue(kMethodInput).toInt()); + } + + virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; + static const QString kTextureInput; static const QString kMethodInput; static const QString kRadiusInput; @@ -50,6 +65,21 @@ public: static const QString kVertInput; static const QString kRepeatEdgePixelsInput; + static const QString kDirectionalDegreesInput; + + static const QString kRadialCenterInput; + +protected slots: + virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override; + +protected: + virtual void InputValueChangedEvent(const QString& input, int element) override; + +private: + void UpdateInputs(Method method); + + PointGizmo *radial_center_gizmo_; + }; } diff --git a/app/node/gizmo/gizmo.cpp b/app/node/gizmo/gizmo.cpp index f885a62e9..f69451869 100644 --- a/app/node/gizmo/gizmo.cpp +++ b/app/node/gizmo/gizmo.cpp @@ -22,7 +22,8 @@ namespace olive { -NodeGizmo::NodeGizmo(QObject *parent) +NodeGizmo::NodeGizmo(QObject *parent) : + visible_(true) { setParent(parent); } diff --git a/app/node/gizmo/gizmo.h b/app/node/gizmo/gizmo.h index 5a3e585d2..07c519886 100644 --- a/app/node/gizmo/gizmo.h +++ b/app/node/gizmo/gizmo.h @@ -39,11 +39,16 @@ public: const NodeGlobals &GetGlobals() const { return globals_; } void SetGlobals(const NodeGlobals &globals) { globals_ = globals; } + bool IsVisible() const { return visible_; } + void SetVisible(bool e) { visible_ = e; } + signals: private: NodeGlobals globals_; + bool visible_; + }; } diff --git a/app/node/node.cpp b/app/node/node.cpp index b76f27d83..b2eff40f2 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -917,6 +917,7 @@ void Node::SetInputFlags(const QString &input, const InputFlags &f) if (i) { i->flags = f; + emit InputFlagsChanged(input, i->flags); } else { ReportInvalidInput("set flags of", input); } diff --git a/app/node/node.h b/app/node/node.h index 6125dc01c..8850703ae 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -1168,6 +1168,8 @@ signals: void NodeRemovedFromContext(Node *node); + void InputFlagsChanged(const QString &input, const InputFlags &flags); + private: class ArrayInsertCommand : public UndoCommand { diff --git a/app/shaders/blur.frag b/app/shaders/blur.frag index e0378a4bf..426362813 100644 --- a/app/shaders/blur.frag +++ b/app/shaders/blur.frag @@ -6,6 +6,12 @@ uniform bool vert_in; uniform bool repeat_edge_pixels_in; uniform vec2 resolution_in; +// Directional +uniform float directional_degrees_in; + +// Radial +uniform vec2 radial_center_in; + uniform int ove_iteration; in vec2 ove_texcoord; @@ -17,6 +23,8 @@ out vec4 frag_color; // Methods #define METHOD_BOX_BLUR 0 #define METHOD_GAUSSIAN_BLUR 1 +#define METHOD_DIRECTIONAL_BLUR 2 +#define METHOD_RADIAL_BLUR 3 // Mode #define MODE_NONE 0 @@ -60,6 +68,19 @@ int determine_mode() { } } +vec4 add_to_composite(vec4 composite, vec2 pixel_coord, float weight) +{ + if (repeat_edge_pixels_in + || (pixel_coord.x >= 0.0 + && pixel_coord.x < 1.0 + && pixel_coord.y >= 0.0 + && pixel_coord.y < 1.0)) { + composite += texture(tex_in, pixel_coord) * weight; + } + + return composite; +} + void main(void) { int mode = determine_mode(); @@ -75,7 +96,13 @@ void main(void) { float divider, sigma; - if (method_in == METHOD_BOX_BLUR) { + if (method_in == METHOD_DIRECTIONAL_BLUR || method_in == METHOD_RADIAL_BLUR) { + // Despite similar math, these are lighter methods perceptually, so we double the radius to + // better match box/gaussian + real_radius *= 2.0; + } + + if (method_in == METHOD_BOX_BLUR || method_in == METHOD_DIRECTIONAL_BLUR) { // Calculate the weight of each pixel based on the radius divider = 1.0 / real_radius; @@ -95,28 +122,53 @@ void main(void) { } - for (float i = -real_radius + 0.5; i <= real_radius; i += 2.0) { - float weight; + if (method_in == METHOD_BOX_BLUR || method_in == METHOD_GAUSSIAN_BLUR) { + for (float i = -real_radius + 0.5; i <= real_radius; i += 2.0) { + float weight; - if (method_in == METHOD_BOX_BLUR) { - weight = divider; - } else if (method_in == METHOD_GAUSSIAN_BLUR) { - weight = gaussian2(i, 0.0, sigma) / divider; + if (method_in == METHOD_BOX_BLUR) { + weight = divider; + } else if (method_in == METHOD_GAUSSIAN_BLUR) { + weight = gaussian2(i, 0.0, sigma) / divider; + } + + vec2 pixel_coord = ove_texcoord; + if (mode == MODE_HORIZONTAL) { + pixel_coord.x += i / resolution_in.x; + } else if (mode == MODE_VERTICAL) { + pixel_coord.y += i / resolution_in.y; + } + + composite = add_to_composite(composite, pixel_coord, weight); + } + } else if (method_in == METHOD_DIRECTIONAL_BLUR || method_in == METHOD_RADIAL_BLUR) { + float angle; + + if (method_in == METHOD_DIRECTIONAL_BLUR) { + // Convert directional degrees to radians + angle = (directional_degrees_in*M_PI)/180.0; + } else { + // Calculate angle from distance of center to current coordinate + vec2 distance = (ove_texcoord - 0.5) * (resolution_in) - radial_center_in; + angle = atan(distance.y/distance.x); + + float multiplier = length(distance) / resolution_in.y * 2.0; + + real_radius = ceil(radius_in * multiplier); + divider = 1.0 / real_radius; } - vec2 pixel_coord = ove_texcoord; - if (mode == MODE_HORIZONTAL) { - pixel_coord.x += i / resolution_in.x; - } else if (mode == MODE_VERTICAL) { - pixel_coord.y += i / resolution_in.y; - } + // Get angles + float sin_angle = sin(angle); + float cos_angle = cos(angle); - if (repeat_edge_pixels_in - || (pixel_coord.x >= 0.0 - && pixel_coord.x < 1.0 - && pixel_coord.y >= 0.0 - && pixel_coord.y < 1.0)) { - composite += texture(tex_in, pixel_coord) * weight; + for (float i = -real_radius + 0.5; i <= real_radius; i += 2.0) { + vec2 pixel_coord = ove_texcoord; + + pixel_coord.y += sin_angle * i / resolution_in.y; + pixel_coord.x += cos_angle * i / resolution_in.x; + + composite = add_to_composite(composite, pixel_coord, divider); } } diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index 9a61e0718..9cba6f83c 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -46,21 +46,22 @@ const int NodeParamViewItemBody::kMaxWidgetColumn = kKeyControlColumn; NodeParamViewItem::NodeParamViewItem(Node *node, NodeParamViewCheckBoxBehavior create_checkboxes, QWidget *parent) : super(parent), + body_(nullptr), node_(node), + create_checkboxes_(create_checkboxes), ctx_(nullptr) { node_->Retranslate(); // Create and add contents widget - body_ = new NodeParamViewItemBody(node_, create_checkboxes); - connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode); - connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime); - connect(body_, &NodeParamViewItemBody::ArrayExpandedChanged, this, &NodeParamViewItem::ArrayExpandedChanged); - connect(body_, &NodeParamViewItemBody::InputCheckedChanged, this, &NodeParamViewItem::InputCheckedChanged); - SetBody(body_); + RecreateBody(); connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate); + // FIXME: Implemented to pick up when an input is set to hidden or not - DEFINITELY not a fast + // way of doing this, but "fine" for now. + connect(node_, &Node::InputFlagsChanged, this, &NodeParamViewItem::RecreateBody); + setBackgroundRole(QPalette::Window); // Connect title bar enabled checkbox @@ -80,6 +81,23 @@ void NodeParamViewItem::Retranslate() body_->Retranslate(); } +void NodeParamViewItem::RecreateBody() +{ + QWidget *old_body = body_; + + body_ = new NodeParamViewItemBody(node_, create_checkboxes_); + connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode); + connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime); + connect(body_, &NodeParamViewItemBody::ArrayExpandedChanged, this, &NodeParamViewItem::ArrayExpandedChanged); + connect(body_, &NodeParamViewItemBody::InputCheckedChanged, this, &NodeParamViewItem::InputCheckedChanged); + body_->Retranslate(); + body_->SetTime(time_); + body_->SetTimebase(timebase_); + SetBody(body_); + + old_body->deleteLater(); +} + int NodeParamViewItem::GetElementY(const NodeInput &c) const { if (IsExpanded()) { diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 3db8692a1..1653a5ada 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -179,6 +179,8 @@ public: void SetTimebase(const rational& timebase) { + timebase_ = timebase; + body_->SetTimebase(timebase); } @@ -228,12 +230,18 @@ private: Node* node_; + NodeParamViewCheckBoxBehavior create_checkboxes_; + Node *ctx_; rational time_; + rational timebase_; KeyframeView::NodeConnections keyframe_connections_; +private slots: + void RecreateBody(); + }; } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 6000e7f0d..231bc40cd 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -529,7 +529,9 @@ void ViewerDisplayWidget::OnPaint() gizmos_->UpdateGizmoPositions(gizmo_db_, NodeTraverser::GenerateGlobals(gizmo_params_, range)); foreach (NodeGizmo *gizmo, gizmos_->GetGizmos()) { - gizmo->Draw(&p); + if (gizmo->IsVisible()) { + gizmo->Draw(&p); + } } } @@ -748,21 +750,23 @@ NodeGizmo *ViewerDisplayWidget::TryGizmoPress(const NodeValueRow &row, const QPo { for (auto it=gizmos_->GetGizmos().crbegin(); it!=gizmos_->GetGizmos().crend(); it++) { NodeGizmo *gizmo = *it; - if (PointGizmo *point = dynamic_cast(gizmo)) { - if (point->GetClickingRect(GenerateGizmoTransform()).contains(p)) { - return point; + if (gizmo->IsVisible()) { + if (PointGizmo *point = dynamic_cast(gizmo)) { + if (point->GetClickingRect(GenerateGizmoTransform()).contains(p)) { + return point; + } + } else if (PolygonGizmo *poly = dynamic_cast(gizmo)) { + if (poly->GetPolygon().containsPoint(p, Qt::OddEvenFill)) { + return poly; + } + } else if (PathGizmo *path = dynamic_cast(gizmo)) { + if (path->GetPath().contains(p)) { + return path; + } + } else if (ScreenGizmo *screen = dynamic_cast(gizmo)) { + // NOTE: Perhaps this should limit to the actual visible screen space? We'll see. + return screen; } - } else if (PolygonGizmo *poly = dynamic_cast(gizmo)) { - if (poly->GetPolygon().containsPoint(p, Qt::OddEvenFill)) { - return poly; - } - } else if (PathGizmo *path = dynamic_cast(gizmo)) { - if (path->GetPath().contains(p)) { - return path; - } - } else if (ScreenGizmo *screen = dynamic_cast(gizmo)) { - // NOTE: Perhaps this should limit to the actual visible screen space? We'll see. - return screen; } } From 93e5351d335e119a18ff19223f79a1819e40b0ac Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 16:56:31 -0700 Subject: [PATCH 77/96] nodes: implemented mask node --- app/node/distort/CMakeLists.txt | 1 + app/node/distort/mask/CMakeLists.txt | 22 +++++++ app/node/distort/mask/mask.cpp | 62 +++++++++++++++++ app/node/distort/mask/mask.h | 66 +++++++++++++++++++ .../distort/transform/transformdistortnode.h | 5 -- app/node/factory.cpp | 3 + app/node/factory.h | 1 + app/node/generator/polygon/polygon.cpp | 9 ++- app/node/generator/polygon/polygon.h | 3 + app/shaders/multiply.frag | 11 ++++ 10 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 app/node/distort/mask/CMakeLists.txt create mode 100644 app/node/distort/mask/mask.cpp create mode 100644 app/node/distort/mask/mask.h create mode 100644 app/shaders/multiply.frag diff --git a/app/node/distort/CMakeLists.txt b/app/node/distort/CMakeLists.txt index 375232ccc..de3480361 100644 --- a/app/node/distort/CMakeLists.txt +++ b/app/node/distort/CMakeLists.txt @@ -17,6 +17,7 @@ add_subdirectory(cornerpin) add_subdirectory(crop) add_subdirectory(flip) +add_subdirectory(mask) add_subdirectory(transform) set(OLIVE_SOURCES diff --git a/app/node/distort/mask/CMakeLists.txt b/app/node/distort/mask/CMakeLists.txt new file mode 100644 index 000000000..67ff95dee --- /dev/null +++ b/app/node/distort/mask/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 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/distort/mask/mask.cpp + node/distort/mask/mask.h + PARENT_SCOPE +) diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp new file mode 100644 index 000000000..df0a41cef --- /dev/null +++ b/app/node/distort/mask/mask.cpp @@ -0,0 +1,62 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "mask.h" + +namespace olive { + +#define super PolygonGenerator + +MaskDistortNode::MaskDistortNode() +{ + // Mask should always be (1.0, 1.0, 1.0) for multiply to work correctly + SetInputFlags(kColorInput, InputFlags(GetInputFlags(kColorInput) | kInputFlagHidden)); +} + +ShaderCode MaskDistortNode::GetShaderCode(const ShaderRequest &request) const +{ + Q_UNUSED(request) + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/multiply.frag"))); +} + +void MaskDistortNode::Retranslate() +{ + super::Retranslate(); + + SetInputName(kBaseInput, tr("Texture")); +} + +void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + GenerateJob job = GetGenerateJob(value); + + if (!value[kBaseInput].data().isNull()) { + // Push as merge node + ShaderJob merge; + + merge.SetShaderID(QStringLiteral("mrg")); + merge.InsertValue(QStringLiteral("tex_a"), value[kBaseInput]); + merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, QVariant::fromValue(job), this)); + + table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); + } +} + +} diff --git a/app/node/distort/mask/mask.h b/app/node/distort/mask/mask.h new file mode 100644 index 000000000..d4794ac99 --- /dev/null +++ b/app/node/distort/mask/mask.h @@ -0,0 +1,66 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 MASKDISTORTNODE_H +#define MASKDISTORTNODE_H + +#include "node/generator/polygon/polygon.h" + +namespace olive { + +class MaskDistortNode : public PolygonGenerator +{ + Q_OBJECT +public: + MaskDistortNode(); + + NODE_DEFAULT_FUNCTIONS(MaskDistortNode) + + virtual QString Name() const override + { + return tr("Mask"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.mask"); + } + + virtual QVector Category() const override + { + return {kCategoryDistort}; + } + + virtual QString Description() const override + { + return tr("Apply a polygonal mask."); + } + + virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override; + + virtual void Retranslate() override; + + virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; + +}; + +} + +#endif // MASKDISTORTNODE_H diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h index 9738c7e68..e2ae7eb93 100644 --- a/app/node/distort/transform/transformdistortnode.h +++ b/app/node/distort/transform/transformdistortnode.h @@ -41,11 +41,6 @@ public: return tr("Transform"); } - virtual QString ShortName() const override - { - return Node::ShortName(); - } - virtual QString id() const override { return QStringLiteral("org.olivevideoeditor.Olive.transform"); diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 4292d5037..042ee3175 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -34,6 +34,7 @@ #include "distort/cornerpin/cornerpindistortnode.h" #include "distort/crop/cropdistortnode.h" #include "distort/flip/flipdistortnode.h" +#include "distort/mask/mask.h" #include "distort/transform/transformdistortnode.h" #include "effect/opacity/opacityeffect.h" #include "generator/matrix/matrix.h" @@ -290,6 +291,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) return new OCIOGradingTransformLinearNode(); case kChromaKey: return new ChromaKeyNode(); + case kMaskDistort: + return new MaskDistortNode(); case kInternalNodeCount: break; diff --git a/app/node/factory.h b/app/node/factory.h index 54e417b3e..f9531b1e7 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -73,6 +73,7 @@ public: kDisplayTransform, kOCIOGradingTransformLinear, kChromaKey, + kMaskDistort, // Count value kInternalNodeCount diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index cb294b9ed..65c1c8f58 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -89,7 +89,7 @@ void PolygonGenerator::Retranslate() SetInputName(kColorInput, tr("Color")); } -void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +GenerateJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const { GenerateJob job; @@ -97,6 +97,13 @@ void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globa job.SetRequestedFormat(VideoParams::kFormatFloat32); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); + return job; +} + +void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const +{ + GenerateJob job = GetGenerateJob(value); + PushMergableJob(value, QVariant::fromValue(job), table); } diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index 0b2d98457..7107818df 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -57,6 +57,9 @@ public: static const QString kPointsInput; static const QString kColorInput; +protected: + GenerateJob GetGenerateJob(const NodeValueRow &value) const; + protected slots: virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override; diff --git a/app/shaders/multiply.frag b/app/shaders/multiply.frag new file mode 100644 index 000000000..901a310c3 --- /dev/null +++ b/app/shaders/multiply.frag @@ -0,0 +1,11 @@ +// Input texture +uniform sampler2D tex_a; +uniform sampler2D tex_b; + +// Input texture coordinate +in vec2 ove_texcoord; +out vec4 frag_color; + +void main() { + frag_color = texture(tex_a, ove_texcoord) * texture(tex_b, ove_texcoord); +} From c1ddf0b724c62e660b5c15d08feec66db8a93ae5 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 17:07:34 -0700 Subject: [PATCH 78/96] node: add extra or operators for InputFlag types --- app/node/param.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/node/param.h b/app/node/param.h index da2e12320..4eb000191 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -65,6 +65,19 @@ public: return *this; } + InputFlags operator|(const InputFlag &f) const + { + InputFlags i = *this; + i |= f; + return i; + } + + InputFlags &operator|=(const InputFlag &f) + { + f_ |= f; + return *this; + } + InputFlags operator&(const InputFlags &f) const { InputFlags i = *this; From 53a3cfc9b256e5d0b4aca9b3e55c603571be18eb Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 22:04:49 -0700 Subject: [PATCH 79/96] colordifferencekey: revert values to 1.0 I changed these which made them worse, using the original values with a custom "base" is a much better approach --- app/node/keying/colordifferencekey/colordifferencekey.cpp | 6 ++++-- app/shaders/colordifferencekey.frag | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index 6039c1c03..aaf9b77f0 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -37,11 +37,13 @@ ColorDifferenceKeyNode::ColorDifferenceKeyNode() AddInput(kColorInput, NodeValue::kCombo, 0); - AddInput(kHighlightsInput, NodeValue::kFloat, 100.0f); + AddInput(kHighlightsInput, NodeValue::kFloat, 1.0f); SetInputProperty(kHighlightsInput, QStringLiteral("min"), 0.0); + SetInputProperty(kHighlightsInput, QStringLiteral("base"), 0.01); - AddInput(kShadowsInput, NodeValue::kFloat, 100.0f); + AddInput(kShadowsInput, NodeValue::kFloat, 1.0f); SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0); + SetInputProperty(kShadowsInput, QStringLiteral("base"), 0.01); AddInput(kMaskOnlyInput, NodeValue::kBoolean, false); diff --git a/app/shaders/colordifferencekey.frag b/app/shaders/colordifferencekey.frag index 5ed5fb9ec..e47ee88db 100644 --- a/app/shaders/colordifferencekey.frag +++ b/app/shaders/colordifferencekey.frag @@ -51,7 +51,7 @@ void main(void) { } // Crush blacks and push whites - mask = highlights_in * 0.01 * (shadows_in * 0.01 * mask - 1.0) + 1.0; + mask = highlights_in * (shadows_in * mask - 1.0) + 1.0; mask = clamp(mask, 0.0, 1.0); // Invert mask From c8e2373fbb50a9163b55e348f6ff203a232a58d3 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 8 May 2022 22:29:10 -0700 Subject: [PATCH 80/96] export: increase default h264/5 quality --- app/dialog/export/codec/h264section.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/dialog/export/codec/h264section.h b/app/dialog/export/codec/h264section.h index 78fbef19a..8e095d938 100644 --- a/app/dialog/export/codec/h264section.h +++ b/app/dialog/export/codec/h264section.h @@ -38,8 +38,8 @@ public: int GetValue() const; - static const int kDefaultH264CRF = 23; - static const int kDefaultH265CRF = 28; + static const int kDefaultH264CRF = 18; + static const int kDefaultH265CRF = 23; private: static const int kMinimumCRF = 0; From c25960e5afcb0124d73f4aa3556d1d4b2e396dda Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 08:06:35 -0700 Subject: [PATCH 81/96] fixed completely pointless compiler warning Fixes #1921 --- app/widget/nodeview/nodeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 69af099fa..f8af45ca6 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -1311,7 +1311,7 @@ void NodeView::UngroupNodes() return; } - NodeGroup *group; + NodeGroup *group = nullptr; foreach (NodeViewItem *i, items) { if ((group = dynamic_cast(i->GetNode()))) { group_item = i; From 13aedfa29456162443dd2757fe75bac47319e745 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 08:44:36 -0700 Subject: [PATCH 82/96] nodes: use flag instead of hidden array in factory --- app/node/factory.cpp | 9 ++------- app/node/factory.h | 2 -- app/node/generator/text/textv1.cpp | 2 ++ app/node/generator/text/textv2.cpp | 2 ++ app/node/group/group.cpp | 1 + app/node/node.h | 3 ++- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/node/factory.cpp b/app/node/factory.cpp index 042ee3175..6e60b1ccb 100644 --- a/app/node/factory.cpp +++ b/app/node/factory.cpp @@ -65,8 +65,8 @@ #include "time/timeremap/timeremap.h" namespace olive { + QList NodeFactory::library_; -QVector NodeFactory::hidden_; void NodeFactory::Initialize() { @@ -78,10 +78,6 @@ void NodeFactory::Initialize() library_.append(created_node); } - - hidden_.append(kTextGeneratorV1); - hidden_.append(kTextGeneratorV2); - hidden_.append(kGroupNode); } void NodeFactory::Destroy() @@ -107,8 +103,7 @@ Menu *NodeFactory::CreateMenu(QWidget* parent, bool create_none_item, Node::Cate continue; } - if (hidden_.contains(i)) { - // Skip this node + if (n->GetFlags() & Node::kDontShowInCreateMenu) { continue; } diff --git a/app/node/factory.h b/app/node/factory.h index f9531b1e7..05bde90f4 100644 --- a/app/node/factory.h +++ b/app/node/factory.h @@ -100,8 +100,6 @@ public: private: static QList library_; - static QVector hidden_; - }; } diff --git a/app/node/generator/text/textv1.cpp b/app/node/generator/text/textv1.cpp index 9a850d4d4..516c7bd31 100644 --- a/app/node/generator/text/textv1.cpp +++ b/app/node/generator/text/textv1.cpp @@ -53,6 +53,8 @@ TextGeneratorV1::TextGeneratorV1() AddInput(kFontInput, NodeValue::kFont); AddInput(kFontSizeInput, NodeValue::kFloat, 72.0f); + + SetFlags(kDontShowInCreateMenu); } QString TextGeneratorV1::Name() const diff --git a/app/node/generator/text/textv2.cpp b/app/node/generator/text/textv2.cpp index 12eb94b06..788f80bbd 100644 --- a/app/node/generator/text/textv2.cpp +++ b/app/node/generator/text/textv2.cpp @@ -57,6 +57,8 @@ TextGeneratorV2::TextGeneratorV2() SetStandardValue(kColorInput, QVariant::fromValue(Color(1.0f, 1.0f, 1.0))); SetStandardValue(kSizeInput, QVector2D(400, 300)); + + SetFlags(kDontShowInCreateMenu); } QString TextGeneratorV2::Name() const diff --git a/app/node/group/group.cpp b/app/node/group/group.cpp index a3089478d..9c7fe1c6b 100644 --- a/app/node/group/group.cpp +++ b/app/node/group/group.cpp @@ -29,6 +29,7 @@ namespace olive { NodeGroup::NodeGroup() : output_passthrough_(nullptr) { + SetFlags(kDontShowInCreateMenu); } QString NodeGroup::Name() const diff --git a/app/node/node.h b/app/node/node.h index 8850703ae..949cd6890 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -101,7 +101,8 @@ public: kNone = 0, kDontShowInParamView = 0x1, kVideoEffect = 0x2, - kAudioEffect = 0x4 + kAudioEffect = 0x4, + kDontShowInCreateMenu = 0x8 }; struct ContextPair { From 839f63d78fde46eee660ce3f7e2c23f959109fb4 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 10:07:45 -0700 Subject: [PATCH 83/96] color: minor refactor --- app/render/color.cpp | 104 +++++++++++++++++++------------------------ app/render/color.h | 103 +++++++++++++++++++++++++++++------------- 2 files changed, 119 insertions(+), 88 deletions(-) diff --git a/app/render/color.cpp b/app/render/color.cpp index bbf9a9601..ea00896d4 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -27,12 +27,12 @@ namespace olive { -Color Color::fromHsv(const float &h, const float &s, const float &v) +Color Color::fromHsv(const DataType &h, const DataType &s, const DataType &v) { - float C = s * v; - float X = C * (1.0 - abs(fmod(h / 60.0, 2.0) - 1.0)); - float m = v - C; - float Rs, Gs, Bs; + DataType C = s * v; + DataType X = C * (1.0 - abs(fmod(h / 60.0, 2.0) - 1.0)); + DataType m = v - C; + DataType Rs, Gs, Bs; if(h >= 0.0 && h < 60.0) { Rs = C; @@ -81,11 +81,11 @@ Color::Color(const QColor &c) set_alpha(c.alphaF()); } -void Color::toHsv(float *hue, float *sat, float *val) const +void Color::toHsv(DataType *hue, DataType *sat, DataType *val) const { - float fCMax = qMax(qMax(red(), green()), blue()); - float fCMin = qMin(qMin(red(), green()), blue()); - float fDelta = fCMax - fCMin; + DataType fCMax = qMax(qMax(red(), green()), blue()); + DataType fCMin = qMin(qMin(red(), green()), blue()); + DataType fDelta = fCMax - fCMin; if(fDelta > 0) { if(fCMax == red()) { @@ -114,31 +114,31 @@ void Color::toHsv(float *hue, float *sat, float *val) const } } -float Color::hsv_hue() const +Color::DataType Color::hsv_hue() const { - float h, s, v; + DataType h, s, v; toHsv(&h, &s, &v); return h; } -float Color::hsv_saturation() const +Color::DataType Color::hsv_saturation() const { - float h, s, v; + DataType h, s, v; toHsv(&h, &s, &v); return s; } -float Color::value() const +Color::DataType Color::value() const { - float h, s, v; + DataType h, s, v; toHsv(&h, &s, &v); return v; } -void Color::toHsl(float *hue, float *sat, float *lightness) const +void Color::toHsl(DataType *hue, DataType *sat, DataType *lightness) const { - float fCMin = qMin(red(), qMin(green(), blue())); - float fCMax = qMax(red(), qMax(green(), blue())); + DataType fCMin = qMin(red(), qMin(green(), blue())); + DataType fCMax = qMax(red(), qMax(green(), blue())); *lightness = 0.5 * (fCMin + fCMax); @@ -176,23 +176,23 @@ void Color::toHsl(float *hue, float *sat, float *lightness) const } } -float Color::hsl_hue() const +Color::DataType Color::hsl_hue() const { - float h, s, l; + DataType h, s, l; toHsl(&h, &s, &l); return h; } -float Color::hsl_saturation() const +Color::DataType Color::hsl_saturation() const { - float h, s, l; + DataType h, s, l; toHsl(&h, &s, &l); return s; } -float Color::lightness() const +Color::DataType Color::lightness() const { - float h, s, l; + DataType h, s, l; toHsl(&h, &s, &l); return l; } @@ -232,12 +232,12 @@ QColor Color::toQColor() const return c; } -float Color::GetRoughLuminance() const +Color::DataType Color::GetRoughLuminance() const { return (2*red()+blue()+3*green())/6.0; } -const Color &Color::operator+=(const Color &rhs) +Color &Color::operator+=(const Color &rhs) { for (int i=0;i Date: Mon, 9 May 2022 13:07:34 -0700 Subject: [PATCH 84/96] nodevalue: begin abstracting qvariant --- app/node/audio/pan/pan.cpp | 4 +- app/node/block/transition/transition.cpp | 4 +- app/node/color/ociobase/ociobase.cpp | 4 +- .../ociogradingtransformlinear.cpp | 14 ++-- .../cornerpin/cornerpindistortnode.cpp | 47 ++++++------ app/node/distort/crop/cropdistortnode.cpp | 20 ++--- app/node/distort/flip/flipdistortnode.cpp | 4 +- app/node/distort/mask/mask.cpp | 2 +- .../transform/transformdistortnode.cpp | 22 +++--- app/node/effect/opacity/opacityeffect.cpp | 4 +- app/node/filter/blur/blur.cpp | 16 ++-- app/node/filter/mosaic/mosaicfilternode.cpp | 8 +- app/node/filter/stroke/stroke.cpp | 6 +- app/node/generator/matrix/matrix.cpp | 26 +++---- app/node/generator/polygon/polygon.cpp | 14 ++-- .../generator/shape/generatorwithmerge.cpp | 2 +- app/node/generator/shape/shapenodebase.cpp | 4 +- app/node/generator/text/textv1.cpp | 14 ++-- app/node/generator/text/textv2.cpp | 18 ++--- app/node/generator/text/textv3.cpp | 12 +-- app/node/hashtraverser.cpp | 4 +- app/node/keying/chromakey/chromakey.cpp | 4 +- .../colordifferencekey/colordifferencekey.cpp | 2 +- app/node/keying/despill/despill.cpp | 2 +- app/node/math/math/mathbase.cpp | 34 ++++----- app/node/math/merge/merge.cpp | 8 +- app/node/math/trigonometry/trigonometry.cpp | 2 +- app/node/project/footage/footage.cpp | 4 +- app/node/traverser.cpp | 39 +++++----- app/node/value.cpp | 4 +- app/node/value.h | 73 +++++++++++-------- app/render/job/samplejob.h | 4 +- app/render/opengl/openglrenderer.cpp | 22 +++--- app/render/renderprocessor.cpp | 13 ++-- app/widget/nodetableview/nodetableview.cpp | 2 +- app/widget/nodevaluetree/nodevaluetree.cpp | 2 +- 36 files changed, 235 insertions(+), 229 deletions(-) diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index c6311e67a..10661f30a 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -76,7 +76,7 @@ void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV if (job.samples()->audio_params().channel_count() == 2) { // If the input is static, we can just do it now which will be faster if (IsInputStatic(kPanningInput)) { - float pan_volume = job.GetValue(kPanningInput).data().toFloat(); + float pan_volume = job.GetValue(kPanningInput).toDouble(); if (!qIsNull(pan_volume)) { if (pan_volume > 0) { job.samples()->transform_volume_for_channel(0, 1.0f - pan_volume); @@ -96,7 +96,7 @@ void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const { - float pan_val = values[kPanningInput].data().toFloat(); + float pan_val = values[kPanningInput].toDouble(); for (int i=0;iaudio_params().channel_count();i++) { output->data(i)[index] = input->data(i)[index]; diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 97f97a31b..9cfaf24c2 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -206,8 +206,8 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global push_job = QVariant::fromValue(job); } else if (data_type == NodeValue::kSamples) { // This must be an audio transition - SampleBufferPtr from_samples = out_buffer.data().value(); - SampleBufferPtr to_samples = in_buffer.data().value(); + SampleBufferPtr from_samples = out_buffer.toSamples(); + SampleBufferPtr to_samples = in_buffer.toSamples(); if (from_samples || to_samples) { double time_in = globals.time().in().toDouble(); diff --git a/app/node/color/ociobase/ociobase.cpp b/app/node/color/ociobase/ociobase.cpp index 22e03f3ba..7ce711050 100644 --- a/app/node/color/ociobase/ociobase.cpp +++ b/app/node/color/ociobase/ociobase.cpp @@ -56,11 +56,11 @@ void OCIOBaseNode::ParentChanged(NodeGraph *graph) void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (!value[kTextureInput].data().isNull() && processor_) { + if (value[kTextureInput].toTexture() && processor_) { ColorTransformJob job; job.SetColorProcessor(processor_); - job.SetInputTexture(value[kTextureInput].data().value()); + job.SetInputTexture(value[kTextureInput].toTexture()); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index 7a8bc1c74..ba2ab8e1c 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -155,11 +155,11 @@ void OCIOGradingTransformLinearNode::GenerateProcessor() void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (!value[kTextureInput].data().isNull() && processor()) { + if (value[kTextureInput].toTexture() && processor()) { ColorTransformJob job; job.SetColorProcessor(processor()); - job.SetInputTexture(value[kTextureInput].data().value()); + job.SetInputTexture(value[kTextureInput].toTexture()); job.InsertValue(value); @@ -172,29 +172,29 @@ void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const Node // Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API. // Therefore, this code has been duplicated from OCIO here: // https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157 - QVector4D offset = value[kOffsetInput].value(); + QVector4D offset = value[kOffsetInput].toVec4(); offset[RED_CHANNEL] += offset[MASTER_CHANNEL]; offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL]; offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL]; job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); - QVector4D exposure = value[kExposureInput].value(); + QVector4D exposure = value[kExposureInput].toVec4(); exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]); exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]); exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]); job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); - QVector4D contrast = value[kContrastInput].value(); + QVector4D contrast = value[kContrastInput].toVec4(); contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL]; contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL]; contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL]; job.InsertValue(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); - if (!value[kClampBlackEnableInput].data().toBool()) { + if (!value[kClampBlackEnableInput].toBool()) { job.InsertValue(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); } - if (!value[kClampWhiteEnableInput].data().toBool()) { + if (!value[kClampWhiteEnableInput].toBool()) { job.InsertValue(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); } diff --git a/app/node/distort/cornerpin/cornerpindistortnode.cpp b/app/node/distort/cornerpin/cornerpindistortnode.cpp index aa3d0e97d..f7500505b 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.cpp +++ b/app/node/distort/cornerpin/cornerpindistortnode.cpp @@ -94,16 +94,16 @@ void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g job.SetVertexCoordinates(adjusted_vertices); // If no texture do nothing - if (!job.GetValue(kTextureInput).data().isNull()) { + if (job.GetValue(kTextureInput).toTexture()) { // In the special case that all sliders are in their default position just // push the texture. - if (!(job.GetValue(kTopLeftInput).data().value().isNull() - && job.GetValue(kTopRightInput).data().value().isNull() && - job.GetValue(kBottomRightInput).data().value().isNull() && - job.GetValue(kBottomLeftInput).data().value().isNull())) { + if (!(job.GetValue(kTopLeftInput).toVec2().isNull() + && job.GetValue(kTopRightInput).toVec2().isNull() && + job.GetValue(kBottomRightInput).toVec2().isNull() && + job.GetValue(kBottomLeftInput).toVec2().isNull())) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(NodeValue::kTexture, job.GetValue(kTextureInput).data(), this); + table->Push(job.GetValue(kTextureInput)); } } } @@ -119,25 +119,24 @@ ShaderCode CornerPinDistortNode::GetShaderCode(const ShaderRequest &request) con QPointF CornerPinDistortNode::ValueToPixel(int value, const NodeValueRow& row, const QVector2D &resolution) const { Q_ASSERT(value >= 0 && value <= 3); + + QVector2D v; + switch (value) { - case 0: // Top left - return QPointF(row[kTopLeftInput].data().value().x(), - row[kTopLeftInput].data().value().y()); - break; - case 1: // Top right - return QPointF(resolution.x() + row[kTopRightInput].data().value().x(), - row[kTopRightInput].data().value().y()); - break; - case 2: // Bottom right - return QPointF(resolution.x() + row[kBottomRightInput].data().value().x(), - resolution.y() + row[kBottomRightInput].data().value().y()); - break; - case 3: //Bottom left - return QPointF(row[kBottomLeftInput].data().value().x(), - row[kBottomLeftInput].data().value().y() + resolution.y()); - break; - default: // We should never get here - return QPointF(); + case 0: // Top left + v = row[kTopLeftInput].toVec2(); + return QPointF(v.x(), v.y()); + case 1: // Top right + v = row[kTopRightInput].toVec2(); + return QPointF(resolution.x() + v.x(), v.y()); + case 2: // Bottom right + v = row[kBottomRightInput].toVec2(); + return QPointF(resolution.x() + v.x(), resolution.y() + v.y()); + case 3: //Bottom left + v = row[kBottomLeftInput].toVec2(); + return QPointF(v.x(), v.y() + resolution.y()); + default: // We should never get here + return QPointF(); } } diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp index 847a4a139..05b487abd 100644 --- a/app/node/distort/crop/cropdistortnode.cpp +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -82,14 +82,14 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - if (!job.GetValue(kTextureInput).data().isNull()) { - if (!qIsNull(job.GetValue(kLeftInput).data().toDouble()) - || !qIsNull(job.GetValue(kRightInput).data().toDouble()) - || !qIsNull(job.GetValue(kTopInput).data().toDouble()) - || !qIsNull(job.GetValue(kBottomInput).data().toDouble())) { + if (job.GetValue(kTextureInput).toTexture()) { + if (!qIsNull(job.GetValue(kLeftInput).toDouble()) + || !qIsNull(job.GetValue(kRightInput).toDouble()) + || !qIsNull(job.GetValue(kTopInput).toDouble()) + || !qIsNull(job.GetValue(kBottomInput).toDouble())) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(NodeValue::kTexture, job.GetValue(kTextureInput).data(), this); + table->Push(job.GetValue(kTextureInput)); } } } @@ -104,10 +104,10 @@ void CropDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGl { const QVector2D &resolution = globals.resolution(); - double left_pt = resolution.x() * row[kLeftInput].data().toDouble(); - double top_pt = resolution.y() * row[kTopInput].data().toDouble(); - double right_pt = resolution.x() * (1.0 - row[kRightInput].data().toDouble()); - double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].data().toDouble()); + double left_pt = resolution.x() * row[kLeftInput].toDouble(); + double top_pt = resolution.y() * row[kTopInput].toDouble(); + double right_pt = resolution.x() * (1.0 - row[kRightInput].toDouble()); + double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].toDouble()); double center_x_pt = mid(left_pt, right_pt); double center_y_pt = mid(top_pt, bottom_pt); diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index 10b90e0ac..efd9ad75f 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -82,9 +82,9 @@ void FlipDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global job.InsertValue(value); // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { + if (job.GetValue(kTextureInput).toTexture()) { // Only run shader if at least one of flip or flop are selected - if (job.GetValue(kHorizontalInput).data().toBool() || job.GetValue(kVerticalInput).data().toBool()) { + if (job.GetValue(kHorizontalInput).toBool() || job.GetValue(kVerticalInput).toBool()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { // If we're not flipping or flopping just push the texture diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp index df0a41cef..1f1e3d832 100644 --- a/app/node/distort/mask/mask.cpp +++ b/app/node/distort/mask/mask.cpp @@ -47,7 +47,7 @@ void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global { GenerateJob job = GetGenerateJob(value); - if (!value[kBaseInput].data().isNull()) { + if (value[kBaseInput].toTexture()) { // Push as merge node ShaderJob merge; diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index 9987e1526..cc98174e7 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -92,7 +92,7 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g bool pushed_job = false; // If we have a texture, generate a matrix and make it happen - if (TexturePtr texture = texture_meta.data().value()) { + if (TexturePtr texture = texture_meta.toTexture()) { // Adjust our matrix by the resolutions involved QMatrix4x4 real_matrix = GenerateAutoScaledMatrix(generated_matrix, value, globals, texture->params()); @@ -101,7 +101,7 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g ShaderJob job; job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture), this)); job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, real_matrix, this)); - job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast(value[kInterpolationInput].data().toInt())); + job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast(value[kInterpolationInput].toInt())); // FIXME: This should be optimized, we can use matrix math to determine if this operation will // end up with gaps in the screen that will require an alpha channel. @@ -140,7 +140,7 @@ void TransformDistortNode::Hash(QCryptographicHash &hash, const NodeGlobals &glo traverser.SetCacheVideoParams(video_params); NodeValueRow db = traverser.GenerateRow(this, globals.time()); - TexturePtr tex = db[kTextureInput].data().value(); + TexturePtr tex = db[kTextureInput].toTexture(); if (tex) { VideoParams tex_params = tex->params(); QMatrix4x4 matrix = GenerateMatrix(db, true, false, false, false); @@ -167,13 +167,13 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou } else if (IsAScaleGizmo(gizmo)) { // Dragging scale handle - TexturePtr tex = row[kTextureInput].data().value(); + TexturePtr tex = row[kTextureInput].toTexture(); if (!tex) { return; } - gizmo_scale_uniform_ = row[kUniformScaleInput].data().toBool(); - gizmo_anchor_pt_ = (row[kAnchorInput].data().value() + gizmo->GetGlobals().resolution()/2).toPointF(); + gizmo_scale_uniform_ = row[kUniformScaleInput].toBool(); + gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF(); if (gizmo == point_gizmo_[kGizmoScaleTopLeft] || gizmo == point_gizmo_[kGizmoScaleTopRight] || gizmo == point_gizmo_[kGizmoScaleBottomLeft] || gizmo == point_gizmo_[kGizmoScaleBottomRight]) { @@ -187,7 +187,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou // Store texture size VideoParams texture_params = tex->params(); QVector2D texture_sz(texture_params.square_pixel_width(), texture_params.height()); - gizmo_scale_anchor_ = row[kAnchorInput].data().value() + texture_sz/2; + gizmo_scale_anchor_ = row[kAnchorInput].toVec2() + texture_sz/2; if (gizmo == point_gizmo_[kGizmoScaleTopRight] || gizmo == point_gizmo_[kGizmoScaleBottomRight] @@ -208,7 +208,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou } else if (gizmo == rotation_gizmo_) { - gizmo_anchor_pt_ = (row[kAnchorInput].data().value() + gizmo->GetGlobals().resolution()/2).toPointF(); + gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF(); gizmo_start_angle_ = qAtan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x()); gizmo_last_angle_ = gizmo_start_angle_; gizmo_last_alt_angle_ = qAtan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y()); @@ -368,7 +368,7 @@ QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - TexturePtr tex = row[kTextureInput].data().value(); + TexturePtr tex = row[kTextureInput].toTexture(); if (!tex) { return; } @@ -384,7 +384,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N QVector2D tex_offset = tex_params.offset(); // Retrieve autoscale value - AutoScaleType autoscale = static_cast(row[kAutoscaleInput].data().toInt()); + AutoScaleType autoscale = static_cast(row[kAutoscaleInput].toInt()); // Fold values into a matrix for the rectangle QMatrix4x4 rectangle_matrix; @@ -441,7 +441,7 @@ QMatrix4x4 TransformDistortNode::GenerateAutoScaledMatrix(const QMatrix4x4& gene { const QVector2D &sequence_res = globals.resolution(); QVector2D texture_res(texture_params.square_pixel_width(), texture_params.height()); - AutoScaleType autoscale = static_cast(value[kAutoscaleInput].data().toInt()); + AutoScaleType autoscale = static_cast(value[kAutoscaleInput].toInt()); return AdjustMatrixByResolutions(generated_matrix, sequence_res, diff --git a/app/node/effect/opacity/opacityeffect.cpp b/app/node/effect/opacity/opacityeffect.cpp index 4fe76014f..334641174 100644 --- a/app/node/effect/opacity/opacityeffect.cpp +++ b/app/node/effect/opacity/opacityeffect.cpp @@ -50,8 +50,8 @@ void OpacityEffect::Value(const NodeValueRow &value, const NodeGlobals &globals, job.InsertValue(value); // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { - if (!qFuzzyCompare(job.GetValue(kValueInput).data().toDouble(), 1.0)) { + if (job.GetValue(kTextureInput).toTexture()) { + if (!qFuzzyCompare(job.GetValue(kValueInput).toDouble(), 1.0)) { job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index de9bcbaf9..86f950893 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -124,22 +124,22 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals job.InsertValue(value); job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - Method method = static_cast(job.GetValue(kMethodInput).data().toInt()); + Method method = static_cast(job.GetValue(kMethodInput).toInt()); // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { + if (job.GetValue(kTextureInput).toTexture()) { bool can_push_job = true; // Check if radius is > 0 - if (job.GetValue(kRadiusInput).data().toDouble() > 0.0) { + if (job.GetValue(kRadiusInput).toDouble() > 0.0) { // Method-specific considerations switch (method) { case kBox: case kGaussian: { - bool horiz = job.GetValue(kHorizInput).data().toBool(); - bool vert = job.GetValue(kVertInput).data().toBool(); + bool horiz = job.GetValue(kHorizInput).toBool(); + bool vert = job.GetValue(kVertInput).toBool(); if (!horiz && !vert) { // Disable job if horiz and vert are unchecked @@ -160,7 +160,7 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals if (can_push_job) { // If we're not repeating pixels, expect an alpha channel to appear - if (!job.GetValue(kRepeatEdgePixelsInput).data().toBool()) { + if (!job.GetValue(kRepeatEdgePixelsInput).toBool()) { job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); } @@ -175,12 +175,12 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals void BlurFilterNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) { - if (row[kMethodInput].data().toInt() == kRadial) { + if (row[kMethodInput].toInt() == kRadial) { const QVector2D &sequence_res = globals.resolution(); QVector2D sequence_half_res = sequence_res * 0.5; radial_center_gizmo_->SetVisible(true); - radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].value().toPointF()); + radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].toVec2().toPointF()); SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res); } else{ diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp index 4e77a524d..31a14f28f 100644 --- a/app/node/filter/mosaic/mosaicfilternode.cpp +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -60,12 +60,12 @@ void MosaicFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa // Mipmapping makes this look weird, so we just use bilinear for finding the color of each block job.SetInterpolation(kTextureInput, Texture::kLinear); - if (!job.GetValue(kTextureInput).data().isNull()) { - TexturePtr texture = job.GetValue(kTextureInput).data().value(); + if (job.GetValue(kTextureInput).toTexture()) { + TexturePtr texture = job.GetValue(kTextureInput).toTexture(); if (texture - && job.GetValue(kHorizInput).data().toInt() != texture->width() - && job.GetValue(kVertInput).data().toInt() != texture->height()) { + && job.GetValue(kHorizInput).toInt() != texture->width() + && job.GetValue(kVertInput).toInt() != texture->height()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { table->Push(job.GetValue(kTextureInput)); diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index 5a8ac7da7..32996ea9b 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -91,9 +91,9 @@ void StrokeFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa job.InsertValue(value); job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - if (!job.GetValue(kTextureInput).data().isNull()) { - if (job.GetValue(kRadiusInput).data().toDouble() > 0.0 - && job.GetValue(kOpacityInput).data().toDouble() > 0.0) { + if (job.GetValue(kTextureInput).toTexture()) { + if (job.GetValue(kRadiusInput).toDouble() > 0.0 + && job.GetValue(kOpacityInput).toDouble() > 0.0) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { table->Push(job.GetValue(kTextureInput)); diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index 0d5184335..d545ab2d9 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -103,47 +103,47 @@ QMatrix4x4 MatrixGenerator::GenerateMatrix(const NodeValueRow &value, bool take, if (!ignore_anchor) { if (take) { // Take and store - anchor = value[kAnchorInput].data().value(); + anchor = value[kAnchorInput].toVec2(); } else { // Get and store - anchor = value[kAnchorInput].data().value(); + anchor = value[kAnchorInput].toVec2(); } } else if (take) { // Just take - value[kAnchorInput].data().value(); + value[kAnchorInput].toVec2(); } if (!ignore_scale) { if (take) { - scale = value[kScaleInput].data().value(); + scale = value[kScaleInput].toVec2(); } else { - scale = value[kScaleInput].data().value(); + scale = value[kScaleInput].toVec2(); } } else if (take) { - value[kScaleInput].data().value(); + value[kScaleInput].toVec2(); } if (!ignore_position) { if (take) { - position = value[kPositionInput].data().value(); + position = value[kPositionInput].toVec2(); } else { - position = value[kPositionInput].data().value(); + position = value[kPositionInput].toVec2(); } } else if (take) { - value[kPositionInput].data().value(); + value[kPositionInput].toVec2(); } if (take) { return GenerateMatrix(position, - value[kRotationInput].data().toFloat(), + value[kRotationInput].toDouble(), scale, - value[kUniformScaleInput].data().toBool(), + value[kUniformScaleInput].toBool(), anchor); } else { return GenerateMatrix(position, - value[kRotationInput].data().toFloat(), + value[kRotationInput].toDouble(), scale, - value[kUniformScaleInput].data().toBool(), + value[kUniformScaleInput].toBool(), anchor); } diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 65c1c8f58..412299df1 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -116,7 +116,7 @@ void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) con QImage img(frame->width(), frame->height(), QImage::Format_Grayscale8); img.fill(Qt::transparent); - QVector points = job.GetValue(kPointsInput).data().value< QVector >(); + QVector points = job.GetValue(kPointsInput).value< QVector >(); QPainterPath path = GeneratePath(points); @@ -130,7 +130,7 @@ void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) con p.drawPath(path); // Transplant alpha channel to frame - Color rgba = job.GetValue(kColorInput).data().value(); + Color rgba = job.GetValue(kColorInput).toColor(); #if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM) __m128 sse_color = _mm_loadu_ps(rgba.data()); #endif @@ -196,7 +196,7 @@ void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeG { QPointF half_res(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2); - QVector points = row[kPointsInput].data().value< QVector >(); + QVector points = row[kPointsInput].value< QVector >(); int current_pos_sz = gizmo_position_handles_.size(); @@ -223,7 +223,7 @@ void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeG if (!points.isEmpty()) { for (int i=0; i(); + const Bezier &pt = points.at(i).toBezier(); QPointF main = pt.ToPointF() + half_res; QPointF cp1 = main + pt.ControlPoint1ToPointF(); @@ -267,14 +267,14 @@ QPainterPath PolygonGenerator::GeneratePath(const QVector &points) QPainterPath path; if (!points.isEmpty()) { - const Bezier &first_pt = points.first().data().value(); + const Bezier &first_pt = points.first().toBezier(); path.moveTo(first_pt.ToPointF()); for (int i=1; i(), points.at(i).data().value()); + AddPointToPath(&path, points.at(i-1).toBezier(), points.at(i).toBezier()); } - AddPointToPath(&path, points.last().data().value(), first_pt); + AddPointToPath(&path, points.last().toBezier(), first_pt); } return path; diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp index fac36b0ff..47ae76e88 100644 --- a/app/node/generator/shape/generatorwithmerge.cpp +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -53,7 +53,7 @@ ShaderCode GeneratorWithMerge::GetShaderCode(const ShaderRequest &request) const void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const { - if (!value[kBaseInput].data().isNull()) { + if (value[kBaseInput].toTexture()) { // Push as merge node ShaderJob merge; diff --git a/app/node/generator/shape/shapenodebase.cpp b/app/node/generator/shape/shapenodebase.cpp index 4eb411079..77a25f5e3 100644 --- a/app/node/generator/shape/shapenodebase.cpp +++ b/app/node/generator/shape/shapenodebase.cpp @@ -79,8 +79,8 @@ void ShapeNodeBase::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlob QVector2D center_pt = globals.resolution() * 0.5; SetInputProperty(kPositionInput, QStringLiteral("offset"), center_pt); - QVector2D pos = row[kPositionInput].data().value(); - QVector2D sz = row[kSizeInput].data().value(); + QVector2D pos = row[kPositionInput].toVec2(); + QVector2D sz = row[kSizeInput].toVec2(); QVector2D half_sz = sz * 0.5; double left_pt = pos.x() + center_pt.x() - half_sz.x(); diff --git a/app/node/generator/text/textv1.cpp b/app/node/generator/text/textv1.cpp index 516c7bd31..395783dfa 100644 --- a/app/node/generator/text/textv1.cpp +++ b/app/node/generator/text/textv1.cpp @@ -96,7 +96,7 @@ void TextGeneratorV1::Value(const NodeValueRow &value, const NodeGlobals &global job.InsertValue(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - if (!job.GetValue(kTextInput).data().toString().isEmpty()) { + if (!job.GetValue(kTextInput).toString().isEmpty()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } @@ -114,15 +114,15 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Set default font QFont default_font; - default_font.setFamily(job.GetValue(kFontInput).data().toString()); - default_font.setPointSizeF(job.GetValue(kFontSizeInput).data().toFloat()); + default_font.setFamily(job.GetValue(kFontInput).toString()); + default_font.setPointSizeF(job.GetValue(kFontSizeInput).toDouble()); text_doc.setDefaultFont(default_font); // Center by default text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter)); - QString html = job.GetValue(kTextInput).data().toString(); - if (job.GetValue(kHtmlInput).data().toBool()) { + QString html = job.GetValue(kTextInput).toString(); + if (job.GetValue(kHtmlInput).toBool()) { html.replace('\n', QStringLiteral("
")); text_doc.setHtml(html); } else { @@ -140,7 +140,7 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Push 10% inwards to compensate for title safe area p.translate(tenth_of_width, 0); - TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).data().toInt()); + TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -163,7 +163,7 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons text_doc.documentLayout()->draw(&p, ctx); // Transplant alpha channel to frame - Color rgb = job.GetValue(kColorInput).data().value(); + Color rgb = job.GetValue(kColorInput).toColor(); for (int x=0; xwidth(); x++) { for (int y=0; yheight(); y++) { uchar src_alpha = img.bits()[img.bytesPerLine() * y + x]; diff --git a/app/node/generator/text/textv2.cpp b/app/node/generator/text/textv2.cpp index 788f80bbd..0d607715d 100644 --- a/app/node/generator/text/textv2.cpp +++ b/app/node/generator/text/textv2.cpp @@ -100,7 +100,7 @@ void TextGeneratorV2::Value(const NodeValueRow &value, const NodeGlobals &global job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); job.SetRequestedFormat(VideoParams::kFormatFloat32); - if (!job.GetValue(kTextInput).data().toString().isEmpty()) { + if (!job.GetValue(kTextInput).toString().isEmpty()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } @@ -124,19 +124,19 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Set default font QFont default_font; - default_font.setFamily(job.GetValue(kFontInput).data().toString()); - default_font.setPointSizeF(job.GetValue(kFontSizeInput).data().toFloat()); + default_font.setFamily(job.GetValue(kFontInput).toString()); + default_font.setPointSizeF(job.GetValue(kFontSizeInput).toDouble()); text_doc.setDefaultFont(default_font); - QString html = job.GetValue(kTextInput).data().toString(); - if (job.GetValue(kHtmlInput).data().toBool()) { + QString html = job.GetValue(kTextInput).toString(); + if (job.GetValue(kHtmlInput).toBool()) { html.replace('\n', QStringLiteral("
")); text_doc.setHtml(html); } else { text_doc.setPlainText(html); } - QVector2D size = job.GetValue(kSizeInput).data().value(); + QVector2D size = job.GetValue(kSizeInput).toVec2(); text_doc.setTextWidth(size.x()); // Draw rich text onto image @@ -144,12 +144,12 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider()); - QVector2D pos = job.GetValue(kPositionInput).data().value(); + QVector2D pos = job.GetValue(kPositionInput).toVec2(); p.translate(pos.x() - size.x()/2, pos.y() - size.y()/2); p.translate(frame->video_params().width()/2, frame->video_params().height()/2); p.setClipRect(0, 0, size.x(), size.y()); - TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).data().toInt()); + TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -171,7 +171,7 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons text_doc.documentLayout()->draw(&p, ctx); // Transplant alpha channel to frame - Color rgba = job.GetValue(kColorInput).data().value(); + Color rgba = job.GetValue(kColorInput).toColor(); #if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM) __m128 sse_color = _mm_loadu_ps(rgba.data()); #endif diff --git a/app/node/generator/text/textv3.cpp b/app/node/generator/text/textv3.cpp index 4413d6f65..d01c1b93d 100644 --- a/app/node/generator/text/textv3.cpp +++ b/app/node/generator/text/textv3.cpp @@ -88,9 +88,9 @@ void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &global // FIXME: Provide user override for this job.SetColorspace(project()->color_manager()->GetDefaultInputColorSpace()); - if (!job.GetValue(kTextInput).data().toString().isEmpty()) { + if (!job.GetValue(kTextInput).toString().isEmpty()) { PushMergableJob(value, QVariant::fromValue(job), table); - } else if (!value[kBaseInput].data().isNull()) { + } else if (value[kBaseInput].toTexture()) { table->Push(value[kBaseInput]); } } @@ -108,17 +108,17 @@ void TextGeneratorV3::GenerateFrame(FramePtr frame, const GenerateJob& job) cons QTextDocument text_doc; text_doc.documentLayout()->setPaintDevice(&img); - QString html = job.GetValue(kTextInput).data().toString(); + QString html = job.GetValue(kTextInput).toString(); Html::HtmlToDoc(&text_doc, html); - QVector2D size = job.GetValue(kSizeInput).data().value(); + QVector2D size = job.GetValue(kSizeInput).toVec2(); text_doc.setTextWidth(size.x()); // Draw rich text onto image QPainter p(&img); p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider()); - QVector2D pos = job.GetValue(kPositionInput).data().value(); + QVector2D pos = job.GetValue(kPositionInput).toVec2(); p.translate(pos.x() - size.x()/2, pos.y() - size.y()/2); p.translate(frame->video_params().width()/2, frame->video_params().height()/2); p.setClipRect(0, 0, size.x(), size.y()); @@ -136,7 +136,7 @@ void TextGeneratorV3::UpdateGizmoPositions(const NodeValueRow &row, const NodeGl QRectF rect = poly_gizmo()->GetPolygon().boundingRect(); text_gizmo_->SetRect(rect); - text_gizmo_->SetHtml(row[kTextInput].data().toString()); + text_gizmo_->SetHtml(row[kTextInput].toString()); } } diff --git a/app/node/hashtraverser.cpp b/app/node/hashtraverser.cpp index fe469535e..cff52dd77 100644 --- a/app/node/hashtraverser.cpp +++ b/app/node/hashtraverser.cpp @@ -144,10 +144,10 @@ void HashTraverser::HashNodeValue(const NodeValue &value) if (value_type == NodeValue::kSamples || value_type == NodeValue::kTexture) { QByteArray id_for_buffer; if (value_type == NodeValue::kTexture) { - TexturePtr texture = value.data().value(); + TexturePtr texture = value.toTexture(); id_for_buffer = texture_ids_.value(texture.get()); } else { - SampleBufferPtr samples = value.data().value(); + SampleBufferPtr samples = value.toSamples(); id_for_buffer = texture_ids_.value(samples.get()); } diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 18910e886..3dbc1f56e 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -128,13 +128,13 @@ void ChromaKeyNode::GenerateProcessor() void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - if (!value[kTextureInput].data().isNull() && processor()) { + if (value[kTextureInput].toTexture() && processor()) { ColorTransformJob job; job.InsertValue(value); job.SetAlphaChannelRequired(ColorTransformJob::kAlphaForceOn); job.SetColorProcessor(processor()); - job.SetInputTexture(value[kTextureInput].data().value()); + job.SetInputTexture(value[kTextureInput].toTexture()); job.SetNeedsCustomShader(this); job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65")); diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index aaf9b77f0..bd1113518 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -98,7 +98,7 @@ void ColorDifferenceKeyNode::Value(const NodeValueRow &value, const NodeGlobals job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { + if (job.GetValue(kTextureInput).toTexture()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index 364e04a1f..577cfbab5 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -91,7 +91,7 @@ void DespillNode::Value(const NodeValueRow &value, const NodeGlobals &globals, N NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]))); // If there's no texture, no need to run an operation - if (!job.GetValue(kTextureInput).data().isNull()) { + if (job.GetValue(kTextureInput).toTexture()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 00c0b7ce4..9a78b1f97 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -141,12 +141,12 @@ QVector4D MathNodeBase::RetrieveVector(const NodeValue &val) // QVariant doesn't know that QVector*D can convert themselves so we do it here switch (val.type()) { case NodeValue::kVec2: - return val.data().value(); + return val.toVec2(); case NodeValue::kVec3: - return val.data().value(); + return val.toVec3(); case NodeValue::kVec4: default: - return val.data().value(); + return val.toVec4(); } } @@ -225,7 +225,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt if (val_a.type() == NodeValue::kRational && val_b.type() == NodeValue::kRational && operation != kOpPower) { // Preserve rationals output->Push(NodeValue::kRational, - QVariant::fromValue(PerformAddSubMultDiv(operation, val_a.data().value(), val_b.data().value())), + QVariant::fromValue(PerformAddSubMultDiv(operation, val_a.toRational(), val_b.toRational())), this); } else { output->Push(NodeValue::kFloat, @@ -247,7 +247,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt case kPairMatrixVec: { - QMatrix4x4 matrix = (val_a.type() == NodeValue::kMatrix) ? val_a.data().value() : val_b.data().value(); + QMatrix4x4 matrix = (val_a.type() == NodeValue::kMatrix) ? val_a.toMatrix() : val_b.toMatrix(); QVector4D vec = (val_a.type() == NodeValue::kMatrix) ? RetrieveVector(val_b) : RetrieveVector(val_a); // Only valid operation is multiply @@ -269,16 +269,16 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt case kPairMatrixMatrix: { - QMatrix4x4 mat_a = val_a.data().value(); - QMatrix4x4 mat_b = val_b.data().value(); + QMatrix4x4 mat_a = val_a.toMatrix(); + QMatrix4x4 mat_b = val_b.toMatrix(); output->Push(NodeValue::kMatrix, PerformAddSubMult(operation, mat_a, mat_b), this); break; } case kPairColorColor: { - Color col_a = val_a.data().value(); - Color col_b = val_b.data().value(); + Color col_a = val_a.toColor(); + Color col_b = val_b.toColor(); // Only add and subtract are valid operations output->Push(NodeValue::kColor, QVariant::fromValue(PerformAddSub(operation, col_a, col_b)), this); @@ -288,8 +288,8 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt case kPairNumberColor: { - Color col = (val_a.type() == NodeValue::kColor) ? val_a.data().value() : val_b.data().value(); - float num = (val_a.type() == NodeValue::kColor) ? val_b.data().toFloat() : val_a.data().toFloat(); + Color col = (val_a.type() == NodeValue::kColor) ? val_a.toColor() : val_b.toColor(); + float num = (val_a.type() == NodeValue::kColor) ? val_b.toDouble() : val_a.toDouble(); // Only multiply and divide are valid operations output->Push(NodeValue::kColor, QVariant::fromValue(PerformMult(operation, col, num)), this); @@ -298,8 +298,8 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt case kPairSampleSample: { - SampleBufferPtr samples_a = val_a.data().value(); - SampleBufferPtr samples_b = val_b.data().value(); + SampleBufferPtr samples_a = val_a.toSamples(); + SampleBufferPtr samples_b = val_b.toSamples(); int max_samples = qMax(samples_a->sample_count(), samples_b->sample_count()); int min_samples = qMin(samples_a->sample_count(), samples_b->sample_count()); @@ -348,7 +348,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt const NodeValue& number_val = val_a.type() == NodeValue::kTexture ? val_b : val_a; const NodeValue& texture_val = val_a.type() == NodeValue::kTexture ? val_a : val_b; - TexturePtr texture = texture_val.data().value(); + TexturePtr texture = texture_val.toTexture(); if (!texture) { operation_is_noop = true; @@ -361,7 +361,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt const QVector2D &sequence_res = globals.resolution(); QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height()); - QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.data().value(), + QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.toMatrix(), sequence_res, texture->params().offset(), texture_res); @@ -449,9 +449,9 @@ void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBa float MathNodeBase::RetrieveNumber(const NodeValue &val) { if (val.type() == NodeValue::kRational) { - return val.data().value().toDouble(); + return val.toRational().toDouble(); } else { - return val.data().toFloat(); + return val.toDouble(); } } diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 335cb9e74..02506c9f3 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -79,8 +79,8 @@ void MergeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, Nod ShaderJob job; job.InsertValue(value); - TexturePtr base_tex = job.GetValue(kBaseIn).data().value(); - TexturePtr blend_tex = job.GetValue(kBlendIn).data().value(); + TexturePtr base_tex = job.GetValue(kBaseIn).toTexture(); + TexturePtr blend_tex = job.GetValue(kBlendIn).toTexture(); if (base_tex || blend_tex) { if (!base_tex || (blend_tex && blend_tex->channel_count() < VideoParams::kRGBAChannelCount)) { @@ -108,8 +108,8 @@ void MergeNode::Hash(QCryptographicHash &hash, const NodeGlobals &globals, const NodeValueDatabase db = traverser.GenerateDatabase(this, globals.time()); - TexturePtr base_tex = db[kBaseIn].Get(NodeValue::kTexture).value(); - TexturePtr blend_tex = db[kBlendIn].Get(NodeValue::kTexture).value(); + TexturePtr base_tex = db[kBaseIn].Get(NodeValue::kTexture).toTexture(); + TexturePtr blend_tex = db[kBlendIn].Get(NodeValue::kTexture).toTexture(); if (base_tex || blend_tex) { bool passthrough_base = !blend_tex; diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index 461ba538a..426604ca1 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -79,7 +79,7 @@ void TrigonometryNode::Retranslate() void TrigonometryNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - double x = value[kXIn].data().toFloat(); + double x = value[kXIn].toDouble(); switch (static_cast(GetStandardValue(kMethodIn).toInt())) { case kOpSine: diff --git a/app/node/project/footage/footage.cpp b/app/node/project/footage/footage.cpp index 59d520d96..825470782 100644 --- a/app/node/project/footage/footage.cpp +++ b/app/node/project/footage/footage.cpp @@ -322,9 +322,9 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV Q_UNUSED(globals) // Pop filename from table - QString file = value[kFilenameInput].data().toString(); + QString file = value[kFilenameInput].toString(); - LoopMode loop_mode = static_cast(value[kLoopModeInput].data().toInt()); + LoopMode loop_mode = static_cast(value[kLoopModeInput].toInt()); // If the file exists and the reference is valid, push a footage job to the renderer if (QFileInfo(file).exists()) { diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 7c5c0e37f..54cd8758c 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -71,7 +71,7 @@ NodeValue NodeTraverser::GenerateRowValue(const Node *node, const QString &input if (value.array()) { // Resolve each element of array - QVector tables = value.data().value >(); + QVector tables = value.value >(); QVector output(tables.size()); for (int i=0; i(); - if (tex) { + if (TexturePtr tex = it.value().toTexture()) { max_channel_count = qMax(max_channel_count, tex->channel_count()); } } @@ -304,11 +303,9 @@ QVector2D NodeTraverser::GenerateResolution() const void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) { if (val.type() == NodeValue::kTexture || val.type() == NodeValue::kSamples) { - const QVariant &v = val.data(); + if (val.canConvert()) { - if (v.canConvert()) { - - ShaderJob job = v.value(); + ShaderJob job = val.value(); VideoParams tex_params = GetCacheVideoParams(); tex_params.set_channel_count(GetChannelCountFromJob(job)); @@ -318,11 +315,11 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) PreProcessRow(range, job.GetValues()); ProcessShader(tex, val.source(), range, job); - val.set_data(QVariant::fromValue(tex)); + val.set_value(tex); - } else if (v.canConvert()) { + } else if (val.canConvert()) { - GenerateJob job = v.value(); + GenerateJob job = val.value(); VideoParams tex_params = GetCacheVideoParams(); tex_params.set_channel_count(GetChannelCountFromJob(job)); @@ -346,11 +343,11 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) tex = dest; } - val.set_data(QVariant::fromValue(tex)); + val.set_value(tex); - } else if (v.canConvert()) { + } else if (val.canConvert()) { - ColorTransformJob job = v.value(); + ColorTransformJob job = val.value(); VideoParams src_params = job.GetInputTexture()->params(); src_params.set_channel_count(GetChannelCountFromJob(job)); @@ -359,11 +356,11 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) ProcessColorTransform(dest, val.source(), job); - val.set_data(QVariant::fromValue(dest)); + val.set_value(dest); - } else if (v.canConvert()) { + } else if (val.canConvert()) { - FootageJob job = v.value(); + FootageJob job = val.value(); if (job.type() == Track::kVideo) { @@ -399,22 +396,22 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) ProcessVideoFootage(tex, job, footage_time); } - val.set_data(QVariant::fromValue(tex)); + val.set_value(tex); } else if (job.type() == Track::kAudio) { SampleBufferPtr buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length()); ProcessAudioFootage(buffer, job, range); - val.set_data(QVariant::fromValue(buffer)); + val.set_value(buffer); } - } else if (v.canConvert()) { + } else if (val.canConvert()) { - SampleJob job = v.value(); + SampleJob job = val.value(); SampleBufferPtr output_buffer = CreateSampleBuffer(job.samples()->audio_params(), job.samples()->sample_count()); ProcessSamples(output_buffer, val.source(), range, job); - val.set_data(QVariant::fromValue(output_buffer)); + val.set_value(QVariant::fromValue(output_buffer)); } diff --git a/app/node/value.cpp b/app/node/value.cpp index cdafe2151..d103b1973 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -418,7 +418,7 @@ NodeValue::Type NodeValue::GetDataTypeFromName(const QString &n) return NodeValue::kNone; } -NodeValue NodeValueTable::GetWithMeta(const QVector &type, const QString &tag) const +NodeValue NodeValueTable::Get(const QVector &type, const QString &tag) const { int value_index = GetValueIndex(type, tag); @@ -429,7 +429,7 @@ NodeValue NodeValueTable::GetWithMeta(const QVector &type, cons return NodeValue(); } -NodeValue NodeValueTable::TakeWithMeta(const QVector &type, const QString &tag) +NodeValue NodeValueTable::Take(const QVector &type, const QString &tag) { int value_index = GetValueIndex(type, tag); diff --git a/app/node/value.h b/app/node/value.h index e16fc1055..bb5b56dbe 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -21,10 +21,16 @@ #ifndef NODEVALUE_H #define NODEVALUE_H +#include #include #include #include +#include "codec/samplebuffer.h" +#include "common/bezier.h" +#include "node/splitvalue.h" +#include "render/color.h" +#include "render/texture.h" #include "undo/undocommand.h" namespace olive { @@ -209,14 +215,16 @@ public: return data_.value(); } - const QVariant& data() const + template + void set_value(const T &v) { - return data_; + data_ = QVariant::fromValue(v); } - void set_data(const QVariant& data) + template + bool canConvert() const { - data_ = data; + return data_.canConvert(); } const QString& tag() const @@ -245,6 +253,10 @@ public: static NodeValue::Type GetDataTypeFromName(const QString &n); static QString ValueToString(Type data_type, const QVariant& value, bool value_is_a_key_track); + static QString ValueToString(const NodeValue &v, bool value_is_a_key_track) + { + return ValueToString(v.type_, v.data_, value_is_a_key_track); + } static QVariant StringToValue(Type data_type, const QString &string, bool value_is_a_key_track); @@ -254,13 +266,18 @@ public: static QByteArray ValueToBytes(Type type, const QVariant& value); static QByteArray ValueToBytes(const NodeValue &value) { - return ValueToBytes(value.type(), value.data()); + return ValueToBytes(value.type(), value.data_); } static QVector split_normal_value_into_track_values(Type type, const QVariant &value); static QVariant combine_track_values_into_normal_value(Type type, const QVector& split); + SplitValue to_split_value() const + { + return split_normal_value_into_track_values(type_, data_); + } + /** * @brief Returns whether a data type can be interpolated or not */ @@ -289,6 +306,22 @@ public: static void ValidateVectorString(QStringList* list, int count); + TexturePtr toTexture() const { return value(); } + SampleBufferPtr toSamples() const { return value(); } + bool toBool() const { return value(); } + double toDouble() const { return value(); } + int64_t toInt() const { return value(); } + rational toRational() const { return value(); } + QString toString() const { return value(); } + Color toColor() const { return value(); } + QMatrix4x4 toMatrix() const { return value(); } + VideoParams toVideoParams() const { return value(); } + AudioParams toAudioParams() const { return value(); } + QVector2D toVec2() const { return value(); } + QVector3D toVec3() const { return value(); } + QVector4D toVec4() const { return value(); } + Bezier toBezier() const { return value(); } + private: Type type_; QVariant data_; @@ -303,43 +336,21 @@ class NodeValueTable public: NodeValueTable() = default; - QVariant Get(NodeValue::Type type, const QString& tag = QString()) const + NodeValue Get(NodeValue::Type type, const QString& tag = QString()) const { QVector types = {type}; return Get(types, tag); } - QVariant Get(const QVector& type, const QString& tag = QString()) const - { - return GetWithMeta(type, tag).data(); - } + NodeValue Get(const QVector& type, const QString& tag = QString()) const; - NodeValue GetWithMeta(NodeValue::Type type, const QString& tag = QString()) const - { - QVector types = {type}; - return GetWithMeta(types, tag); - } - - NodeValue GetWithMeta(const QVector& type, const QString& tag = QString()) const; - - QVariant Take(NodeValue::Type type, const QString& tag = QString()) + NodeValue Take(NodeValue::Type type, const QString& tag = QString()) { QVector types = {type}; return Take(types, tag); } - QVariant Take(const QVector& type, const QString& tag = QString()) - { - return TakeWithMeta(type, tag).data(); - } - - NodeValue TakeWithMeta(NodeValue::Type type, const QString& tag = QString()) - { - QVector types = {type}; - return TakeWithMeta(types, tag); - } - - NodeValue TakeWithMeta(const QVector& type, const QString& tag = QString()); + NodeValue Take(const QVector& type, const QString& tag = QString()); void Push(const NodeValue& value) { diff --git a/app/render/job/samplejob.h b/app/render/job/samplejob.h index ad78bb6d2..65aca18f5 100644 --- a/app/render/job/samplejob.h +++ b/app/render/job/samplejob.h @@ -35,12 +35,12 @@ public: SampleJob(const NodeValue& value) { - samples_ = value.data().value(); + samples_ = value.toSamples(); } SampleJob(const QString& from, const NodeValueRow& row) { - samples_ = row[from].data().value(); + samples_ = row[from].toSamples(); } SampleBufferPtr samples() const diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index 628ed8f15..d5553704d 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -449,48 +449,48 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video case NodeValue::kInt: // kInt technically specifies a LongLong, but OpenGL doesn't support those. This may lead to // over/underflows if the number is large enough, but the likelihood of that is quite low. - functions_->glUniform1i(variable_location, value.data().toInt()); + functions_->glUniform1i(variable_location, value.toInt()); break; case NodeValue::kFloat: // kFloat technically specifies a double but as above, OpenGL doesn't support those. - functions_->glUniform1f(variable_location, value.data().toFloat()); + functions_->glUniform1f(variable_location, value.toDouble()); break; case NodeValue::kVec2: { - QVector2D v = value.data().value(); + QVector2D v = value.toVec2(); functions_->glUniform2fv(variable_location, 1, reinterpret_cast(&v)); break; } case NodeValue::kVec3: { - QVector3D v = value.data().value(); + QVector3D v = value.toVec3(); functions_->glUniform3fv(variable_location, 1, reinterpret_cast(&v)); break; } case NodeValue::kVec4: { - QVector4D v = value.data().value(); + QVector4D v = value.toVec4(); functions_->glUniform4fv(variable_location, 1, reinterpret_cast(&v)); break; } case NodeValue::kMatrix: - functions_->glUniformMatrix4fv(variable_location, 1, false, value.data().value().constData()); + functions_->glUniformMatrix4fv(variable_location, 1, false, value.toMatrix().constData()); break; case NodeValue::kCombo: - functions_->glUniform1i(variable_location, value.data().value()); + functions_->glUniform1i(variable_location, value.toInt()); break; case NodeValue::kColor: { - Color color = value.data().value(); + Color color = value.toColor(); functions_->glUniform4f(variable_location, color.red(), color.green(), color.blue(), color.alpha()); break; } case NodeValue::kBoolean: - functions_->glUniform1i(variable_location, value.data().toBool()); + functions_->glUniform1i(variable_location, value.toBool()); break; case NodeValue::kTexture: { - TexturePtr texture = value.data().value(); + TexturePtr texture = value.toTexture(); // Set value to bound texture functions_->glUniform1i(variable_location, textures_to_bind.size()); @@ -552,7 +552,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video // Ensure matrix is set, at least to identity GLint mvpmat_location = functions_->glGetUniformLocation(shader, "ove_mvpmat"); if (mvpmat_location > -1) { - functions_->glUniformMatrix4fv(mvpmat_location, 1, false, job.GetValue(QStringLiteral("ove_mvpmat")).data().value().constData()); + functions_->glUniformMatrix4fv(mvpmat_location, 1, false, job.GetValue(QStringLiteral("ove_mvpmat")).toMatrix().constData()); } // Set the viewport to the "physical" resolution of the destination diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index c5586022b..e81a056f7 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -55,11 +55,11 @@ TexturePtr RenderProcessor::GenerateTexture(const rational &time, const rational table = GenerateTable(texture_output, viewer->GetValueHintForInput(ViewerOutput::kTextureInput), range); } - NodeValue tex_val = table.GetWithMeta(NodeValue::kTexture); + NodeValue tex_val = table.Get(NodeValue::kTexture); ResolveJobs(tex_val, range); - return tex_val.data().value(); + return tex_val.toTexture(); } FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time) @@ -196,12 +196,11 @@ void RenderProcessor::Run() table = GenerateTable(texture_output, viewer->GetValueHintForInput(ViewerOutput::kSamplesInput),time); } - NodeValue sample_val = table.GetWithMeta(NodeValue::kSamples); + NodeValue sample_val = table.Get(NodeValue::kSamples); ResolveJobs(sample_val, time); - QVariant sample_variant = sample_val.data(); - SampleBufferPtr samples = sample_variant.value(); + SampleBufferPtr samples = sample_val.toSamples(); if (samples && ticket_->property("enablewaveforms").toBool()) { AudioVisualWaveform vis; vis.set_channel_count(samples->audio_params().channel_count()); @@ -212,7 +211,7 @@ void RenderProcessor::Run() if (ticket_->IsCancelled()) { ticket_->Finish(); } else { - ticket_->Finish(sample_variant); + ticket_->Finish(QVariant::fromValue(samples)); } break; } @@ -293,7 +292,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim // Destination buffer NodeValueTable table = GenerateTable(b, track->GetValueHintForInput(Track::kBlockInput, track->GetArrayIndexFromBlock(b)),Track::TransformRangeForBlock(b, range_for_block)); - SampleBufferPtr samples_from_this_block = table.Take(NodeValue::kSamples).value(); + SampleBufferPtr samples_from_this_block = table.Take(NodeValue::kSamples).toSamples(); ClipBlock *clip_cast = dynamic_cast(b); if (samples_from_this_block) { diff --git a/app/widget/nodetableview/nodetableview.cpp b/app/widget/nodetableview/nodetableview.cpp index 174b3df3e..8981552fa 100644 --- a/app/widget/nodetableview/nodetableview.cpp +++ b/app/widget/nodetableview/nodetableview.cpp @@ -151,7 +151,7 @@ void NodeTableView::SetTime(const rational &time) } default: { - QVector split_values = NodeValue::split_normal_value_into_track_values(node->GetInputDataType(l.key()), value.data()); + QVector split_values = value.to_split_value(); for (int k=0;ksetText(2 + k, NodeValue::ValueToString(value.type(), split_values.at(k), true)); } diff --git a/app/widget/nodevaluetree/nodevaluetree.cpp b/app/widget/nodevaluetree/nodevaluetree.cpp index 689330237..2f263b125 100644 --- a/app/widget/nodevaluetree/nodevaluetree.cpp +++ b/app/widget/nodevaluetree/nodevaluetree.cpp @@ -53,7 +53,7 @@ void NodeValueTree::SetNode(const NodeInput &input, const rational &time) setItemWidget(item, 0, radio); item->setText(1, NodeValue::GetPrettyDataTypeName(value.type())); - item->setText(2, NodeValue::ValueToString(value.type(), value.data(), false)); + item->setText(2, NodeValue::ValueToString(value, false)); item->setText(3, value.source()->GetLabelAndName()); } } From bb0fedabba303c2de78c346af0bd77cfecdf38be Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 14:55:51 -0700 Subject: [PATCH 85/96] simplified and optimized samplebuffer --- app/audio/audiovisualwaveform.cpp | 20 +++--- app/audio/audiovisualwaveform.h | 6 +- app/codec/decoder.cpp | 12 ++-- app/codec/decoder.h | 4 +- app/codec/encoder.h | 2 +- app/codec/ffmpeg/ffmpegdecoder.cpp | 4 +- app/codec/ffmpeg/ffmpegencoder.cpp | 18 +++--- app/codec/ffmpeg/ffmpegencoder.h | 2 +- app/codec/oiio/oiioencoder.cpp | 2 +- app/codec/oiio/oiioencoder.h | 2 +- app/codec/samplebuffer.cpp | 61 +++++++++---------- app/codec/samplebuffer.h | 24 +++----- app/core.cpp | 2 +- app/node/audio/pan/pan.cpp | 33 +++++----- app/node/audio/pan/pan.h | 2 +- app/node/audio/volume/volume.cpp | 2 +- app/node/audio/volume/volume.h | 2 +- .../crossdissolve/crossdissolvetransition.cpp | 22 +++---- .../crossdissolve/crossdissolvetransition.h | 2 +- app/node/block/transition/transition.cpp | 29 ++------- app/node/block/transition/transition.h | 4 +- app/node/hashtraverser.cpp | 14 +---- app/node/hashtraverser.h | 4 +- app/node/math/math/math.cpp | 2 +- app/node/math/math/math.h | 2 +- app/node/math/math/mathbase.cpp | 43 ++++++------- app/node/math/math/mathbase.h | 2 +- app/node/node.cpp | 2 +- app/node/node.h | 2 +- app/node/traverser.cpp | 4 +- app/node/traverser.h | 12 ++-- app/node/value.h | 2 +- app/render/audioplaybackcache.cpp | 8 +-- app/render/audioplaybackcache.h | 2 +- app/render/job/samplejob.h | 7 +-- app/render/previewautocacher.cpp | 2 +- app/render/renderprocessor.cpp | 52 ++++++++-------- app/render/renderprocessor.h | 8 +-- app/task/export/export.cpp | 6 +- app/task/export/export.h | 6 +- app/task/precache/precachetask.cpp | 2 +- app/task/precache/precachetask.h | 2 +- app/task/render/render.cpp | 2 +- app/task/render/render.h | 2 +- app/widget/audiomonitor/audiomonitor.cpp | 4 +- app/widget/audiomonitor/audiomonitor.h | 4 +- app/widget/viewer/viewer.cpp | 15 ++--- 47 files changed, 214 insertions(+), 252 deletions(-) diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index dbc0cb973..7719d7090 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -40,10 +40,10 @@ AudioVisualWaveform::AudioVisualWaveform() : } } -void AudioVisualWaveform::OverwriteSamplesFromBuffer(SampleBufferPtr samples, int sample_rate, const rational &start, double target_rate, Sample& data, int &start_index, int &samples_length) +void AudioVisualWaveform::OverwriteSamplesFromBuffer(const SampleBuffer &samples, int sample_rate, const rational &start, double target_rate, Sample& data, int &start_index, int &samples_length) { start_index = time_to_samples(start, target_rate); - samples_length = time_to_samples(static_cast(samples->sample_count()) / static_cast(sample_rate), target_rate); + samples_length = time_to_samples(static_cast(samples.sample_count()) / static_cast(sample_rate), target_rate); int end_index = start_index + samples_length; if (data.size() < end_index) { @@ -54,7 +54,7 @@ void AudioVisualWaveform::OverwriteSamplesFromBuffer(SampleBufferPtr samples, in for (int i=0; isample_count()); + int src_end = qMin(qRound((double(i + channels_) * chunk_size)) / channels_, samples.sample_count()); Sample summary = SumSamples(samples, src_start, @@ -91,7 +91,7 @@ void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform:: input_length = samples_length; } -void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start) +void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int sample_rate, const rational &start) { if (!channels_) { qWarning() << "Failed to write samples - channel count is zero"; @@ -125,7 +125,7 @@ void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_r current_mipmap->second); } - rational sample_length(samples->sample_count(), sample_rate); + rational sample_length(samples.sample_count(), sample_rate); length_ = qMax(length_, start + sample_length); } @@ -277,7 +277,7 @@ AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const ration return AudioVisualWaveform::Sample(channel_count(), {0, 0}); } -void ExpandMinMaxChannel(float *a, int start, int length, float &min_val, float &max_val) +void ExpandMinMaxChannel(const float *a, int start, int length, float &min_val, float &max_val) { #if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM) // SSE optimized @@ -321,13 +321,13 @@ void ExpandMinMaxChannel(float *a, int start, int length, float &min_val, float #endif } -AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(SampleBufferPtr samples, int start_index, int length) +AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &samples, int start_index, int length) { - int channels = samples->audio_params().channel_count(); + int channels = samples.audio_params().channel_count(); AudioVisualWaveform::Sample summed_samples(channels); - for (int channel=0; channelaudio_params().channel_count(); channel++) { - ExpandMinMaxChannel(samples->data(channel), start_index, length, summed_samples[channel].min, summed_samples[channel].max); + for (int channel=0; channel &filenames, const Audi return false; } -bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params) +bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params) { PlanarFileDevice input; if (input.open(conform_filenames, QFile::ReadOnly)) { qint64 read_index = input_params.time_to_bytes(range.in()) / input_params.channel_count(); qint64 write_index = 0; - const qint64 buffer_length_in_bytes = sample_buffer->sample_count() * input_params.bytes_per_sample_per_channel(); + const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel(); while (write_index < buffer_length_in_bytes) { if (loop_mode == Footage::kLoopModeLoop) { @@ -297,15 +297,15 @@ bool Decoder::RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVec if (read_index < 0) { // Reading before 0, write silence here until audio data would actually start write_count = qMin(-read_index, buffer_length_in_bytes); - sample_buffer->silence_bytes(write_index, write_index + write_count); + sample_buffer.silence_bytes(write_index, write_index + write_count); } else if (read_index >= input.size()) { // Reading after data length, write silence until the end of the buffer write_count = buffer_length_in_bytes - write_index; - sample_buffer->silence_bytes(write_index, write_index + write_count); + sample_buffer.silence_bytes(write_index, write_index + write_count); } else { write_count = qMin(input.size() - read_index, buffer_length_in_bytes - write_index); input.seek(read_index); - input.read(reinterpret_cast(sample_buffer->to_raw_ptrs()), write_count, write_index); + input.read(reinterpret_cast(sample_buffer.to_raw_ptrs().data()), write_count, write_index); } read_index += write_count; diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 2234753d9..3191ade23 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -201,7 +201,7 @@ public: * * This function is thread safe and can only run while the decoder is open. \see Open() */ - RetrieveAudioStatus RetrieveAudio(SampleBufferPtr dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode); + RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode); /** * @brief Determine the last time this decoder instance was used in any way @@ -307,7 +307,7 @@ signals: private: void UpdateLastAccessed(); - bool RetrieveAudioFromConform(SampleBufferPtr sample_buffer, const QVector &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams ¶ms); + bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams ¶ms); CodecStream stream_; diff --git a/app/codec/encoder.h b/app/codec/encoder.h index 102b0430e..f94473dbb 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -183,7 +183,7 @@ public slots: virtual bool Open() = 0; virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) = 0; - virtual bool WriteAudio(olive::SampleBufferPtr audio) = 0; + virtual bool WriteAudio(const olive::SampleBuffer &audio) = 0; virtual bool WriteSubtitle(const SubtitleBlock *sub_block) = 0; virtual void Close() = 0; diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 04f889a34..df6c874da 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -515,7 +515,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector &filenames, cons // Resample audio to our destination parameters nb_samples = swr_convert(resampler, - reinterpret_cast(data.to_raw_ptrs()), + reinterpret_cast(data.to_raw_ptrs().data()), nb_samples, const_cast(frame->data), frame->nb_samples); @@ -526,7 +526,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector &filenames, cons nb_bytes_per_channel = params.samples_to_bytes(nb_samples) / nb_channels; // Write to files - wave_out.write(const_cast(reinterpret_cast(data.to_raw_ptrs())), nb_bytes_per_channel); + wave_out.write(const_cast(reinterpret_cast(data.to_raw_ptrs().data())), nb_bytes_per_channel); } // Free buffer diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 8a0462e2d..6c42df4da 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -266,26 +266,26 @@ fail: return success; } -bool FFmpegEncoder::WriteAudio(SampleBufferPtr audio) +bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio) { bool result = true; // Create input buffer int input_sample_count = 0; uint8_t** input_data = nullptr; - if (audio) { - input_sample_count = audio->sample_count(); + if (audio.is_allocated()) { + input_sample_count = audio.sample_count(); int input_linesize; - av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio->audio_params().channel_count(), - input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio->audio_params().format()), 0); + av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio.audio_params().channel_count(), + input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio.audio_params().format()), 0); - for (int i=0; iaudio_params().channel_count(); i++) { - memcpy(input_data[i], audio->data(i), input_sample_count * audio->audio_params().bytes_per_sample_per_channel()); + for (int i=0; iaudio_params() : params().audio_params(), const_cast(input_data), input_sample_count); + result = WriteAudioData(audio.audio_params().is_valid() ? audio.audio_params() : params().audio_params(), const_cast(input_data), input_sample_count); if (input_data) { av_freep(&input_data[0]); @@ -774,7 +774,7 @@ void FFmpegEncoder::FlushEncoders() } if (audio_codec_ctx_) { - WriteAudio(nullptr); + WriteAudio(SampleBuffer()); FlushCodecCtx(audio_codec_ctx_, audio_stream_); } diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index a38955f3f..465f7c40a 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -47,7 +47,7 @@ public: virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override; - virtual bool WriteAudio(olive::SampleBufferPtr audio) override; + virtual bool WriteAudio(const olive::SampleBuffer &audio) override; bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data, int input_sample_count); diff --git a/app/codec/oiio/oiioencoder.cpp b/app/codec/oiio/oiioencoder.cpp index f872a758b..679dbd550 100644 --- a/app/codec/oiio/oiioencoder.cpp +++ b/app/codec/oiio/oiioencoder.cpp @@ -62,7 +62,7 @@ bool OIIOEncoder::WriteFrame(FramePtr frame, rational time) return true; } -bool OIIOEncoder::WriteAudio(SampleBufferPtr audio) +bool OIIOEncoder::WriteAudio(const SampleBuffer &audio) { // Do nothing return false; diff --git a/app/codec/oiio/oiioencoder.h b/app/codec/oiio/oiioencoder.h index 7325cdf49..1099e68ca 100644 --- a/app/codec/oiio/oiioencoder.h +++ b/app/codec/oiio/oiioencoder.h @@ -35,7 +35,7 @@ public slots: virtual bool Open() override; virtual bool WriteFrame(olive::FramePtr frame, olive::rational time) override; - virtual bool WriteAudio(SampleBufferPtr audio) override; + virtual bool WriteAudio(const SampleBuffer &audio) override; virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override; virtual void Close() override; diff --git a/app/codec/samplebuffer.cpp b/app/codec/samplebuffer.cpp index 1dede4ae5..b7d93ec83 100644 --- a/app/codec/samplebuffer.cpp +++ b/app/codec/samplebuffer.cpp @@ -20,6 +20,8 @@ #include "samplebuffer.h" +#include "common/cpuoptimize.h" + namespace olive { SampleBuffer::SampleBuffer() : @@ -27,25 +29,18 @@ SampleBuffer::SampleBuffer() : { } -SampleBufferPtr SampleBuffer::Create() +SampleBuffer::SampleBuffer(const AudioParams &audio_params, const rational &length) : + audio_params_(audio_params) { - return std::make_shared(); + sample_count_per_channel_ = audio_params_.time_to_samples(length); + allocate(); } -SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, const rational &length) +SampleBuffer::SampleBuffer(const AudioParams &audio_params, int samples_per_channel) : + audio_params_(audio_params), + sample_count_per_channel_(samples_per_channel) { - return CreateAllocated(audio_params, audio_params.time_to_samples(length)); -} - -SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, int samples_per_channel) -{ - SampleBufferPtr buffer = Create(); - - buffer->set_audio_params(audio_params); - buffer->set_sample_count(samples_per_channel); - buffer->allocate(); - - return buffer; + allocate(); } const AudioParams &SampleBuffer::audio_params() const @@ -104,14 +99,11 @@ void SampleBuffer::allocate() for (int i=0; i; - /** * @brief A buffer of audio samples * @@ -42,12 +39,8 @@ class SampleBuffer { public: SampleBuffer(); - - static SampleBufferPtr Create(); - static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, const rational& length); - static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, int samples_per_channel); - - DISABLE_COPY_MOVE(SampleBuffer) + SampleBuffer(const AudioParams& audio_params, const rational& length); + SampleBuffer(const AudioParams& audio_params, int samples_per_channel); const AudioParams& audio_params() const; void set_audio_params(const AudioParams& params); @@ -69,9 +62,13 @@ public: return data_.at(channel).constData(); } - float **to_raw_ptrs() + QVector to_raw_ptrs() { - return raw_ptrs_.data(); + QVector r(data_.size()); + for (int i=0; i > data_; - QVector raw_ptrs_; }; } -Q_DECLARE_METATYPE(olive::SampleBufferPtr) +Q_DECLARE_METATYPE(olive::SampleBuffer) #endif // SAMPLEBUFFER_H diff --git a/app/core.cpp b/app/core.cpp index eacde37e8..0010cae4d 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -108,7 +108,7 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index 10661f30a..5951ef921 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -67,45 +67,48 @@ void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV Q_UNUSED(globals) // Create a sample job - SampleJob job(kSamplesInput, value); - - if (job.HasSamples()) { - bool push_job = false; + SampleBuffer samples = value[kSamplesInput].toSamples(); + if (samples.is_allocated()) { + bool pushed_job = false; // This node is only compatible with stereo audio - if (job.samples()->audio_params().channel_count() == 2) { + if (samples.audio_params().channel_count() == 2) { // If the input is static, we can just do it now which will be faster if (IsInputStatic(kPanningInput)) { - float pan_volume = job.GetValue(kPanningInput).toDouble(); + float pan_volume = value[kPanningInput].toDouble(); if (!qIsNull(pan_volume)) { if (pan_volume > 0) { - job.samples()->transform_volume_for_channel(0, 1.0f - pan_volume); + samples.transform_volume_for_channel(0, 1.0f - pan_volume); } else { - job.samples()->transform_volume_for_channel(1, 1.0f + pan_volume); + samples.transform_volume_for_channel(1, 1.0f + pan_volume); } } } else { // Requires job - push_job = true; + + pushed_job = true; + table->Push(NodeValue::kSamples, SampleJob(kSamplesInput, value), this); } } - table->Push(NodeValue::kSamples, push_job ? QVariant::fromValue(job) : QVariant::fromValue(job.samples()), this); + if (!pushed_job) { + table->Push(value[kSamplesInput]); + } } } -void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const +void PanNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const { float pan_val = values[kPanningInput].toDouble(); - for (int i=0;iaudio_params().channel_count();i++) { - output->data(i)[index] = input->data(i)[index]; + for (int i=0;i 0) { - output->data(0)[index] *= (1.0F - pan_val); + output.data(0)[index] *= (1.0F - pan_val); } else if (pan_val < 0) { - output->data(1)[index] *= (1.0F - qAbs(pan_val)); + output.data(1)[index] *= (1.0F - qAbs(pan_val)); } } diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index 075eafb02..8d915a6fa 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -40,7 +40,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; + virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override; virtual void Retranslate() override; diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index e03d284b2..e0e05b6a4 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -73,7 +73,7 @@ void VolumeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, No table); } -void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const +void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const { return ProcessSamplesInternal(values, kOpMultiply, kSamplesInput, kVolumeInput, input, output, index); } diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index 38ba243d8..73f0c43df 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -40,7 +40,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; + virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override; virtual void Retranslate() override; diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index bc7466785..bba754160 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -60,27 +60,27 @@ void CrossDissolveTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJo job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); } -void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const +void CrossDissolveTransition::SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const { - for (int i=0; isample_count(); i++) { - double this_sample_time = out_samples->audio_params().samples_to_time(i).toDouble() + time_in; + for (int i=0; iaudio_params().channel_count(); j++) { - out_samples->data(j)[i] = 0; + for (int j=0; jsample_count()) { - out_samples->data(j)[i] += from_samples->data(j)[i] * TransformCurve(1.0 - progress); + if (from_samples.is_allocated()) { + if (i < from_samples.sample_count()) { + out_samples.data(j)[i] += from_samples.data(j)[i] * TransformCurve(1.0 - progress); } } - if (to_samples) { + if (to_samples.is_allocated()) { // Offset input samples from the end - int in_index = i - (out_samples->sample_count() - to_samples->sample_count()); + int in_index = i - (out_samples.sample_count() - to_samples.sample_count()); if (in_index >= 0) { - out_samples->data(j)[i] += to_samples->data(j)[in_index] * TransformCurve(progress); + out_samples.data(j)[i] += to_samples.data(j)[in_index] * TransformCurve(progress); } } } diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index b1787dbf2..6cd7c8960 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -45,7 +45,7 @@ public: protected: virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const override; - virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const override; + virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const override; }; diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 9cfaf24c2..5a3ade0d8 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -206,25 +206,22 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global push_job = QVariant::fromValue(job); } else if (data_type == NodeValue::kSamples) { // This must be an audio transition - SampleBufferPtr from_samples = out_buffer.toSamples(); - SampleBufferPtr to_samples = in_buffer.toSamples(); + SampleBuffer from_samples = out_buffer.toSamples(); + SampleBuffer to_samples = in_buffer.toSamples(); - if (from_samples || to_samples) { + if (from_samples.is_allocated() || to_samples.is_allocated()) { double time_in = globals.time().in().toDouble(); double time_out = globals.time().out().toDouble(); - const AudioParams& params = (from_samples) ? from_samples->audio_params() : to_samples->audio_params(); + const AudioParams& params = (from_samples.is_allocated()) ? from_samples.audio_params() : to_samples.audio_params(); - SampleBufferPtr out_samples; + SampleBuffer out_samples; if (params.is_valid()) { int nb_samples = params.time_to_samples(time_out - time_in); - out_samples = SampleBuffer::CreateAllocated(params, nb_samples); + out_samples = SampleBuffer(params, nb_samples); SampleJobEvent(from_samples, to_samples, out_samples, time_in); - } else { - // Create dummy sample buffer - out_samples = SampleBuffer::Create(); } job_type = NodeValue::kSamples; @@ -251,20 +248,6 @@ void TransitionBlock::InvalidateCache(const TimeRange &range, const QString &fro super::InvalidateCache(r, from, element, options); } -void TransitionBlock::ShaderJobEvent(const NodeValueRow &value, ShaderJob &job) const -{ - Q_UNUSED(value) - Q_UNUSED(job) -} - -void TransitionBlock::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const -{ - Q_UNUSED(from_samples) - Q_UNUSED(to_samples) - Q_UNUSED(out_samples) - Q_UNUSED(time_in) -} - double TransitionBlock::TransformCurve(double linear) const { switch (static_cast(GetStandardValue(kCurveInput).toInt())) { diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index e76888edd..0e3f740a6 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -73,9 +73,9 @@ public: static const QString kCenterInput; protected: - virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const; + virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const {} - virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const; + virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const {} double TransformCurve(double linear) const; diff --git a/app/node/hashtraverser.cpp b/app/node/hashtraverser.cpp index cff52dd77..28948cef8 100644 --- a/app/node/hashtraverser.cpp +++ b/app/node/hashtraverser.cpp @@ -72,14 +72,8 @@ void HashTraverser::ProcessVideoFootage(TexturePtr destination, const FootageJob texture_ids_.insert(destination.get(), hash_.result()); } -void HashTraverser::ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time) +void HashTraverser::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) { - Hash(FileFunctions::GetUniqueFileIdentifier(stream.filename())); - Hash(stream.loop_mode()); - Hash(stream.audio_params().stream_index()); - Hash(input_time); - - texture_ids_.insert(destination.get(), hash_.result()); } void HashTraverser::ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob &job) @@ -104,9 +98,8 @@ void HashTraverser::ProcessColorTransform(TexturePtr destination, const Node *no texture_ids_.insert(destination.get(), hash_.result()); } -void HashTraverser::ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) +void HashTraverser::ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) { - texture_ids_.insert(destination.get(), hash_.result()); } void HashTraverser::ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob &job) @@ -146,9 +139,6 @@ void HashTraverser::HashNodeValue(const NodeValue &value) if (value_type == NodeValue::kTexture) { TexturePtr texture = value.toTexture(); id_for_buffer = texture_ids_.value(texture.get()); - } else { - SampleBufferPtr samples = value.toSamples(); - id_for_buffer = texture_ids_.value(samples.get()); } if (!id_for_buffer.isEmpty()) { diff --git a/app/node/hashtraverser.h b/app/node/hashtraverser.h index c013f26b8..bdf0a70f4 100644 --- a/app/node/hashtraverser.h +++ b/app/node/hashtraverser.h @@ -35,13 +35,13 @@ public: protected: virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time) override; - virtual void ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time) override; + virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) override; virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job) override; virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override; - virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) override; + virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) override; virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job) override; diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index babe0b9a5..6bade4174 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -109,7 +109,7 @@ void MathNode::Value(const NodeValueRow &value, const NodeGlobals &globals, Node table); } -void MathNode::ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const +void MathNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const { return ProcessSamplesInternal(values, GetOperation(), kParamAIn, kParamBIn, input, output, index); } diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index 60c910140..65a63720e 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -54,7 +54,7 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; - virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; + virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const override; static const QString kMethodIn; static const QString kParamAIn; diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index 9a78b1f97..c1132fc7d 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -298,18 +298,18 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt case kPairSampleSample: { - SampleBufferPtr samples_a = val_a.toSamples(); - SampleBufferPtr samples_b = val_b.toSamples(); + SampleBuffer samples_a = val_a.toSamples(); + SampleBuffer samples_b = val_b.toSamples(); - int max_samples = qMax(samples_a->sample_count(), samples_b->sample_count()); - int min_samples = qMin(samples_a->sample_count(), samples_b->sample_count()); + int max_samples = qMax(samples_a.sample_count(), samples_b.sample_count()); + int min_samples = qMin(samples_a.sample_count(), samples_b.sample_count()); - SampleBufferPtr mixed_samples = SampleBuffer::CreateAllocated(samples_a->audio_params(), max_samples); + SampleBuffer mixed_samples = SampleBuffer(samples_a.audio_params(), max_samples); - for (int i=0;iaudio_params().channel_count();i++) { + for (int i=0;idata(i)[j] = PerformAll(operation, samples_a->data(i)[j], samples_b->data(i)[j]); + mixed_samples.data(i)[j] = PerformAll(operation, samples_a.data(i)[j], samples_b.data(i)[j]); } } @@ -317,11 +317,11 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt // Fill in remainder space with 0s int remainder = max_samples - min_samples; - SampleBufferPtr larger_buffer = (max_samples == samples_a->sample_count()) ? samples_a : samples_b; + const SampleBuffer &larger_buffer = (max_samples == samples_a.sample_count()) ? samples_a : samples_b; - for (int i=0;iaudio_params().channel_count();i++) { - memcpy(&mixed_samples->data(i)[min_samples], - &larger_buffer->data(i)[min_samples], + for (int i=0;iaudio_params().channel_count();i++) { + for (int i=0;idata(i), number, 0, job.samples()->sample_count()); + PerformAllOnFloatBufferSSE(operation, buffer.data(i), number, 0, buffer.sample_count()); #else - PerformAllOnFloatBuffer(operation, job.samples()->data(i), number, 0, job.samples()->sample_count()); + PerformAllOnFloatBuffer(operation, buffer.data(i), number, 0, buffer.sample_count()); #endif } } - output->Push(NodeValue::kSamples, QVariant::fromValue(job.samples()), this); + output->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this); } else { + SampleJob job(val_a.type() == NodeValue::kSamples ? val_a : val_b); + job.InsertValue(number_param, NodeValue(NodeValue::kFloat, number, this)); output->Push(NodeValue::kSamples, QVariant::fromValue(job), this); } } @@ -426,7 +427,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt } } -void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBase::Operation operation, const QString ¶m_a_in, const QString ¶m_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const +void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBase::Operation operation, const QString ¶m_a_in, const QString ¶m_b_in, const olive::SampleBuffer &input, olive::SampleBuffer &output, int index) const { // This function is only used for sample+number pairing NodeValue number_val = values[param_a_in]; @@ -441,8 +442,8 @@ void MathNodeBase::ProcessSamplesInternal(const NodeValueRow &values, MathNodeBa float number_flt = RetrieveNumber(number_val); - for (int i=0;iaudio_params().channel_count();i++) { - output->data(i)[index] = PerformAll(operation, input->data(i)[index], number_flt); + for (int i=0;i(operation, input.data(i)[index], number_flt); } } diff --git a/app/node/math/math/mathbase.h b/app/node/math/math/mathbase.h index 77f3fe336..80cb792a7 100644 --- a/app/node/math/math/mathbase.h +++ b/app/node/math/math/mathbase.h @@ -121,7 +121,7 @@ protected: void ValueInternal(Operation operation, Pairing pairing, const QString& param_a_in, const NodeValue &val_a, const QString& param_b_in, const NodeValue& val_b, const NodeGlobals &globals, NodeValueTable *output) const; - void ProcessSamplesInternal(const NodeValueRow &values, Operation operation, const QString& param_a_in, const QString& param_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const; + void ProcessSamplesInternal(const NodeValueRow &values, Operation operation, const QString& param_a_in, const QString& param_b_in, const SampleBuffer &input, SampleBuffer &output, int index) const; }; diff --git a/app/node/node.cpp b/app/node/node.cpp index b2eff40f2..e6c542f8d 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1525,7 +1525,7 @@ ShaderCode Node::GetShaderCode(const ShaderRequest &request) const return ShaderCode(QString(), QString()); } -void Node::ProcessSamples(const NodeValueRow &, const SampleBufferPtr, SampleBufferPtr, int) const +void Node::ProcessSamples(const NodeValueRow &, const SampleBuffer &, SampleBuffer &, int) const { } diff --git a/app/node/node.h b/app/node/node.h index 949cd6890..61af71fd7 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -691,7 +691,7 @@ public: /** * @brief If Value() pushes a ShaderJob, this is the function that will process them. */ - virtual void ProcessSamples(const NodeValueRow &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const; + virtual void ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const; /** * @brief If Value() pushes a GenerateJob, override this function for the image to create diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 54cd8758c..2139bae4d 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -400,7 +400,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) } else if (job.type() == Track::kAudio) { - SampleBufferPtr buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length()); + SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length()); ProcessAudioFootage(buffer, job, range); val.set_value(buffer); @@ -409,7 +409,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) } else if (val.canConvert()) { SampleJob job = val.value(); - SampleBufferPtr output_buffer = CreateSampleBuffer(job.samples()->audio_params(), job.samples()->sample_count()); + SampleBuffer output_buffer = CreateSampleBuffer(job.samples().audio_params(), job.samples().sample_count()); ProcessSamples(output_buffer, val.source(), range, job); val.set_value(QVariant::fromValue(output_buffer)); diff --git a/app/node/traverser.h b/app/node/traverser.h index b806230cb..090599673 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -85,13 +85,13 @@ protected: virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time){} - virtual void ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time){} + virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time){} virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job){} virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job){} - virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job){} + virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job){} virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){} @@ -102,18 +102,18 @@ protected: return CreateDummyTexture(p); } - virtual SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, int sample_count) + virtual SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, int sample_count) { // Return dummy by default - return SampleBuffer::Create(); + return SampleBuffer(); } - SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, const rational &length) + SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, const rational &length) { if (params.is_valid()) { return CreateSampleBuffer(params, params.time_to_samples(length)); } else { - return SampleBuffer::Create(); + return SampleBuffer(); } } diff --git a/app/node/value.h b/app/node/value.h index bb5b56dbe..6c8534a2a 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -307,7 +307,7 @@ public: static void ValidateVectorString(QStringList* list, int count); TexturePtr toTexture() const { return value(); } - SampleBufferPtr toSamples() const { return value(); } + SampleBuffer toSamples() const { return value(); } bool toBool() const { return value(); } double toDouble() const { return value(); } int64_t toInt() const { return value(); } diff --git a/app/render/audioplaybackcache.cpp b/app/render/audioplaybackcache.cpp index e96d6cead..f014a2cf6 100644 --- a/app/render/audioplaybackcache.cpp +++ b/app/render/audioplaybackcache.cpp @@ -58,7 +58,7 @@ void AudioPlaybackCache::SetParameters(const AudioParams ¶ms) emit ParametersChanged(); } -void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, SampleBufferPtr samples) +void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples) { // Ensure if we have enough segments to write this data, creating more if not qint64 length_diff = params_.time_to_bytes_per_channel(range.out()) - playlist_.GetLength(); @@ -72,7 +72,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v TimeRangeList ranges_we_validated; // Calculate buffer size per channel - qint64 buffer_size_per_channel = samples ? samples->sample_count() * params_.bytes_per_sample_per_channel() : 0; + qint64 buffer_size_per_channel = samples.sample_count() * params_.bytes_per_sample_per_channel(); // Write each valid range to the segments foreach (const TimeRange& r, valid_ranges) { @@ -114,7 +114,7 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v if (possible_write_length > 0) { // Assume `samples` is valid if we're here, or else `buffer_size_per_channel` and // therefore `possible_write_length` will be 0. - seg_file.write(reinterpret_cast(samples->data(i)) + src_offset, possible_write_length); + seg_file.write(reinterpret_cast(samples.data(i)) + src_offset, possible_write_length); } if (possible_write_length < total_write_length) { @@ -167,7 +167,7 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range) { // WritePCM will automatically fill non-existent bytes with silence, so we just have to send // it an empty sample buffer - WritePCM(range, {range}, nullptr); + WritePCM(range, {range}, SampleBuffer()); } void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational &to_in_time) diff --git a/app/render/audioplaybackcache.h b/app/render/audioplaybackcache.h index 8394975a9..8a75b0173 100644 --- a/app/render/audioplaybackcache.h +++ b/app/render/audioplaybackcache.h @@ -66,7 +66,7 @@ public: void SetParameters(const AudioParams& params); - void WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, SampleBufferPtr samples); + void WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples); void WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform); diff --git a/app/render/job/samplejob.h b/app/render/job/samplejob.h index 65aca18f5..f2cd928e6 100644 --- a/app/render/job/samplejob.h +++ b/app/render/job/samplejob.h @@ -30,7 +30,6 @@ class SampleJob : public AcceleratedJob { public: SampleJob() { - samples_ = nullptr; } SampleJob(const NodeValue& value) @@ -43,18 +42,18 @@ public: samples_ = row[from].toSamples(); } - SampleBufferPtr samples() const + const SampleBuffer &samples() const { return samples_; } bool HasSamples() const { - return samples_ && samples_->is_allocated(); + return samples_.is_allocated(); } private: - SampleBufferPtr samples_; + SampleBuffer samples_; }; diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index c548b1f8f..6b17b1387 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -207,7 +207,7 @@ void PreviewAutoCacher::AudioRendered() // WritePCM is tolerant to its buffer being null, it will just write silence instead viewer_node_->audio_playback_cache()->WritePCM(range, valid_ranges, - watcher->Get().value()); + watcher->Get().value()); } viewer_node_->audio_playback_cache()->WriteWaveform(range, valid_ranges, &waveform); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index e81a056f7..de733dec5 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -200,11 +200,11 @@ void RenderProcessor::Run() ResolveJobs(sample_val, time); - SampleBufferPtr samples = sample_val.toSamples(); - if (samples && ticket_->property("enablewaveforms").toBool()) { + SampleBuffer samples = sample_val.toSamples(); + if (samples.is_allocated() && ticket_->property("enablewaveforms").toBool()) { AudioVisualWaveform vis; - vis.set_channel_count(samples->audio_params().channel_count()); - vis.OverwriteSamples(samples, samples->audio_params().sample_rate()); + vis.set_channel_count(samples.audio_params().channel_count()); + vis.OverwriteSamples(samples, samples.audio_params().sample_rate()); ticket_->setProperty("waveform", QVariant::fromValue(vis)); } @@ -275,9 +275,8 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim QVector active_blocks = track->BlocksAtTimeRange(range); // All these blocks will need to output to a buffer so we create one here - SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params, - audio_params.time_to_samples(range.length())); - block_range_buffer->silence(); + SampleBuffer block_range_buffer(audio_params, range.length()); + block_range_buffer.silence(); NodeValueTable merged_table; @@ -292,10 +291,10 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim // Destination buffer NodeValueTable table = GenerateTable(b, track->GetValueHintForInput(Track::kBlockInput, track->GetArrayIndexFromBlock(b)),Track::TransformRangeForBlock(b, range_for_block)); - SampleBufferPtr samples_from_this_block = table.Take(NodeValue::kSamples).toSamples(); + SampleBuffer samples_from_this_block = table.Take(NodeValue::kSamples).toSamples(); ClipBlock *clip_cast = dynamic_cast(b); - if (samples_from_this_block) { + if (samples_from_this_block.is_allocated()) { // If this is a clip, we might have extra speed/reverse information if (clip_cast) { double speed_value = clip_cast->speed(); @@ -303,12 +302,12 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim if (qIsNull(speed_value)) { // Just silence, don't think there's any other practical application of 0 speed audio - samples_from_this_block->silence(); + samples_from_this_block.silence(); } else if (!qFuzzyCompare(speed_value, 1.0)) { if (clip_cast->maintain_audio_pitch()) { AudioProcessor processor; - if (processor.Open(samples_from_this_block->audio_params(), samples_from_this_block->audio_params(), speed_value)) { + if (processor.Open(samples_from_this_block.audio_params(), samples_from_this_block.audio_params(), speed_value)) { AudioProcessor::Buffer out; // FIXME: This is not the best way to do this, the TempoProcessor works best @@ -317,7 +316,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim // well on export (assuming audio is all generated at once on export), but // users may hear clicks and pops in the audio during preview due to this // approach. - int r = processor.Convert(samples_from_this_block->to_raw_ptrs(), samples_from_this_block->sample_count(), nullptr); + int r = processor.Convert(samples_from_this_block.to_raw_ptrs().data(), samples_from_this_block.sample_count(), nullptr); if (r < 0) { qCritical() << "Failed to change tempo of audio:" << r; @@ -327,16 +326,13 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim processor.Convert(nullptr, 0, &out); if (!out.empty()) { - int nb_samples = out.front().size() * samples_from_this_block->audio_params().bytes_per_sample_per_channel(); + int nb_samples = out.front().size() * samples_from_this_block.audio_params().bytes_per_sample_per_channel(); if (nb_samples) { - SampleBufferPtr new_samples = SampleBuffer::Create(); - new_samples->set_audio_params(samples_from_this_block->audio_params()); - new_samples->set_sample_count(nb_samples); - new_samples->allocate(); + SampleBuffer new_samples(samples_from_this_block.audio_params(), nb_samples); for (int i=0; idata(i), out[i].data(), out[i].size()); + memcpy(new_samples.data(i), out[i].data(), out[i].size()); } samples_from_this_block = new_samples; @@ -346,20 +342,20 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim } } else { // Multiply time - samples_from_this_block->speed(speed_value); + samples_from_this_block.speed(speed_value); } } if (reversed) { - samples_from_this_block->reverse(); + samples_from_this_block.reverse(); } } - int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count()); + int copy_length = qMin(max_dest_sz, samples_from_this_block.sample_count()); // Copy samples into destination buffer - for (int i=0; iaudio_params().channel_count(); i++) { - block_range_buffer->set(i, samples_from_this_block->data(i), destination_offset, copy_length); + for (int i=0; iin(); - if (!(waveform_info.silence = !samples_from_this_block.get())) { + if (!(waveform_info.silence = !samples_from_this_block.is_allocated())) { // Generate a visual waveform from the samples acquired from this block AudioVisualWaveform visual_waveform; visual_waveform.set_channel_count(audio_params.channel_count()); @@ -483,7 +479,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ } } -void RenderProcessor::ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time) +void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) { DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index())); @@ -526,9 +522,9 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, co render_ctx_->BlitToTexture(shader, job, destination.get()); } -void RenderProcessor::ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) +void RenderProcessor::ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) { - if (!job.samples() || !job.samples()->is_allocated()) { + if (!job.samples().is_allocated()) { return; } @@ -536,7 +532,7 @@ void RenderProcessor::ProcessSamples(SampleBufferPtr destination, const Node *no const AudioParams& audio_params = GetCacheAudioParams(); - for (int i=0;isample_count();i++) { + for (int i=0;i(i) / static_cast(audio_params.sample_rate()); diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 8397b5f45..017cedada 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -46,11 +46,11 @@ protected: virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time) override; - virtual void ProcessAudioFootage(SampleBufferPtr destination, const FootageJob &stream, const TimeRange &input_time) override; + virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time) override; virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job) override; - virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) override; + virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job) override; virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override; @@ -63,9 +63,9 @@ protected: return render_ctx_->CreateTexture(p); } - virtual SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, int sample_count) override + virtual SampleBuffer CreateSampleBuffer(const AudioParams ¶ms, int sample_count) override { - return SampleBuffer::CreateAllocated(params, sample_count); + return SampleBuffer(params, sample_count); } virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs) override; diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index 819d9251e..21c330c29 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -192,7 +192,7 @@ bool ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect return true; } -bool ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) +bool ExportTask::AudioDownloaded(const TimeRange &range, const SampleBuffer &samples) { TimeRange adjusted_range = range; @@ -221,7 +221,7 @@ bool ExportTask::EncodeSubtitle(const SubtitleBlock *sub) } } -bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples) +bool ExportTask::WriteAudioLoop(const TimeRange& time, const SampleBuffer &samples) { if (!encoder_->WriteAudio(samples)) { SetError(encoder_->GetError()); @@ -232,7 +232,7 @@ bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples) for (auto it=audio_map_.begin(); it!=audio_map_.end(); it++) { TimeRange t = it.key(); - SampleBufferPtr s = it.value(); + SampleBuffer s = it.value(); if (t.in() == audio_time_) { // Erase from audio map since we're just about to write it diff --git a/app/task/export/export.h b/app/task/export/export.h index 2efade730..2ab27f917 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -40,7 +40,7 @@ protected: virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; - virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; + virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) override; virtual bool EncodeSubtitle(const SubtitleBlock *sub) override; @@ -50,11 +50,11 @@ protected: } private: - bool WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples); + bool WriteAudioLoop(const TimeRange &time, const SampleBuffer &samples); QHash time_map_; - QHash audio_map_; + QHash audio_map_; ColorManager* color_manager_; diff --git a/app/task/precache/precachetask.cpp b/app/task/precache/precachetask.cpp index bb1af998f..71cedb900 100644 --- a/app/task/precache/precachetask.cpp +++ b/app/task/precache/precachetask.cpp @@ -97,7 +97,7 @@ bool PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const return true; } -bool PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) +bool PreCacheTask::AudioDownloaded(const TimeRange &range, const SampleBuffer &samples) { // Pre-cache doesn't cache any audio diff --git a/app/task/precache/precachetask.h b/app/task/precache/precachetask.h index 78e153744..dcd9369bf 100644 --- a/app/task/precache/precachetask.h +++ b/app/task/precache/precachetask.h @@ -40,7 +40,7 @@ protected: virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; - virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; + virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) override; private: Project* project_; diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index 56e9975a2..c37c7cd93 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -195,7 +195,7 @@ bool RenderTask::Render(ColorManager* manager, TimeRange range = watcher->property("range").value(); - if (!AudioDownloaded(range, watcher->Get().value())) { + if (!AudioDownloaded(range, watcher->Get().value())) { result = false; } diff --git a/app/task/render/render.h b/app/task/render/render.h index 75d6c73c0..01909081f 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -53,7 +53,7 @@ protected: virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) = 0; - virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0; + virtual bool AudioDownloaded(const TimeRange& range, const SampleBuffer &samples) = 0; virtual bool EncodeSubtitle(const SubtitleBlock *subtitle); diff --git a/app/widget/audiomonitor/audiomonitor.cpp b/app/widget/audiomonitor/audiomonitor.cpp index 10777ba00..982bb152a 100644 --- a/app/widget/audiomonitor/audiomonitor.cpp +++ b/app/widget/audiomonitor/audiomonitor.cpp @@ -75,7 +75,7 @@ void AudioMonitor::Stop() // loop will stop itself since file_ and waveform_ are null. } -void AudioMonitor::PushSampleBuffer(SampleBufferPtr d) +void AudioMonitor::PushSampleBuffer(const SampleBuffer &d) { if (!params_.channel_count()) { return; @@ -83,7 +83,7 @@ void AudioMonitor::PushSampleBuffer(SampleBufferPtr d) QVector v(params_.channel_count(), 0); - AudioVisualWaveform::Sample summed = AudioVisualWaveform::SumSamples(d, 0, d->sample_count()); + AudioVisualWaveform::Sample summed = AudioVisualWaveform::SumSamples(d, 0, d.sample_count()); AudioVisualWaveformSampleToInternalValues(summed, v); diff --git a/app/widget/audiomonitor/audiomonitor.h b/app/widget/audiomonitor/audiomonitor.h index f532aa206..3c5e27d81 100644 --- a/app/widget/audiomonitor/audiomonitor.h +++ b/app/widget/audiomonitor/audiomonitor.h @@ -59,7 +59,7 @@ public: } } - static void PushSampleBufferOnAll(SampleBufferPtr d) + static void PushSampleBufferOnAll(const SampleBuffer &d) { foreach (AudioMonitor *m, instances_) { m->PushSampleBuffer(d); @@ -71,7 +71,7 @@ public slots: void Stop(); - void PushSampleBuffer(SampleBufferPtr samples); + void PushSampleBuffer(const SampleBuffer &samples); void StartWaveform(const AudioVisualWaveform *waveform, const rational& start, int playback_speed); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 1568f3237..f638bc67c 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -511,16 +511,16 @@ void ViewerWidget::ReceivedAudioBufferForPlayback() audio_playback_queue_.pop_front(); if (watcher->HasResult()) { - SampleBufferPtr samples = watcher->Get().value(); - if (samples) { + SampleBuffer samples = watcher->Get().value(); + if (samples.is_allocated()) { // If the samples must be reversed, reverse them now if (playback_speed_ < 0) { - samples->reverse(); + samples.reverse(); } // Convert to packed data for audio output AudioProcessor::Buffer buf; - int r = audio_processor_.Convert(samples->to_raw_ptrs(), samples->sample_count(), &buf); + int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf); // TempoProcessor may have emptied the array if (r >= 0) { @@ -556,8 +556,9 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing() RenderTicketWatcher *watcher = static_cast(sender()); if (watcher->HasResult()) { - if (SampleBufferPtr samples = watcher->Get().value()) { - if (samples->audio_params().channel_count() > 0) { + SampleBuffer samples = watcher->Get().value(); + if (samples.is_allocated()) { + if (samples.audio_params().channel_count() > 0) { /* Fade code const int kFadeSz = qMin(200, samples->sample_count()/4); for (int i=0; ito_raw_ptrs(), samples->sample_count(), &buf); + int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf); if (r >= 0) { if (!buf.empty()) { From 7af12bda9556c9ec1c569165e11796ddbb9c3d17 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 14:56:32 -0700 Subject: [PATCH 86/96] nodevalue: further qvariant abstraction --- app/node/value.h | 11 +++++++---- app/render/renderer.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/node/value.h b/app/node/value.h index 6c8534a2a..345b7ed4d 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -195,13 +195,14 @@ public: { } - NodeValue(Type type, const QVariant& data, const Node* from = nullptr, bool array = false, const QString& tag = QString()) : + template + NodeValue(Type type, const T& data, const Node* from = nullptr, bool array = false, const QString& tag = QString()) : type_(type), - data_(data), from_(from), tag_(tag), array_(array) { + set_value(data); } Type type() const @@ -362,7 +363,8 @@ public: values_.append(value.values_); } - void Push(NodeValue::Type type, const QVariant& data, const Node *from, bool array = false, const QString& tag = QString()) + template + void Push(NodeValue::Type type, const T& data, const Node *from, bool array = false, const QString& tag = QString()) { Push(NodeValue(type, data, from, array, tag)); } @@ -372,7 +374,8 @@ public: values_.prepend(value); } - void Prepend(NodeValue::Type type, const QVariant& data, const Node *from, bool array = false, const QString& tag = QString()) + template + void Prepend(NodeValue::Type type, const T& data, const Node *from, bool array = false, const QString& tag = QString()) { Prepend(NodeValue(type, data, from, array, tag)); } diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 2d75ae47f..bd18c725f 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -216,7 +216,7 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *des job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); - job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, color_job.GetInputAlphaAssociation())); + job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, int(color_job.GetInputAlphaAssociation()))); job.InsertValue(color_job.GetValues()); job.SetAlphaChannelRequired(color_job.GetAlphaChannelRequired()); From bc126ce1b776b00d7a00d01175736275be616eaa Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 14:56:42 -0700 Subject: [PATCH 87/96] volume: implement custom value function --- app/node/audio/volume/volume.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index e0e05b6a4..a12a939e1 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -63,14 +63,27 @@ QString VolumeNode::Description() const void VolumeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - return ValueInternal(kOpMultiply, - kPairSampleNumber, - kSamplesInput, - value[kSamplesInput], - kVolumeInput, - value[kVolumeInput], - globals, - table); + Q_UNUSED(globals) + + // Create a sample job + SampleBuffer buffer = value[kSamplesInput].toSamples(); + + if (buffer.is_allocated()) { + // If the input is static, we can just do it now which will be faster + if (IsInputStatic(kVolumeInput)) { + auto volume = value[kVolumeInput].toDouble(); + + if (!qFuzzyCompare(volume, 1.0)) { + buffer.transform_volume(volume); + } + + table->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this); + } else { + // Requires job + SampleJob job(kSamplesInput, value); + table->Push(NodeValue::kSamples, QVariant::fromValue(job), this); + } + } } void VolumeNode::ProcessSamples(const NodeValueRow &values, const SampleBuffer &input, SampleBuffer &output, int index) const From 6c7dbc852119853bf1f15add39ec858a110eb88c Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 15:14:23 -0700 Subject: [PATCH 88/96] maskdistort: add feather input --- app/node/distort/mask/mask.cpp | 38 +++++++++++++++++++++++++++++++--- app/node/distort/mask/mask.h | 2 ++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp index 1f1e3d832..ab510068d 100644 --- a/app/node/distort/mask/mask.cpp +++ b/app/node/distort/mask/mask.cpp @@ -20,20 +20,32 @@ #include "mask.h" +#include "node/filter/blur/blur.h" + namespace olive { #define super PolygonGenerator +const QString MaskDistortNode::kFeatherInput = QStringLiteral("feather_in"); + MaskDistortNode::MaskDistortNode() { // Mask should always be (1.0, 1.0, 1.0) for multiply to work correctly SetInputFlags(kColorInput, InputFlags(GetInputFlags(kColorInput) | kInputFlagHidden)); + + AddInput(kFeatherInput, NodeValue::kFloat, 0.0); + SetInputProperty(kFeatherInput, QStringLiteral("min"), 0.0); } ShaderCode MaskDistortNode::GetShaderCode(const ShaderRequest &request) const { - Q_UNUSED(request) - return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/multiply.frag"))); + if (request.id == QStringLiteral("mrg")) { + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/multiply.frag"))); + } else if (request.id == QStringLiteral("feather")) { + return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/blur.frag"))); + } else { + return ShaderCode(); + } } void MaskDistortNode::Retranslate() @@ -41,6 +53,7 @@ void MaskDistortNode::Retranslate() super::Retranslate(); SetInputName(kBaseInput, tr("Texture")); + SetInputName(kFeatherInput, tr("Feather")); } void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const @@ -53,7 +66,26 @@ void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global merge.SetShaderID(QStringLiteral("mrg")); merge.InsertValue(QStringLiteral("tex_a"), value[kBaseInput]); - merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, QVariant::fromValue(job), this)); + + if (value[kFeatherInput].toDouble() > 0.0) { + // Nest a blur shader in there too + ShaderJob feather; + + feather.SetShaderID(QStringLiteral("feather")); + feather.InsertValue(BlurFilterNode::kTextureInput, NodeValue(NodeValue::kTexture, job, this)); + feather.InsertValue(BlurFilterNode::kMethodInput, NodeValue(NodeValue::kInt, int(BlurFilterNode::kGaussian), this)); + feather.InsertValue(BlurFilterNode::kHorizInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.InsertValue(BlurFilterNode::kVertInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.InsertValue(BlurFilterNode::kRepeatEdgePixelsInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.InsertValue(BlurFilterNode::kRadiusInput, NodeValue(NodeValue::kFloat, value[kFeatherInput].toDouble(), this)); + feather.SetIterations(2, BlurFilterNode::kTextureInput); + feather.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + feather.SetAlphaChannelRequired(ShaderJob::kAlphaForceOn); + + merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, feather, this)); + } else { + merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, job, this)); + } table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); } diff --git a/app/node/distort/mask/mask.h b/app/node/distort/mask/mask.h index d4794ac99..c782cb15a 100644 --- a/app/node/distort/mask/mask.h +++ b/app/node/distort/mask/mask.h @@ -59,6 +59,8 @@ public: virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override; + static const QString kFeatherInput; + }; } From b88e15b8cf2e1fd7320c6bdfba2ef197065e56bb Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 15:16:46 -0700 Subject: [PATCH 89/96] accleratedjob: simplified function calls --- .../diptocolor/diptocolortransition.cpp | 2 +- app/node/block/transition/transition.cpp | 12 +++++------ .../ociogradingtransformlinear.cpp | 12 +++++------ .../cornerpin/cornerpindistortnode.cpp | 16 +++++++-------- app/node/distort/crop/cropdistortnode.cpp | 16 +++++++-------- app/node/distort/flip/flipdistortnode.cpp | 8 ++++---- app/node/distort/mask/mask.cpp | 20 +++++++++---------- .../transform/transformdistortnode.cpp | 4 ++-- app/node/effect/opacity/opacityeffect.cpp | 8 ++++---- app/node/filter/blur/blur.cpp | 18 ++++++++--------- app/node/filter/mosaic/mosaicfilternode.cpp | 12 +++++------ app/node/filter/stroke/stroke.cpp | 12 +++++------ app/node/generator/noise/noise.cpp | 4 ++-- app/node/generator/polygon/polygon.cpp | 6 +++--- .../generator/shape/generatorwithmerge.cpp | 4 ++-- app/node/generator/shape/shapenode.cpp | 4 ++-- app/node/generator/solid/solid.cpp | 2 +- app/node/generator/text/textv1.cpp | 16 +++++++-------- app/node/generator/text/textv2.cpp | 20 +++++++++---------- app/node/generator/text/textv3.cpp | 10 +++++----- app/node/keying/chromakey/chromakey.cpp | 2 +- .../colordifferencekey/colordifferencekey.cpp | 4 ++-- app/node/keying/despill/despill.cpp | 6 +++--- app/node/math/math/mathbase.cpp | 8 ++++---- app/node/math/merge/merge.cpp | 10 +++++----- app/render/job/acceleratedjob.h | 8 ++++---- app/render/opengl/openglrenderer.cpp | 2 +- app/render/renderer.cpp | 20 +++++++++---------- app/render/renderprocessor.cpp | 4 ++-- app/widget/scope/histogram/histogram.cpp | 10 +++++----- app/widget/scope/scopebase/scopebase.cpp | 2 +- app/widget/scope/waveform/waveform.cpp | 8 ++++---- app/widget/viewer/viewerdisplay.cpp | 8 ++++---- 33 files changed, 149 insertions(+), 149 deletions(-) diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index dd49ea8b3..8700c3628 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -58,7 +58,7 @@ ShaderCode DipToColorTransition::GetShaderCode(const ShaderRequest &request) con void DipToColorTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJob &job) const { - job.InsertValue(kColorInput, value); + job.Insert(kColorInput, value); } } diff --git a/app/node/block/transition/transition.cpp b/app/node/block/transition/transition.cpp index 5a3ade0d8..38b956ad4 100644 --- a/app/node/block/transition/transition.cpp +++ b/app/node/block/transition/transition.cpp @@ -162,15 +162,15 @@ double TransitionBlock::GetInternalTransitionTime(const double &time) const void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &time) const { // Provides total transition progress from 0.0 (start) - 1.0 (end) - job->InsertValue(QStringLiteral("ove_tprog_all"), + job->Insert(QStringLiteral("ove_tprog_all"), NodeValue(NodeValue::kFloat, GetTotalProgress(time), this)); // Provides progress of out section from 1.0 (start) - 0.0 (end) - job->InsertValue(QStringLiteral("ove_tprog_out"), + job->Insert(QStringLiteral("ove_tprog_out"), NodeValue(NodeValue::kFloat, GetOutProgress(time), this)); // Provides progress of in section from 0.0 (start) - 1.0 (end) - job->InsertValue(QStringLiteral("ove_tprog_in"), + job->Insert(QStringLiteral("ove_tprog_in"), NodeValue(NodeValue::kFloat, GetInProgress(time), this)); } @@ -188,14 +188,14 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global ShaderJob job; if (out_buffer.type() != NodeValue::kNone) { - job.InsertValue(kOutBlockInput, out_buffer); + job.Insert(kOutBlockInput, out_buffer); } if (in_buffer.type() != NodeValue::kNone) { - job.InsertValue(kInBlockInput, in_buffer); + job.Insert(kInBlockInput, in_buffer); } - job.InsertValue(kCurveInput, value); + job.Insert(kCurveInput, value); double time = globals.time().in().toDouble(); InsertTransitionTimes(&job, time); diff --git a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp index ba2ab8e1c..5aa6ee8dc 100644 --- a/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp +++ b/app/node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp @@ -161,7 +161,7 @@ void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const Node job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].toTexture()); - job.InsertValue(value); + job.Insert(value); const int MASTER_CHANNEL = 0; const int RED_CHANNEL = 1; @@ -176,26 +176,26 @@ void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const Node offset[RED_CHANNEL] += offset[MASTER_CHANNEL]; offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL]; offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL]; - job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); + job.Insert(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL]))); QVector4D exposure = value[kExposureInput].toVec4(); exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]); exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]); exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]); - job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); + job.Insert(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL]))); QVector4D contrast = value[kContrastInput].toVec4(); contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL]; contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL]; contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL]; - job.InsertValue(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); + job.Insert(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL]))); if (!value[kClampBlackEnableInput].toBool()) { - job.InsertValue(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); + job.Insert(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack())); } if (!value[kClampWhiteEnableInput].toBool()) { - job.InsertValue(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); + job.Insert(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite())); } table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); diff --git a/app/node/distort/cornerpin/cornerpindistortnode.cpp b/app/node/distort/cornerpin/cornerpindistortnode.cpp index f7500505b..62015df1a 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.cpp +++ b/app/node/distort/cornerpin/cornerpindistortnode.cpp @@ -70,9 +70,9 @@ void CornerPinDistortNode::Retranslate() void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); // Convert slider values to their pixel values and then convert to clip space (-1.0 ... 1.0) for overriding the // vertex coordinates. @@ -94,16 +94,16 @@ void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g job.SetVertexCoordinates(adjusted_vertices); // If no texture do nothing - if (job.GetValue(kTextureInput).toTexture()) { + if (job.Get(kTextureInput).toTexture()) { // In the special case that all sliders are in their default position just // push the texture. - if (!(job.GetValue(kTopLeftInput).toVec2().isNull() - && job.GetValue(kTopRightInput).toVec2().isNull() && - job.GetValue(kBottomRightInput).toVec2().isNull() && - job.GetValue(kBottomLeftInput).toVec2().isNull())) { + if (!(job.Get(kTopLeftInput).toVec2().isNull() + && job.Get(kTopRightInput).toVec2().isNull() && + job.Get(kBottomRightInput).toVec2().isNull() && + job.Get(kBottomLeftInput).toVec2().isNull())) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } } diff --git a/app/node/distort/crop/cropdistortnode.cpp b/app/node/distort/crop/cropdistortnode.cpp index 05b487abd..62532f839 100644 --- a/app/node/distort/crop/cropdistortnode.cpp +++ b/app/node/distort/crop/cropdistortnode.cpp @@ -78,18 +78,18 @@ void CropDistortNode::Retranslate() void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - if (job.GetValue(kTextureInput).toTexture()) { - if (!qIsNull(job.GetValue(kLeftInput).toDouble()) - || !qIsNull(job.GetValue(kRightInput).toDouble()) - || !qIsNull(job.GetValue(kTopInput).toDouble()) - || !qIsNull(job.GetValue(kBottomInput).toDouble())) { + if (job.Get(kTextureInput).toTexture()) { + if (!qIsNull(job.Get(kLeftInput).toDouble()) + || !qIsNull(job.Get(kRightInput).toDouble()) + || !qIsNull(job.Get(kTopInput).toDouble()) + || !qIsNull(job.Get(kBottomInput).toDouble())) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } } diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index efd9ad75f..050bbcc84 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -79,16 +79,16 @@ void FlipDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global { ShaderJob job; - job.InsertValue(value); + job.Insert(value); // If there's no texture, no need to run an operation - if (job.GetValue(kTextureInput).toTexture()) { + if (job.Get(kTextureInput).toTexture()) { // Only run shader if at least one of flip or flop are selected - if (job.GetValue(kHorizontalInput).toBool() || job.GetValue(kVerticalInput).toBool()) { + if (job.Get(kHorizontalInput).toBool() || job.Get(kVerticalInput).toBool()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { // If we're not flipping or flopping just push the texture - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } diff --git a/app/node/distort/mask/mask.cpp b/app/node/distort/mask/mask.cpp index ab510068d..b891a262d 100644 --- a/app/node/distort/mask/mask.cpp +++ b/app/node/distort/mask/mask.cpp @@ -65,26 +65,26 @@ void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global ShaderJob merge; merge.SetShaderID(QStringLiteral("mrg")); - merge.InsertValue(QStringLiteral("tex_a"), value[kBaseInput]); + merge.Insert(QStringLiteral("tex_a"), value[kBaseInput]); if (value[kFeatherInput].toDouble() > 0.0) { // Nest a blur shader in there too ShaderJob feather; feather.SetShaderID(QStringLiteral("feather")); - feather.InsertValue(BlurFilterNode::kTextureInput, NodeValue(NodeValue::kTexture, job, this)); - feather.InsertValue(BlurFilterNode::kMethodInput, NodeValue(NodeValue::kInt, int(BlurFilterNode::kGaussian), this)); - feather.InsertValue(BlurFilterNode::kHorizInput, NodeValue(NodeValue::kBoolean, true, this)); - feather.InsertValue(BlurFilterNode::kVertInput, NodeValue(NodeValue::kBoolean, true, this)); - feather.InsertValue(BlurFilterNode::kRepeatEdgePixelsInput, NodeValue(NodeValue::kBoolean, true, this)); - feather.InsertValue(BlurFilterNode::kRadiusInput, NodeValue(NodeValue::kFloat, value[kFeatherInput].toDouble(), this)); + feather.Insert(BlurFilterNode::kTextureInput, NodeValue(NodeValue::kTexture, job, this)); + feather.Insert(BlurFilterNode::kMethodInput, NodeValue(NodeValue::kInt, int(BlurFilterNode::kGaussian), this)); + feather.Insert(BlurFilterNode::kHorizInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.Insert(BlurFilterNode::kVertInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.Insert(BlurFilterNode::kRepeatEdgePixelsInput, NodeValue(NodeValue::kBoolean, true, this)); + feather.Insert(BlurFilterNode::kRadiusInput, NodeValue(NodeValue::kFloat, value[kFeatherInput].toDouble(), this)); feather.SetIterations(2, BlurFilterNode::kTextureInput); - feather.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + feather.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); feather.SetAlphaChannelRequired(ShaderJob::kAlphaForceOn); - merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, feather, this)); + merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, feather, this)); } else { - merge.InsertValue(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, job, this)); + merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, job, this)); } table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index cc98174e7..093808738 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -99,8 +99,8 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g if (!real_matrix.isIdentity()) { // The matrix will transform things ShaderJob job; - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture), this)); - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, real_matrix, this)); + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture), this)); + job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, real_matrix, this)); job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast(value[kInterpolationInput].toInt())); // FIXME: This should be optimized, we can use matrix math to determine if this operation will diff --git a/app/node/effect/opacity/opacityeffect.cpp b/app/node/effect/opacity/opacityeffect.cpp index 334641174..9ebabbc20 100644 --- a/app/node/effect/opacity/opacityeffect.cpp +++ b/app/node/effect/opacity/opacityeffect.cpp @@ -47,16 +47,16 @@ void OpacityEffect::Value(const NodeValueRow &value, const NodeGlobals &globals, { ShaderJob job; - job.InsertValue(value); + job.Insert(value); // If there's no texture, no need to run an operation - if (job.GetValue(kTextureInput).toTexture()) { - if (!qFuzzyCompare(job.GetValue(kValueInput).toDouble(), 1.0)) { + if (job.Get(kTextureInput).toTexture()) { + if (!qFuzzyCompare(job.Get(kValueInput).toDouble(), 1.0)) { job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { // 1.0 float is a no-op, so just push the texture - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } } diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 86f950893..6b822cf43 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -121,25 +121,25 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals { ShaderJob job; - job.InsertValue(value); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - Method method = static_cast(job.GetValue(kMethodInput).toInt()); + Method method = static_cast(job.Get(kMethodInput).toInt()); // If there's no texture, no need to run an operation - if (job.GetValue(kTextureInput).toTexture()) { + if (job.Get(kTextureInput).toTexture()) { bool can_push_job = true; // Check if radius is > 0 - if (job.GetValue(kRadiusInput).toDouble() > 0.0) { + if (job.Get(kRadiusInput).toDouble() > 0.0) { // Method-specific considerations switch (method) { case kBox: case kGaussian: { - bool horiz = job.GetValue(kHorizInput).toBool(); - bool vert = job.GetValue(kVertInput).toBool(); + bool horiz = job.Get(kHorizInput).toBool(); + bool vert = job.Get(kVertInput).toBool(); if (!horiz && !vert) { // Disable job if horiz and vert are unchecked @@ -160,14 +160,14 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals if (can_push_job) { // If we're not repeating pixels, expect an alpha channel to appear - if (!job.GetValue(kRepeatEdgePixelsInput).toBool()) { + if (!job.Get(kRepeatEdgePixelsInput).toBool()) { job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); } table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { // If we're not performing the blur job, just push the texture - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } diff --git a/app/node/filter/mosaic/mosaicfilternode.cpp b/app/node/filter/mosaic/mosaicfilternode.cpp index 31a14f28f..cf80a2139 100644 --- a/app/node/filter/mosaic/mosaicfilternode.cpp +++ b/app/node/filter/mosaic/mosaicfilternode.cpp @@ -55,20 +55,20 @@ void MosaicFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa { ShaderJob job; - job.InsertValue(value); + job.Insert(value); // Mipmapping makes this look weird, so we just use bilinear for finding the color of each block job.SetInterpolation(kTextureInput, Texture::kLinear); - if (job.GetValue(kTextureInput).toTexture()) { - TexturePtr texture = job.GetValue(kTextureInput).toTexture(); + if (job.Get(kTextureInput).toTexture()) { + TexturePtr texture = job.Get(kTextureInput).toTexture(); if (texture - && job.GetValue(kHorizInput).toInt() != texture->width() - && job.GetValue(kVertInput).toInt() != texture->height()) { + && job.Get(kHorizInput).toInt() != texture->width() + && job.Get(kVertInput).toInt() != texture->height()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } } diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index 32996ea9b..f3edea14e 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -88,15 +88,15 @@ void StrokeFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globa { ShaderJob job; - job.InsertValue(value); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); - if (job.GetValue(kTextureInput).toTexture()) { - if (job.GetValue(kRadiusInput).toDouble() > 0.0 - && job.GetValue(kOpacityInput).toDouble() > 0.0) { + if (job.Get(kTextureInput).toTexture()) { + if (job.Get(kRadiusInput).toDouble() > 0.0 + && job.Get(kOpacityInput).toDouble() > 0.0) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } else { - table->Push(job.GetValue(kTextureInput)); + table->Push(job.Get(kTextureInput)); } } } diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index 09dfaabd3..dff259996 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -82,8 +82,8 @@ void NoiseGeneratorNode::Value(const NodeValueRow &value, const NodeGlobals &glo { ShaderJob job; - job.InsertValue(value); - job.InsertValue(QStringLiteral("time_in"), NodeValue(NodeValue::kFloat, globals.time().in().toDouble(), this)); + job.Insert(value); + job.Insert(QStringLiteral("time_in"), NodeValue(NodeValue::kFloat, globals.time().in().toDouble(), this)); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index 412299df1..9677799af 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -93,7 +93,7 @@ GenerateJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const { GenerateJob job; - job.InsertValue(value); + job.Insert(value); job.SetRequestedFormat(VideoParams::kFormatFloat32); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); @@ -116,7 +116,7 @@ void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) con QImage img(frame->width(), frame->height(), QImage::Format_Grayscale8); img.fill(Qt::transparent); - QVector points = job.GetValue(kPointsInput).value< QVector >(); + QVector points = job.Get(kPointsInput).value< QVector >(); QPainterPath path = GeneratePath(points); @@ -130,7 +130,7 @@ void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) con p.drawPath(path); // Transplant alpha channel to frame - Color rgba = job.GetValue(kColorInput).toColor(); + Color rgba = job.Get(kColorInput).toColor(); #if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM) __m128 sse_color = _mm_loadu_ps(rgba.data()); #endif diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp index 47ae76e88..3e36c9229 100644 --- a/app/node/generator/shape/generatorwithmerge.cpp +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -58,8 +58,8 @@ void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, const QVaria ShaderJob merge; merge.SetShaderID(QStringLiteral("mrg")); - merge.InsertValue(MergeNode::kBaseIn, value[kBaseInput]); - merge.InsertValue(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, job, this)); + merge.Insert(MergeNode::kBaseIn, value[kBaseInput]); + merge.Insert(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, job, this)); table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); } else { diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp index 9f77939ad..b8af51bf9 100644 --- a/app/node/generator/shape/shapenode.cpp +++ b/app/node/generator/shape/shapenode.cpp @@ -74,8 +74,8 @@ void ShapeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, Nod { ShaderJob job; - job.InsertValue(value); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); + job.Insert(value); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this)); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); job.SetShaderID(QStringLiteral("shape")); diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index d06076666..237c98fde 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -64,7 +64,7 @@ void SolidGenerator::Retranslate() void SolidGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); + job.Insert(value); table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } diff --git a/app/node/generator/text/textv1.cpp b/app/node/generator/text/textv1.cpp index 395783dfa..b70aaa05b 100644 --- a/app/node/generator/text/textv1.cpp +++ b/app/node/generator/text/textv1.cpp @@ -93,10 +93,10 @@ void TextGeneratorV1::Retranslate() void TextGeneratorV1::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { GenerateJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - if (!job.GetValue(kTextInput).toString().isEmpty()) { + if (!job.Get(kTextInput).toString().isEmpty()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } @@ -114,15 +114,15 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Set default font QFont default_font; - default_font.setFamily(job.GetValue(kFontInput).toString()); - default_font.setPointSizeF(job.GetValue(kFontSizeInput).toDouble()); + default_font.setFamily(job.Get(kFontInput).toString()); + default_font.setPointSizeF(job.Get(kFontSizeInput).toDouble()); text_doc.setDefaultFont(default_font); // Center by default text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter)); - QString html = job.GetValue(kTextInput).toString(); - if (job.GetValue(kHtmlInput).toBool()) { + QString html = job.Get(kTextInput).toString(); + if (job.Get(kHtmlInput).toBool()) { html.replace('\n', QStringLiteral("
")); text_doc.setHtml(html); } else { @@ -140,7 +140,7 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Push 10% inwards to compensate for title safe area p.translate(tenth_of_width, 0); - TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).toInt()); + TextVerticalAlign valign = static_cast(job.Get(kVAlignInput).toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -163,7 +163,7 @@ void TextGeneratorV1::GenerateFrame(FramePtr frame, const GenerateJob& job) cons text_doc.documentLayout()->draw(&p, ctx); // Transplant alpha channel to frame - Color rgb = job.GetValue(kColorInput).toColor(); + Color rgb = job.Get(kColorInput).toColor(); for (int x=0; xwidth(); x++) { for (int y=0; yheight(); y++) { uchar src_alpha = img.bits()[img.bytesPerLine() * y + x]; diff --git a/app/node/generator/text/textv2.cpp b/app/node/generator/text/textv2.cpp index 0d607715d..2d091c4c9 100644 --- a/app/node/generator/text/textv2.cpp +++ b/app/node/generator/text/textv2.cpp @@ -96,11 +96,11 @@ void TextGeneratorV2::Retranslate() void TextGeneratorV2::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { GenerateJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); job.SetRequestedFormat(VideoParams::kFormatFloat32); - if (!job.GetValue(kTextInput).toString().isEmpty()) { + if (!job.Get(kTextInput).toString().isEmpty()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } @@ -124,19 +124,19 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons // Set default font QFont default_font; - default_font.setFamily(job.GetValue(kFontInput).toString()); - default_font.setPointSizeF(job.GetValue(kFontSizeInput).toDouble()); + default_font.setFamily(job.Get(kFontInput).toString()); + default_font.setPointSizeF(job.Get(kFontSizeInput).toDouble()); text_doc.setDefaultFont(default_font); - QString html = job.GetValue(kTextInput).toString(); - if (job.GetValue(kHtmlInput).toBool()) { + QString html = job.Get(kTextInput).toString(); + if (job.Get(kHtmlInput).toBool()) { html.replace('\n', QStringLiteral("
")); text_doc.setHtml(html); } else { text_doc.setPlainText(html); } - QVector2D size = job.GetValue(kSizeInput).toVec2(); + QVector2D size = job.Get(kSizeInput).toVec2(); text_doc.setTextWidth(size.x()); // Draw rich text onto image @@ -144,12 +144,12 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider()); - QVector2D pos = job.GetValue(kPositionInput).toVec2(); + QVector2D pos = job.Get(kPositionInput).toVec2(); p.translate(pos.x() - size.x()/2, pos.y() - size.y()/2); p.translate(frame->video_params().width()/2, frame->video_params().height()/2); p.setClipRect(0, 0, size.x(), size.y()); - TextVerticalAlign valign = static_cast(job.GetValue(kVAlignInput).toInt()); + TextVerticalAlign valign = static_cast(job.Get(kVAlignInput).toInt()); int doc_height = text_doc.size().height(); switch (valign) { @@ -171,7 +171,7 @@ void TextGeneratorV2::GenerateFrame(FramePtr frame, const GenerateJob& job) cons text_doc.documentLayout()->draw(&p, ctx); // Transplant alpha channel to frame - Color rgba = job.GetValue(kColorInput).toColor(); + Color rgba = job.Get(kColorInput).toColor(); #if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM) __m128 sse_color = _mm_loadu_ps(rgba.data()); #endif diff --git a/app/node/generator/text/textv3.cpp b/app/node/generator/text/textv3.cpp index d01c1b93d..40628ec46 100644 --- a/app/node/generator/text/textv3.cpp +++ b/app/node/generator/text/textv3.cpp @@ -81,14 +81,14 @@ void TextGeneratorV3::Retranslate() void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { GenerateJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); job.SetRequestedFormat(VideoParams::kFormatUnsigned8); // FIXME: Provide user override for this job.SetColorspace(project()->color_manager()->GetDefaultInputColorSpace()); - if (!job.GetValue(kTextInput).toString().isEmpty()) { + if (!job.Get(kTextInput).toString().isEmpty()) { PushMergableJob(value, QVariant::fromValue(job), table); } else if (value[kBaseInput].toTexture()) { table->Push(value[kBaseInput]); @@ -108,17 +108,17 @@ void TextGeneratorV3::GenerateFrame(FramePtr frame, const GenerateJob& job) cons QTextDocument text_doc; text_doc.documentLayout()->setPaintDevice(&img); - QString html = job.GetValue(kTextInput).toString(); + QString html = job.Get(kTextInput).toString(); Html::HtmlToDoc(&text_doc, html); - QVector2D size = job.GetValue(kSizeInput).toVec2(); + QVector2D size = job.Get(kSizeInput).toVec2(); text_doc.setTextWidth(size.x()); // Draw rich text onto image QPainter p(&img); p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider()); - QVector2D pos = job.GetValue(kPositionInput).toVec2(); + QVector2D pos = job.Get(kPositionInput).toVec2(); p.translate(pos.x() - size.x()/2, pos.y() - size.y()/2); p.translate(frame->video_params().width()/2, frame->video_params().height()/2); p.setClipRect(0, 0, size.x(), size.y()); diff --git a/app/node/keying/chromakey/chromakey.cpp b/app/node/keying/chromakey/chromakey.cpp index 3dbc1f56e..4d7701476 100644 --- a/app/node/keying/chromakey/chromakey.cpp +++ b/app/node/keying/chromakey/chromakey.cpp @@ -131,7 +131,7 @@ void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, if (value[kTextureInput].toTexture() && processor()) { ColorTransformJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(ColorTransformJob::kAlphaForceOn); job.SetColorProcessor(processor()); job.SetInputTexture(value[kTextureInput].toTexture()); diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index bd1113518..e4629816b 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -94,11 +94,11 @@ ShaderCode ColorDifferenceKeyNode::GetShaderCode(const ShaderRequest &request) c void ColorDifferenceKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); + job.Insert(value); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); // If there's no texture, no need to run an operation - if (job.GetValue(kTextureInput).toTexture()) { + if (job.Get(kTextureInput).toTexture()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index 577cfbab5..3f8e22723 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -82,16 +82,16 @@ ShaderCode DespillNode::GetShaderCode(const ShaderRequest &request) const { void DespillNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); + job.Insert(value); // Set luma coefficients double luma_coeffs[3] = {0.0f, 0.0f, 0.0f}; project()->color_manager()->GetDefaultLumaCoefs(luma_coeffs); - job.InsertValue(QStringLiteral("luma_coeffs"), + job.Insert(QStringLiteral("luma_coeffs"), NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]))); // If there's no texture, no need to run an operation - if (job.GetValue(kTextureInput).toTexture()) { + if (job.Get(kTextureInput).toTexture()) { table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); } } diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index c1132fc7d..d07658d94 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -341,8 +341,8 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt QString::number(val_a.type()), QString::number(val_b.type()))); - job.InsertValue(param_a_in, val_a); - job.InsertValue(param_b_in, val_b); + job.Insert(param_a_in, val_a); + job.Insert(param_b_in, val_b); bool operation_is_noop = false; @@ -370,7 +370,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt operation_is_noop = true; } else { // Replace with adjusted matrix - job.InsertValue(val_a.type() == NodeValue::kTexture ? param_b_in : param_a_in, + job.Insert(val_a.type() == NodeValue::kTexture ? param_b_in : param_a_in, NodeValue(NodeValue::kMatrix, adjusted_matrix, this)); // It's likely an alpha channel will result from this operation @@ -414,7 +414,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt output->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this); } else { SampleJob job(val_a.type() == NodeValue::kSamples ? val_a : val_b); - job.InsertValue(number_param, NodeValue(NodeValue::kFloat, number, this)); + job.Insert(number_param, NodeValue(NodeValue::kFloat, number, this)); output->Push(NodeValue::kSamples, QVariant::fromValue(job), this); } } diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 02506c9f3..4d758f175 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -77,18 +77,18 @@ ShaderCode MergeNode::GetShaderCode(const ShaderRequest &request) const void MergeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { ShaderJob job; - job.InsertValue(value); + job.Insert(value); - TexturePtr base_tex = job.GetValue(kBaseIn).toTexture(); - TexturePtr blend_tex = job.GetValue(kBlendIn).toTexture(); + TexturePtr base_tex = job.Get(kBaseIn).toTexture(); + TexturePtr blend_tex = job.Get(kBlendIn).toTexture(); if (base_tex || blend_tex) { if (!base_tex || (blend_tex && blend_tex->channel_count() < VideoParams::kRGBAChannelCount)) { // We only have a blend texture or the blend texture is RGB only, no need to alpha over - table->Push(job.GetValue(kBlendIn)); + table->Push(job.Get(kBlendIn)); } else if (!blend_tex) { // We only have a base texture, no need to alpha over - table->Push(job.GetValue(kBaseIn)); + table->Push(job.Get(kBaseIn)); } else { // We have both textures, push the job if (base_tex->channel_count() < VideoParams::kRGBAChannelCount) { diff --git a/app/render/job/acceleratedjob.h b/app/render/job/acceleratedjob.h index 534f4a528..c09138585 100644 --- a/app/render/job/acceleratedjob.h +++ b/app/render/job/acceleratedjob.h @@ -30,22 +30,22 @@ class AcceleratedJob { public: AcceleratedJob() = default; - NodeValue GetValue(const QString& input) const + NodeValue Get(const QString& input) const { return value_map_.value(input); } - void InsertValue(const QString &input, const NodeValueRow &row) + void Insert(const QString &input, const NodeValueRow &row) { value_map_.insert(input, row.value(input)); } - void InsertValue(const QString& input, const NodeValue& value) + void Insert(const QString& input, const NodeValue& value) { value_map_.insert(input, value); } - void InsertValue(const NodeValueRow &row) + void Insert(const NodeValueRow &row) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) value_map_.insert(row); diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index d5553704d..7f7119143 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -552,7 +552,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video // Ensure matrix is set, at least to identity GLint mvpmat_location = functions_->glGetUniformLocation(shader, "ove_mvpmat"); if (mvpmat_location > -1) { - functions_->glUniformMatrix4fv(mvpmat_location, 1, false, job.GetValue(QStringLiteral("ove_mvpmat")).toMatrix().constData()); + functions_->glUniformMatrix4fv(mvpmat_location, 1, false, job.Get(QStringLiteral("ove_mvpmat")).toMatrix().constData()); } // Set the viewport to the "physical" resolution of the destination diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index bd18c725f..a75d6c02f 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -61,9 +61,9 @@ TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const V color_cache_mutex_.unlock(); ShaderJob job; - job.InsertValue(QStringLiteral("top_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(top))); - job.InsertValue(QStringLiteral("bottom_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(bottom))); - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(params.effective_width(), params.effective_height()))); + job.Insert(QStringLiteral("top_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(top))); + job.Insert(QStringLiteral("bottom_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(bottom))); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(params.effective_width(), params.effective_height()))); TexturePtr output = CreateTexture(params); @@ -213,19 +213,19 @@ void Renderer::BlitColorManaged(const ColorTransformJob &color_job, Texture *des } ShaderJob job; - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); - job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); - job.InsertValue(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, int(color_job.GetInputAlphaAssociation()))); - job.InsertValue(color_job.GetValues()); + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(color_job.GetInputTexture()))); + job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, color_job.GetTransformMatrix())); + job.Insert(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, color_job.GetCropMatrix().inverted())); + job.Insert(QStringLiteral("ove_maintex_alpha"), NodeValue(NodeValue::kInt, int(color_job.GetInputAlphaAssociation()))); + job.Insert(color_job.GetValues()); job.SetAlphaChannelRequired(color_job.GetAlphaChannelRequired()); foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { - job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); + job.Insert(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); job.SetInterpolation(l.name, l.interpolation); } foreach (const ColorContext::LUT& l, color_ctx.lut1d_textures) { - job.InsertValue(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); + job.Insert(l.name, NodeValue(NodeValue::kTexture, QVariant::fromValue(l.texture))); job.SetInterpolation(l.name, l.interpolation); } diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index de733dec5..eb0ebff20 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -114,8 +114,8 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time } else { // No color transform, just blit ShaderJob job; - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture))); - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix)); + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture))); + job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix)); render_ctx_->BlitToTexture(default_shader_, job, blit_tex.get()); } diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index c03138a36..1027333a4 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -70,9 +70,9 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) ShaderJob shader_job; - shader_job.InsertValue(QStringLiteral("viewport"), NodeValue(NodeValue::kVec2, QVector2D(width(), height()))); - shader_job.InsertValue(QStringLiteral("histogram_scale"), NodeValue(NodeValue::kFloat, histogram_scale)); - shader_job.InsertValue(QStringLiteral("histogram_power"), NodeValue(NodeValue::kFloat, histogram_power)); + shader_job.Insert(QStringLiteral("viewport"), NodeValue(NodeValue::kVec2, QVector2D(width(), height()))); + shader_job.Insert(QStringLiteral("histogram_scale"), NodeValue(NodeValue::kFloat, histogram_scale)); + shader_job.Insert(QStringLiteral("histogram_power"), NodeValue(NodeValue::kFloat, histogram_power)); if (!texture_row_sums_ || texture_row_sums_->width() != this->width() @@ -83,11 +83,11 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) } // Draw managed texture to a sums texture - shader_job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); + shader_job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->BlitToTexture(pipeline, shader_job, texture_row_sums_.get()); // Draw sums into a histogram - shader_job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_row_sums_))); + shader_job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_row_sums_))); renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params()); // Draw line overlays diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index fc7c11774..e01b4978c 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -50,7 +50,7 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline) { ShaderJob job; - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 7bd440751..9e664cb49 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -54,22 +54,22 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) ShaderJob job; // Set viewport size - job.InsertValue(QStringLiteral("viewport"), + job.Insert(QStringLiteral("viewport"), NodeValue(NodeValue::kVec2, QVector2D(width(), height()))); // Set luma coefficients double luma_coeffs[3] = {0.0f, 0.0f, 0.0f}; color_manager()->GetDefaultLumaCoefs(luma_coeffs); - job.InsertValue(QStringLiteral("luma_coeffs"), + job.Insert(QStringLiteral("luma_coeffs"), NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]))); // Scale of the waveform relative to the viewport surface. - job.InsertValue(QStringLiteral("waveform_scale"), + job.Insert(QStringLiteral("waveform_scale"), NodeValue(NodeValue::kFloat, waveform_scale)); // Insert source texture - job.InsertValue(QStringLiteral("ove_maintex"), + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 231bc40cd..2ceb202e3 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -456,8 +456,8 @@ void ViewerDisplayWidget::OnPaint() } ShaderJob job; - job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_)); - job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_)); + job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_)); + job.Insert(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_)); renderer()->Blit(blank_shader_, job, device_params, false); } else if (color_service()) { @@ -496,8 +496,8 @@ void ViewerDisplayWidget::OnPaint() } ShaderJob job; - job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height()))); - job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw))); + job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height()))); + job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw))); renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get()); From 616121ee7a7daa3d902f0681921264d1f846f7da Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 15:58:19 -0700 Subject: [PATCH 90/96] nodevalue: remove unnecessary vecs --- app/node/value.cpp | 4 ---- app/node/value.h | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/node/value.cpp b/app/node/value.cpp index d103b1973..5b1355451 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -34,10 +34,6 @@ namespace olive { -const QVector NodeValue::kNumber = {kFloat, kInt, kRational}; -const QVector NodeValue::kBuffer = {kTexture, kSamples}; -const QVector NodeValue::kVector = {kVec2, kVec3, kVec4}; - QString NodeValue::ValueToString(Type data_type, const QVariant &value, bool value_is_a_key_track) { if (!value_is_a_key_track && data_type == kVec2) { diff --git a/app/node/value.h b/app/node/value.h index 345b7ed4d..49f977ad0 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -184,10 +184,6 @@ public: kDataTypeCount }; - static const QVector kNumber; - static const QVector kBuffer; - static const QVector kVector; - NodeValue() : type_(kNone), from_(nullptr), @@ -295,12 +291,22 @@ public: static bool type_is_numeric(NodeValue::Type type) { - return kNumber.contains(type); + return type == kFloat + || type == kInt + || type == kRational; } static bool type_is_vector(NodeValue::Type type) { - return kVector.contains(type); + return type == kVec2 + || type == kVec3 + || type == kVec4; + } + + static bool type_is_buffer(NodeValue::Type type) + { + return type == kTexture + || type == kSamples; } static int get_number_of_keyframe_tracks(Type type); From 1afb33e373ac7f0d0fce432f99c03dc9e10b3c38 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 16:11:15 -0700 Subject: [PATCH 91/96] timebasedwidget: snap to workarea --- app/widget/timebased/timebasedwidget.cpp | 8 ++++++++ app/widget/timebased/timebasedwidget.h | 1 + 2 files changed, 9 insertions(+) diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index ae9ae8746..844ac3386 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -782,6 +782,14 @@ bool TimeBasedWidget::SnapPoint(const std::vector &start_times, ration } } + if ((snap_points & kSnapToWorkarea) && ruler()->GetTimelinePoints()) { + const rational &workarea_in = ruler()->GetTimelinePoints()->workarea()->in(); + const rational &workarea_out = ruler()->GetTimelinePoints()->workarea()->out(); + + AttemptSnap(potential_snaps, screen_pt, TimeToScene(workarea_in), start_times, workarea_in); + AttemptSnap(potential_snaps, screen_pt, TimeToScene(workarea_out), start_times, workarea_out); + } + if ((snap_points & kSnapToKeyframes) && GetSnapKeyframes()) { for (auto it=GetSnapKeyframes()->cbegin(); it!=GetSnapKeyframes()->cend(); it++) { const QVector &keys = (*it)->GetKeyframes(); diff --git a/app/widget/timebased/timebasedwidget.h b/app/widget/timebased/timebasedwidget.h index 3dce38e5a..b2c2dee75 100644 --- a/app/widget/timebased/timebasedwidget.h +++ b/app/widget/timebased/timebasedwidget.h @@ -62,6 +62,7 @@ public: kSnapToPlayhead = 0x2, kSnapToMarkers = 0x4, kSnapToKeyframes = 0x8, + kSnapToWorkarea = 0x10, kSnapAll = UINT32_MAX }; From 063051c29a3fdd450f431a1fe37e8a0af386df63 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 16:11:30 -0700 Subject: [PATCH 92/96] render: fix crash if cancelled at specific point --- app/task/render/render.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index c37c7cd93..32b214e8b 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -87,7 +87,7 @@ bool RenderTask::Render(ColorManager* manager, rational r; for (int i=0; iterator.GetNext(&r); i++) { if (IsCancelled()) { - return true; + break; } times[i] = r; @@ -97,7 +97,7 @@ bool RenderTask::Render(ColorManager* manager, // Filter out duplicates for (int i=0; i Date: Mon, 9 May 2022 16:24:43 -0700 Subject: [PATCH 93/96] previewautocacher: don't write waveform if ticket was incomplete --- app/render/previewautocacher.cpp | 58 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index 6b17b1387..98e1e73d1 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -221,39 +221,39 @@ void PreviewAutoCacher::AudioRendered() // Wait for conform audio_needing_conform_.insert(range); } - } + } else{ + // Retrieve visual waveforms + QVector waveform_list = watcher->GetTicket()->property("waveforms").value< QVector >(); + foreach (const RenderProcessor::RenderedWaveform& waveform_info, waveform_list) { + // Find original track + ClipBlock* block = nullptr; - // Retrieve visual waveforms - QVector waveform_list = watcher->GetTicket()->property("waveforms").value< QVector >(); - foreach (const RenderProcessor::RenderedWaveform& waveform_info, waveform_list) { - // Find original track - ClipBlock* block = nullptr; - - for (auto it=copy_map_.cbegin(); it!=copy_map_.cend(); it++) { - if (it.value() == waveform_info.block) { - block = static_cast(it.key()); - break; - } - } - - if (block && !valid_ranges.isEmpty()) { - // Generate visual waveform in this background thread - block->waveform().set_channel_count(viewer_node_->GetAudioParams().channel_count()); - - // Determine which of the waveform ranges we got intersects with the valid ranges - TimeRangeList intersections = valid_ranges.Intersects(waveform_info.range + block->in()); - foreach (TimeRange r, intersections) { - // For each range, adjust it relative to the block and write it - r -= block->in(); - - if (waveform_info.silence) { - block->waveform().OverwriteSilence(r.in(), r.length()); - } else { - block->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length()); + for (auto it=copy_map_.cbegin(); it!=copy_map_.cend(); it++) { + if (it.value() == waveform_info.block) { + block = static_cast(it.key()); + break; } } - emit block->PreviewChanged(); + if (block && !valid_ranges.isEmpty()) { + // Generate visual waveform in this background thread + block->waveform().set_channel_count(viewer_node_->GetAudioParams().channel_count()); + + // Determine which of the waveform ranges we got intersects with the valid ranges + TimeRangeList intersections = valid_ranges.Intersects(waveform_info.range + block->in()); + foreach (TimeRange r, intersections) { + // For each range, adjust it relative to the block and write it + r -= block->in(); + + if (waveform_info.silence) { + block->waveform().OverwriteSilence(r.in(), r.length()); + } else { + block->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length()); + } + } + + emit block->PreviewChanged(); + } } } } From 0f99d8a662f2cfbe23001d200612cf85c053e891 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 17:53:21 -0700 Subject: [PATCH 94/96] timeruler: add ability to resize markers and workarea --- app/timeline/timelinemarker.cpp | 7 +- app/timeline/timelinemarker.h | 5 +- .../timebased/timebasedviewselectionmanager.h | 18 +++ app/widget/timebased/timebasedwidget.cpp | 9 +- app/widget/timebased/timebasedwidget.h | 3 +- .../undo/timelineundoworkarea.h | 22 +-- app/widget/timeruler/seekablewidget.cpp | 151 +++++++++++++++++- app/widget/timeruler/seekablewidget.h | 26 +++ 8 files changed, 218 insertions(+), 23 deletions(-) diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index 5fb5fb1fd..cc770e894 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -204,9 +204,7 @@ void TimelineMarkerList::HandleMarkerTimeChange() auto it = std::find(markers_.begin(), markers_.end(), m); - if ((it+1 != markers_.end() && (*(it+1))->time() < m->time()) - || (it != markers_.begin() && (*(it-1))->time() > m->time())) { - // Re-sort into list + if (it != markers_.end()) { markers_.erase(it); InsertIntoList(m); } @@ -304,8 +302,9 @@ void MarkerChangeNameCommand::undo() marker_->set_name(old_name_); } -MarkerChangeTimeCommand::MarkerChangeTimeCommand(TimelineMarker* marker, TimeRange time) : +MarkerChangeTimeCommand::MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time, const TimeRange &old_time) : marker_(marker), + old_time_(old_time), new_time_(time) { } diff --git a/app/timeline/timelinemarker.h b/app/timeline/timelinemarker.h index 492c61b9b..ae7cc4484 100644 --- a/app/timeline/timelinemarker.h +++ b/app/timeline/timelinemarker.h @@ -227,7 +227,10 @@ private: class MarkerChangeTimeCommand : public UndoCommand { public: - MarkerChangeTimeCommand(TimelineMarker* marker, TimeRange time); + MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time, const TimeRange &old_time); + MarkerChangeTimeCommand(TimelineMarker* marker, const TimeRange &time) : + MarkerChangeTimeCommand(marker, time, marker->time_range()) + {} virtual Project* GetRelevantProject() const override; diff --git a/app/widget/timebased/timebasedviewselectionmanager.h b/app/widget/timebased/timebasedviewselectionmanager.h index 106eef182..8c8a0cb6a 100644 --- a/app/widget/timebased/timebasedviewselectionmanager.h +++ b/app/widget/timebased/timebasedviewselectionmanager.h @@ -195,8 +195,26 @@ public: rational time_diff = view_->SceneToTimeNoGrid(view_->mapToScene(event->pos()).x() - drag_mouse_start_.x()); // Snap points + rational presnap_time_diff = time_diff; SnapPoints(&time_diff); + // Validate snapping + if (Core::instance()->snapping() && view_->GetSnapService()) { + for (size_t i=0; ihas_sibling_at_time(proposed_time)) { + // Unsnap + time_diff = presnap_time_diff; + if (view_->GetSnapService()) { + view_->GetSnapService()->HideSnaps(); + } + break; + } + } + } + // Validate movement for (size_t i=0; iadd_child(new WorkareaSetRangeCommand(viewer_node_->project(), points, TimeRange(in_point, out_point))); + command->add_child(new WorkareaSetRangeCommand(points->workarea(), TimeRange(in_point, out_point))); Core::instance()->undo_stack()->push(command); } @@ -511,7 +511,7 @@ void TimeBasedWidget::ResetPoint(Timeline::MovementMode m) r.set_out(TimelineWorkArea::kResetOut); } - Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(viewer_node_->project(), points, r)); + Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(points->workarea(), r)); } void TimeBasedWidget::PageScrollInternal(QScrollBar *bar, int maximum, int screen_position, bool whole_page_scroll) @@ -772,6 +772,11 @@ bool TimeBasedWidget::SnapPoint(const std::vector &start_times, ration for (auto it=ruler()->GetTimelinePoints()->markers()->cbegin(); it!=ruler()->GetTimelinePoints()->markers()->cend(); it++) { TimelineMarker* m = *it; + // Ignore selected markers + if (std::find(ruler()->GetSelectedMarkers().cbegin(), ruler()->GetSelectedMarkers().cend(), m) != ruler()->GetSelectedMarkers().cend()) { + continue; + } + qreal marker_pos = TimeToScene(m->time_range().in()); AttemptSnap(potential_snaps, screen_pt, marker_pos, start_times, m->time_range().in()); diff --git a/app/widget/timebased/timebasedwidget.h b/app/widget/timebased/timebasedwidget.h index b2c2dee75..3555cad98 100644 --- a/app/widget/timebased/timebasedwidget.h +++ b/app/widget/timebased/timebasedwidget.h @@ -141,6 +141,7 @@ protected: virtual const QVector *GetSnapBlocks() const { return nullptr; } virtual const QVector *GetSnapKeyframes() const { return nullptr; } virtual const std::vector *GetSnapIgnoreKeyframes() const { return nullptr; } + virtual const std::vector *GetSnapIgnoreMarkers() const { return nullptr; } protected slots: /** @@ -164,8 +165,6 @@ signals: void ConnectedNodeChanged(ViewerOutput* old, ViewerOutput* now); private: - - /** * @brief Set either in or out point to the current playhead * diff --git a/app/widget/timelinewidget/undo/timelineundoworkarea.h b/app/widget/timelinewidget/undo/timelineundoworkarea.h index c431178ec..a7b1e2655 100644 --- a/app/widget/timelinewidget/undo/timelineundoworkarea.h +++ b/app/widget/timelinewidget/undo/timelineundoworkarea.h @@ -65,34 +65,36 @@ private: class WorkareaSetRangeCommand : public UndoCommand { public: - WorkareaSetRangeCommand(Project *project, TimelinePoints* points, const TimeRange& range) : - project_(project), - points_(points), - old_range_(points_->workarea()->range()), + WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange& range, const TimeRange &old_range) : + workarea_(workarea), + old_range_(old_range), new_range_(range) { } + WorkareaSetRangeCommand(TimelineWorkArea *workarea, const TimeRange& range) : + WorkareaSetRangeCommand(workarea, range, workarea->range()) + { + } + virtual Project* GetRelevantProject() const override { - return project_; + return Project::GetProjectFromObject(workarea_); } protected: virtual void redo() override { - points_->workarea()->set_range(new_range_); + workarea_->set_range(new_range_); } virtual void undo() override { - points_->workarea()->set_range(old_range_); + workarea_->set_range(old_range_); } private: - Project* project_; - - TimelinePoints* points_; + TimelineWorkArea *workarea_; TimeRange old_range_; diff --git a/app/widget/timeruler/seekablewidget.cpp b/app/widget/timeruler/seekablewidget.cpp index 5af1f030a..8e0a657b5 100644 --- a/app/widget/timeruler/seekablewidget.cpp +++ b/app/widget/timeruler/seekablewidget.cpp @@ -26,12 +26,14 @@ #include #include "common/qtutils.h" +#include "common/range.h" #include "core.h" #include "dialog/markerproperties/markerpropertiesdialog.h" #include "node/project/serializer/serializer.h" #include "widget/colorlabelmenu/colorlabelmenu.h" #include "widget/menu/menushared.h" #include "widget/timebased/timebasedwidget.h" +#include "widget/timelinewidget/undo/timelineundoworkarea.h" namespace olive { @@ -42,7 +44,10 @@ SeekableWidget::SeekableWidget(QWidget* parent) : timeline_points_(nullptr), dragging_(false), ignore_next_focus_out_(false), - selection_manager_(this) + selection_manager_(this), + resize_item_(nullptr), + marker_top_(0), + marker_bottom_(0) { QFontMetrics fm = fontMetrics(); @@ -53,8 +58,9 @@ SeekableWidget::SeekableWidget(QWidget* parent) : setContextMenuPolicy(Qt::CustomContextMenu); setFocusPolicy(Qt::ClickFocus); + setMouseTracking(true); - selection_manager_.SetSnapMask(TimeBasedWidget::kSnapAll & ~TimeBasedWidget::kSnapToMarkers); + selection_manager_.SetSnapMask(TimeBasedWidget::kSnapAll); } void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points) @@ -159,7 +165,17 @@ bool SeekableWidget::PasteMarkers(bool insert, rational insert_time) void SeekableWidget::mousePressEvent(QMouseEvent *event) { - if (TimelineMarker *initial = selection_manager_.MousePress(event)) { + if (resize_item_) { + // Handle selection, even though we won't be using it for dragging + if (!(event->modifiers() & Qt::ShiftModifier)) { + selection_manager_.ClearSelection(); + } + if (TimelineMarker *m = dynamic_cast(resize_item_)) { + selection_manager_.Select(m); + } + dragging_ = true; + resize_start_ = mapToScene(event->pos()); + } else if (TimelineMarker *initial = selection_manager_.MousePress(event)) { selection_manager_.DragStart(initial, event); } else if (!selection_manager_.GetObjectAtPoint(event->pos()) && event->button() == Qt::LeftButton) { SeekToScenePoint(mapToScene(event->pos()).x()); @@ -174,7 +190,15 @@ void SeekableWidget::mouseMoveEvent(QMouseEvent *event) if (selection_manager_.IsDragging()) { selection_manager_.DragMove(event); } else if (dragging_) { - SeekToScenePoint(mapToScene(event->pos()).x()); + QPointF scene = mapToScene(event->pos()); + if (resize_item_) { + DragResizeHandle(scene); + } else { + SeekToScenePoint(scene.x()); + } + } else if (timeline_points_) { + // Look for resize points + setCursor(FindResizeHandle(event) ? Qt::SizeHorCursor : Qt::ArrowCursor); } } @@ -190,6 +214,11 @@ void SeekableWidget::mouseReleaseEvent(QMouseEvent *event) GetSnapService()->HideSnaps(); } + if (resize_item_) { + CommitResizeHandle(); + resize_item_ = nullptr; + } + dragging_ = false; } @@ -326,9 +355,12 @@ void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom) } QRect marker_rect = marker->Draw(p, QPoint(marker_left, marker_bottom), GetScale(), selection_manager_.IsSelected(marker)); + marker_top_ = marker_rect.top(); selection_manager_.DeclareDrawnObject(marker, marker_rect); } } + + marker_bottom_ = marker_bottom; } void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y) @@ -384,4 +416,115 @@ bool SeekableWidget::ShowContextMenu(const QPoint &p) } } +bool SeekableWidget::FindResizeHandle(QMouseEvent *event) +{ + resize_item_ = nullptr; + resize_mode_ = kResizeNone; + + QPointF scene = mapToScene(event->pos()); + const int border = 10; + rational min = SceneToTimeNoGrid(scene.x() - border); + rational max = SceneToTimeNoGrid(scene.x() + border); + + // Test for workarea + if (timeline_points_->workarea()->in() >= min && timeline_points_->workarea()->in() < max) { + resize_mode_ = kResizeIn; + } else if (timeline_points_->workarea()->out() >= min && timeline_points_->workarea()->out() < max) { + resize_mode_ = kResizeOut; + } + + if (resize_mode_ != kResizeNone) { + resize_item_ = timeline_points_->workarea(); + resize_item_range_ = timeline_points_->workarea()->range(); + resize_snap_mask_ = TimeBasedWidget::kSnapAll & ~TimeBasedWidget::kSnapToWorkarea; + } else if (event->pos().y() >= marker_top_ && event->pos().y() < marker_bottom_) { + // Check for markers + for (auto it=timeline_points_->markers()->cbegin(); it!=timeline_points_->markers()->cend(); it++) { + TimelineMarker *m = *it; + if (m->time_range().in() != m->time_range().out()) { + if (m->time_range().in() >= min && m->time_range().in() < max) { + resize_mode_ = kResizeIn; + } else if (m->time_range().out() >= min && m->time_range().out() < max) { + resize_mode_ = kResizeOut; + } + + if (resize_mode_ != kResizeNone) { + resize_item_ = m; + resize_item_range_ = m->time_range(); + resize_snap_mask_ = TimeBasedWidget::kSnapAll; + break; + } + } + } + } + + return resize_item_; +} + +void SeekableWidget::DragResizeHandle(const QPointF &scene) +{ + qreal diff = scene.x() - resize_start_.x(); + + rational proposed_time; + + if (resize_mode_ == kResizeIn) { + proposed_time = qMax(rational(0), qMin(resize_item_range_.out(), resize_item_range_.in() + SceneToTimeNoGrid(diff))); + } else { + proposed_time = qMax(resize_item_range_.in(), resize_item_range_.out() + SceneToTimeNoGrid(diff)); + } + + rational presnap_time = proposed_time; + + if (Core::instance()->snapping() && GetSnapService()) { + rational movement; + + GetSnapService()->SnapPoint({proposed_time}, &movement, resize_snap_mask_); + + proposed_time += movement; + } + + TimeRange new_range = resize_item_range_; + if (resize_mode_ == kResizeIn) { + // Markers should not have the same time as anything else + // NOTE: This code is largely duplicated from TimeBasedViewSelectionManager::DragMove. Not ideal, + // but I'm not sure if there's a good way to re-use that code + if (TimelineMarker *marker = dynamic_cast(resize_item_)) { + if (marker->has_sibling_at_time(proposed_time)) { + proposed_time = presnap_time; + + if (GetSnapService()) { + GetSnapService()->HideSnaps(); + } + } + + while (marker->has_sibling_at_time(proposed_time)) { + proposed_time += rational(1, 1000); + } + } + + new_range.set_in(proposed_time); + } else { + new_range.set_out(proposed_time); + } + + if (TimelineMarker *marker = dynamic_cast(resize_item_)) { + marker->set_time(new_range); + } else if (TimelineWorkArea *workarea = dynamic_cast(resize_item_)) { + workarea->set_range(new_range); + } +} + +void SeekableWidget::CommitResizeHandle() +{ + MultiUndoCommand *command = new MultiUndoCommand(); + + if (TimelineMarker *marker = dynamic_cast(resize_item_)) { + command->add_child(new MarkerChangeTimeCommand(marker, marker->time_range(), resize_item_range_)); + } else if (TimelineWorkArea *workarea = dynamic_cast(resize_item_)) { + command->add_child(new WorkareaSetRangeCommand(workarea, workarea->range(), resize_item_range_)); + } + + Core::instance()->undo_stack()->pushIfHasChildren(command); +} + } diff --git a/app/widget/timeruler/seekablewidget.h b/app/widget/timeruler/seekablewidget.h index 1bc8e61de..e151bbc4d 100644 --- a/app/widget/timeruler/seekablewidget.h +++ b/app/widget/timeruler/seekablewidget.h @@ -60,6 +60,11 @@ public: void SeekToScenePoint(qreal scene); + const std::vector &GetSelectedMarkers() const + { + return selection_manager_.GetSelectedObjects(); + } + virtual void SelectionManagerSelectEvent(void *obj) override; virtual void SelectionManagerDeselectEvent(void *obj) override; @@ -95,6 +100,18 @@ protected slots: virtual bool ShowContextMenu(const QPoint &p); private: + enum ResizeMode { + kResizeNone, + kResizeIn, + kResizeOut + }; + + bool FindResizeHandle(QMouseEvent *event); + + void DragResizeHandle(const QPointF &scene_pos); + + void CommitResizeHandle(); + TimelinePoints* timeline_points_; int text_height_; @@ -107,6 +124,15 @@ private: TimeBasedViewSelectionManager selection_manager_; + QObject *resize_item_; + ResizeMode resize_mode_; + TimeRange resize_item_range_; + QPointF resize_start_; + uint32_t resize_snap_mask_; + + int marker_top_; + int marker_bottom_; + private slots: void SetMarkerColor(int c); From e2db72860db4b140af527d89d694f1e459260b1b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 9 May 2022 20:21:05 -0700 Subject: [PATCH 95/96] core: remove unused functions --- app/core.cpp | 19 ------------------- app/core.h | 3 --- 2 files changed, 22 deletions(-) diff --git a/app/core.cpp b/app/core.cpp index 0010cae4d..a465d8add 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -1412,25 +1412,6 @@ int Core::CountFilesInFileList(const QFileInfoList &filenames) return file_count; } -QString GetRenderModePreferencePrefix(RenderMode::Mode mode, const QString &preference) { - QString key; - - key.append((mode == RenderMode::kOffline) ? QStringLiteral("Offline") : QStringLiteral("Online")); - key.append(preference); - - return key; -} - -QVariant Core::GetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference) -{ - return OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)); -} - -void Core::SetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference, const QVariant &value) -{ - OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)) = value; -} - bool Core::LabelNodes(const QVector &nodes, MultiUndoCommand *parent) { if (nodes.isEmpty()) { diff --git a/app/core.h b/app/core.h index 759cdd522..8466fa435 100644 --- a/app/core.h +++ b/app/core.h @@ -247,9 +247,6 @@ public: */ static int CountFilesInFileList(const QFileInfoList &filenames); - static QVariant GetPreferenceForRenderMode(RenderMode::Mode mode, const QString& preference); - static void SetPreferenceForRenderMode(RenderMode::Mode mode, const QString& preference, const QVariant& value); - /** * @brief Show a dialog to the user to rename a set of nodes */ From 158c1fecb64aab86bef0ae3631019d015d2dff78 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Tue, 10 May 2022 09:08:49 -0700 Subject: [PATCH 96/96] import: fixed crash when importing folders --- app/task/project/import/import.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index 900cc1d8b..150fcaedf 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -222,7 +222,7 @@ void ProjectImportTask::ValidateImageSequence(Footage *footage, QFileInfoList& i void ProjectImportTask::AddItemToFolder(Folder *folder, Node *item, MultiUndoCommand *command) { // Create undoable command that adds the items to the model - Project* project = folder->project(); + Project* project = folder_->project(); NodeAddCommand* nac = new NodeAddCommand(project, item); nac->PushToThread(project->thread());