From 08e73814d7fc6990737adf19041cd1c795dbb7b6 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Mon, 14 Apr 2025 11:26:55 +0200 Subject: [PATCH] Compositor: Turn Bokeh Image options into inputs This patch turns the options of the Bokeh Image node into inputs. Reference #137223. Pull Request: https://projects.blender.org/blender/blender/pulls/137350 --- .../blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/node.cc | 19 +++ .../blenloader/intern/versioning_400.cc | 112 +++++++++++++++++ source/blender/makesdna/DNA_node_types.h | 10 +- .../blender/makesrna/intern/rna_nodetree.cc | 64 ++++++++-- .../nodes/node_composite_bokehimage.cc | 114 +++++++++++------- 6 files changed, 262 insertions(+), 59 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 3139b8a128a..0fd45b3c5b0 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 21 +#define BLENDER_FILE_SUBVERSION 22 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 1299235e7e7..e831023882a 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -680,10 +680,29 @@ static void write_compositor_legacy_properties(bNodeTree &node_tree) property = input->default_value_typed()->value; }; + auto write_input_to_property_int = [&](const char *identifier, int &property) { + const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier); + property = input->default_value_typed()->value; + }; + + auto write_input_to_property_float = [&](const char *identifier, float &property) { + const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier); + property = input->default_value_typed()->value; + }; + if (node->type_legacy == CMP_NODE_GLARE) { NodeGlare *storage = static_cast(node->storage); write_input_to_property_bool_char("Diagonal Star", storage->star_45); } + + if (node->type_legacy == CMP_NODE_BOKEHIMAGE) { + NodeBokehImage *storage = static_cast(node->storage); + write_input_to_property_int("Flaps", storage->flaps); + write_input_to_property_float("Angle", storage->angle); + write_input_to_property_float("Roundness", storage->rounding); + write_input_to_property_float("Catadioptric Size", storage->catadioptric); + write_input_to_property_float("Color Shift", storage->lensshift); + } } } diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index bd182855ecb..f1a88e1ada3 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -1797,6 +1797,92 @@ static void do_version_glare_node_star_45_option_to_input_animation(bNodeTree *n }); } +/* The options were converted into inputs. */ +static void do_version_bokeh_image_node_options_to_inputs(bNodeTree *node_tree, bNode *node) +{ + NodeBokehImage *storage = static_cast(node->storage); + if (!storage) { + return; + } + + if (!blender::bke::node_find_socket(*node, SOCK_IN, "Flaps")) { + bNodeSocket *input = blender::bke::node_add_static_socket( + *node_tree, *node, SOCK_IN, SOCK_INT, PROP_NONE, "Flaps", "Flaps"); + input->default_value_typed()->value = storage->flaps; + } + + if (!blender::bke::node_find_socket(*node, SOCK_IN, "Angle")) { + bNodeSocket *input = blender::bke::node_add_static_socket( + *node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_ANGLE, "Angle", "Angle"); + input->default_value_typed()->value = storage->angle; + } + + if (!blender::bke::node_find_socket(*node, SOCK_IN, "Roundness")) { + bNodeSocket *input = blender::bke::node_add_static_socket( + *node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_FACTOR, "Roundness", "Roundness"); + input->default_value_typed()->value = storage->rounding; + } + + if (!blender::bke::node_find_socket(*node, SOCK_IN, "Catadioptric Size")) { + bNodeSocket *input = blender::bke::node_add_static_socket(*node_tree, + *node, + SOCK_IN, + SOCK_FLOAT, + PROP_FACTOR, + "Catadioptric Size", + "Catadioptric Size"); + input->default_value_typed()->value = storage->catadioptric; + } + + if (!blender::bke::node_find_socket(*node, SOCK_IN, "Color Shift")) { + bNodeSocket *input = blender::bke::node_add_static_socket( + *node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_FACTOR, "Color Shift", "Color Shift"); + input->default_value_typed()->value = storage->lensshift; + } +} + +/* The options were converted into inputs. */ +static void do_version_bokeh_image_node_options_to_inputs_animation(bNodeTree *node_tree, + bNode *node) +{ + /* Compute the RNA path of the node. */ + char escaped_node_name[sizeof(node->name) * 2 + 1]; + BLI_str_escape(escaped_node_name, node->name, sizeof(escaped_node_name)); + const std::string node_rna_path = fmt::format("nodes[\"{}\"]", escaped_node_name); + + BKE_fcurves_id_cb(&node_tree->id, [&](ID * /*id*/, FCurve *fcurve) { + /* The FCurve does not belong to the node since its RNA path doesn't start with the node's RNA + * path. */ + if (!blender::StringRef(fcurve->rna_path).startswith(node_rna_path)) { + return; + } + + /* Change the RNA path of the FCurve from the old properties to the new inputs, adjusting the + * values of the FCurves frames when needed. */ + char *old_rna_path = fcurve->rna_path; + if (BLI_str_endswith(fcurve->rna_path, "flaps")) { + fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[0].default_value"); + } + else if (BLI_str_endswith(fcurve->rna_path, "angle")) { + fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[1].default_value"); + } + else if (BLI_str_endswith(fcurve->rna_path, "rounding")) { + fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[2].default_value"); + } + else if (BLI_str_endswith(fcurve->rna_path, "catadioptric")) { + fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[3].default_value"); + } + else if (BLI_str_endswith(fcurve->rna_path, "shift")) { + fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[4].default_value"); + } + + /* The RNA path was changed, free the old path. */ + if (fcurve->rna_path != old_rna_path) { + MEM_freeN(old_rna_path); + } + }); +} + static void do_version_viewer_shortcut(bNodeTree *node_tree) { LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_tree->nodes) { @@ -2238,6 +2324,19 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 22)) { + FOREACH_NODETREE_BEGIN (bmain, node_tree, id) { + if (node_tree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { + if (node->type_legacy == CMP_NODE_BOKEHIMAGE) { + do_version_bokeh_image_node_options_to_inputs_animation(node_tree, node); + } + } + } + } + FOREACH_NODETREE_END; + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. @@ -6797,6 +6896,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 22)) { + FOREACH_NODETREE_BEGIN (bmain, node_tree, id) { + if (node_tree->type == NTREE_COMPOSIT) { + LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { + if (node->type_legacy == CMP_NODE_BOKEHIMAGE) { + do_version_bokeh_image_node_options_to_inputs(node_tree, node); + } + } + } + } + FOREACH_NODETREE_END; + } + /* Always run this versioning (keep at the bottom of the function). Meshes are written with the * legacy format which always needs to be converted to the new format on file load. To be moved * to a subversion check in 5.0. */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index e6b6b11a067..c7136bba7f4 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1096,11 +1096,11 @@ typedef struct NodeColorCorrection { } NodeColorCorrection; typedef struct NodeBokehImage { - float angle; - int flaps; - float rounding; - float catadioptric; - float lensshift; + float angle DNA_DEPRECATED; + int flaps DNA_DEPRECATED; + float rounding DNA_DEPRECATED; + float catadioptric DNA_DEPRECATED; + float lensshift DNA_DEPRECATED; } NodeBokehImage; typedef struct NodeBoxMask { diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 53ff8c6512d..c6d43e314d5 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -3786,6 +3786,8 @@ static void rna_NodeGlare_color_modulation_set(PointerRNA *ptr, const float valu RNA_float_set(&input_rna_pointer, "default_value", blender::math::clamp(value, 0.0f, 1.0f)); } +/* A getter that returns the value of the input socket with the given template identifier and type. + * The RNA pointer is assumed to represent a node. */ template static T rna_node_property_to_input_getter(PointerRNA *ptr) { @@ -3808,6 +3810,8 @@ static T rna_node_property_to_input_getter(PointerRNA *ptr) } } +/* A setter that sets the given value to the input socket with the given template identifier and + * type. The RNA pointer is assumed to represent a node. */ template static void rna_node_property_to_input_setter(PointerRNA *ptr, const T value) { @@ -3829,8 +3833,19 @@ static void rna_node_property_to_input_setter(PointerRNA *ptr, const T value) } } +/* The following are global static strings used as template arguments to + * rna_node_property_to_input_getter and rna_node_property_to_input_setter. */ + +/* Glare node. */ static const char node_input_diagonal_star[] = "Diagonal Star"; +/* Bokeh Image node. */ +static const char node_input_flaps[] = "Flaps"; +static const char node_input_angle[] = "Angle"; +static const char node_input_roundness[] = "Roundness"; +static const char node_input_catadioptric_size[] = "Catadioptric Size"; +static const char node_input_color_shift[] = "Color Shift"; + /* -------------------------------------------------------------------- * White Balance Node. */ @@ -9015,41 +9030,66 @@ static void def_cmp_bokehimage(BlenderRNA * /*brna*/, StructRNA *srna) { PropertyRNA *prop; - RNA_def_struct_sdna_from(srna, "NodeBokehImage", "storage"); - prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_sdna(prop, nullptr, "angle"); + RNA_def_property_float_funcs(prop, + "rna_node_property_to_input_getter", + "rna_node_property_to_input_setter", + nullptr); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, DEG2RADF(-720.0f), DEG2RADF(720.0f)); - RNA_def_property_ui_text(prop, "Angle", "Angle of the bokeh"); + RNA_def_property_ui_text( + prop, "Angle", "Angle of the bokeh. (Deprecated: Use Angle input instead)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "flaps", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, nullptr, "flaps"); + RNA_def_property_int_funcs(prop, + "rna_node_property_to_input_getter", + "rna_node_property_to_input_setter", + nullptr); RNA_def_property_int_default(prop, 5); RNA_def_property_range(prop, 3, 24); - RNA_def_property_ui_text(prop, "Flaps", "Number of flaps"); + RNA_def_property_ui_text( + prop, "Flaps", "Number of flaps. (Deprecated: Use Flaps input instead)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "rounding", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, nullptr, "rounding"); + RNA_def_property_float_funcs(prop, + "rna_node_property_to_input_getter", + "rna_node_property_to_input_setter", + nullptr); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Rounding", "Level of rounding of the bokeh"); + RNA_def_property_ui_text( + prop, + "Rounding", + "Level of rounding of the bokeh. (Deprecated: Use Roundness input instead)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "catadioptric", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, nullptr, "catadioptric"); + RNA_def_property_float_funcs( + prop, + "rna_node_property_to_input_getter", + "rna_node_property_to_input_setter", + nullptr); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Catadioptric", "Level of catadioptric of the bokeh"); + RNA_def_property_ui_text( + prop, + "Catadioptric", + "Level of catadioptric of the bokeh. (Deprecated: Use Catadioptric Size input instead)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "shift", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, nullptr, "lensshift"); + RNA_def_property_float_funcs(prop, + "rna_node_property_to_input_getter", + "rna_node_property_to_input_setter", + nullptr); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1.0f, 1.0f); - RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components"); + RNA_def_property_ui_text( + prop, + "Lens Shift", + "Shift of the lens components. (Deprecated: Use Color Shift input instead)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc index acb232e36cc..9b960d0aa07 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc @@ -6,6 +6,7 @@ * \ingroup cmpnodes */ +#include "BLI_math_base.hh" #include "BLI_math_vector_types.hh" #include "UI_interface.hh" @@ -20,48 +21,54 @@ namespace blender::nodes::node_composite_bokehimage_cc { -NODE_STORAGE_FUNCS(NodeBokehImage) - static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b) { + b.add_input("Flaps") + .default_value(5) + .min(3) + .max(24) + .description("The number of flaps in the bokeh") + .compositor_expects_single_value(); + b.add_input("Angle") + .default_value(0.0f) + .subtype(PROP_ANGLE) + .description("The angle of the bokeh") + .compositor_expects_single_value(); + b.add_input("Roundness") + .default_value(0.0f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .description("Specifies how round the bokeh is, maximum roundness produces a circular bokeh") + .compositor_expects_single_value(); + b.add_input("Catadioptric Size") + .default_value(0.0f) + .subtype(PROP_FACTOR) + .min(0.0f) + .max(1.0f) + .description("Specifies the size of the catadioptric iris, zero means no iris") + .compositor_expects_single_value(); + b.add_input("Color Shift") + .default_value(0.0f) + .subtype(PROP_FACTOR) + .min(-1.0f) + .max(1.0f) + .description( + "Specifies the amount of color shifting. 1 means maximum shifting towards blue while -1 " + "means maximum shifting toward red") + .compositor_expects_single_value(); + b.add_output("Image"); } static void node_composit_init_bokehimage(bNodeTree * /*ntree*/, bNode *node) { + /* All members are deprecated and needn't be set, but the data is still allocated for forward + * compatibility. */ NodeBokehImage *data = MEM_callocN(__func__); - data->angle = 0.0f; - data->flaps = 5; - data->rounding = 0.0f; - data->catadioptric = 0.0f; - data->lensshift = 0.0f; node->storage = data; } -static void node_composit_buts_bokehimage(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "flaps", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - uiItemR(layout, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); - uiItemR(layout, - ptr, - "rounding", - UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, - std::nullopt, - ICON_NONE); - uiItemR(layout, - ptr, - "catadioptric", - UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, - std::nullopt, - ICON_NONE); - uiItemR(layout, - ptr, - "shift", - UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, - std::nullopt, - ICON_NONE); -} - using namespace blender::compositor; class BokehImageOperation : public NodeOperation { @@ -70,18 +77,18 @@ class BokehImageOperation : public NodeOperation { void execute() override { - const Domain domain = compute_domain(); + const Domain domain = this->compute_domain(); - const Result &bokeh_kernel = context().cache_manager().bokeh_kernels.get( - context(), + const Result &bokeh_kernel = this->context().cache_manager().bokeh_kernels.get( + this->context(), domain.size, - node_storage(bnode()).flaps, - node_storage(bnode()).angle, - node_storage(bnode()).rounding, - node_storage(bnode()).catadioptric, - node_storage(bnode()).lensshift); + this->get_flaps(), + this->get_angle(), + this->get_roundness(), + this->get_catadioptric_size(), + this->get_color_shift()); - Result &output = get_result("Image"); + Result &output = this->get_result("Image"); output.wrap_external(bokeh_kernel); } @@ -89,6 +96,32 @@ class BokehImageOperation : public NodeOperation { { return Domain(int2(512)); } + + int get_flaps() + { + return math::clamp(this->get_input("Flaps").get_single_value_default(5), 3, 24); + } + + float get_angle() + { + return this->get_input("Angle").get_single_value_default(0.0f); + } + + float get_roundness() + { + return math::clamp(this->get_input("Roundness").get_single_value_default(0.0f), 0.0f, 1.0f); + } + + float get_catadioptric_size() + { + return math::clamp( + this->get_input("Catadioptric Size").get_single_value_default(0.0f), 0.0f, 1.0f); + } + + float get_color_shift() + { + return math::clamp(this->get_input("Color Shift").get_single_value_default(0.0f), -1.0f, 1.0f); + } }; static NodeOperation *get_compositor_operation(Context &context, DNode node) @@ -110,7 +143,6 @@ void register_node_type_cmp_bokehimage() ntype.enum_name_legacy = "BOKEHIMAGE"; ntype.nclass = NODE_CLASS_INPUT; ntype.declare = file_ns::cmp_node_bokehimage_declare; - ntype.draw_buttons = file_ns::node_composit_buts_bokehimage; ntype.flag |= NODE_PREVIEW; ntype.initfunc = file_ns::node_composit_init_bokehimage; blender::bke::node_type_storage(