Implement color LUT v0.4 features

This commit is contained in:
2026-06-07 00:24:08 +08:00
parent 0daad22129
commit cac5a40b58
25 changed files with 996 additions and 2 deletions
+2
View File
@@ -18,6 +18,8 @@ add_subdirectory(colormanager)
add_subdirectory(displaytransform)
add_subdirectory(ociobase)
add_subdirectory(ociogradingtransformlinear)
add_subdirectory(ociolut)
add_subdirectory(threewaycolor)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
+14
View File
@@ -0,0 +1,14 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2026 Oak 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.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/color/ociolut/ociolut.cpp
node/color/ociolut/ociolut.h
PARENT_SCOPE
)
+138
View File
@@ -0,0 +1,138 @@
/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak 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 "ociolut.h"
#include <QFileInfo>
#include "node/color/colormanager/colormanager.h"
namespace olive
{
const QString OCIOLutNode::kFileInput = QStringLiteral("lut_file_in");
const QString OCIOLutNode::kDirectionInput = QStringLiteral("lut_dir_in");
#define super OCIOBaseNode
OCIOLutNode::OCIOLutNode()
{
AddInput(kFileInput, NodeValue::kFile, QString(),
InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
SetInputProperty(
kFileInput, QStringLiteral("filter"),
tr("LUT Files (*.cube *.3dl);;Cube LUT (*.cube);;3DL LUT (*.3dl);;All Files (*)"));
SetInputProperty(kFileInput, QStringLiteral("placeholder"),
tr("Select a .cube or .3dl LUT file"));
AddInput(kDirectionInput, NodeValue::kCombo, 0,
InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
}
QString OCIOLutNode::Name() const
{
return tr("OCIO LUT");
}
QString OCIOLutNode::id() const
{
return QStringLiteral("org.olivevideoeditor.Olive.ociolut");
}
QVector<Node::CategoryID> OCIOLutNode::Category() const
{
return { kCategoryColor };
}
QString OCIOLutNode::Description() const
{
return tr("Applies a LUT file through OpenColorIO.");
}
void OCIOLutNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kFileInput, tr("LUT File"));
SetInputName(kDirectionInput, tr("Direction"));
SetComboBoxStrings(kDirectionInput, { tr("Forward"), tr("Inverse") });
}
void OCIOLutNode::InputValueChangedEvent(const QString &input, int element)
{
Q_UNUSED(element)
if (input == kFileInput || input == kDirectionInput) {
GenerateProcessor();
}
}
void OCIOLutNode::ConfigChanged()
{
GenerateProcessor();
}
void OCIOLutNode::GenerateProcessor()
{
if (!manager()) {
set_processor(nullptr);
return;
}
const QString path = GetStandardValue(kFileInput).toString();
if (path.isEmpty()) {
set_processor(nullptr);
return;
}
const QFileInfo info(path);
if (!info.exists() || !info.isFile()) {
qWarning() << "OCIO LUT file does not exist:" << path;
set_processor(nullptr);
return;
}
const QString suffix = info.suffix();
if (!OCIO::FileTransform::IsFormatExtensionSupported(suffix.toUtf8().constData())) {
qWarning() << "Unsupported OCIO LUT file extension:" << path;
set_processor(nullptr);
return;
}
try {
OCIO::FileTransformRcPtr transform = OCIO::FileTransform::Create();
transform->setSrc(path.toUtf8().constData());
transform->setInterpolation(OCIO::INTERP_LINEAR);
transform->setDirection(
static_cast<ColorProcessor::Direction>(
GetStandardValue(kDirectionInput).toInt()) == ColorProcessor::kNormal
? OCIO::TRANSFORM_DIR_FORWARD
: OCIO::TRANSFORM_DIR_INVERSE);
set_processor(ColorProcessor::Create(
manager()->GetConfig()->getProcessor(transform)));
} catch (const OCIO::Exception &e) {
qWarning() << "OCIO LUT processor error:" << e.what();
set_processor(nullptr);
}
}
} // namespace olive
+58
View File
@@ -0,0 +1,58 @@
/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak 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 OCIOLUTNODE_H
#define OCIOLUTNODE_H
#include "node/color/ociobase/ociobase.h"
#include "render/colorprocessor.h"
namespace olive
{
class OCIOLutNode : public OCIOBaseNode {
Q_OBJECT
public:
OCIOLutNode();
NODE_DEFAULT_FUNCTIONS(OCIOLutNode)
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;
static const QString kFileInput;
static const QString kDirectionInput;
protected slots:
virtual void ConfigChanged() override;
private:
void GenerateProcessor();
};
} // namespace olive
#endif // OCIOLUTNODE_H
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 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/threewaycolor/threewaycolor.h
node/color/threewaycolor/threewaycolor.cpp
PARENT_SCOPE
)
@@ -0,0 +1,124 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2026 mikesolar
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 "threewaycolor.h"
#include <QVector3D>
#include "node/project.h"
#include "widget/slider/floatslider.h"
namespace olive
{
#define super Node
const QString ThreeWayColorNode::kTextureInput = QStringLiteral("tex_in");
const QString ThreeWayColorNode::kShadowsColorInput =
QStringLiteral("shadows_color_in");
const QString ThreeWayColorNode::kMidtonesColorInput =
QStringLiteral("midtones_color_in");
const QString ThreeWayColorNode::kHighlightsColorInput =
QStringLiteral("highlights_color_in");
const QString ThreeWayColorNode::kShadowsAmountInput =
QStringLiteral("shadows_amount_in");
const QString ThreeWayColorNode::kMidtonesAmountInput =
QStringLiteral("midtones_amount_in");
const QString ThreeWayColorNode::kHighlightsAmountInput =
QStringLiteral("highlights_amount_in");
const QString ThreeWayColorNode::kLumaCoefficientsInput =
QStringLiteral("luma_coefficients_in");
ThreeWayColorNode::ThreeWayColorNode()
{
AddInput(kTextureInput, NodeValue::kTexture,
InputFlags(kInputFlagNotKeyframable));
const QVariant neutral = QVariant::fromValue(Color(0.5, 0.5, 0.5, 1.0));
AddInput(kShadowsColorInput, NodeValue::kColor, neutral);
AddInput(kMidtonesColorInput, NodeValue::kColor, neutral);
AddInput(kHighlightsColorInput, NodeValue::kColor, neutral);
AddInput(kShadowsAmountInput, NodeValue::kFloat, 1.0);
AddInput(kMidtonesAmountInput, NodeValue::kFloat, 1.0);
AddInput(kHighlightsAmountInput, NodeValue::kFloat, 1.0);
const QString min = QStringLiteral("min");
const QString view = QStringLiteral("view");
SetInputProperty(kShadowsAmountInput, min, 0.0);
SetInputProperty(kMidtonesAmountInput, min, 0.0);
SetInputProperty(kHighlightsAmountInput, min, 0.0);
SetInputProperty(kShadowsAmountInput, view, FloatSlider::kPercentage);
SetInputProperty(kMidtonesAmountInput, view, FloatSlider::kPercentage);
SetInputProperty(kHighlightsAmountInput, view, FloatSlider::kPercentage);
SetEffectInput(kTextureInput);
SetFlag(kVideoEffect);
}
void ThreeWayColorNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kShadowsColorInput, tr("Shadows"));
SetInputName(kMidtonesColorInput, tr("Midtones"));
SetInputName(kHighlightsColorInput, tr("Highlights"));
SetInputName(kShadowsAmountInput, tr("Shadows Amount"));
SetInputName(kMidtonesAmountInput, tr("Midtones Amount"));
SetInputName(kHighlightsAmountInput, tr("Highlights Amount"));
}
ShaderCode
ThreeWayColorNode::GetShaderCode(const ShaderRequest &request) const
{
Q_UNUSED(request)
return ShaderCode(
FileFunctions::ReadFileAsString(":/shaders/threewaycolor.frag"));
}
void ThreeWayColorNode::Value(const NodeValueRow &value,
const NodeGlobals &globals,
NodeValueTable *table) const
{
Q_UNUSED(globals)
if (TexturePtr tex = value[kTextureInput].toTexture()) {
ShaderJob job(value);
double luma_coeffs[3] = { 0.0, 0.0, 0.0 };
if (project() && project()->color_manager()) {
project()->color_manager()->GetDefaultLumaCoefs(luma_coeffs);
} else {
luma_coeffs[0] = 0.2126;
luma_coeffs[1] = 0.7152;
luma_coeffs[2] = 0.0722;
}
job.Insert(kLumaCoefficientsInput,
NodeValue(NodeValue::kVec3,
QVector3D(luma_coeffs[0], luma_coeffs[1],
luma_coeffs[2])));
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
}
@@ -0,0 +1,77 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2026 mikesolar
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 THREEWAYCOLORNODE_H
#define THREEWAYCOLORNODE_H
#include "node/node.h"
namespace olive
{
class ThreeWayColorNode : public Node {
Q_OBJECT
public:
ThreeWayColorNode();
NODE_DEFAULT_FUNCTIONS(ThreeWayColorNode)
virtual QString Name() const override
{
return tr("Three-Way Color");
}
virtual QString id() const override
{
return QStringLiteral("org.olivevideoeditor.Olive.threewaycolor");
}
virtual QVector<CategoryID> Category() const override
{
return { kCategoryColor };
}
virtual QString Description() const override
{
return tr("Adjusts shadows, midtones, and highlights separately.");
}
virtual void Retranslate() override;
virtual ShaderCode
GetShaderCode(const ShaderRequest &request) const override;
virtual void Value(const NodeValueRow &value, const NodeGlobals &globals,
NodeValueTable *table) const override;
static const QString kTextureInput;
static const QString kShadowsColorInput;
static const QString kMidtonesColorInput;
static const QString kHighlightsColorInput;
static const QString kShadowsAmountInput;
static const QString kMidtonesAmountInput;
static const QString kHighlightsAmountInput;
static const QString kLumaCoefficientsInput;
};
}
#endif // THREEWAYCOLORNODE_H
+6
View File
@@ -32,6 +32,8 @@
#include "block/transition/diptocolor/diptocolortransition.h"
#include "color/displaytransform/displaytransform.h"
#include "color/ociogradingtransformlinear/ociogradingtransformlinear.h"
#include "color/ociolut/ociolut.h"
#include "color/threewaycolor/threewaycolor.h"
#include "common/Current.h"
#include "distort/cornerpin/cornerpindistortnode.h"
#include "distort/crop/cropdistortnode.h"
@@ -358,6 +360,10 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new DisplayTransformNode();
case kOCIOGradingTransformLinear:
return new OCIOGradingTransformLinearNode();
case kOCIOLut:
return new OCIOLutNode();
case kThreeWayColor:
return new ThreeWayColorNode();
case kChromaKey:
return new ChromaKeyNode();
case kMaskDistort:
+2
View File
@@ -73,6 +73,8 @@ public:
kCornerPinDistort,
kDisplayTransform,
kOCIOGradingTransformLinear,
kOCIOLut,
kThreeWayColor,
kChromaKey,
kMaskDistort,
kDropShadowFilter,