Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHallam Roberts <MysteryPancake>2022-05-04 19:44:03 +0300
committerHans Goudey <h.goudey@me.com>2022-05-04 19:44:03 +0300
commit82df48227bb7742466d429a5b465e0ada95d959d (patch)
tree59a44fc91b211beac52fb50002b51012f41931ed
parent7d41e1ed40ad74368a1019db554e47c6ab1baedb (diff)
Nodes: Add general Combine/Separate Color nodes
Inspired by D12936 and D12929, this patch adds general purpose "Combine Color" and "Separate Color" nodes to Geometry, Compositor, Shader and Texture nodes. - Within Geometry Nodes, it replaces the existing "Combine RGB" and "Separate RGB" nodes. - Within Compositor Nodes, it replaces the existing "Combine RGBA/HSVA/YCbCrA/YUVA" and "Separate RGBA/HSVA/YCbCrA/YUVA" nodes. - Within Texture Nodes, it replaces the existing "Combine RGBA" and "Separate RGBA" nodes. - Within Shader Nodes, it replaces the existing "Combine RGB/HSV" and "Separate RGB/HSV" nodes. Python addons have not been updated to the new nodes yet. **New shader code** In node_color.h, color.h and gpu_shader_material_color_util.glsl, missing methods hsl_to_rgb and rgb_to_hsl are added by directly converting existing C code. They always produce the same result. **Old code** As requested by T96219, old nodes still exist but are not displayed in the add menu. This means Python scripts can still create them as usual. Otherwise, versioning replaces the old nodes with the new nodes when opening .blend files. Differential Revision: https://developer.blender.org/D14034
-rw-r--r--intern/cycles/blender/shader.cpp12
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/osl/shaders/node_color.h50
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_color.osl12
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_color.osl26
-rw-r--r--intern/cycles/kernel/svm/color_util.h26
-rw-r--r--intern/cycles/kernel/svm/sepcomb_color.h53
-rw-r--r--intern/cycles/kernel/svm/svm.h7
-rw-r--r--intern/cycles/kernel/svm/types.h8
-rw-r--r--intern/cycles/scene/shader_nodes.cpp121
-rw-r--r--intern/cycles/scene/shader_nodes.h20
-rw-r--r--intern/cycles/util/color.h49
-rw-r--r--release/scripts/startup/nodeitems_builtins.py24
-rw-r--r--source/blender/blenkernel/BKE_node.h36
-rw-r--r--source/blender/blenkernel/intern/node.cc8
-rw-r--r--source/blender/blenlib/intern/math_color.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c245
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc24
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cc57
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc78
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cc57
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.h39
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc110
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h56
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cc62
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.h20
-rw-r--r--source/blender/editors/space_node/drawnode.cc40
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl50
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl28
-rw-r--r--source/blender/makesdna/DNA_node_types.h27
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c75
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_shader.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h38
-rw-r--r--source/blender/nodes/NOD_texture.h2
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc139
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc4
-rw-r--r--source/blender/nodes/function/CMakeLists.txt2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_color.cc108
-rw-r--r--source/blender/nodes/function/nodes/node_fn_separate_color.cc205
-rw-r--r--source/blender/nodes/intern/node_util.c33
-rw-r--r--source/blender/nodes/intern/node_util.h1
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc162
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc4
-rw-r--r--source/blender/nodes/texture/CMakeLists.txt2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_combine_color.c76
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_separate_color.c102
62 files changed, 2252 insertions, 196 deletions
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index d3527567b96..35c98a71558 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -355,6 +355,18 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
node = graph->create_node<CombineHSVNode>();
}
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateColor)) {
+ BL::ShaderNodeSeparateColor b_separate_node(b_node);
+ SeparateColorNode *separate_node = graph->create_node<SeparateColorNode>();
+ separate_node->set_color_type((NodeCombSepColorType)b_separate_node.mode());
+ node = separate_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineColor)) {
+ BL::ShaderNodeCombineColor b_combine_node(b_node);
+ CombineColorNode *combine_node = graph->create_node<CombineColorNode>();
+ combine_node->set_color_type((NodeCombSepColorType)b_combine_node.mode());
+ node = combine_node;
+ }
else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
node = graph->create_node<SeparateXYZNode>();
}
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index d97854a52d0..473bdb67920 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -145,6 +145,7 @@ set(SRC_KERNEL_SVM_HEADERS
svm/normal.h
svm/ramp.h
svm/ramp_util.h
+ svm/sepcomb_color.h
svm/sepcomb_hsv.h
svm/sepcomb_vector.h
svm/sky.h
diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 7ced21c5670..741bce7c399 100644
--- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -16,6 +16,7 @@ set(SRC_OSL
node_camera.osl
node_checker_texture.osl
node_clamp.osl
+ node_combine_color.osl
node_combine_rgb.osl
node_combine_hsv.osl
node_combine_xyz.osl
@@ -68,6 +69,7 @@ set(SRC_OSL
node_refraction_bsdf.osl
node_rgb_curves.osl
node_rgb_ramp.osl
+ node_separate_color.osl
node_separate_rgb.osl
node_separate_hsv.osl
node_separate_xyz.osl
diff --git a/intern/cycles/kernel/osl/shaders/node_color.h b/intern/cycles/kernel/osl/shaders/node_color.h
index 388dd114e9a..06735f5b03d 100644
--- a/intern/cycles/kernel/osl/shaders/node_color.h
+++ b/intern/cycles/kernel/osl/shaders/node_color.h
@@ -148,3 +148,53 @@ color hsv_to_rgb(color hsv)
return rgb;
}
+
+color rgb_to_hsl(color rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ return color(h, s, l);
+}
+
+color hsl_to_rgb(color hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ return color((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_combine_color.osl b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
new file mode 100644
index 00000000000..94d624d82ad
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_combine_color(string color_type = "rgb", float Red = 0.0, float Green = 0.0, float Blue = 0.0, output color Color = 0.8)
+{
+ if (color_type == "rgb" || color_type == "hsv" || color_type == "hsl")
+ Color = color(color_type, Red, Green, Blue);
+ else
+ warning("%s", "Unknown color space!");
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_separate_color.osl b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
new file mode 100644
index 00000000000..cba2d85da05
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "node_color.h"
+#include "stdcycles.h"
+
+shader node_separate_color(string color_type = "rgb",
+ color Color = 0.8,
+ output float Red = 0.0,
+ output float Green = 0.0,
+ output float Blue = 0.0)
+{
+ color col;
+ if (color_type == "rgb")
+ col = Color;
+ else if (color_type == "hsv")
+ col = rgb_to_hsv(Color);
+ else if (color_type == "hsl")
+ col = rgb_to_hsl(Color);
+ else
+ warning("%s", "Unknown color space!");
+
+ Red = col[0];
+ Green = col[1];
+ Blue = col[2];
+}
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
index b439721383c..fa22d4bc8c2 100644
--- a/intern/cycles/kernel/svm/color_util.h
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -307,4 +307,30 @@ ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness,
return color;
}
+ccl_device float3 svm_combine_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return hsv_to_rgb(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return hsl_to_rgb(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
+ccl_device float3 svm_separate_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return rgb_to_hsv(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return rgb_to_hsl(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sepcomb_color.h b/intern/cycles/kernel/svm/sepcomb_color.h
new file mode 100644
index 00000000000..a1a8cdfd9b0
--- /dev/null
+++ b/intern/cycles/kernel/svm/sepcomb_color.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_combine_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset)
+{
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(inputs_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ float r = stack_load_float(stack, red_stack_offset);
+ float g = stack_load_float(stack, green_stack_offset);
+ float b = stack_load_float(stack, blue_stack_offset);
+
+ /* Combine, and convert back to RGB */
+ float3 color = svm_combine_color((NodeCombSepColorType)color_type, make_float3(r, g, b));
+
+ if (stack_valid(result_stack_offset))
+ stack_store_float3(stack, result_stack_offset, color);
+}
+
+ccl_device_noinline void svm_node_separate_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint input_stack_offset,
+ uint results_stack_offsets)
+{
+ float3 color = stack_load_float3(stack, input_stack_offset);
+
+ /* Convert color space */
+ color = svm_separate_color((NodeCombSepColorType)color_type, color);
+
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(
+ results_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ if (stack_valid(red_stack_offset))
+ stack_store_float(stack, red_stack_offset, color.x);
+ if (stack_valid(green_stack_offset))
+ stack_store_float(stack, green_stack_offset, color.y);
+ if (stack_valid(blue_stack_offset))
+ stack_store_float(stack, blue_stack_offset, color.z);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 6b969da7e52..293501946c4 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -181,6 +181,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/noisetex.h"
#include "kernel/svm/normal.h"
#include "kernel/svm/ramp.h"
+#include "kernel/svm/sepcomb_color.h"
#include "kernel/svm/sepcomb_hsv.h"
#include "kernel/svm/sepcomb_vector.h"
#include "kernel/svm/sky.h"
@@ -520,6 +521,12 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
case NODE_MIX:
offset = svm_node_mix(kg, sd, stack, node.y, node.z, node.w, offset);
break;
+ case NODE_SEPARATE_COLOR:
+ svm_node_separate_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_COMBINE_COLOR:
+ svm_node_combine_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
case NODE_SEPARATE_VECTOR:
svm_node_separate_vector(sd, stack, node.y, node.z, node.w);
break;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index bede58f7a54..82109ec4c4f 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -92,6 +92,8 @@ typedef enum ShaderNodeType {
NODE_NORMAL_MAP,
NODE_INVERT,
NODE_MIX,
+ NODE_SEPARATE_COLOR,
+ NODE_COMBINE_COLOR,
NODE_SEPARATE_VECTOR,
NODE_COMBINE_VECTOR,
NODE_SEPARATE_HSV,
@@ -487,6 +489,12 @@ typedef enum NodePrincipledHairParametrization {
NODE_PRINCIPLED_HAIR_NUM,
} NodePrincipledHairParametrization;
+typedef enum NodeCombSepColorType {
+ NODE_COMBSEP_COLOR_RGB,
+ NODE_COMBSEP_COLOR_HSV,
+ NODE_COMBSEP_COLOR_HSL,
+} NodeCombSepColorType;
+
/* Closure */
typedef enum ClosureType {
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 95fccf725f3..06a2052d4cb 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -5010,6 +5010,63 @@ void MixNode::constant_fold(const ConstantFolder &folder)
}
}
+/* Combine Color */
+
+NODE_DEFINE(CombineColorNode)
+{
+ NodeType *type = NodeType::add("combine_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_FLOAT(r, "Red", 0.0f);
+ SOCKET_IN_FLOAT(g, "Green", 0.0f);
+ SOCKET_IN_FLOAT(b, "Blue", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+CombineColorNode::CombineColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_combine_color(color_type, make_float3(r, g, b)));
+ }
+}
+
+void CombineColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *red_in = input("Red");
+ ShaderInput *green_in = input("Green");
+ ShaderInput *blue_in = input("Blue");
+ ShaderOutput *color_out = output("Color");
+
+ int red_stack_offset = compiler.stack_assign(red_in);
+ int green_stack_offset = compiler.stack_assign(green_in);
+ int blue_stack_offset = compiler.stack_assign(blue_in);
+ int color_stack_offset = compiler.stack_assign(color_out);
+
+ compiler.add_node(
+ NODE_COMBINE_COLOR,
+ color_type,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset),
+ color_stack_offset);
+}
+
+void CombineColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_combine_color");
+}
+
/* Combine RGB */
NODE_DEFINE(CombineRGBNode)
@@ -5250,6 +5307,70 @@ void BrightContrastNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_brightness");
}
+/* Separate Color */
+
+NODE_DEFINE(SeparateColorNode)
+{
+ NodeType *type = NodeType::add("separate_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_FLOAT(r, "Red");
+ SOCKET_OUT_FLOAT(g, "Green");
+ SOCKET_OUT_FLOAT(b, "Blue");
+
+ return type;
+}
+
+SeparateColorNode::SeparateColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 col = svm_separate_color(color_type, color);
+
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(col[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *red_out = output("Red");
+ ShaderOutput *green_out = output("Green");
+ ShaderOutput *blue_out = output("Blue");
+
+ int color_stack_offset = compiler.stack_assign(color_in);
+ int red_stack_offset = compiler.stack_assign(red_out);
+ int green_stack_offset = compiler.stack_assign(green_out);
+ int blue_stack_offset = compiler.stack_assign(blue_out);
+
+ compiler.add_node(
+ NODE_SEPARATE_COLOR,
+ color_type,
+ color_stack_offset,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset));
+}
+
+void SeparateColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_separate_color");
+}
+
/* Separate RGB */
NODE_DEFINE(SeparateRGBNode)
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index 9aef5d3151f..ac40a397c1e 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1101,6 +1101,17 @@ class MixNode : public ShaderNode {
NODE_SOCKET_API(float, fac)
};
+class CombineColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float, r)
+ NODE_SOCKET_API(float, g)
+ NODE_SOCKET_API(float, b)
+};
+
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
@@ -1150,6 +1161,15 @@ class BrightContrastNode : public ShaderNode {
NODE_SOCKET_API(float, contrast)
};
+class SeparateColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float3, color)
+};
+
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
diff --git a/intern/cycles/util/color.h b/intern/cycles/util/color.h
index cccccde3ba6..a390b49cf7b 100644
--- a/intern/cycles/util/color.h
+++ b/intern/cycles/util/color.h
@@ -152,6 +152,55 @@ ccl_device float3 hsv_to_rgb(float3 hsv)
return rgb;
}
+ccl_device float3 rgb_to_hsl(float3 rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
+ cmin = min(rgb.x, min(rgb.y, rgb.z));
+ l = min(1.0f, (cmax + cmin) / 2.0f);
+
+ if (cmax == cmin) {
+ h = s = 0.0f; /* achromatic */
+ } else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5f ? cdelta / (2.0f - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb.x) {
+ h = (rgb.y - rgb.z) / cdelta + (rgb.y < rgb.z ? 6.0f : 0.0f);
+ }
+ else if (cmax == rgb.y) {
+ h = (rgb.z - rgb.x) / cdelta + 2.0f;
+ }
+ else {
+ h = (rgb.x - rgb.y) / cdelta + 4.0f;
+ }
+ }
+ h /= 6.0f;
+
+ return make_float3(h, s, l);
+}
+
+ccl_device float3 hsl_to_rgb(float3 hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl.x;
+ s = hsl.y;
+ l = hsl.z;
+
+ nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
+ ng = 2.0f - fabsf(h * 6.0f - 2.0f);
+ nb = 2.0f - fabsf(h * 6.0f - 4.0f);
+
+ nr = clamp(nr, 0.0f, 1.0f);
+ nb = clamp(nb, 0.0f, 1.0f);
+ ng = clamp(ng, 0.0f, 1.0f);
+
+ chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
+
+ return make_float3((nr - 0.5f) * chroma + l, (ng - 0.5f) * chroma + l, (nb - 0.5f) * chroma + l);
+}
+
ccl_device float3 xyY_to_xyz(float x, float y, float Y)
{
float X, Z;
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 4f94184f006..817c53cca62 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -419,12 +419,10 @@ shader_node_categories = [
NodeItem("ShaderNodeRGBToBW"),
NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll),
NodeItem("ShaderNodeVectorMath"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("ShaderNodeSeparateColor"),
+ NodeItem("ShaderNodeCombineColor"),
NodeItem("ShaderNodeSeparateXYZ"),
NodeItem("ShaderNodeCombineXYZ"),
- NodeItem("ShaderNodeSeparateHSV"),
- NodeItem("ShaderNodeCombineHSV"),
NodeItem("ShaderNodeWavelength"),
NodeItem("ShaderNodeBlackbody"),
]),
@@ -483,14 +481,8 @@ compositor_node_categories = [
NodeItem("CompositorNodePremulKey"),
NodeItem("CompositorNodeIDMask"),
NodeItem("CompositorNodeRGBToBW"),
- NodeItem("CompositorNodeSepRGBA"),
- NodeItem("CompositorNodeCombRGBA"),
- NodeItem("CompositorNodeSepHSVA"),
- NodeItem("CompositorNodeCombHSVA"),
- NodeItem("CompositorNodeSepYUVA"),
- NodeItem("CompositorNodeCombYUVA"),
- NodeItem("CompositorNodeSepYCCA"),
- NodeItem("CompositorNodeCombYCCA"),
+ NodeItem("CompositorNodeSeparateColor"),
+ NodeItem("CompositorNodeCombineColor"),
NodeItem("CompositorNodeSeparateXYZ"),
NodeItem("CompositorNodeCombineXYZ"),
NodeItem("CompositorNodeSwitchView"),
@@ -576,8 +568,8 @@ texture_node_categories = [
NodeItem("TextureNodeCurveRGB"),
NodeItem("TextureNodeInvert"),
NodeItem("TextureNodeHueSaturation"),
- NodeItem("TextureNodeCompose"),
- NodeItem("TextureNodeDecompose"),
+ NodeItem("TextureNodeCombineColor"),
+ NodeItem("TextureNodeSeparateColor"),
]),
TextureNodeCategory("TEX_PATTERN", "Pattern", items=[
NodeItem("TextureNodeChecker"),
@@ -629,8 +621,8 @@ geometry_node_categories = [
NodeItem("ShaderNodeMixRGB"),
NodeItem("ShaderNodeRGBCurve"),
NodeItem("ShaderNodeValToRGB"),
- NodeItem("ShaderNodeSeparateRGB"),
- NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("FunctionNodeSeparateColor"),
+ NodeItem("FunctionNodeCombineColor"),
]),
GeometryNodeCategory("GEO_CURVE", "Curve", items=curve_node_items),
GeometryNodeCategory("GEO_PRIMITIVES_CURVE", "Curve Primitives", items=[
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index c9228db9ecc..1ff10d06b00 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1090,8 +1090,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_SQUEEZE 117
//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
-#define SH_NODE_SEPRGB 120
-#define SH_NODE_COMBRGB 121
+#define SH_NODE_SEPRGB_LEGACY 120
+#define SH_NODE_COMBRGB_LEGACY 121
#define SH_NODE_HUE_SAT 122
#define SH_NODE_OUTPUT_MATERIAL 124
@@ -1147,8 +1147,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_WAVELENGTH 180
#define SH_NODE_BLACKBODY 181
#define SH_NODE_VECT_TRANSFORM 182
-#define SH_NODE_SEPHSV 183
-#define SH_NODE_COMBHSV 184
+#define SH_NODE_SEPHSV_LEGACY 183
+#define SH_NODE_COMBHSV_LEGACY 184
#define SH_NODE_BSDF_HAIR 185
// #define SH_NODE_LAMP 186
#define SH_NODE_UVMAP 187
@@ -1175,6 +1175,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_VECTOR_ROTATE 708
#define SH_NODE_CURVE_FLOAT 709
#define SH_NODE_POINT_INFO 710
+#define SH_NODE_COMBINE_COLOR 711
+#define SH_NODE_SEPARATE_COLOR 712
/** \} */
@@ -1202,8 +1204,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_MAP_VALUE 213
#define CMP_NODE_TIME 214
#define CMP_NODE_VECBLUR 215
-#define CMP_NODE_SEPRGBA 216
-#define CMP_NODE_SEPHSVA 217
+#define CMP_NODE_SEPRGBA_LEGACY 216
+#define CMP_NODE_SEPHSVA_LEGACY 217
#define CMP_NODE_SETALPHA 218
#define CMP_NODE_HUE_SAT 219
#define CMP_NODE_IMAGE 220
@@ -1213,14 +1215,14 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_TEXTURE 224
#define CMP_NODE_TRANSLATE 225
#define CMP_NODE_ZCOMBINE 226
-#define CMP_NODE_COMBRGBA 227
+#define CMP_NODE_COMBRGBA_LEGACY 227
#define CMP_NODE_DILATEERODE 228
#define CMP_NODE_ROTATE 229
#define CMP_NODE_SCALE 230
-#define CMP_NODE_SEPYCCA 231
-#define CMP_NODE_COMBYCCA 232
-#define CMP_NODE_SEPYUVA 233
-#define CMP_NODE_COMBYUVA 234
+#define CMP_NODE_SEPYCCA_LEGACY 231
+#define CMP_NODE_COMBYCCA_LEGACY 232
+#define CMP_NODE_SEPYUVA_LEGACY 233
+#define CMP_NODE_COMBYUVA_LEGACY 234
#define CMP_NODE_DIFF_MATTE 235
#define CMP_NODE_COLOR_SPILL 236
#define CMP_NODE_CHROMA_MATTE 237
@@ -1232,7 +1234,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_ID_MASK 243
#define CMP_NODE_DEFOCUS 244
#define CMP_NODE_DISPLACE 245
-#define CMP_NODE_COMBHSVA 246
+#define CMP_NODE_COMBHSVA_LEGACY 246
#define CMP_NODE_MATH 247
#define CMP_NODE_LUMA_MATTE 248
#define CMP_NODE_BRIGHTCONTRAST 249
@@ -1289,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_SCENE_TIME 329
#define CMP_NODE_SEPARATE_XYZ 330
#define CMP_NODE_COMBINE_XYZ 331
+#define CMP_NODE_COMBINE_COLOR 332
+#define CMP_NODE_SEPARATE_COLOR 333
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1354,11 +1358,13 @@ struct TexResult;
#define TEX_NODE_TRANSLATE 416
#define TEX_NODE_COORD 417
#define TEX_NODE_DISTANCE 418
-#define TEX_NODE_COMPOSE 419
-#define TEX_NODE_DECOMPOSE 420
+#define TEX_NODE_COMPOSE_LEGACY 419
+#define TEX_NODE_DECOMPOSE_LEGACY 420
#define TEX_NODE_VALTONOR 421
#define TEX_NODE_SCALE 422
#define TEX_NODE_AT 423
+#define TEX_NODE_COMBINE_COLOR 424
+#define TEX_NODE_SEPARATE_COLOR 425
/* 501-599 reserved. Use like this: TEX_NODE_PROC + TEX_CLOUDS, etc */
#define TEX_NODE_PROC 500
@@ -1511,6 +1517,8 @@ struct TexResult;
#define FN_NODE_REPLACE_STRING 1218
#define FN_NODE_INPUT_BOOL 1219
#define FN_NODE_INPUT_INT 1220
+#define FN_NODE_SEPARATE_COLOR 1221
+#define FN_NODE_COMBINE_COLOR 1222
/** \} */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 200eefb73ec..ffa39f79e7c 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4502,6 +4502,8 @@ static void registerCompositNodes()
register_node_type_cmp_premulkey();
register_node_type_cmp_separate_xyz();
register_node_type_cmp_combine_xyz();
+ register_node_type_cmp_separate_color();
+ register_node_type_cmp_combine_color();
register_node_type_cmp_diff_matte();
register_node_type_cmp_distance_matte();
@@ -4574,6 +4576,8 @@ static void registerShaderNodes()
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
register_node_type_sh_invert();
+ register_node_type_sh_sepcolor();
+ register_node_type_sh_combcolor();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
register_node_type_sh_sephsv();
@@ -4660,6 +4664,8 @@ static void registerTextureNodes()
register_node_type_tex_distance();
register_node_type_tex_compose();
register_node_type_tex_decompose();
+ register_node_type_tex_combine_color();
+ register_node_type_tex_separate_color();
register_node_type_tex_output();
register_node_type_tex_viewer();
@@ -4821,6 +4827,7 @@ static void registerFunctionNodes()
{
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
+ register_node_type_fn_combine_color();
register_node_type_fn_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
@@ -4832,6 +4839,7 @@ static void registerFunctionNodes()
register_node_type_fn_random_value();
register_node_type_fn_replace_string();
register_node_type_fn_rotate_euler();
+ register_node_type_fn_separate_color();
register_node_type_fn_slice_string();
register_node_type_fn_string_length();
register_node_type_fn_value_to_string();
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index aeeaf47d813..07e9eaf0f42 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -238,7 +238,7 @@ void rgb_to_hsl(float r, float g, float b, float *r_h, float *r_s, float *r_l)
{
const float cmax = max_fff(r, g, b);
const float cmin = min_fff(r, g, b);
- float h, s, l = min_ff(1.0, (cmax + cmin) / 2.0f);
+ float h, s, l = min_ff(1.0f, (cmax + cmin) / 2.0f);
if (cmax == cmin) {
h = s = 0.0f; /* achromatic */
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index e6a214452fe..0a69ef5f7cd 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2772,5 +2772,250 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Replace legacy combine/separate color nodes */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = FN_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = FN_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
+ * combine/separate color */
+ if (ntree->type == NTREE_COMPOSIT) {
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case CMP_NODE_COMBRGBA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBHSVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYCCA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYUVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPRGBA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPHSVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYCCA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYUVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In texture nodes, replace combine/separate RGBA with combine/separate color */
+ if (ntree->type == NTREE_TEXTURE) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case TEX_NODE_COMPOSE_LEGACY: {
+ node->type = TEX_NODE_COMBINE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeCombineColor");
+ break;
+ }
+ case TEX_NODE_DECOMPOSE_LEGACY: {
+ node->type = TEX_NODE_SEPARATE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeSeparateColor");
+ break;
+ }
+ }
+ }
+ }
+
+ /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
+ if (ntree->type == NTREE_SHADER) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_COMBHSV_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPHSV_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 66f813e02b2..55e349423bb 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -259,12 +259,16 @@ set(SRC
# converter nodes
nodes/COM_CombineColorNode.cc
nodes/COM_CombineColorNode.h
+ nodes/COM_CombineColorNodeLegacy.cc
+ nodes/COM_CombineColorNodeLegacy.h
nodes/COM_CombineXYZNode.cc
nodes/COM_CombineXYZNode.h
nodes/COM_IDMaskNode.cc
nodes/COM_IDMaskNode.h
nodes/COM_SeparateColorNode.cc
nodes/COM_SeparateColorNode.h
+ nodes/COM_SeparateColorNodeLegacy.cc
+ nodes/COM_SeparateColorNodeLegacy.h
nodes/COM_SeparateXYZNode.cc
nodes/COM_SeparateXYZNode.h
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 13d412a338b..6d7341376e9 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -29,6 +29,7 @@
#include "COM_ColorSpillNode.h"
#include "COM_ColorToBWNode.h"
#include "COM_CombineColorNode.h"
+#include "COM_CombineColorNodeLegacy.h"
#include "COM_CombineXYZNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
@@ -82,6 +83,7 @@
#include "COM_ScaleOperation.h"
#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
+#include "COM_SeparateColorNodeLegacy.h"
#include "COM_SeparateXYZNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
@@ -169,28 +171,34 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_BRIGHTCONTRAST:
node = new BrightnessNode(b_node);
break;
- case CMP_NODE_SEPRGBA:
+ case CMP_NODE_SEPARATE_COLOR:
+ node = new SeparateColorNode(b_node);
+ break;
+ case CMP_NODE_COMBINE_COLOR:
+ node = new CombineColorNode(b_node);
+ break;
+ case CMP_NODE_SEPRGBA_LEGACY:
node = new SeparateRGBANode(b_node);
break;
- case CMP_NODE_COMBRGBA:
+ case CMP_NODE_COMBRGBA_LEGACY:
node = new CombineRGBANode(b_node);
break;
- case CMP_NODE_SEPHSVA:
+ case CMP_NODE_SEPHSVA_LEGACY:
node = new SeparateHSVANode(b_node);
break;
- case CMP_NODE_COMBHSVA:
+ case CMP_NODE_COMBHSVA_LEGACY:
node = new CombineHSVANode(b_node);
break;
- case CMP_NODE_SEPYUVA:
+ case CMP_NODE_SEPYUVA_LEGACY:
node = new SeparateYUVANode(b_node);
break;
- case CMP_NODE_COMBYUVA:
+ case CMP_NODE_COMBYUVA_LEGACY:
node = new CombineYUVANode(b_node);
break;
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_SEPYCCA_LEGACY:
node = new SeparateYCCANode(b_node);
break;
- case CMP_NODE_COMBYCCA:
+ case CMP_NODE_COMBYCCA_LEGACY:
node = new CombineYCCANode(b_node);
break;
case CMP_NODE_ALPHAOVER:
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc
index 0c8748fd2d6..c766a359d63 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cc
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc
@@ -40,7 +40,39 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
converter.map_input_socket(input_asocket, operation->get_input_socket(3));
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertHSVToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertHSLToRGBOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertYUVToRGBOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -52,27 +84,4 @@ void CombineColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertHSVToRGBOperation();
-}
-
-NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertYUVToRGBOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.h b/source/blender/compositor/nodes/COM_CombineColorNode.h
index 2bead24cb02..7576cc9eb2d 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.h
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.h
@@ -12,45 +12,6 @@ class CombineColorNode : public Node {
CombineColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class CombineRGBANode : public CombineColorNode {
- public:
- CombineRGBANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineHSVANode : public CombineColorNode {
- public:
- CombineHSVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYCCANode : public CombineColorNode {
- public:
- CombineYCCANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class CombineYUVANode : public CombineColorNode {
- public:
- CombineYUVANode(bNode *editor_node) : CombineColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
new file mode 100644
index 00000000000..d5ba379bfc2
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.cc
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_CombineColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+CombineColorNodeLegacy::CombineColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void CombineColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *input_rsocket = this->get_input_socket(0);
+ NodeInput *input_gsocket = this->get_input_socket(1);
+ NodeInput *input_bsocket = this->get_input_socket(2);
+ NodeInput *input_asocket = this->get_input_socket(3);
+ NodeOutput *output_socket = this->get_output_socket(0);
+
+ CombineChannelsOperation *operation = new CombineChannelsOperation();
+ if (input_rsocket->is_linked()) {
+ operation->set_canvas_input_index(0);
+ }
+ else if (input_gsocket->is_linked()) {
+ operation->set_canvas_input_index(1);
+ }
+ else if (input_bsocket->is_linked()) {
+ operation->set_canvas_input_index(2);
+ }
+ else {
+ operation->set_canvas_input_index(3);
+ }
+ converter.add_operation(operation);
+
+ converter.map_input_socket(input_rsocket, operation->get_input_socket(0));
+ converter.map_input_socket(input_gsocket, operation->get_input_socket(1));
+ converter.map_input_socket(input_bsocket, operation->get_input_socket(2));
+ converter.map_input_socket(input_asocket, operation->get_input_socket(3));
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.add_link(operation->get_output_socket(), color_conv->get_input_socket(0));
+ converter.map_output_socket(output_socket, color_conv->get_output_socket());
+ }
+ else {
+ converter.map_output_socket(output_socket, operation->get_output_socket());
+ }
+}
+
+NodeOperation *CombineRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *CombineHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertHSVToRGBOperation();
+}
+
+NodeOperation *CombineYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *CombineYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertYUVToRGBOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
new file mode 100644
index 00000000000..edc66c8932f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_CombineColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class CombineColorNodeLegacy : public Node {
+ public:
+ CombineColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class CombineRGBANode : public CombineColorNodeLegacy {
+ public:
+ CombineRGBANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineHSVANode : public CombineColorNodeLegacy {
+ public:
+ CombineHSVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYCCANode : public CombineColorNodeLegacy {
+ public:
+ CombineYCCANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class CombineYUVANode : public CombineColorNodeLegacy {
+ public:
+ CombineYUVANode(bNode *editor_node) : CombineColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
index 221d80e67f2..6e69bd097a1 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cc
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc
@@ -20,7 +20,39 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
NodeOutput *output_bsocket = this->get_output_socket(2);
NodeOutput *output_asocket = this->get_output_socket(3);
- NodeOperation *color_conv = get_color_converter(context);
+ bNode *editor_node = this->get_bnode();
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)editor_node->storage;
+
+ NodeOperation *color_conv = nullptr;
+ switch (storage->mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSV: {
+ color_conv = new ConvertRGBToHSVOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_HSL: {
+ color_conv = new ConvertRGBToHSLOperation();
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YCC: {
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ operation->set_mode(storage->ycc_mode);
+ color_conv = operation;
+ break;
+ }
+ case CMP_NODE_COMBSEP_COLOR_YUV: {
+ color_conv = new ConvertRGBToYUVOperation();
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+
if (color_conv) {
converter.add_operation(color_conv);
@@ -84,27 +116,4 @@ void SeparateColorNode::convert_to_operations(NodeConverter &converter,
}
}
-NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return nullptr; /* no conversion needed */
-}
-
-NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToHSVOperation();
-}
-
-NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
- bNode *editor_node = this->get_bnode();
- operation->set_mode(editor_node->custom1);
- return operation;
-}
-
-NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
-{
- return new ConvertRGBToYUVOperation();
-}
-
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.h b/source/blender/compositor/nodes/COM_SeparateColorNode.h
index 78ab0959f43..6adb2d0bb22 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.h
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.h
@@ -12,45 +12,6 @@ class SeparateColorNode : public Node {
SeparateColorNode(bNode *editor_node);
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
-
- protected:
- virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
-};
-
-class SeparateRGBANode : public SeparateColorNode {
- public:
- SeparateRGBANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateHSVANode : public SeparateColorNode {
- public:
- SeparateHSVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYCCANode : public SeparateColorNode {
- public:
- SeparateYCCANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
-};
-
-class SeparateYUVANode : public SeparateColorNode {
- public:
- SeparateYUVANode(bNode *editor_node) : SeparateColorNode(editor_node)
- {
- }
-
- NodeOperation *get_color_converter(const CompositorContext &context) const override;
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
new file mode 100644
index 00000000000..c3728bc152f
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.cc
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#include "COM_SeparateColorNodeLegacy.h"
+
+#include "COM_ConvertOperation.h"
+
+namespace blender::compositor {
+
+SeparateColorNodeLegacy::SeparateColorNodeLegacy(bNode *editor_node) : Node(editor_node)
+{
+}
+
+void SeparateColorNodeLegacy::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ NodeInput *image_socket = this->get_input_socket(0);
+ NodeOutput *output_rsocket = this->get_output_socket(0);
+ NodeOutput *output_gsocket = this->get_output_socket(1);
+ NodeOutput *output_bsocket = this->get_output_socket(2);
+ NodeOutput *output_asocket = this->get_output_socket(3);
+
+ NodeOperation *color_conv = get_color_converter(context);
+ if (color_conv) {
+ converter.add_operation(color_conv);
+
+ converter.map_input_socket(image_socket, color_conv->get_input_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(0);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_rsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(1);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_gsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(2);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_bsocket, operation->get_output_socket(0));
+ }
+
+ {
+ SeparateChannelOperation *operation = new SeparateChannelOperation();
+ operation->set_channel(3);
+ converter.add_operation(operation);
+
+ if (color_conv) {
+ converter.add_link(color_conv->get_output_socket(), operation->get_input_socket(0));
+ }
+ else {
+ converter.map_input_socket(image_socket, operation->get_input_socket(0));
+ }
+ converter.map_output_socket(output_asocket, operation->get_output_socket(0));
+ }
+}
+
+NodeOperation *SeparateRGBANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return nullptr; /* no conversion needed */
+}
+
+NodeOperation *SeparateHSVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToHSVOperation();
+}
+
+NodeOperation *SeparateYCCANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
+ bNode *editor_node = this->get_bnode();
+ operation->set_mode(editor_node->custom1);
+ return operation;
+}
+
+NodeOperation *SeparateYUVANode::get_color_converter(const CompositorContext & /*context*/) const
+{
+ return new ConvertRGBToYUVOperation();
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
new file mode 100644
index 00000000000..10b33039c86
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SeparateColorNodeLegacy.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2011 Blender Foundation. */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+class SeparateColorNodeLegacy : public Node {
+ public:
+ SeparateColorNodeLegacy(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ protected:
+ virtual NodeOperation *get_color_converter(const CompositorContext &context) const = 0;
+};
+
+class SeparateRGBANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateRGBANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateHSVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateHSVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYCCANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYCCANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+class SeparateYUVANode : public SeparateColorNodeLegacy {
+ public:
+ SeparateYUVANode(bNode *editor_node) : SeparateColorNodeLegacy(editor_node)
+ {
+ }
+
+ NodeOperation *get_color_converter(const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc
index 7579abf792a..24c0c577ac7 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cc
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cc
@@ -464,6 +464,68 @@ void ConvertHSVToRGBOperation::update_memory_buffer_partial(BuffersIterator<floa
}
}
+/* ******** RGB to HSL ******** */
+
+ConvertRGBToHSLOperation::ConvertRGBToHSLOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertRGBToHSLOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ rgb_to_hsl_v(input_color, output);
+ output[3] = input_color[3];
+}
+
+void ConvertRGBToHSLOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ rgb_to_hsl_v(in, it.out);
+ it.out[3] = in[3];
+ }
+}
+
+/* ******** HSL to RGB ******** */
+
+ConvertHSLToRGBOperation::ConvertHSLToRGBOperation() : ConvertBaseOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+}
+
+void ConvertHSLToRGBOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ float input_color[4];
+ input_operation_->read_sampled(input_color, x, y, sampler);
+ hsl_to_rgb_v(input_color, output);
+ output[0] = max_ff(output[0], 0.0f);
+ output[1] = max_ff(output[1], 0.0f);
+ output[2] = max_ff(output[2], 0.0f);
+ output[3] = input_color[3];
+}
+
+void ConvertHSLToRGBOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
+{
+ for (; !it.is_end(); ++it) {
+ const float *in = it.in(0);
+ hsl_to_rgb_v(in, it.out);
+ it.out[0] = max_ff(it.out[0], 0.0f);
+ it.out[1] = max_ff(it.out[1], 0.0f);
+ it.out[2] = max_ff(it.out[2], 0.0f);
+ it.out[3] = in[3];
+ }
+}
+
/* ******** Premul to Straight ******** */
ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation()
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h
index e1904d61d46..16d1e2e6bb5 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertOperation.h
@@ -172,6 +172,26 @@ class ConvertHSVToRGBOperation : public ConvertBaseOperation {
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
+class ConvertRGBToHSLOperation : public ConvertBaseOperation {
+ public:
+ ConvertRGBToHSLOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
+class ConvertHSLToRGBOperation : public ConvertBaseOperation {
+ public:
+ ConvertHSLToRGBOperation();
+
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ protected:
+ void update_memory_buffer_partial(BuffersIterator<float> &it) override;
+};
+
class ConvertPremulToStraightOperation : public ConvertBaseOperation {
public:
ConvertPremulToStraightOperation();
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 958a9fdfc60..d5507619e0d 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -213,6 +213,11 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
+static void node_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
if (node->type == NODE_FRAME) {
@@ -480,6 +485,10 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
+ case SH_NODE_COMBINE_COLOR:
+ case SH_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_buts_combsep_color;
+ break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -589,6 +598,19 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_composit_buts_combsep_color(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+ if (storage->mode == CMP_NODE_COMBSEP_COLOR_YCC) {
+ uiItemR(layout, ptr, "ycc_mode", DEFAULT_FLAGS, "", ICON_NONE);
+ }
+}
+
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -821,8 +843,12 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_COMBYCCA:
- case CMP_NODE_SEPYCCA:
+ case CMP_NODE_COMBINE_COLOR:
+ case CMP_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_composit_buts_combsep_color;
+ break;
+ case CMP_NODE_COMBYCCA_LEGACY:
+ case CMP_NODE_SEPYCCA_LEGACY:
ntype->draw_buttons = node_composit_buts_ycc;
break;
case CMP_NODE_MASK_BOX:
@@ -975,6 +1001,11 @@ static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), Poin
uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
+static void node_texture_buts_combsep_color(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
/* only once called */
static void node_texture_set_butfunc(bNodeType *ntype)
{
@@ -1020,6 +1051,11 @@ static void node_texture_set_butfunc(bNodeType *ntype)
case TEX_NODE_OUTPUT:
ntype->draw_buttons = node_texture_buts_output;
break;
+
+ case TEX_NODE_COMBINE_COLOR:
+ case TEX_NODE_SEPARATE_COLOR:
+ ntype->draw_buttons = node_texture_buts_combsep_color;
+ break;
}
}
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 7c6390971dd..1e54d5fb7ee 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -317,6 +317,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_clamp.glsl
shaders/material/gpu_shader_material_color_ramp.glsl
shaders/material/gpu_shader_material_color_util.glsl
+ shaders/material/gpu_shader_material_combine_color.glsl
shaders/material/gpu_shader_material_combine_hsv.glsl
shaders/material/gpu_shader_material_combine_rgb.glsl
shaders/material/gpu_shader_material_combine_xyz.glsl
@@ -359,6 +360,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_refraction.glsl
shaders/material/gpu_shader_material_rgb_curves.glsl
shaders/material/gpu_shader_material_rgb_to_bw.glsl
+ shaders/material/gpu_shader_material_separate_color.glsl
shaders/material/gpu_shader_material_separate_hsv.glsl
shaders/material/gpu_shader_material_separate_rgb.glsl
shaders/material/gpu_shader_material_separate_xyz.glsl
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
index a5c3a990d90..fe89985ae7f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl
@@ -90,6 +90,56 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
outcol = vec4(rgb, hsv.w);
}
+void rgb_to_hsl(vec4 rgb, out vec4 outcol)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ outcol = vec4(h, s, l, rgb.w);
+}
+
+void hsl_to_rgb(vec4 hsl, out vec4 outcol)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ outcol = vec4((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l, hsl.w);
+}
+
void color_alpha_clear(vec4 color, out vec4 result)
{
result = vec4(color.rgb, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
new file mode 100644
index 00000000000..3a250fcae8b
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl
@@ -0,0 +1,16 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
+void combine_color_rgb(float r, float g, float b, out vec4 col)
+{
+ col = vec4(r, g, b, 1.0);
+}
+
+void combine_color_hsv(float h, float s, float v, out vec4 col)
+{
+ hsv_to_rgb(vec4(h, s, v, 1.0), col);
+}
+
+void combine_color_hsl(float h, float s, float l, out vec4 col)
+{
+ hsl_to_rgb(vec4(h, s, l, 1.0), col);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
new file mode 100644
index 00000000000..7425e53ce7b
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl
@@ -0,0 +1,28 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
+void separate_color_rgb(vec4 col, out float r, out float g, out float b)
+{
+ r = col.r;
+ g = col.g;
+ b = col.b;
+}
+
+void separate_color_hsv(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsv;
+
+ rgb_to_hsv(col, hsv);
+ r = hsv[0];
+ g = hsv[1];
+ b = hsv[2];
+}
+
+void separate_color_hsl(vec4 col, out float r, out float g, out float b)
+{
+ vec4 hsl;
+
+ rgb_to_hsl(col, hsl);
+ r = hsl[0];
+ g = hsl[1];
+ b = hsl[2];
+}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index d18fe1b81dd..92c4d8fe938 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -855,6 +855,12 @@ typedef struct NodeVertexCol {
char name[64];
} NodeVertexCol;
+typedef struct NodeCMPCombSepColor {
+ /* CMPNodeCombSepColorMode */
+ uint8_t mode;
+ uint8_t ycc_mode;
+} NodeCMPCombSepColor;
+
/** Defocus blur node. */
typedef struct NodeDefocus {
char bktype, _pad0, preview, gamco;
@@ -1485,6 +1491,11 @@ typedef struct NodeFunctionCompare {
char _pad[1];
} NodeFunctionCompare;
+typedef struct NodeCombSepColor {
+ /* NodeCombSepColorMode */
+ int8_t mode;
+} NodeCombSepColor;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1877,6 +1888,16 @@ typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_ACCURATE = 2
} CMPNodeDenoisePrefilter;
+/* Color combine/separate modes */
+
+typedef enum CMPNodeCombSepColorMode {
+ CMP_NODE_COMBSEP_COLOR_RGB = 0,
+ CMP_NODE_COMBSEP_COLOR_HSV = 1,
+ CMP_NODE_COMBSEP_COLOR_HSL = 2,
+ CMP_NODE_COMBSEP_COLOR_YCC = 3,
+ CMP_NODE_COMBSEP_COLOR_YUV = 4,
+} CMPNodeCombSepColorMode;
+
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
/* Point Density shader node */
@@ -2135,6 +2156,12 @@ typedef enum GeometryNodeScaleElementsMode {
GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
} GeometryNodeScaleElementsMode;
+typedef enum NodeCombSepColorMode {
+ NODE_COMBSEP_COLOR_RGB = 0,
+ NODE_COMBSEP_COLOR_HSV = 1,
+ NODE_COMBSEP_COLOR_HSL = 2,
+} NodeCombSepColorMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index eaf2142495e..4cd12acd038 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -489,6 +489,13 @@ static const EnumPropertyItem rna_node_geometry_curve_handle_side_items[] = {
{GEO_NODE_CURVE_HANDLE_RIGHT, "RIGHT", ICON_NONE, "Right", "Use the right handles"},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem rna_node_combsep_color_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem node_sampler_type_items[] = {
{0, "NEAREST", 0, "Nearest", ""},
@@ -5050,6 +5057,18 @@ static void def_fn_input_string(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_fn_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -- Shader Nodes ---------------------------------------------------------- */
static void def_sh_output(StructRNA *srna)
@@ -5401,6 +5420,17 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_tex_combsep_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_node_combsep_color_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_image_texture(StructRNA *srna)
{
static const EnumPropertyItem fn_tex_prop_interpolation_items[] = {
@@ -6308,6 +6338,25 @@ static void def_sh_output_aov(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem type_items[] = {
+ {NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_sh_script(StructRNA *srna)
{
PropertyRNA *prop;
@@ -8071,6 +8120,32 @@ static void def_cmp_ycc(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_combsep_color(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {CMP_NODE_COMBSEP_COLOR_RGB, "RGB", ICON_NONE, "RGB", "Use RGB color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSV, "HSV", ICON_NONE, "HSV", "Use HSV color processing"},
+ {CMP_NODE_COMBSEP_COLOR_HSL, "HSL", ICON_NONE, "HSL", "Use HSL color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YCC, "YCC", ICON_NONE, "YCbCr", "Use YCbCr color processing"},
+ {CMP_NODE_COMBSEP_COLOR_YUV, "YUV", ICON_NONE, "YUV", "Use YUV color processing"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeCMPCombSepColor", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of color processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "ycc_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_ycc_items);
+ RNA_def_property_ui_text(prop, "Color Space", "Color space used for YCbCrA processing");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_movieclip(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 3d3450d9252..5d782674f16 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -126,6 +126,8 @@ void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
void register_node_type_cmp_separate_xyz(void);
void register_node_type_cmp_combine_xyz(void);
+void register_node_type_cmp_separate_color(void);
+void register_node_type_cmp_combine_color(void);
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
void node_cmp_rlayers_register_pass(struct bNodeTree *ntree,
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index cde4b67e120..ad96fba1929 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -8,6 +8,7 @@ extern "C" {
void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
+void register_node_type_fn_combine_color(void);
void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_bool(void);
@@ -19,6 +20,7 @@ void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_value(void);
void register_node_type_fn_replace_string(void);
void register_node_type_fn_rotate_euler(void);
+void register_node_type_fn_separate_color(void);
void register_node_type_fn_slice_string(void);
void register_node_type_fn_string_length(void);
void register_node_type_fn_value_to_string(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 4996f12e27d..1d1310360b8 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -43,6 +43,8 @@ void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
void register_node_type_sh_dynamic(void);
void register_node_type_sh_invert(void);
+void register_node_type_sh_sepcolor(void);
+void register_node_type_sh_combcolor(void);
void register_node_type_sh_seprgb(void);
void register_node_type_sh_combrgb(void);
void register_node_type_sh_sephsv(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 5818fa631e7..7dd732e7fad 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -42,8 +42,8 @@ DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH",
DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
-DefNode(ShaderNode, SH_NODE_COMBRGB, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
+DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
+DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
@@ -106,8 +106,8 @@ DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX
DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" )
DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "" )
DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "" )
-DefNode(ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
-DefNode(ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
+DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
+DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "" )
DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
@@ -120,6 +120,8 @@ DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" )
+DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -137,8 +139,8 @@ DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VA
DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" )
DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" )
-DefNode(CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPRGBA_LEGACY, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPHSVA_LEGACY, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode(CompositorNode, CMP_NODE_SETALPHA, def_cmp_set_alpha, "SETALPHA", SetAlpha, "Set Alpha", "" )
DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
@@ -149,16 +151,16 @@ DefNode(CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT
DefNode(CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
DefNode(CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" )
DefNode(CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" )
-DefNode(CompositorNode, CMP_NODE_COMBRGBA, 0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBRGBA_LEGACY,0, "COMBRGBA", CombRGBA, "Combine RGBA", "" )
DefNode(CompositorNode, CMP_NODE_DILATEERODE, def_cmp_dilate_erode, "DILATEERODE", DilateErode, "Dilate/Erode", "" )
DefNode(CompositorNode, CMP_NODE_INPAINT, def_cmp_inpaint, "INPAINT", Inpaint, "Inpaint", "" )
DefNode(CompositorNode, CMP_NODE_DESPECKLE, def_cmp_despeckle, "DESPECKLE", Despeckle, "Despeckle", "" )
DefNode(CompositorNode, CMP_NODE_ROTATE, def_cmp_rotate, "ROTATE", Rotate, "Rotate", "" )
DefNode(CompositorNode, CMP_NODE_SCALE, def_cmp_scale, "SCALE", Scale, "Scale", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYCCA, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYCCA, def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
-DefNode(CompositorNode, CMP_NODE_SEPYUVA, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
-DefNode(CompositorNode, CMP_NODE_COMBYUVA, 0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYCCA_LEGACY, def_cmp_ycc, "SEPYCCA", SepYCCA, "Separate YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYCCA_LEGACY,def_cmp_ycc, "COMBYCCA", CombYCCA, "Combine YCbCrA", "" )
+DefNode(CompositorNode, CMP_NODE_SEPYUVA_LEGACY, 0, "SEPYUVA", SepYUVA, "Separate YUVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBYUVA_LEGACY,0, "COMBYUVA", CombYUVA, "Combine YUVA", "" )
DefNode(CompositorNode, CMP_NODE_DIFF_MATTE, def_cmp_diff_matte, "DIFF_MATTE", DiffMatte, "Difference Key", "" )
DefNode(CompositorNode, CMP_NODE_COLOR_SPILL, def_cmp_color_spill, "COLOR_SPILL", ColorSpill, "Color Spill", "" )
DefNode(CompositorNode, CMP_NODE_CHROMA_MATTE, def_cmp_chroma_matte, "CHROMA_MATTE", ChromaMatte, "Chroma Key", "" )
@@ -170,7 +172,7 @@ DefNode(CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MAS
DefNode(CompositorNode, CMP_NODE_DOUBLEEDGEMASK, def_cmp_double_edge_mask,"DOUBLEEDGEMASK", DoubleEdgeMask, "Double Edge Mask", "" )
DefNode(CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" )
DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" )
-DefNode(CompositorNode, CMP_NODE_COMBHSVA, 0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
+DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
@@ -215,9 +217,11 @@ DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSU
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
-DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
+DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBINE_XYZ", CombineXYZ, "Combine XYZ", "" )
DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
+DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
+DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
@@ -237,11 +241,13 @@ DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER
DefNode(TextureNode, TEX_NODE_TRANSLATE, 0, "TRANSLATE", Translate, "Translate", "" )
DefNode(TextureNode, TEX_NODE_COORD, 0, "COORD", Coordinates, "Coordinates", "" )
DefNode(TextureNode, TEX_NODE_DISTANCE, 0, "DISTANCE", Distance, "Distance", "" )
-DefNode(TextureNode, TEX_NODE_COMPOSE, 0, "COMPOSE", Compose, "Combine RGBA", "" )
-DefNode(TextureNode, TEX_NODE_DECOMPOSE, 0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
+DefNode(TextureNode, TEX_NODE_COMPOSE_LEGACY, 0, "COMPOSE", Compose, "Combine RGBA", "" )
+DefNode(TextureNode, TEX_NODE_DECOMPOSE_LEGACY,0, "DECOMPOSE", Decompose, "Separate RGBA", "" )
DefNode(TextureNode, TEX_NODE_VALTONOR, 0, "VALTONOR", ValToNor, "Value to Normal", "" )
DefNode(TextureNode, TEX_NODE_SCALE, 0, "SCALE", Scale, "Scale", "" )
DefNode(TextureNode, TEX_NODE_AT, 0, "AT", At, "At", "" )
+DefNode(TextureNode, TEX_NODE_COMBINE_COLOR, def_tex_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
+DefNode(TextureNode, TEX_NODE_SEPARATE_COLOR, def_tex_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
/* procedural textures */
DefNode(TextureNode, TEX_NODE_PROC+TEX_VORONOI, 0, "TEX_VORONOI", TexVoronoi, "Voronoi", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_BLEND, 0, "TEX_BLEND", TexBlend, "Blend", "" )
@@ -256,6 +262,7 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
+DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, def_fn_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "")
DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
@@ -267,6 +274,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR",
DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "")
DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
+DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h
index 0f07b17f165..9a2dc705c0d 100644
--- a/source/blender/nodes/NOD_texture.h
+++ b/source/blender/nodes/NOD_texture.h
@@ -46,6 +46,8 @@ void register_node_type_tex_at(void);
void register_node_type_tex_compose(void);
void register_node_type_tex_decompose(void);
+void register_node_type_tex_combine_color(void);
+void register_node_type_tex_separate_color(void);
void register_node_type_tex_proc_voronoi(void);
void register_node_type_tex_proc_blend(void);
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index 57f76f20ac6..c0100d77889 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
nodes/node_composite_rotate.cc
nodes/node_composite_scale.cc
nodes/node_composite_scene_time.cc
+ nodes/node_composite_sepcomb_color.cc
nodes/node_composite_sepcomb_hsva.cc
nodes/node_composite_sepcomb_rgba.cc
nodes/node_composite_sepcomb_xyz.cc
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
new file mode 100644
index 00000000000..689c069c50f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_color.cc
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_composite_util.hh"
+
+static void node_cmp_combsep_color_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeCMPCombSepColor *data = MEM_cnew<NodeCMPCombSepColor>(__func__);
+ data->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ data->ycc_mode = BLI_YCC_ITU_BT709;
+ node->storage = data;
+}
+
+static void node_cmp_combsep_color_label(const ListBase *sockets, CMPNodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case CMP_NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YCC:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "Cb");
+ node_sock_label(sock3, "Cr");
+ break;
+ case CMP_NODE_COMBSEP_COLOR_YUV:
+ node_sock_label(sock1, "Y");
+ node_sock_label(sock2, "U");
+ node_sock_label(sock3, "V");
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_composite_separate_color_cc {
+
+static void cmp_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void cmp_node_separate_color_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->outputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_separate_color_cc
+
+void register_node_type_cmp_separate_color()
+{
+ namespace file_ns = blender::nodes::node_composite_separate_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_separate_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_separate_color_update);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_composite_combine_color_cc {
+
+static void cmp_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+static void cmp_node_combine_color_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)node->storage;
+ node_cmp_combsep_color_label(&node->inputs, (CMPNodeCombSepColorMode)storage->mode);
+}
+
+} // namespace blender::nodes::node_composite_combine_color_cc
+
+void register_node_type_cmp_combine_color()
+{
+ namespace file_ns = blender::nodes::node_composite_combine_color_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combine_color_declare;
+ node_type_init(&ntype, node_cmp_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCMPCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_update(&ntype, file_ns::cmp_node_combine_color_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
index 349c27d876d..a0d2485ea5a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sephsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
@@ -54,7 +54,7 @@ void register_node_type_cmp_combhsva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
index c46603be847..ae46681b0f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -27,7 +27,7 @@ void register_node_type_cmp_seprgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
@@ -54,7 +54,7 @@ void register_node_type_cmp_combrgba()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 9b5c153fddf..a3c40b61e64 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -33,7 +33,7 @@ void register_node_type_cmp_sepycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA_LEGACY, "Separate YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
@@ -66,7 +66,7 @@ void register_node_type_cmp_combycca()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA_LEGACY, "Combine YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combycca_declare;
node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
index e458c9cfb7e..7fdece5904d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -28,7 +28,7 @@ void register_node_type_cmp_sepyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
@@ -55,7 +55,7 @@ void register_node_type_cmp_combyuva()
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
index 6ccc4c7bf5c..d03f1cb63ff 100644
--- a/source/blender/nodes/function/CMakeLists.txt
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -20,6 +20,7 @@ set(INC
set(SRC
nodes/node_fn_align_euler_to_vector.cc
nodes/node_fn_boolean_math.cc
+ nodes/node_fn_combine_color.cc
nodes/node_fn_compare.cc
nodes/node_fn_float_to_int.cc
nodes/node_fn_input_bool.cc
@@ -31,6 +32,7 @@ set(SRC
nodes/node_fn_random_value.cc
nodes/node_fn_replace_string.cc
nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_separate_color.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_value_to_string.cc
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
new file mode 100644
index 00000000000..8167cf55028
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_combine_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+};
+
+static void fn_node_combine_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_combine_color_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &bnode)
+{
+ const NodeCombSepColor &storage = node_storage(bnode);
+
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> rgba_fn{
+ "RGB", [](float r, float g, float b, float a) { return ColorGeometry4f(r, g, b, a); }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsva_fn{
+ "HSV", [](float h, float s, float v, float a) {
+ ColorGeometry4f r_color;
+ hsv_to_rgb(h, s, v, &r_color.r, &r_color.g, &r_color.b);
+ r_color.a = a;
+ return r_color;
+ }};
+ static fn::CustomMF_SI_SI_SI_SI_SO<float, float, float, float, ColorGeometry4f> hsla_fn{
+ "HSL", [](float h, float s, float l, float a) {
+ ColorGeometry4f color;
+ hsl_to_rgb(h, s, l, &color.r, &color.g, &color.b);
+ color.a = a;
+ return color;
+ }};
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return &rgba_fn;
+ case NODE_COMBSEP_COLOR_HSV:
+ return &hsva_fn;
+ case NODE_COMBSEP_COLOR_HSL:
+ return &hsla_fn;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static void fn_node_combine_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_combine_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_combine_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_combine_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_combine_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_combine_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_combine_color_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_separate_color.cc b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
new file mode 100644
index 00000000000..3fea4c4c040
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_function_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void fn_node_separate_color_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+ b.add_output<decl::Float>(N_("Alpha"));
+};
+
+static void fn_node_separate_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void fn_node_separate_color_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static void fn_node_separate_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+class SeparateRGBAFunction : public fn::MultiFunction {
+ public:
+ SeparateRGBAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Red");
+ signature.single_output<float>("Green");
+ signature.single_output<float>("Blue");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> red = params.uninitialized_single_output<float>(1, "Red");
+ MutableSpan<float> green = params.uninitialized_single_output<float>(2, "Green");
+ MutableSpan<float> blue = params.uninitialized_single_output<float>(3, "Blue");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ red[i] = colors[i].r;
+ green[i] = colors[i].g;
+ blue[i] = colors[i].b;
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSVAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSVAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Value");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> value = params.uninitialized_single_output<float>(3, "Value");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsv(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &value[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+class SeparateHSLAFunction : public fn::MultiFunction {
+ public:
+ SeparateHSLAFunction()
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Separate Color"};
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<float>("Hue");
+ signature.single_output<float>("Saturation");
+ signature.single_output<float>("Lightness");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> hue = params.uninitialized_single_output<float>(1, "Hue");
+ MutableSpan<float> saturation = params.uninitialized_single_output<float>(2, "Saturation");
+ MutableSpan<float> lightness = params.uninitialized_single_output<float>(3, "Lightness");
+ MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
+
+ for (int64_t i : mask) {
+ rgb_to_hsl(colors[i].r, colors[i].g, colors[i].b, &hue[i], &saturation[i], &lightness[i]);
+ }
+
+ if (!alpha.is_empty()) {
+ for (int64_t i : mask) {
+ alpha[i] = colors[i].a;
+ }
+ }
+ }
+};
+
+static void fn_node_separate_color_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const NodeCombSepColor &storage = node_storage(builder.node());
+
+ switch (storage.mode) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ static SeparateRGBAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ static SeparateHSVAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ static SeparateHSLAFunction fn;
+ builder.set_matching_fn(fn);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_fn_separate_color(void)
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = blender::nodes::fn_node_separate_color_declare;
+ node_type_update(&ntype, blender::nodes::fn_node_separate_color_update);
+ node_type_init(&ntype, blender::nodes::fn_node_separate_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = blender::nodes::fn_node_separate_color_build_multi_function;
+ ntype.draw_buttons = blender::nodes::fn_node_separate_color_layout;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 5d2e1663ae3..e8be093c606 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -226,6 +226,39 @@ void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *
BLI_strncpy(label, IFACE_(name), maxlen);
}
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index de03a176c0c..0a2a7a70091 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -65,6 +65,7 @@ void node_filter_label(const struct bNodeTree *ntree,
const struct bNode *node,
char *label,
int maxlen);
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode);
/*** Link Handling */
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 9b4ea0e0db6..3e90f185168 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC
nodes/node_shader_rgb.cc
nodes/node_shader_rgb_to_bw.cc
nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_color.cc
nodes/node_shader_sepcomb_hsv.cc
nodes/node_shader_sepcomb_rgb.cc
nodes/node_shader_sepcomb_xyz.cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
new file mode 100644
index 00000000000..a80b4ed0444
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_color.cc
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static void node_combsep_color_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeCombSepColor *data = MEM_cnew<NodeCombSepColor>(__func__);
+ data->mode = NODE_COMBSEP_COLOR_RGB;
+ node->storage = data;
+}
+
+/* **************** SEPARATE COLOR ******************** */
+
+namespace blender::nodes::node_shader_separate_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_sepcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Float>(N_("Red"));
+ b.add_output<decl::Float>(N_("Green"));
+ b.add_output<decl::Float>(N_("Blue"));
+}
+
+static void node_sepcolor_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "separate_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "separate_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "separate_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_sepcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_separate_color_cc
+
+void register_node_type_sh_sepcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_separate_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepcolor_declare;
+ node_type_update(&ntype, file_ns::node_sepcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepcolor);
+
+ nodeRegisterType(&ntype);
+}
+
+/* **************** COMBINE COLOR ******************** */
+
+namespace blender::nodes::node_shader_combine_color_cc {
+
+NODE_STORAGE_FUNCS(NodeCombSepColor)
+
+static void sh_node_combcolor_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Red")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Green"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Blue"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static void node_combcolor_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)storage.mode);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ return "combine_color_rgb";
+ case NODE_COMBSEP_COLOR_HSV:
+ return "combine_color_hsv";
+ case NODE_COMBSEP_COLOR_HSL:
+ return "combine_color_hsl";
+ }
+
+ return nullptr;
+}
+
+static int gpu_shader_combcolor(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ const NodeCombSepColor &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.mode);
+ if (name != nullptr) {
+ return GPU_stack_link(mat, node, name, in, out);
+ }
+
+ return 0;
+}
+
+} // namespace blender::nodes::node_shader_combine_color_cc
+
+void register_node_type_sh_combcolor()
+{
+ namespace file_ns = blender::nodes::node_shader_combine_color_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combcolor_declare;
+ node_type_update(&ntype, file_ns::node_combcolor_update);
+ node_type_init(&ntype, node_combsep_color_init);
+ node_type_storage(
+ &ntype, "NodeCombSepColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_combcolor);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
index 129c8cf4b97..6dfabe48292 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -36,7 +36,7 @@ void register_node_type_sh_sephsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV_LEGACY, "Separate HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_sephsv;
node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
@@ -72,7 +72,7 @@ void register_node_type_sh_combhsv()
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV_LEGACY, "Combine HSV", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare_combhsv;
node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 657f591a50c..28b55047633 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -76,7 +76,7 @@ void register_node_type_sh_seprgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB_LEGACY, "Separate RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_seprgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
@@ -119,7 +119,7 @@ void register_node_type_sh_combrgb()
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB_LEGACY, "Combine RGB", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::sh_node_combrgb_declare;
node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
index 7706f118507..8eb4d2bfacd 100644
--- a/source/blender/nodes/texture/CMakeLists.txt
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SRC
nodes/node_texture_bricks.c
nodes/node_texture_checker.c
nodes/node_texture_common.c
+ nodes/node_texture_combine_color.c
nodes/node_texture_compose.c
nodes/node_texture_coord.c
nodes/node_texture_curves.c
@@ -38,6 +39,7 @@ set(SRC
nodes/node_texture_output.c
nodes/node_texture_proc.c
nodes/node_texture_rotate.c
+ nodes/node_texture_separate_color.c
nodes/node_texture_scale.c
nodes/node_texture_texture.c
nodes/node_texture_translate.c
diff --git a/source/blender/nodes/texture/nodes/node_texture_combine_color.c b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
new file mode 100644
index 00000000000..3ba6755e7c6
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_combine_color.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_FLOAT, N_("Red"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Green"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Blue"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_RGBA, N_("Color")},
+ {-1, ""},
+};
+
+static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ out[i] = tex_input_value(in[i], p, thread);
+ }
+ /* Apply color space if required. */
+ switch (node->custom1) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ hsv_to_rgb_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ hsl_to_rgb_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void update(bNodeTree *ntree, bNode *node)
+{
+ node_combsep_color_label(&node->inputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &colorfn, data);
+}
+
+void register_node_type_tex_combine_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_COMBINE_COLOR, "Combine Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index e341b65ac97..ef14062c72d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -42,7 +42,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE_LEGACY, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 21c3944e255..2d42fa4602e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -62,7 +62,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE_LEGACY, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_separate_color.c b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
new file mode 100644
index 00000000000..94f9fafe838
--- /dev/null
+++ b/source/blender/nodes/texture/nodes/node_texture_separate_color.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup texnodes
+ */
+
+#include "BLI_listbase.h"
+#include "NOD_texture.h"
+#include "node_texture_util.h"
+#include <math.h>
+
+static bNodeSocketTemplate inputs[] = {
+ {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ {-1, ""},
+};
+static bNodeSocketTemplate outputs[] = {
+ {SOCK_FLOAT, N_("Red")},
+ {SOCK_FLOAT, N_("Green")},
+ {SOCK_FLOAT, N_("Blue")},
+ {SOCK_FLOAT, N_("Alpha")},
+ {-1, ""},
+};
+
+static void apply_color_space(float *out, NodeCombSepColorMode type)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_RGB: {
+ /* Pass */
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSV: {
+ rgb_to_hsv_v(out, out);
+ break;
+ }
+ case NODE_COMBSEP_COLOR_HSL: {
+ rgb_to_hsl_v(out, out);
+ break;
+ }
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+static void valuefn_r(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[0];
+}
+
+static void valuefn_g(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[1];
+}
+
+static void valuefn_b(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ apply_color_space(out, (NodeCombSepColorMode)node->custom1);
+ *out = out[2];
+}
+
+static void valuefn_a(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
+{
+ tex_input_rgba(out, in[0], p, thread);
+ *out = out[3];
+}
+
+static void update(bNodeTree *ntree, bNode *node)
+{
+ node_combsep_color_label(&node->outputs, (NodeCombSepColorMode)node->custom1);
+}
+
+static void exec(void *data,
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *execdata,
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ tex_output(node, execdata, in, out[0], &valuefn_r, data);
+ tex_output(node, execdata, in, out[1], &valuefn_g, data);
+ tex_output(node, execdata, in, out[2], &valuefn_b, data);
+ tex_output(node, execdata, in, out[3], &valuefn_a, data);
+}
+
+void register_node_type_tex_separate_color(void)
+{
+ static bNodeType ntype;
+
+ tex_node_type_base(&ntype, TEX_NODE_SEPARATE_COLOR, "Separate Color", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_exec(&ntype, NULL, NULL, exec);
+ node_type_update(&ntype, update);
+
+ nodeRegisterType(&ntype);
+}