Merge pull request #1875 from ThomasWilshaw/ocio_node

Initial OCIO node implementation
This commit is contained in:
itsmattkc
2022-05-08 11:57:05 -07:00
committed by GitHub
46 changed files with 1486 additions and 118 deletions
+3
View File
@@ -15,6 +15,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(colormanager)
add_subdirectory(displaytransform)
add_subdirectory(ociobase)
add_subdirectory(ociogradingtransformlinear)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
@@ -273,6 +273,7 @@ void ColorManager::InputValueChangedEvent(const QString &input, int element)
try {
SetConfig(OCIO::Config::CreateFromFile(GetConfigFilename().toUtf8()));
emit ConfigChanged();
} catch (OCIO::Exception&) {}
}
@@ -121,6 +121,9 @@ public:
virtual void Retranslate() override;
signals:
void ConfigChanged();
protected:
virtual void InputValueChangedEvent(const QString &input, int element) override;
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/color/displaytransform/displaytransform.cpp
node/color/displaytransform/displaytransform.h
PARENT_SCOPE
)
@@ -0,0 +1,144 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "displaytransform.h"
#include "node/color/colormanager/colormanager.h"
namespace olive {
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(kDisplayInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
AddInput(kViewInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
AddInput(kDirectionInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
}
QString DisplayTransformNode::Name() const
{
return tr("Display Transform");
}
QString DisplayTransformNode::id() const
{
return QStringLiteral("org.olivevideoeditor.Olive.displaytransform");
}
QVector<Node::CategoryID> DisplayTransformNode::Category() const
{
return {kCategoryColor};
}
QString DisplayTransformNode::Description() const
{
return tr("Converts an image to or from a display color space.");
}
void DisplayTransformNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kDisplayInput, tr("Display"));
SetInputName(kViewInput, tr("View"));
SetInputName(kDirectionInput, tr("Direction"));
SetComboBoxStrings(kDirectionInput, {tr("Forward"), tr("Inverse")});
}
void DisplayTransformNode::InputValueChangedEvent(const QString &input, int element)
{
Q_UNUSED(element);
if (input == kDisplayInput || input == kDirectionInput || input == kViewInput) {
if (input == kDisplayInput) {
UpdateViews();
}
GenerateProcessor();
}
}
QString DisplayTransformNode::GetDisplay() const
{
if (manager()) {
int index = GetStandardValue(kDisplayInput).toInt();
if (index < manager()->ListAvailableDisplays().size()) {
return manager()->ListAvailableDisplays().at(index);
}
}
return QString();
}
QString DisplayTransformNode::GetView() const
{
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();
}
ColorProcessor::Direction DisplayTransformNode::GetDirection() const
{
return static_cast<ColorProcessor::Direction>(GetStandardValue(kDirectionInput).toInt());;
}
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()));
}
}
}
@@ -0,0 +1,67 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef DISPLAYTRANSFORMNODE_H
#define DISPLAYTRANSFORMNODE_H
#include "node/color/ociobase/ociobase.h"
#include "render/colorprocessor.h"
namespace olive {
class DisplayTransformNode : public OCIOBaseNode
{
Q_OBJECT
public:
DisplayTransformNode();
NODE_DEFAULT_FUNCTIONS(DisplayTransformNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
virtual void InputValueChangedEvent(const QString &input, int element) override;
QString GetDisplay() const;
QString GetView() const;
ColorProcessor::Direction GetDirection() const;
static const QString kDisplayInput;
static const QString kViewInput;
static const QString kDirectionInput;
protected slots:
virtual void ConfigChanged() override;
private:
void GenerateProcessor();
void UpdateDisplays();
void UpdateViews();
};
} // olive
#endif // DISPLAYTRANSFORMNODE_H
+22
View File
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/color/ociobase/ociobase.cpp
node/color/ociobase/ociobase.h
PARENT_SCOPE
)
+69
View File
@@ -0,0 +1,69 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#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));
SetEffectInput(kTextureInput);
connect(this, &Node::AddedToGraph, this, &OCIOBaseNode::ParentChanged);
SetFlags(kVideoEffect);
}
void OCIOBaseNode::ParentChanged(NodeGraph *graph)
{
if (manager_) {
disconnect(manager_, &ColorManager::ConfigChanged, this, &OCIOBaseNode::ConfigChanged);
manager_ = nullptr;
}
if (Project *p = dynamic_cast<Project*>(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<TexturePtr>());
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
}
}
}
+60
View File
@@ -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 <http://www.gnu.org/licenses/>.
***/
#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
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/color/ociogradingtransformlinear/ociogradingtransformlinear.cpp
node/color/ociogradingtransformlinear/ociogradingtransformlinear.h
PARENT_SCOPE
)
@@ -0,0 +1,218 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "ociogradingtransformlinear.h"
#include <iostream>
#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("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("ocio_grading_primary_clampBlack");
const QString OCIOGradingTransformLinearNode::kClampWhiteEnableInput = QStringLiteral("clamp_white_enable_in");
const QString OCIOGradingTransformLinearNode::kClampWhiteInput = QStringLiteral("ocio_grading_primary_clampWhite");
#define super OCIOBaseNode
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);
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("view"), FloatSlider::kPercentage);
SetInputProperty(kSaturationInput, QStringLiteral("min"), 0.0);
AddInput(kPivotInput, NodeValue::kFloat, 0.18); // Default listed in OCIO::GradingPrimary
SetInputProperty(kPivotInput, QStringLiteral("base"), 0.01);
AddInput(kClampBlackEnableInput, NodeValue::kBoolean, false);
AddInput(kClampBlackInput, NodeValue::kFloat, 0.0);
SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool());
SetInputProperty(kClampBlackInput, QStringLiteral("base"), 0.01);
AddInput(kClampWhiteEnableInput, NodeValue::kBoolean, false);
AddInput(kClampWhiteInput, NodeValue::kFloat, 1.0);
SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool());
SetInputProperty(kClampWhiteInput, QStringLiteral("base"), 0.01);
// 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
{
return tr("OCIO Color Grading (Linear)");
}
QString OCIOGradingTransformLinearNode::id() const
{
return QStringLiteral("org.olivevideoeditor.Olive.ociogradingtransformlinear");
}
QVector<Node::CategoryID> OCIOGradingTransformLinearNode::Category() const
{
return {kCategoryColor};
}
QString OCIOGradingTransformLinearNode::Description() const
{
return tr("Simple linear color grading using OpenColorIO.");
}
void OCIOGradingTransformLinearNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
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"));
SetInputName(kClampBlackInput, tr("Black 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 == kClampWhiteEnableInput) {
SetInputProperty(kClampWhiteInput, QStringLiteral("enabled"), GetStandardValue(kClampWhiteEnableInput).toBool());
} else if (input == kClampBlackEnableInput) {
SetInputProperty(kClampBlackInput, QStringLiteral("enabled"), GetStandardValue(kClampBlackEnableInput).toBool());
} else if (input == kClampBlackInput) {
// Ensure the white clamp is always greater than the black clamp as per OCIO::GradingPrimary::validate
// 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();
}
void OCIOGradingTransformLinearNode::GenerateProcessor()
{
if (manager()) {
OCIO::GradingPrimaryTransformRcPtr gp = OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LIN);
gp->makeDynamic();
gp->setDirection(OCIO::TransformDirection::TRANSFORM_DIR_FORWARD);
try {
set_processor(ColorProcessor::Create(manager()->GetConfig()->getProcessor(gp)));
} catch (const OCIO::Exception &e) {
std::cerr << std::endl << e.what() << std::endl;
}
}
}
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<TexturePtr>());
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<QVector4D>();
offset[RED_CHANNEL] += offset[MASTER_CHANNEL];
offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL];
offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL];
job.InsertValue(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL])));
QVector4D exposure = value[kExposureInput].value<QVector4D>();
exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]);
exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]);
exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]);
job.InsertValue(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL])));
QVector4D contrast = value[kContrastInput].value<QVector4D>();
contrast[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);
}
}
void OCIOGradingTransformLinearNode::ConfigChanged()
{
GenerateProcessor();
}
void OCIOGradingTransformLinearNode::SetVec4InputColors(const QString &input)
{
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());
}
}
@@ -0,0 +1,68 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef OCIOGRADINGTRANSFORMLINEARNODE_H
#define OCIOGRADINGTRANSFORMLINEARNODE_H
#include "node/color/ociobase/ociobase.h"
#include "render/colorprocessor.h"
namespace olive {
class OCIOGradingTransformLinearNode : public OCIOBaseNode
{
Q_OBJECT
public:
OCIOGradingTransformLinearNode();
NODE_DEFAULT_FUNCTIONS(OCIOGradingTransformLinearNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
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;
static const QString kSaturationInput;
static const QString kPivotInput;
static const QString kClampBlackEnableInput;
static const QString kClampBlackInput;
static const QString kClampWhiteEnableInput;
static const QString kClampWhiteInput;
protected slots:
virtual void ConfigChanged() override;
private:
void SetVec4InputColors(const QString &input);
};
} // olive
#endif
+9
View File
@@ -29,6 +29,8 @@
#include "block/subtitle/subtitle.h"
#include "block/transition/crossdissolve/crossdissolvetransition.h"
#include "block/transition/diptocolor/diptocolortransition.h"
#include "color/displaytransform/displaytransform.h"
#include "color/ociogradingtransformlinear/ociogradingtransformlinear.h"
#include "distort/cornerpin/cornerpindistortnode.h"
#include "distort/crop/cropdistortnode.h"
#include "distort/flip/flipdistortnode.h"
@@ -52,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"
@@ -281,6 +284,12 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new TimeOffsetNode();
case kCornerPinDistort:
return new CornerPinDistortNode();
case kDisplayTransform:
return new DisplayTransformNode();
case kOCIOGradingTransformLinear:
return new OCIOGradingTransformLinearNode();
case kChromaKey:
return new ChromaKeyNode();
case kInternalNodeCount:
break;
+3
View File
@@ -70,6 +70,9 @@ public:
kNoiseGenerator,
kTimeOffsetNode,
kCornerPinDistort,
kDisplayTransform,
kOCIOGradingTransformLinear,
kChromaKey,
// Count value
kInternalNodeCount
+1 -1
View File
@@ -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());
}
}
+6
View File
@@ -98,6 +98,12 @@ void HashTraverser::ProcessShader(TexturePtr destination, const Node *node, cons
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob &job)
{
Hash(job.GetColorProcessor()->id());
texture_ids_.insert(destination.get(), hash_.result());
}
void HashTraverser::ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job)
{
texture_ids_.insert(destination.get(), hash_.result());
+2
View File
@@ -39,6 +39,8 @@ protected:
virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job) override;
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job) override;
virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job) override;
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job) override;
+1
View File
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(chromakey)
add_subdirectory(colordifferencekey)
add_subdirectory(despill)
+22
View File
@@ -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 <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/keying/chromakey/chromakey.h
node/keying/chromakey/chromakey.cpp
PARENT_SCOPE
)
+150
View File
@@ -0,0 +1,150 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "chromakey.h"
#include "node/color/colormanager/colormanager.h"
#include "render/colorprocessor.h"
namespace olive {
#define super OCIOBaseNode
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()
{
AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0.0f, 1.0f, 0.0f, 1.0f)));
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("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));
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);
}
QString ChromaKeyNode::Name() const
{
return tr("Chroma Key");
}
QString ChromaKeyNode::id() const
{
return QStringLiteral("org.olivevideoeditor.Olive.chromakey");
}
QVector<Node::CategoryID> 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"));
SetInputName(kShadowsInput, tr("Shadows"));
SetInputName(kHighlightsInput, tr("Highlights"));
SetInputName(kUpperToleranceInput, tr("Upper Tolerance"));
SetInputName(kLowerToleranceInput, tr("Lower Tolerance"));
SetInputName(kMaskOnlyInput, tr("Show Mask Only"));
}
void ChromaKeyNode::InputValueChangedEvent(const QString &input, int element)
{
Q_UNUSED(element);
if (input == kLowerToleranceInput) {
// 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();
}
ShaderCode ChromaKeyNode::GetShaderCode(const ShaderRequest &request) const
{
return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/chromakey.frag")).arg(request.stub));
}
void ChromaKeyNode::GenerateProcessor()
{
if (manager()){
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;
}
}
}
void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
if (!value[kTextureInput].data().isNull() && processor()) {
ColorTransformJob job;
job.InsertValue(value);
job.SetAlphaChannelRequired(ColorTransformJob::kAlphaForceOn);
job.SetColorProcessor(processor());
job.SetInputTexture(value[kTextureInput].data().value<TexturePtr>());
job.SetNeedsCustomShader(this);
job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65"));
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
}
}
void ChromaKeyNode::ConfigChanged()
{
GenerateProcessor();
}
} // namespace olive
+62
View File
@@ -0,0 +1,62 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef CHROMAKEYNODE_H
#define CHROMAKEYNODE_H
#include "node/color/ociobase/ociobase.h"
namespace olive {
class ChromaKeyNode : public OCIOBaseNode {
Q_OBJECT
public:
ChromaKeyNode();
NODE_DEFAULT_FUNCTIONS(ChromaKeyNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> 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 ShaderRequest &request) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override;
virtual void ConfigChanged() override;
static const QString kColorInput;
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();
};
} // namespace olive
#endif // CHROMAKEYNODE_H
+1 -2
View File
@@ -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);
}
+13 -4
View File
@@ -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 {
@@ -667,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;
};
@@ -1058,10 +1069,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)
@@ -1380,7 +1390,6 @@ private:
QVector<NodeGizmo*> gizmos_;
QString effect_input_;
int effect_element_;
private slots:
/**
+23 -1
View File
@@ -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;
}
}
@@ -287,6 +295,7 @@ NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeR
return table;
}
QVector2D NodeTraverser::GenerateResolution() const
{
return QVector2D(video_params_.square_pixel_width(), video_params_.height());
@@ -339,6 +348,19 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
val.set_data(QVariant::fromValue(tex));
} else if (v.canConvert<ColorTransformJob>()) {
ColorTransformJob job = v.value<ColorTransformJob>();
VideoParams src_params = job.GetInputTexture()->params();
src_params.set_channel_count(GetChannelCountFromJob(job));
TexturePtr dest = CreateTexture(src_params);
ProcessColorTransform(dest, val.source(), job);
val.set_data(QVariant::fromValue(dest));
} else if (v.canConvert<FootageJob>()) {
FootageJob job = v.value<FootageJob>();
+3
View File
@@ -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 {
@@ -88,6 +89,8 @@ protected:
virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job){}
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job){}
virtual void ProcessSamples(SampleBufferPtr destination, const Node *node, const TimeRange &range, const SampleJob &job){}
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){}
+11
View File
@@ -203,6 +203,12 @@ public:
return type_;
}
template <typename T>
T value() const
{
return data_.value<T>();
}
const QVariant& data() const
{
return data_;
@@ -340,6 +346,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));
+5
View File
@@ -41,6 +41,11 @@ public:
tables_.insert(key, value);
}
NodeValueTable Take(const QString &key)
{
return tables_.take(key);
}
NodeValueTable Merge() const;
using Tables = QHash<QString, NodeValueTable>;