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;
+}