From ff2eac55a53dd230830d2e74c13f387c50f67b0c Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 1 Feb 2022 16:12:08 +0000 Subject: [PATCH 01/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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 2827758fae9e54301d6edc36780ce43362d53bba Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Wed, 4 May 2022 20:04:43 +0100 Subject: [PATCH 19/48] 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 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 20/48] 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 21/48] 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 7c23ad0b5166fa84bd4f21255b704921dff72681 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Fri, 6 May 2022 18:51:35 +0100 Subject: [PATCH 22/48] 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 23/48] 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 24/48] 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 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 25/48] 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 26/48] 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 27/48] 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 28/48] 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 29/48] 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 30/48] 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 31/48] 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 32/48] 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 33/48] 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 34/48] 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 6d84df828871b6791b0e597981e92ad4001ac33e Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sat, 7 May 2022 21:47:52 +0100 Subject: [PATCH 35/48] 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 36/48] 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 37/48] 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 38/48] 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 39/48] 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 40/48] 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 41/48] 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 42/48] 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 43/48] 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 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 44/48] 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 45/48] 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 46/48] 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 47/48] 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 48/48] 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;