From 24c7d5361c18969a405870aee45faa98a3f9ce0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 10 Apr 2023 11:54:55 +0200 Subject: [PATCH 01/33] Added a new socket type for functions/closures. This uses a closure data type to defer evaluation. --- source/blender/blenkernel/intern/cpp_types.cc | 5 ++++ source/blender/blenkernel/intern/node.cc | 12 ++++++++ source/blender/editors/space_node/drawnode.cc | 1 + .../editors/space_node/node_relationships.cc | 1 + .../editors/space_node/node_templates.cc | 3 ++ source/blender/functions/CMakeLists.txt | 2 ++ source/blender/functions/FN_closure.hh | 30 +++++++++++++++++++ source/blender/functions/intern/closure.cc | 16 ++++++++++ source/blender/makesdna/DNA_node_types.h | 1 + source/blender/makesrna/intern/rna_nodetree.c | 22 +++++++++++++- .../blender/nodes/NOD_socket_declarations.hh | 11 +++++++ .../nodes/geometry/node_geometry_tree.cc | 3 +- source/blender/nodes/intern/node_common.cc | 3 ++ source/blender/nodes/intern/node_socket.cc | 15 ++++++++++ 14 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 source/blender/functions/FN_closure.hh create mode 100644 source/blender/functions/intern/closure.cc diff --git a/source/blender/blenkernel/intern/cpp_types.cc b/source/blender/blenkernel/intern/cpp_types.cc index d1f2c5efa55..b502c3506b4 100644 --- a/source/blender/blenkernel/intern/cpp_types.cc +++ b/source/blender/blenkernel/intern/cpp_types.cc @@ -9,6 +9,7 @@ #include "DNA_meshdata_types.h" +#include "FN_closure.hh" #include "FN_init.h" struct Tex; @@ -30,6 +31,8 @@ BLI_CPP_TYPE_MAKE(MStringProperty, CPPTypeFlags::None); BLI_CPP_TYPE_MAKE(blender::bke::AnonymousAttributeSet, CPPTypeFlags::None); +BLI_CPP_TYPE_MAKE(blender::fn::Closure, CPPTypeFlags::None); + void BKE_cpp_types_init() { blender::register_cpp_types(); @@ -49,4 +52,6 @@ void BKE_cpp_types_init() BLI_CPP_TYPE_REGISTER(MStringProperty); BLI_CPP_TYPE_REGISTER(blender::bke::AnonymousAttributeSet); + + BLI_CPP_TYPE_REGISTER(blender::fn::Closure); } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 364b6635b0d..3e109762025 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -321,6 +321,7 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: break; } } @@ -466,6 +467,7 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so case __SOCK_MESH: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: BLI_assert_unreachable(); break; } @@ -886,6 +888,7 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: break; } } @@ -981,6 +984,7 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: break; } } @@ -1627,6 +1631,7 @@ static void socket_id_user_increment(bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: break; } } @@ -1673,6 +1678,7 @@ static bool socket_id_user_decrement(bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: + case SOCK_FUNCTION: break; } return false; @@ -1855,6 +1861,8 @@ const char *nodeStaticSocketType(const int type, const int subtype) return "NodeSocketTexture"; case SOCK_MATERIAL: return "NodeSocketMaterial"; + case SOCK_FUNCTION: + return "NodeSocketFunction"; default: break; } @@ -1934,6 +1942,8 @@ const char *nodeStaticSocketInterfaceType(const int type, const int subtype) return "NodeSocketInterfaceTexture"; case SOCK_MATERIAL: return "NodeSocketInterfaceMaterial"; + case SOCK_FUNCTION: + return "NodeSocketInterfaceFunction"; default: break; } @@ -1969,6 +1979,8 @@ const char *nodeStaticSocketLabel(const int type, const int /*subtype*/) return "Texture"; case SOCK_MATERIAL: return "Material"; + case SOCK_FUNCTION: + return "Function"; default: break; } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 4eb1dffd880..384475fb9e9 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1198,6 +1198,7 @@ static const float std_node_socket_colors[][4] = { {0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */ {0.62, 0.31, 0.64, 1.0}, /* SOCK_TEXTURE */ {0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */ + {0.65, 0.05, 0.64, 1.0}, /* SOCK_FUNCTION */ }; /* common color callbacks for standard types */ diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 7d65292ae90..5e7561c06d6 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -2241,6 +2241,7 @@ static int get_main_socket_priority(const bNodeSocket *socket) case SOCK_COLLECTION: case SOCK_TEXTURE: case SOCK_MATERIAL: + case SOCK_FUNCTION: return 6; } return -1; diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index cb69800e515..2fe460a77fa 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -405,6 +405,9 @@ static Vector ui_node_link_items(NodeLinkArg *arg, else if (dynamic_cast(&socket_decl)) { item.socket_type = SOCK_OBJECT; } + else if (dynamic_cast(&socket_decl)) { + item.socket_type = SOCK_FUNCTION; + } else { item.socket_type = SOCK_CUSTOM; } diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 54f67122907..b2237f333a8 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC_SYS ) set(SRC + intern/closure.cc intern/cpp_types.cc intern/field.cc intern/field_cpp_type.cc @@ -26,6 +27,7 @@ set(SRC intern/multi_function_procedure_executor.cc intern/multi_function_procedure_optimization.cc + FN_closure.hh FN_field.hh FN_field_cpp_type.hh FN_field_cpp_type_make.hh diff --git a/source/blender/functions/FN_closure.hh b/source/blender/functions/FN_closure.hh new file mode 100644 index 00000000000..16b58e94ba1 --- /dev/null +++ b/source/blender/functions/FN_closure.hh @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup fn + */ + +#include "BLI_cpp_type.hh" + +#include "FN_lazy_function.hh" +#include "FN_lazy_function_graph_executor.hh" + +namespace blender::fn { + +class Closure { + private: + std::shared_ptr function_; + + public: + Closure() = default; + Closure(const Closure &other) = default; + explicit Closure(const lf::GraphExecutor &function); + ~Closure() = default; + + Closure &operator=(const Closure &other) = default; +}; + + +} // namespace blender::fn diff --git a/source/blender/functions/intern/closure.cc b/source/blender/functions/intern/closure.cc new file mode 100644 index 00000000000..24d7c8da7c3 --- /dev/null +++ b/source/blender/functions/intern/closure.cc @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup fn + */ + +#include "FN_closure.hh" + +namespace blender::fn { + +Closure::Closure(const lf::GraphExecutor &function) + : function_(std::make_shared(function)) +{ +} + +} // namespace blender::fn diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 8245637943a..2fca7e86efe 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -236,6 +236,7 @@ typedef enum eNodeSocketDatatype { SOCK_COLLECTION = 11, SOCK_TEXTURE = 12, SOCK_MATERIAL = 13, + SOCK_FUNCTION = 14, } eNodeSocketDatatype; /** Socket shape. */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 2399cfe74e3..6a73c3ccfcd 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -72,6 +72,7 @@ static const EnumPropertyItem node_socket_data_type_items[] = { {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""}, {SOCK_MATERIAL, "MATERIAL", 0, "Material", ""}, + {SOCK_FUNCTION, "FUNCTION", 0, "Function", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -100,6 +101,7 @@ static const EnumPropertyItem node_socket_type_items[] = { {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""}, {SOCK_MATERIAL, "MATERIAL", 0, "Material", ""}, + {SOCK_FUNCTION, "FUNCTION", 0, "Function", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2077,7 +2079,8 @@ static bool switch_type_supported(const EnumPropertyItem *item) SOCK_COLLECTION, SOCK_TEXTURE, SOCK_MATERIAL, - SOCK_IMAGE); + SOCK_IMAGE, + SOCK_FUNCTION); } static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C), @@ -11932,6 +11935,21 @@ static void rna_def_node_socket_material(BlenderRNA *brna, RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } +static void rna_def_node_socket_function(BlenderRNA *brna, + const char *identifier, + const char *interface_idname) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); + RNA_def_struct_ui_text(srna, "Function Node Socket", "Function socket of a node"); + RNA_def_struct_sdna(srna, "bNodeSocket"); + + srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); + RNA_def_struct_ui_text(srna, "Function Node Socket Interface", "Function socket of a node"); + RNA_def_struct_sdna(srna, "bNodeSocket"); +} + static void rna_def_node_socket_standard_types(BlenderRNA *brna) { /* XXX Workaround: Registered functions are not exposed in python by bpy, @@ -12084,6 +12102,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna) rna_def_node_socket_texture(brna, "NodeSocketTexture", "NodeSocketInterfaceTexture"); rna_def_node_socket_material(brna, "NodeSocketMaterial", "NodeSocketInterfaceMaterial"); + + rna_def_node_socket_function(brna, "NodeSocketFunction", "NodeSocketInterfaceFunction"); } static void rna_def_internal_node(BlenderRNA *brna) diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh index 2873170f546..c383415b340 100644 --- a/source/blender/nodes/NOD_socket_declarations.hh +++ b/source/blender/nodes/NOD_socket_declarations.hh @@ -225,6 +225,13 @@ class Shader : public SocketDeclaration { class ShaderBuilder : public SocketDeclarationBuilder { }; +class Function : public IDSocketDeclaration { + public: + using Builder = SocketDeclarationBuilder; + + Function(); +}; + class ExtendBuilder; class Extend : public SocketDeclaration { @@ -401,6 +408,10 @@ inline Texture::Texture() : IDSocketDeclaration("NodeSocketTexture") {} inline Image::Image() : IDSocketDeclaration("NodeSocketImage") {} +inline Function::Function() : IDSocketDeclaration("NodeSocketFunction") +{ +} + /** \} */ SocketDeclarationPtr create_extend_declaration(const eNodeSocketInOut in_out); diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index dbdbf1e616d..be846ca5263 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -102,7 +102,8 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType * /*treetype*/, SOCK_COLLECTION, SOCK_TEXTURE, SOCK_IMAGE, - SOCK_MATERIAL); + SOCK_MATERIAL, + SOCK_FUNCTION); } void register_node_tree_type_geo() diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index b66f16f4d25..a394c675b39 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -251,6 +251,9 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &nt dst = std::move(value); break; } + case SOCK_FUNCTION: + dst = std::make_unique(); + break; case SOCK_CUSTOM: std::unique_ptr decl = std::make_unique(); decl->idname_ = io_socket.idname; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 367897160ff..47a8e47cc90 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -33,6 +33,7 @@ #include "NOD_node_declaration.hh" #include "NOD_socket.h" +#include "FN_closure.hh" #include "FN_field.hh" using namespace blender; @@ -778,6 +779,18 @@ static bNodeSocketType *make_socket_type_material() return socktype; } +static bNodeSocketType *make_socket_type_function() +{ + bNodeSocketType *socktype = make_standard_socket_type(SOCK_FUNCTION, PROP_NONE); + socktype->base_cpp_type = &blender::CPPType::get(); + socktype->get_base_cpp_value = [](const bNodeSocket &/*socket*/, void *r_value) { + new (r_value) fn::Closure(); + }; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; + socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + return socktype; +} + void register_standard_node_socket_types() { /* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */ @@ -824,5 +837,7 @@ void register_standard_node_socket_types() nodeRegisterSocketType(make_socket_type_material()); + nodeRegisterSocketType(make_socket_type_function()); + nodeRegisterSocketType(make_socket_type_virtual()); } -- 2.30.2 From ef77a39184777412fa481a4caa59993e4f141c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 10 Apr 2023 12:32:29 +0200 Subject: [PATCH 02/33] Function color different from texture sockets. --- source/blender/editors/space_node/drawnode.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 384475fb9e9..d353df7657a 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1198,7 +1198,7 @@ static const float std_node_socket_colors[][4] = { {0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */ {0.62, 0.31, 0.64, 1.0}, /* SOCK_TEXTURE */ {0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */ - {0.65, 0.05, 0.64, 1.0}, /* SOCK_FUNCTION */ + {0.98, 0.30, 0.83, 1.0}, /* SOCK_FUNCTION */ }; /* common color callbacks for standard types */ -- 2.30.2 From 651df82e39e563f12f49b34ecf481d64abce98f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 10 Apr 2023 16:23:29 +0200 Subject: [PATCH 03/33] Bind and Evaluate nodes for handling function closures. --- .../startup/bl_ui/node_add_menu_geometry.py | 12 ++++ source/blender/blenkernel/BKE_node.h | 2 + source/blender/makesrna/intern/rna_nodetree.c | 64 +++++++++++++++++++ source/blender/nodes/NOD_static_types.h | 2 + source/blender/nodes/function/CMakeLists.txt | 2 + .../nodes/function/node_function_register.cc | 2 + .../nodes/function/node_function_register.hh | 2 + .../nodes/function/nodes/node_fn_bind.cc | 64 +++++++++++++++++++ .../nodes/function/nodes/node_fn_evaluate.cc | 42 ++++++++++++ 9 files changed, 192 insertions(+) create mode 100644 source/blender/nodes/function/nodes/node_fn_bind.cc create mode 100644 source/blender/nodes/function/nodes/node_fn_evaluate.cc diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index d673f6941b2..2a5b072df69 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -617,6 +617,16 @@ class NODE_MT_category_GEO_GROUP(Menu): node_add_menu.draw_assets_for_catalog(layout, self.bl_label) +class NODE_MT_category_GEO_FUNCTION(Menu): + bl_idname = "NODE_MT_category_GEO_FUNCTION" + bl_label = "Function" + + def draw(self, context): + layout = self.layout + node_add_menu.add_node_type(layout, "FunctionNodeBind") + node_add_menu.add_node_type(layout, "FunctionNodeEvaluate") + + class NODE_MT_category_GEO_LAYOUT(Menu): bl_idname = "NODE_MT_category_GEO_LAYOUT" bl_label = "Layout" @@ -651,6 +661,7 @@ class NODE_MT_geometry_node_add_all(Menu): layout.menu("NODE_MT_category_GEO_UTILITIES") layout.separator() layout.menu("NODE_MT_category_GEO_GROUP") + layout.menu("NODE_MT_category_GEO_FUNCTION") layout.menu("NODE_MT_category_GEO_LAYOUT") node_add_menu.draw_root_assets(layout) @@ -696,6 +707,7 @@ classes = ( NODE_MT_category_GEO_UTILITIES_MATH, NODE_MT_category_GEO_UTILITIES_ROTATION, NODE_MT_category_GEO_GROUP, + NODE_MT_category_GEO_FUNCTION, NODE_MT_category_GEO_LAYOUT, ) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 8553f2fd0fe..1810818c939 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1608,6 +1608,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define FN_NODE_INPUT_INT 1220 #define FN_NODE_SEPARATE_COLOR 1221 #define FN_NODE_COMBINE_COLOR 1222 +#define FN_NODE_BIND 1223 +#define FN_NODE_EVALUATE 1224 /** \} */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 6a73c3ccfcd..852c43e5bda 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4544,6 +4544,51 @@ static const EnumPropertyItem *rna_NodeConvertColorSpace_color_space_itemf( return items; } +static void rna_FunctionNodeBind_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +{ + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNode *node = (bNode *)ptr->data; + + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + DEG_relations_tag_update(bmain); +} + +static void rna_FunctionNodeBind_node_tree_set(PointerRNA *ptr, + const PointerRNA value, + struct ReportList *UNUSED(reports)) +{ + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNode *node = ptr->data; + bNodeTree *ngroup = value.data; + + const char *disabled_hint = NULL; + if (nodeGroupPoll(ntree, ngroup, &disabled_hint)) { + if (node->id) { + id_us_min(node->id); + } + if (ngroup) { + id_us_plus(&ngroup->id); + } + + node->id = &ngroup->id; + } +} + +static bool rna_FunctionNodeBind_node_tree_poll(PointerRNA *ptr, const PointerRNA value) +{ + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNodeTree *ngroup = value.data; + + /* only allow node trees of the same type as the bind node's tree */ + if (ngroup->type != ntree->type) { + return false; + } + + const char *disabled_hint = NULL; + return nodeGroupPoll(ntree, ngroup, &disabled_hint); +} + #else static const EnumPropertyItem prop_image_layer_items[] = { @@ -5200,6 +5245,25 @@ static void def_fn_combsep_color(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_fn_bind(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "NodeTree"); + RNA_def_property_pointer_funcs( + prop, NULL, "rna_FunctionNodeBind_node_tree_set", NULL, "rna_FunctionNodeBind_node_tree_poll"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text(prop, "Node Tree", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNodeBind_update"); +} + +static void def_fn_evaluate(StructRNA *srna) +{ +} + /* -- Shader Nodes ---------------------------------------------------------- */ static void def_sh_output(StructRNA *srna) diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 1bd9896261e..df611a3166f 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -279,6 +279,8 @@ DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_CO 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", "") +DefNode(FunctionNode, FN_NODE_BIND, def_fn_bind, "BIND", Bind, "Bind", "") +DefNode(FunctionNode, FN_NODE_EVALUATE, def_fn_evaluate, "EVALUATE", Evaluate, "Evaluate", "") DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "Retrieve the number of elements in a geometry for each attribute domain") diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt index 756178ffe5a..045abed94a5 100644 --- a/source/blender/nodes/function/CMakeLists.txt +++ b/source/blender/nodes/function/CMakeLists.txt @@ -21,9 +21,11 @@ set(INC_SYS set(SRC nodes/node_fn_align_euler_to_vector.cc + nodes/node_fn_bind.cc nodes/node_fn_boolean_math.cc nodes/node_fn_combine_color.cc nodes/node_fn_compare.cc + nodes/node_fn_evaluate.cc nodes/node_fn_float_to_int.cc nodes/node_fn_input_bool.cc nodes/node_fn_input_color.cc diff --git a/source/blender/nodes/function/node_function_register.cc b/source/blender/nodes/function/node_function_register.cc index 8c5ce489832..62feda8a0ee 100644 --- a/source/blender/nodes/function/node_function_register.cc +++ b/source/blender/nodes/function/node_function_register.cc @@ -7,9 +7,11 @@ void register_function_nodes() { register_node_type_fn_align_euler_to_vector(); + register_node_type_fn_bind(); register_node_type_fn_boolean_math(); register_node_type_fn_combine_color(); register_node_type_fn_compare(); + register_node_type_fn_evaluate(); register_node_type_fn_float_to_int(); register_node_type_fn_input_bool(); register_node_type_fn_input_color(); diff --git a/source/blender/nodes/function/node_function_register.hh b/source/blender/nodes/function/node_function_register.hh index 7f3e7c1cd8c..b78548fb221 100644 --- a/source/blender/nodes/function/node_function_register.hh +++ b/source/blender/nodes/function/node_function_register.hh @@ -3,9 +3,11 @@ #pragma once void register_node_type_fn_align_euler_to_vector(); +void register_node_type_fn_bind(); void register_node_type_fn_boolean_math(); void register_node_type_fn_combine_color(); void register_node_type_fn_compare(); +void register_node_type_fn_evaluate(); void register_node_type_fn_float_to_int(); void register_node_type_fn_input_bool(); void register_node_type_fn_input_color(); diff --git a/source/blender/nodes/function/nodes/node_fn_bind.cc b/source/blender/nodes/function/nodes/node_fn_bind.cc new file mode 100644 index 00000000000..884f5a3ae63 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_bind.cc @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_listbase.h" + +#include "BKE_node_runtime.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "NOD_common.h" + +#include "node_common.h" +#include "node_function_util.hh" +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_bind_cc { + +static void node_declare(const bNodeTree &node_tree, + const bNode &node, + NodeDeclaration &r_declaration) +{ + const bNodeTree *group = reinterpret_cast(node.id); + if (!group) { + return; + } + blender::nodes::node_group_declare_dynamic(node_tree, node, r_declaration); + if (!node.id) { + return; + } + if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) { + return; + } + + const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface; + for (const int i : r_declaration.inputs.index_range()) { + r_declaration.inputs[i]->input_field_type = field_interface.inputs[i]; + } + for (const int i : r_declaration.outputs.index_range()) { + r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i]; + } +} + +static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + uiTemplateIDBrowse( + layout, C, ptr, "node_tree", nullptr, nullptr, nullptr, UI_TEMPLATE_ID_FILTER_ALL, nullptr); +} + +} // namespace blender::nodes::node_fn_bind_cc + +void register_node_type_fn_bind() +{ + namespace file_ns = blender::nodes::node_fn_bind_cc; + + static bNodeType ntype; + + fn_node_type_base(&ntype, FN_NODE_BIND, "Bind", NODE_CLASS_GROUP); + ntype.poll_instance = node_group_poll_instance; + + node_type_size(&ntype, 140, 60, 400); + ntype.declare_dynamic = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/function/nodes/node_fn_evaluate.cc b/source/blender/nodes/function/nodes/node_fn_evaluate.cc new file mode 100644 index 00000000000..541eaef5c47 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_evaluate.cc @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_listbase.h" +#include "BLI_math_vector.h" +#include "BLI_string.h" + +#include "RNA_enum_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_evaluate_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input(N_("Function")); +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ +} + +static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) +{ +} + +} // namespace blender::nodes::node_fn_evaluate_cc + +void register_node_type_fn_evaluate() +{ + namespace file_ns = blender::nodes::node_fn_evaluate_cc; + + static bNodeType ntype; + + fn_node_type_base(&ntype, FN_NODE_EVALUATE, "Evaluate", NODE_CLASS_GROUP); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.updatefunc = file_ns::node_update; + nodeRegisterType(&ntype); +} -- 2.30.2 From 31a2afb11f112e9fbb89c86432118049de359454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 10 Apr 2023 16:24:17 +0200 Subject: [PATCH 04/33] Generic ID_NT support in depsgraph instead of just group nodes. --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 5 ++--- .../depsgraph/intern/builder/deg_builder_relations.cc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index c0ee0b29137..ab4e2923698 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1832,9 +1832,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) else if (id_type == ID_VF) { build_vfont((VFont *)id); } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - bNodeTree *group_ntree = (bNodeTree *)id; - build_nodetree(group_ntree); + else if (id_type == ID_NT) { + build_nodetree((bNodeTree *)id); } else { BLI_assert_msg(0, "Unknown ID type used for node"); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 8398f5888f4..f9a1d49566b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2730,7 +2730,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK); add_relation(vfont_key, ntree_output_key, "VFont -> Node"); } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + else if (id_type == ID_NT) { bNodeTree *group_ntree = (bNodeTree *)id; build_nodetree(group_ntree); ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT); -- 2.30.2 From 248c301563dad77db94dfcd1d8a17b0f98a60a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 10 Apr 2023 17:19:30 +0200 Subject: [PATCH 05/33] Generate input sockets on the Bind node for capturing defaults. --- source/blender/nodes/NOD_node_declaration.hh | 2 ++ .../nodes/function/nodes/node_fn_bind.cc | 18 +++++++++++------- source/blender/nodes/intern/node_common.cc | 4 ++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index 6c5f6699eb4..8c7a446cf09 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -753,4 +753,6 @@ inline Span NodeDeclaration::sockets(eNodeSocketInOut in_o /** \} */ +SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket); + } // namespace blender::nodes diff --git a/source/blender/nodes/function/nodes/node_fn_bind.cc b/source/blender/nodes/function/nodes/node_fn_bind.cc index 884f5a3ae63..fc3446f59b7 100644 --- a/source/blender/nodes/function/nodes/node_fn_bind.cc +++ b/source/blender/nodes/function/nodes/node_fn_bind.cc @@ -8,6 +8,7 @@ #include "UI_resources.h" #include "NOD_common.h" +#include "NOD_node_declaration.hh" #include "node_common.h" #include "node_function_util.hh" @@ -19,25 +20,28 @@ static void node_declare(const bNodeTree &node_tree, const bNode &node, NodeDeclaration &r_declaration) { + NodeDeclarationBuilder builder(r_declaration); + builder.add_output(N_("Function")); + const bNodeTree *group = reinterpret_cast(node.id); if (!group) { return; } - blender::nodes::node_group_declare_dynamic(node_tree, node, r_declaration); - if (!node.id) { + + if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) { + r_declaration.skip_updating_sockets = true; return; } - if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) { - return; + r_declaration.skip_updating_sockets = false; + + LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) { + r_declaration.inputs.append(declaration_for_interface_socket(*input)); } const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface; for (const int i : r_declaration.inputs.index_range()) { r_declaration.inputs[i]->input_field_type = field_interface.inputs[i]; } - for (const int i : r_declaration.outputs.index_range()) { - r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i]; - } } static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr) diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index a394c675b39..aa19609d13f 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -157,8 +157,8 @@ static std::function get_default_id_getter(const bNodeT }; } -static SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree, - const bNodeSocket &io_socket) +SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree, + const bNodeSocket &io_socket) { SocketDeclarationPtr dst; switch (io_socket.type) { -- 2.30.2 From 871d2c418c2bb1fa76a0ce62da816573ab0f1577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 11 Apr 2023 08:34:17 +0200 Subject: [PATCH 06/33] New bNodeFunctionSignature struct to encapsulate interfaces. --- source/blender/blenkernel/BKE_node.h | 47 +++ .../blender/blenkernel/BKE_node_tree_update.h | 2 + source/blender/blenkernel/intern/node.cc | 203 +++++++++++++ .../blenkernel/intern/node_tree_update.cc | 9 + source/blender/makesdna/DNA_node_types.h | 8 + source/blender/makesrna/intern/rna_nodetree.c | 283 ++++++++++++++++++ 6 files changed, 552 insertions(+) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 1810818c939..2d2c578f449 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -224,6 +224,53 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, struct GPUNodeStack *in, struct GPUNodeStack *out); +/* -------------------------------------------------------------------- */ +/** \name Node Function Signature + * \{ */ + +struct bNodeSocket *nodeFunctionSignatureFindSocket(struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const char *identifier); +struct bNodeSocket *nodeFunctionSignatureAddSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const char *idname, + const char *name); +struct bNodeSocket *nodeFunctionSignatureInsertSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const char *idname, + struct bNodeSocket *next_sock, + const char *name); +struct bNodeSocket *nodeFunctionSignatureCopySocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + const struct bNode *from_node, + const struct bNodeSocket *from_sock); +struct bNodeSocket *nodeFunctionSignatureCopySocketEx(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + const struct bNode *from_node, + const struct bNodeSocket *from_sock, + const char *idname, + const char *name); +struct bNodeSocket *nodeFunctionSignatureCopyInsertSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + struct bNodeSocket *next_sock, + const struct bNode *from_node, + const struct bNodeSocket *from_sock); +void nodeFunctionSignatureRemoveSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + struct bNodeSocket *sock); +void nodeFunctionSignatureClear(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out); +void nodeFunctionSignatureMoveSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + int from_index, + int to_index); + +/** \} */ + /** * \brief Defines a node type. * diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h index eafcf0fb8a1..9cec5733f2d 100644 --- a/source/blender/blenkernel/BKE_node_tree_update.h +++ b/source/blender/blenkernel/BKE_node_tree_update.h @@ -54,6 +54,8 @@ void BKE_ntree_update_tag_active_output_changed(struct bNodeTree *ntree); void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree); /** Used when the interface sockets/values have changed. */ void BKE_ntree_update_tag_interface(struct bNodeTree *ntree); +/** Used when a signature is changed. */ +void BKE_ntree_update_tag_signature_changed(struct bNodeTree *ntree, struct bNodeFunctionSignature *sig); /** Used when change parent node. */ void BKE_ntree_update_tag_parent_change(struct bNodeTree *ntree, struct bNode *node); /** Used when an id data block changed that might be used by nodes that need to be updated. */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 3e109762025..490f8658170 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -122,6 +122,209 @@ static void free_localized_node_groups(bNodeTree *ntree); static void node_socket_interface_free(bNodeTree * /*ntree*/, bNodeSocket *sock, const bool do_id_user); +static void node_socket_set_typeinfo(bNodeTree *ntree, + bNodeSocket *sock, + bNodeSocketType *typeinfo); + +/* ************ NODE FUNCTION SIGNATURE *************** */ + +static bNodeSocket *make_signature_socket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *idname, + const char *name) +{ + bNodeSocketType *stype = nodeSocketTypeFind(idname); + if (stype == nullptr) { + return nullptr; + } + + bNodeSocket *sock = MEM_cnew("socket template"); + sock->runtime = MEM_new(__func__); + BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); + sock->in_out = in_out; + sock->type = SOCK_CUSTOM; /* int type undefined by default */ + node_socket_set_typeinfo(ntree, sock, stype); + + /* assign new unique index */ + const int own_index = sig->cur_index++; + /* use the own_index as socket identifier */ + if (in_out == SOCK_IN) { + BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); + } + else { + BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); + } + + sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); + + BLI_strncpy(sock->name, name, NODE_MAXSTR); + sock->storage = nullptr; + sock->flag |= SOCK_COLLAPSED; + + return sock; +} + +bNodeSocket *nodeFunctionSignatureFindSocket(bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *identifier) +{ + ListBase *sockets = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs; + LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { + if (STREQ(iosock->identifier, identifier)) { + return iosock; + } + } + return nullptr; +} + +bNodeSocket *nodeFunctionSignatureAddSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *idname, + const char *name) +{ + bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name); + if (in_out == SOCK_IN) { + BLI_addtail(&sig->inputs, iosock); + } + else if (in_out == SOCK_OUT) { + BLI_addtail(&sig->outputs, iosock); + } + BKE_ntree_update_tag_signature_changed(ntree, sig); + return iosock; +} + +bNodeSocket *nodeFunctionSignatureInsertSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *idname, + bNodeSocket *next_sock, + const char *name) +{ + bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name); + if (in_out == SOCK_IN) { + BLI_insertlinkbefore(&sig->inputs, next_sock, iosock); + } + else if (in_out == SOCK_OUT) { + BLI_insertlinkbefore(&sig->outputs, next_sock, iosock); + } + BKE_ntree_update_tag_signature_changed(ntree, sig); + return iosock; +} + +bNodeSocket *nodeFunctionSignatureCopySocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const bNode *from_node, + const bNodeSocket *from_sock) +{ + return nodeFunctionSignatureCopySocketEx( + ntree, sig, from_node, from_sock, from_sock->idname, from_sock->name); +} + +bNodeSocket *nodeFunctionSignatureCopySocketEx(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const bNode *from_node, + const bNodeSocket *from_sock, + const char *idname, + const char *name) +{ + bNodeSocket *iosock = nodeFunctionSignatureAddSocket( + ntree, sig, static_cast(from_sock->in_out), idname, DATA_(name)); + if (iosock) { + if (iosock->typeinfo->interface_from_socket) { + iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); + } + } + return iosock; +} + +bNodeSocket *nodeFunctionSignatureCopyInsertSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + bNodeSocket *next_sock, + const bNode *from_node, + const bNodeSocket *from_sock) +{ + bNodeSocket *iosock = nodeFunctionSignatureInsertSocket( + ntree, + sig, + static_cast(from_sock->in_out), + from_sock->idname, + next_sock, + from_sock->name); + if (iosock) { + if (iosock->typeinfo->interface_from_socket) { + iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); + } + } + return iosock; +} + +void nodeFunctionSignatureRemoveSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + bNodeSocket *sock) +{ + /* this is fast, this way we don't need an in_out argument */ + BLI_remlink(&sig->inputs, sock); + BLI_remlink(&sig->outputs, sock); + + node_socket_interface_free(ntree, sock, true); + MEM_freeN(sock); + + BKE_ntree_update_tag_signature_changed(ntree, sig); +} + +void nodeFunctionSignatureClear(bNodeTree *ntree, + bNodeFunctionSignature *sig, + eNodeSocketInOut in_out) +{ + if (in_out == SOCK_IN) { + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { + node_socket_interface_free(ntree, sock, true); + } + BLI_freelistN(&sig->inputs); + } + else if (in_out == SOCK_OUT) { + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { + node_socket_interface_free(ntree, sock, true); + } + BLI_freelistN(&sig->outputs); + } + BKE_ntree_update_tag_signature_changed(ntree, sig); +} + +void nodeFunctionSignatureMoveSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + int from_index, + int to_index) +{ + ListBase *socket_list = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs; + + if (from_index == to_index) { + return; + } + if (from_index < 0 || to_index < 0) { + return; + } + + bNodeSocket *sock = (bNodeSocket *)BLI_findlink(socket_list, from_index); + if (to_index < from_index) { + bNodeSocket *nextsock = (bNodeSocket *)BLI_findlink(socket_list, to_index); + if (nextsock) { + BLI_remlink(socket_list, sock); + BLI_insertlinkbefore(socket_list, nextsock, sock); + } + } + else { + bNodeSocket *prevsock = (bNodeSocket *)BLI_findlink(socket_list, to_index); + if (prevsock) { + BLI_remlink(socket_list, sock); + BLI_insertlinkafter(socket_list, prevsock, sock); + } + } + BKE_ntree_update_tag_signature_changed(ntree, sig); +} static void ntree_init_data(ID *id) { diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index c4e25a8e97d..9d6970026fd 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -1181,6 +1181,15 @@ void BKE_ntree_update_tag_interface(bNodeTree *ntree) add_tree_tag(ntree, NTREE_CHANGED_INTERFACE); } +void BKE_ntree_update_tag_signature_changed(bNodeTree *ntree, bNodeFunctionSignature *sig) +{ + /* TODO what needs to happen here for general signatures? + * Flag in bNodeFunctionSignature itself (runtime data), + * then propagate that to parent tree in BKE_ntree_update_main_tree. + */ + add_tree_tag(ntree, NTREE_CHANGED_INTERFACE); +} + void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node) { add_node_tag(ntree, node, NTREE_CHANGED_PARENT); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 2fca7e86efe..d7f3be49bf0 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1626,6 +1626,14 @@ typedef struct NodeShaderMix { char _pad[3]; } NodeShaderMix; +typedef struct bNodeFunctionSignature { + ListBase inputs; + ListBase outputs; + /* Unique ID counter */ + int cur_index; + int _pad; +} bNodeFunctionSignature; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 852c43e5bda..40bca45ee42 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3280,6 +3280,194 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, DEG_relations_tag_update(bmain); } +/* ******** Node Function Signature ******** */ + +static int rna_NodeFunctionSignature_active_input_get(PointerRNA *ptr) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + int index = 0; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) { + if (socket->flag & SELECT) { + return index; + } + } + return -1; +} + +static void rna_NodeFunctionSignature_active_input_set(PointerRNA *ptr, int value) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + int index = 0; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) { + SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); + } +} + +static int rna_NodeFunctionSignature_active_output_get(PointerRNA *ptr) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + int index = 0; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) { + if (socket->flag & SELECT) { + return index; + } + } + return -1; +} + +static void rna_NodeFunctionSignature_active_output_set(PointerRNA *ptr, int value) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + int index = 0; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) { + SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); + } +} + +static bNodeSocket *rna_NodeFunctionSignature_inputs_new(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + const char *type, + const char *name) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return NULL; + } + + bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_IN, type, name); + + if (sock == NULL) { + BKE_report(reports, RPT_ERROR, "Unable to create socket"); + } + else { + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } + + return sock; +} + +static bNodeSocket *rna_NodeFunctionSignature_outputs_new(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + const char *type, + const char *name) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return NULL; + } + + bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_OUT, type, name); + + if (sock == NULL) { + BKE_report(reports, RPT_ERROR, "Unable to create socket"); + } + else { + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } + + return sock; +} + +static void rna_NodeFunctionSignature_socket_remove(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + bNodeSocket *sock) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return; + } + + if (BLI_findindex(&sig->inputs, sock) == -1 && BLI_findindex(&sig->outputs, sock) == -1) { + BKE_reportf(reports, RPT_ERROR, "Unable to locate socket '%s' in node", sock->identifier); + } + else { + nodeFunctionSignatureRemoveSocket(ntree, sig, sock); + + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } +} + +static void rna_NodeFunctionSignature_inputs_clear(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return; + } + + nodeFunctionSignatureClear(ntree, sig, SOCK_IN); + + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); +} + +static void rna_NodeFunctionSignature_outputs_clear(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return; + } + + nodeFunctionSignatureClear(ntree, sig, SOCK_OUT); + + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); +} + +static void rna_NodeFunctionSignature_inputs_move(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + int from_index, + int to_index) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return; + } + + nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_IN, from_index, to_index); + + BKE_ntree_update_tag_interface(ntree); + + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); +} + +static void rna_NodeFunctionSignature_outputs_move(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + int from_index, + int to_index) +{ + bNodeTree *ntree = (bNodeTree *)id; + if (!rna_NodeTree_check(ntree, reports)) { + return; + } + + nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_OUT, from_index, to_index); + + BKE_ntree_update_tag_interface(ntree); + + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); +} + /* ******** Node Types ******** */ static void rna_NodeInternalSocketTemplate_name_get(PointerRNA *ptr, char *value) @@ -5260,6 +5448,100 @@ static void def_fn_bind(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNodeBind_update"); } +static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) +{ + StructRNA *srna; + PropertyRNA *parm; + FunctionRNA *func; + const char *structtype = (in_out == SOCK_IN ? "NodeFunctionSignatureInputs" : "NodeFunctionSignatureOutputs"); + const char *uiname = (in_out == SOCK_IN ? "Node Function Signature Inputs" : "Node Function Signature Outputs"); + const char *newfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_new" : + "rna_NodeFunctionSignature_outputs_new"); + const char *removefunc = "rna_NodeFunctionSignature_socket_remove"; + const char *clearfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_clear" : + "rna_NodeFunctionSignature_outputs_clear"); + const char *movefunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_move" : + "rna_NodeFunctionSignature_outputs_move"); + + RNA_def_property_srna(cprop, structtype); + srna = RNA_def_struct(brna, structtype, NULL); + RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); + RNA_def_struct_ui_text(srna, uiname, "Collection of Node Socket Declarations"); + + func = RNA_def_function(srna, "new", newfunc); + RNA_def_function_ui_description(func, "Add a socket to this signature"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return value */ + parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", removefunc); + RNA_def_function_ui_description(func, "Remove a socket from this signature"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "clear", clearfunc); + RNA_def_function_ui_description(func, "Remove all sockets from this signature"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + + func = RNA_def_function(srna, "move", movefunc); + RNA_def_function_ui_description(func, "Move a socket to another position"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_int( + func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int( + func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); +} + +static void rna_def_node_function_signature(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "NodeFunctionSignature", NULL); + RNA_def_struct_ui_text(srna, "Node Function Signature", "Declaration of inputs and outputs of a node function"); + RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); + + prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); + RNA_def_property_struct_type(prop, "NodeSocketInterface"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Inputs", "Function inputs"); + rna_def_node_function_signature_api(brna, prop, SOCK_IN); + + prop = RNA_def_property(srna, "active_input", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, + "rna_NodeFunctionSignature_active_input_get", + "rna_NodeFunctionSignature_active_input_set", + NULL); + RNA_def_property_ui_text(prop, "Active Input", "Index of the active input"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); + RNA_def_property_struct_type(prop, "NodeSocketInterface"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Outputs", "Function outputs"); + rna_def_node_function_signature_api(brna, prop, SOCK_OUT); + + prop = RNA_def_property(srna, "active_output", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, + "rna_NodeFunctionSignature_active_output_get", + "rna_NodeFunctionSignature_active_output_set", + NULL); + RNA_def_property_ui_text(prop, "Active Output", "Index of the active output"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_NODE, NULL); +} + static void def_fn_evaluate(StructRNA *srna) { } @@ -13170,6 +13452,7 @@ void RNA_def_nodetree(BlenderRNA *brna) rna_def_node_socket(brna); rna_def_node_socket_interface(brna); + rna_def_node_function_signature(brna); rna_def_node(brna); rna_def_node_link(brna); -- 2.30.2 From 59846f395574612548cbf23c2a43c2143c5a0e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 11 Apr 2023 09:20:43 +0200 Subject: [PATCH 07/33] Use a signature in the Evaluate node. --- source/blender/makesdna/DNA_node_types.h | 5 +++++ source/blender/makesrna/intern/rna_nodetree.c | 8 ++++++++ source/blender/nodes/function/nodes/node_fn_evaluate.cc | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d7f3be49bf0..1f2bf057142 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1634,6 +1634,11 @@ typedef struct bNodeFunctionSignature { int _pad; } bNodeFunctionSignature; +typedef struct NodeFunctionEvaluate { + /* Expected signature of the function. */ + bNodeFunctionSignature signature; +} NodeFunctionEvaluate; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 40bca45ee42..4e9c8c76128 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5544,6 +5544,14 @@ static void rna_def_node_function_signature(BlenderRNA *brna) static void def_fn_evaluate(StructRNA *srna) { + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeFunctionEvaluate", "storage"); + + prop = RNA_def_property(srna, "signature", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "signature"); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Signature", "Expected signature of the function"); } /* -- Shader Nodes ---------------------------------------------------------- */ diff --git a/source/blender/nodes/function/nodes/node_fn_evaluate.cc b/source/blender/nodes/function/nodes/node_fn_evaluate.cc index 541eaef5c47..c216b2d6ef9 100644 --- a/source/blender/nodes/function/nodes/node_fn_evaluate.cc +++ b/source/blender/nodes/function/nodes/node_fn_evaluate.cc @@ -18,6 +18,12 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input(N_("Function")); } +static void node_init(bNodeTree * /*tree*/, bNode *node) +{ + NodeFunctionEvaluate *data = MEM_cnew(__func__); + node->storage = data; +} + static void node_update(bNodeTree *ntree, bNode *node) { } @@ -37,6 +43,9 @@ void register_node_type_fn_evaluate() fn_node_type_base(&ntype, FN_NODE_EVALUATE, "Evaluate", NODE_CLASS_GROUP); ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; + ntype.initfunc = file_ns::node_init; ntype.updatefunc = file_ns::node_update; + node_type_storage( + &ntype, "NodeFunctionEvaluate", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); } -- 2.30.2 From d9c8c25e7e809a38c215c5d46c995cc41cbe210b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 11 Apr 2023 22:32:29 +0200 Subject: [PATCH 08/33] Read/Write functions for bNodeFunctionSignature in node trees. --- source/blender/blenkernel/intern/node.cc | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 490f8658170..a0a1da8005b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -703,6 +703,17 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) write_node_socket_default_value(writer, sock); } +static void write_node_function_signature(BlendWriter *writer, bNodeFunctionSignature *sig) +{ + BLO_write_struct(writer, bNodeFunctionSignature, sig); + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { + write_node_socket_interface(writer, sock); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { + write_node_socket_interface(writer, sock); + } +} + void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) { BKE_id_blend_write(writer, &ntree->id); @@ -786,6 +797,11 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); } + else if (node->type == FN_NODE_EVALUATE) { + NodeFunctionEvaluate *storage = (NodeFunctionEvaluate *)node->storage; + BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); + write_node_function_signature(writer, &storage->signature); + } else if (node->typeinfo != &NodeTypeUndefined) { BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); } @@ -851,6 +867,19 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) sock->runtime = MEM_new(__func__); } +static void direct_link_node_function_signature(BlendDataReader *reader, + bNodeFunctionSignature *sig) +{ + BLO_read_list(reader, &sig->inputs); + BLO_read_list(reader, &sig->outputs); + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { + direct_link_node_socket(reader, sock); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { + direct_link_node_socket(reader, sock); + } +} + void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) { /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs @@ -984,6 +1013,11 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &storage->string); break; } + case FN_NODE_EVALUATE: { + NodeFunctionEvaluate *storage = (NodeFunctionEvaluate *)node->storage; + direct_link_node_function_signature(reader, &storage->signature); + break; + } default: break; } -- 2.30.2 From 1724af3161c4055d75a5f7d7ebe5199de3d9975d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 11 Apr 2023 22:33:39 +0200 Subject: [PATCH 09/33] Dynamic declaration for the Evaluate node based on its signature. --- source/blender/nodes/NOD_common.h | 6 ++++++ .../nodes/function/nodes/node_fn_bind.cc | 4 +--- .../nodes/function/nodes/node_fn_evaluate.cc | 21 ++++++++++++++++--- source/blender/nodes/intern/node_common.cc | 21 +++++++++++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index 8c1febcad93..94e38dc4a08 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -29,10 +29,16 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char namespace blender::nodes { +struct FieldInferencingInterface; + void node_group_declare_dynamic(const bNodeTree &node_tree, const bNode &node, NodeDeclaration &r_declaration); +void node_function_signature_declare(const bNodeFunctionSignature &sig, + const FieldInferencingInterface *field_interface, + NodeDeclaration &r_declaration); + } // namespace blender::nodes #endif diff --git a/source/blender/nodes/function/nodes/node_fn_bind.cc b/source/blender/nodes/function/nodes/node_fn_bind.cc index fc3446f59b7..e326fca0c53 100644 --- a/source/blender/nodes/function/nodes/node_fn_bind.cc +++ b/source/blender/nodes/function/nodes/node_fn_bind.cc @@ -59,10 +59,8 @@ void register_node_type_fn_bind() static bNodeType ntype; fn_node_type_base(&ntype, FN_NODE_BIND, "Bind", NODE_CLASS_GROUP); - ntype.poll_instance = node_group_poll_instance; - - node_type_size(&ntype, 140, 60, 400); ntype.declare_dynamic = file_ns::node_declare; + ntype.poll_instance = node_group_poll_instance; ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_evaluate.cc b/source/blender/nodes/function/nodes/node_fn_evaluate.cc index c216b2d6ef9..b6727d82455 100644 --- a/source/blender/nodes/function/nodes/node_fn_evaluate.cc +++ b/source/blender/nodes/function/nodes/node_fn_evaluate.cc @@ -9,13 +9,28 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_common.h" #include "node_function_util.hh" namespace blender::nodes::node_fn_evaluate_cc { -static void node_declare(NodeDeclarationBuilder &b) +NODE_STORAGE_FUNCS(NodeFunctionEvaluate) + +static void node_declare(const bNodeTree &node_tree, + const bNode &node, + NodeDeclaration &r_declaration) { - b.add_input(N_("Function")); + /* May be called before storage is initialized. */ + if (node.storage == nullptr) { + return; + } + const NodeFunctionEvaluate &storage = node_storage(node); + + NodeDeclarationBuilder builder(r_declaration); + builder.add_input(N_("Function")); + + /* TODO define FieldInferencingInterface for this node */ + node_function_signature_declare(storage.signature, nullptr, r_declaration); } static void node_init(bNodeTree * /*tree*/, bNode *node) @@ -41,7 +56,7 @@ void register_node_type_fn_evaluate() static bNodeType ntype; fn_node_type_base(&ntype, FN_NODE_EVALUATE, "Evaluate", NODE_CLASS_GROUP); - ntype.declare = file_ns::node_declare; + ntype.declare_dynamic = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; ntype.initfunc = file_ns::node_init; ntype.updatefunc = file_ns::node_update; diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index aa19609d13f..3b45664a7f1 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -291,6 +291,27 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/, } } +void node_function_signature_declare(const bNodeFunctionSignature &sig, + const FieldInferencingInterface *field_interface, + NodeDeclaration &r_declaration) +{ + int socket_i; + LISTBASE_FOREACH_INDEX (const bNodeSocket *, input, &sig.inputs, socket_i) { + SocketDeclarationPtr decl = declaration_for_interface_socket(*input); + if (field_interface) { + decl->input_field_type = field_interface->inputs[socket_i]; + } + r_declaration.inputs.append(std::move(decl)); + } + LISTBASE_FOREACH_INDEX (const bNodeSocket *, output, &sig.outputs, socket_i) { + SocketDeclarationPtr decl = declaration_for_interface_socket(*output); + if (field_interface) { + decl->output_field_dependency = field_interface->outputs[socket_i]; + } + r_declaration.outputs.append(std::move(decl)); + } +} + } // namespace blender::nodes /** \} */ -- 2.30.2 From b7b86d0811fd0bcb94d42a4b5ceeb49910993410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Wed, 12 Apr 2023 09:44:10 +0200 Subject: [PATCH 10/33] Struct for signature parameters, to avoid complexity in bNodeSocket. --- source/blender/makesdna/DNA_node_types.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 1f2bf057142..be7c6cdf4e3 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1626,12 +1626,19 @@ typedef struct NodeShaderMix { char _pad[3]; } NodeShaderMix; +/* Input or output in a bNodeFunctionSignature. */ +typedef struct bNodeFunctionParameter { + char name[64]; /* MAX_NAME */ + char socket_type[64]; /* MAX_NAME */ +} bNodeFunctionParameter; + typedef struct bNodeFunctionSignature { - ListBase inputs; - ListBase outputs; - /* Unique ID counter */ - int cur_index; - int _pad; + bNodeFunctionParameter *inputs; + bNodeFunctionParameter *outputs; + int inputs_num; + int outputs_num; + int active_input; + int active_output; } bNodeFunctionSignature; typedef struct NodeFunctionEvaluate { -- 2.30.2 From ae68c6d0e82a025b92ce60d499bb2d7fda5118b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 13 Apr 2023 08:47:04 +0200 Subject: [PATCH 11/33] Adapt the signature API functions to the new parameter struct. --- source/blender/blenkernel/BKE_node.h | 64 +++++++------ source/blender/blenkernel/intern/node.cc | 95 +++++++++---------- source/blender/makesdna/DNA_node_types.h | 2 +- source/blender/makesrna/intern/rna_nodetree.c | 42 -------- source/blender/modifiers/intern/MOD_nodes.cc | 2 +- source/blender/nodes/intern/node_common.cc | 67 ++++++++++++- 6 files changed, 142 insertions(+), 130 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 2d2c578f449..056341cc607 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -228,38 +228,42 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, /** \name Node Function Signature * \{ */ -struct bNodeSocket *nodeFunctionSignatureFindSocket(struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const char *identifier); -struct bNodeSocket *nodeFunctionSignatureAddSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const char *idname, - const char *name); -struct bNodeSocket *nodeFunctionSignatureInsertSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const char *idname, - struct bNodeSocket *next_sock, - const char *name); -struct bNodeSocket *nodeFunctionSignatureCopySocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - const struct bNode *from_node, - const struct bNodeSocket *from_sock); -struct bNodeSocket *nodeFunctionSignatureCopySocketEx(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - const struct bNode *from_node, - const struct bNodeSocket *from_sock, - const char *idname, - const char *name); -struct bNodeSocket *nodeFunctionSignatureCopyInsertSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - struct bNodeSocket *next_sock, - const struct bNode *from_node, - const struct bNodeSocket *from_sock); +struct bNodeFunctionParameter *nodeFunctionSignatureFindSocket(struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const char *identifier); +struct bNodeFunctionParameter *nodeFunctionSignatureAddSocket(struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const char *name, + eNodeSocketDatatype socket_type); +struct bNodeFunctionParameter *nodeFunctionSignatureInsertSocket( + struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + eNodeSocketInOut in_out, + const struct bNodeFunctionParameter *next_sock, + const char *name, + eNodeSocketDatatype socket_type); +struct bNodeFunctionParameter *nodeFunctionSignatureCopySocket( + struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + const struct bNode *from_node, + const struct bNodeSocket *from_sock); +struct bNodeFunctionParameter *nodeFunctionSignatureCopySocketEx( + struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + const struct bNode *from_node, + const struct bNodeSocket *from_sock, + const char *idname, + const char *name); +struct bNodeFunctionParameter *nodeFunctionSignatureCopyInsertSocket( + struct bNodeTree *ntree, + struct bNodeFunctionSignature *sig, + struct bNodeSocket *next_sock, + const struct bNode *from_node, + const struct bNodeSocket *from_sock); void nodeFunctionSignatureRemoveSocket(struct bNodeTree *ntree, struct bNodeFunctionSignature *sig, - struct bNodeSocket *sock); + struct bNodeFunctionParameter *param); void nodeFunctionSignatureClear(struct bNodeTree *ntree, struct bNodeFunctionSignature *sig, eNodeSocketInOut in_out); diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a0a1da8005b..90c61094b0c 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -128,64 +128,52 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, /* ************ NODE FUNCTION SIGNATURE *************** */ -static bNodeSocket *make_signature_socket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *idname, - const char *name) +static Span nodeFunctionSignatureGetParams( + const bNodeFunctionSignature *sig, const eNodeSocketInOut in_out) { - bNodeSocketType *stype = nodeSocketTypeFind(idname); - if (stype == nullptr) { - return nullptr; - } - - bNodeSocket *sock = MEM_cnew("socket template"); - sock->runtime = MEM_new(__func__); - BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); - sock->in_out = in_out; - sock->type = SOCK_CUSTOM; /* int type undefined by default */ - node_socket_set_typeinfo(ntree, sock, stype); - - /* assign new unique index */ - const int own_index = sig->cur_index++; - /* use the own_index as socket identifier */ if (in_out == SOCK_IN) { - BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index); + return Span(sig->inputs, sig->inputs_num); } else { - BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index); + return Span(sig->outputs, sig->outputs_num); } - - sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF); - - BLI_strncpy(sock->name, name, NODE_MAXSTR); - sock->storage = nullptr; - sock->flag |= SOCK_COLLAPSED; - - return sock; } -bNodeSocket *nodeFunctionSignatureFindSocket(bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *identifier) +static MutableSpan nodeFunctionSignatureGetParams( + bNodeFunctionSignature *sig, const eNodeSocketInOut in_out) { - ListBase *sockets = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs; - LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { - if (STREQ(iosock->identifier, identifier)) { - return iosock; + if (in_out == SOCK_IN) { + return MutableSpan(sig->inputs, sig->inputs_num); + } + else { + return MutableSpan(sig->outputs, sig->outputs_num); + } +} + +bNodeFunctionParameter *nodeFunctionSignatureFindSocket(bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *name) +{ + for (bNodeFunctionParameter ¶m : nodeFunctionSignatureGetParams(sig, in_out)) { + if (STREQ(param.name, name)) { + return ¶m; } } return nullptr; } -bNodeSocket *nodeFunctionSignatureAddSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *idname, - const char *name) +bNodeFunctionParameter *nodeFunctionSignatureAddSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const char *name, + eNodeSocketDatatype socket_type) { - bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name); + bNodeFunctionParameter param; + BLI_strncpy(param.name, name, sizeof(param.name)); + param.socket_type = socket_type; + if (in_out == SOCK_IN) { + BLI_addtail(&sig->inputs, iosock); } else if (in_out == SOCK_OUT) { @@ -195,16 +183,21 @@ bNodeSocket *nodeFunctionSignatureAddSocket(bNodeTree *ntree, return iosock; } -bNodeSocket *nodeFunctionSignatureInsertSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *idname, - bNodeSocket *next_sock, - const char *name) +bNodeFunctionParameter *nodeFunctionSignatureInsertSocket(bNodeTree *ntree, + bNodeFunctionSignature *sig, + const eNodeSocketInOut in_out, + const bNodeFunctionParameter *next_sock, + const char *name, + eNodeSocketDatatype socket_type) { - bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name); + bNodeFunctionParameter param; + BLI_strncpy(param.name, name, sizeof(param.name)); + param.socket_type = socket_type; + if (in_out == SOCK_IN) { - BLI_insertlinkbefore(&sig->inputs, next_sock, iosock); + bNodeFunctionParameter *old_params = sig->inputs; + sig->inputs = MEM_cnew_array(sig->inputs_num + 1, __func__); + } else if (in_out == SOCK_OUT) { BLI_insertlinkbefore(&sig->outputs, next_sock, iosock); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index be7c6cdf4e3..d8508cfec5f 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1629,7 +1629,7 @@ typedef struct NodeShaderMix { /* Input or output in a bNodeFunctionSignature. */ typedef struct bNodeFunctionParameter { char name[64]; /* MAX_NAME */ - char socket_type[64]; /* MAX_NAME */ + int socket_type; } bNodeFunctionParameter; typedef struct bNodeFunctionSignature { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 4e9c8c76128..6199180dac7 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3282,48 +3282,6 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, /* ******** Node Function Signature ******** */ -static int rna_NodeFunctionSignature_active_input_get(PointerRNA *ptr) -{ - bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; - int index = 0; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) { - if (socket->flag & SELECT) { - return index; - } - } - return -1; -} - -static void rna_NodeFunctionSignature_active_input_set(PointerRNA *ptr, int value) -{ - bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; - int index = 0; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) { - SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); - } -} - -static int rna_NodeFunctionSignature_active_output_get(PointerRNA *ptr) -{ - bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; - int index = 0; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) { - if (socket->flag & SELECT) { - return index; - } - } - return -1; -} - -static void rna_NodeFunctionSignature_active_output_set(PointerRNA *ptr, int value) -{ - bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; - int index = 0; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) { - SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT); - } -} - static bNodeSocket *rna_NodeFunctionSignature_inputs_new(ID *id, bNodeFunctionSignature *sig, Main *bmain, diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 655e1d826ba..67e09c89bd7 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -625,7 +625,7 @@ static void update_input_properties_from_node_tree(const bNodeTree &tree, if (new_prop == nullptr) { /* Out of the set of supported input sockets, only * geometry sockets aren't added to the modifier. */ - BLI_assert(socket.type == SOCK_GEOMETRY); + BLI_assert(ELEM(socket.type, SOCK_GEOMETRY, SOCK_FUNCTION)); continue; } diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index 3b45664a7f1..2a0a6d75a19 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -291,20 +291,77 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/, } } +SocketDeclarationPtr declaration_for_signature_parameter(const bNodeFunctionParameter ¶m, + eNodeSocketInOut in_out) +{ + SocketDeclarationPtr dst; + switch (param.socket_type) { + case SOCK_FLOAT: + dst = std::make_unique(); + break; + case SOCK_VECTOR: + dst = std::make_unique(); + break; + case SOCK_RGBA: + dst = std::make_unique(); + break; + case SOCK_SHADER: + dst = std::make_unique(); + break; + case SOCK_BOOLEAN: + dst = std::make_unique(); + break; + case SOCK_INT: + dst = std::make_unique(); + break; + case SOCK_STRING: + dst = std::make_unique(); + break; + case SOCK_OBJECT: + dst = std::make_unique(); + break; + case SOCK_IMAGE: + dst = std::make_unique(); + break; + case SOCK_GEOMETRY: + dst = std::make_unique(); + break; + case SOCK_COLLECTION: + dst = std::make_unique(); + break; + case SOCK_TEXTURE: + dst = std::make_unique(); + break; + case SOCK_MATERIAL: + dst = std::make_unique(); + break; + case SOCK_FUNCTION: + dst = std::make_unique(); + break; + case SOCK_CUSTOM: + dst = std::make_unique(); + break; + } + dst->name = param.name; + dst->in_out = in_out; + dst->hide_value = true; + dst->compact = false; + return dst; +} + void node_function_signature_declare(const bNodeFunctionSignature &sig, const FieldInferencingInterface *field_interface, NodeDeclaration &r_declaration) { - int socket_i; - LISTBASE_FOREACH_INDEX (const bNodeSocket *, input, &sig.inputs, socket_i) { - SocketDeclarationPtr decl = declaration_for_interface_socket(*input); + for (const int socket_i : IndexRange(sig.inputs_num)) { + SocketDeclarationPtr decl = declaration_for_signature_parameter(sig.inputs[socket_i], SOCK_IN); if (field_interface) { decl->input_field_type = field_interface->inputs[socket_i]; } r_declaration.inputs.append(std::move(decl)); } - LISTBASE_FOREACH_INDEX (const bNodeSocket *, output, &sig.outputs, socket_i) { - SocketDeclarationPtr decl = declaration_for_interface_socket(*output); + for (const int socket_i : IndexRange(sig.outputs_num)) { + SocketDeclarationPtr decl = declaration_for_signature_parameter(sig.outputs[socket_i], SOCK_OUT); if (field_interface) { decl->output_field_dependency = field_interface->outputs[socket_i]; } -- 2.30.2 From d6fa5d6b61b7b22f5121e15c8c2fe8638af11fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 14 Apr 2023 18:06:18 +0200 Subject: [PATCH 12/33] stuff --- source/blender/blenkernel/BKE_node.h | 84 ++--- .../blender/blenkernel/BKE_node_tree_update.h | 1 + source/blender/blenkernel/intern/node.cc | 301 +++++++++--------- source/blender/makesdna/DNA_node_types.h | 4 + 4 files changed, 207 insertions(+), 183 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 056341cc607..4d7e8aa9ba8 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -228,50 +228,52 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, /** \name Node Function Signature * \{ */ -struct bNodeFunctionParameter *nodeFunctionSignatureFindSocket(struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const char *identifier); -struct bNodeFunctionParameter *nodeFunctionSignatureAddSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const char *name, - eNodeSocketDatatype socket_type); -struct bNodeFunctionParameter *nodeFunctionSignatureInsertSocket( - struct bNodeTree *ntree, +enum eNodeFunctionParameterType { + NODE_FUNC_PARAM_IN, + NODE_FUNC_PARAM_OUT, + }; + +/** Set a unique parameter name. + * @return True if the unique name differs from the original name. + */ +bool nodeFunctionParameterSetUniqueName(struct bNodeFunctionSignature *sig, + struct bNodeFunctionParameter *param, + const char *name, + const char *defname); +/** Find the node owning this parameter. */ +struct bNode *nodeFunctionParameterFindNode(struct bNodeTree *ntree, + const struct bNodeFunctionParameter *param); + +/** Find the node owning this signature. */ +struct bNode *nodeFunctionSignatureFindNode(struct bNodeTree *ntree, + const struct bNodeFunctionSignature *sig); +bool nodeFunctionSignatureContainsParameter(const struct bNodeFunctionSignature *sig, + const struct bNodeFunctionParameter *param); +struct bNodeFunctionParameter *nodeFunctionSignatureGetActiveParameter( + struct bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type); +void nodeFunctionSignatureSetActiveParameter(struct bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + struct bNodeFunctionParameter *param); +struct bNodeFunctionParameter *nodeFunctionSignatureFindParameterByName( + struct bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, const char *name); +struct bNodeFunctionParameter *nodeFunctionSignatureAddParameter( struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - const struct bNodeFunctionParameter *next_sock, - const char *name, - eNodeSocketDatatype socket_type); -struct bNodeFunctionParameter *nodeFunctionSignatureCopySocket( - struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - const struct bNode *from_node, - const struct bNodeSocket *from_sock); -struct bNodeFunctionParameter *nodeFunctionSignatureCopySocketEx( - struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - const struct bNode *from_node, - const struct bNodeSocket *from_sock, - const char *idname, + eNodeFunctionParameterType param_type, + short socket_type, const char *name); -struct bNodeFunctionParameter *nodeFunctionSignatureCopyInsertSocket( - struct bNodeTree *ntree, +struct bNodeFunctionParameter *nodeFunctionSignatureInsertParameter( struct bNodeFunctionSignature *sig, - struct bNodeSocket *next_sock, - const struct bNode *from_node, - const struct bNodeSocket *from_sock); -void nodeFunctionSignatureRemoveSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - struct bNodeFunctionParameter *param); -void nodeFunctionSignatureClear(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out); -void nodeFunctionSignatureMoveSocket(struct bNodeTree *ntree, - struct bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - int from_index, - int to_index); + eNodeFunctionParameterType param_type, + short socket_type, + const char *name, + int index); +void nodeFunctionSignatureRemoveParameter(struct bNodeFunctionSignature *sig, + struct bNodeFunctionParameter *item); +void nodeFunctionSignatureClearParameters(struct bNodeFunctionSignature *sig); +void nodeFunctionSignatureMoveParameter(struct bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + int from_index, + int to_index); /** \} */ diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h index 9cec5733f2d..5f780900bc7 100644 --- a/source/blender/blenkernel/BKE_node_tree_update.h +++ b/source/blender/blenkernel/BKE_node_tree_update.h @@ -10,6 +10,7 @@ struct ID; struct ImageUser; struct Main; struct bNode; +struct bNodeFunctionSignature; struct bNodeLink; struct bNodeSocket; struct bNodeTree; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 90c61094b0c..b5290cab92a 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -128,10 +128,12 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, /* ************ NODE FUNCTION SIGNATURE *************** */ +namespace blender::nodes { + static Span nodeFunctionSignatureGetParams( - const bNodeFunctionSignature *sig, const eNodeSocketInOut in_out) + const bNodeFunctionSignature *sig, const eNodeFunctionParameterType param_type) { - if (in_out == SOCK_IN) { + if (param_type == NODE_FUNC_PARAM_IN) { return Span(sig->inputs, sig->inputs_num); } else { @@ -140,9 +142,9 @@ static Span nodeFunctionSignatureGetParams( } static MutableSpan nodeFunctionSignatureGetParams( - bNodeFunctionSignature *sig, const eNodeSocketInOut in_out) + bNodeFunctionSignature *sig, const eNodeFunctionParameterType param_type) { - if (in_out == SOCK_IN) { + if (param_type == NODE_FUNC_PARAM_IN) { return MutableSpan(sig->inputs, sig->inputs_num); } else { @@ -150,173 +152,188 @@ static MutableSpan nodeFunctionSignatureGetParams( } } -bNodeFunctionParameter *nodeFunctionSignatureFindSocket(bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *name) +struct NodeFunctionSignatureUniqueNameArgs { + Span params_span; + const bNodeFunctionParameter *param; +}; + +static bool function_signature_unique_name_check(void *arg, const char *name) { - for (bNodeFunctionParameter ¶m : nodeFunctionSignatureGetParams(sig, in_out)) { - if (STREQ(param.name, name)) { - return ¶m; + const NodeFunctionSignatureUniqueNameArgs &args = + *static_cast(arg); + for (const bNodeFunctionParameter ¶m : args.params_span) { + if (¶m != args.param) { + if (STREQ(param.name, name)) { + return true; + } + } + } + return false; +} + +} // namespace blender::nodes + +bNode *nodeFunctionParameterFindNode(bNodeTree *ntree, const bNodeFunctionParameter *param) +{ + /** TODO */ + return nullptr; +} + +bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig, + bNodeFunctionParameter *param, + const char *name, + const char *defname) +{ + char unique_name[MAX_NAME + 4]; + BLI_strncpy(unique_name, name, sizeof(unique_name)); + + blender::nodes::SimulationItemsUniqueNameArgs args{sim, item}; + const bool name_changed = BLI_uniquename_cb(blender::nodes::simulation_items_unique_name_check, + &args, + defname, + '.', + unique_name, + ARRAY_SIZE(unique_name)); + item->name = BLI_strdup(unique_name); + return name_changed; +} + +bNode *nodeFunctionSignatureFindNode(bNodeTree *ntree, const bNodeFunctionSignature *sig) +{ + /** TODO */ + return nullptr; +} + +bool nodeFunctionSignatureContainsParameter(const bNodeFunctionSignature *sig, + const bNodeFunctionParameter *param) +{ + const int index = item - sim->items; + return index >= 0 && index < sim->items_num; +} + +bNodeFunctionParameter *nodeFunctionSignatureGetActiveParameter( + bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type) +{ + if (sim->active_index >= 0 && sim->active_index < sim->items_num) { + return &sim->items[sim->active_index]; + } + return nullptr; +} + +void nodeFunctionSignatureSetActiveParameter(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + bNodeFunctionParameter *param) +{ + const int index = item - sim->items; + if (index >= 0 && index < sim->items_num) { + sim->active_index = index; + } +} + +bNodeFunctionParameter *nodeFunctionSignatureFindParameterByName( + bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, const char *name) +{ + for (const int i : blender::IndexRange(sim->items_num)) { + if (STREQ(sim->items[i].name, name)) { + return &sim->items[i]; } } return nullptr; } -bNodeFunctionParameter *nodeFunctionSignatureAddSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const char *name, - eNodeSocketDatatype socket_type) +bNodeFunctionParameter *nodeFunctionSignatureAddParameter(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + short socket_type, + const char *name) { - bNodeFunctionParameter param; - BLI_strncpy(param.name, name, sizeof(param.name)); - param.socket_type = socket_type; - - if (in_out == SOCK_IN) { - - BLI_addtail(&sig->inputs, iosock); - } - else if (in_out == SOCK_OUT) { - BLI_addtail(&sig->outputs, iosock); - } - BKE_ntree_update_tag_signature_changed(ntree, sig); - return iosock; + return NOD_geometry_simulation_output_insert_item(sim, socket_type, name, sim->items_num); } -bNodeFunctionParameter *nodeFunctionSignatureInsertSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const eNodeSocketInOut in_out, - const bNodeFunctionParameter *next_sock, - const char *name, - eNodeSocketDatatype socket_type) +bNodeFunctionParameter *nodeFunctionSignatureInsertParameter(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + short socket_type, + const char *name, + int index) { - bNodeFunctionParameter param; - BLI_strncpy(param.name, name, sizeof(param.name)); - param.socket_type = socket_type; + NodeSimulationItem *old_items = sim->items; + sim->items = MEM_cnew_array(sim->items_num + 1, __func__); + for (const int i : blender::IndexRange(0, index)) { + sim->items[i] = old_items[i]; + } + for (const int i : blender::IndexRange(index, sim->items_num - index)) { + sim->items[i + 1] = old_items[i]; + } - if (in_out == SOCK_IN) { - bNodeFunctionParameter *old_params = sig->inputs; - sig->inputs = MEM_cnew_array(sig->inputs_num + 1, __func__); - - } - else if (in_out == SOCK_OUT) { - BLI_insertlinkbefore(&sig->outputs, next_sock, iosock); - } - BKE_ntree_update_tag_signature_changed(ntree, sig); - return iosock; + const char *defname = nodeStaticSocketLabel(socket_type, 0); + NodeSimulationItem &added_item = sim->items[index]; + added_item.identifier = sim->next_identifier++; + NOD_geometry_simulation_output_item_set_unique_name(sim, &added_item, name, defname); + added_item.socket_type = socket_type; + + sim->items_num++; + MEM_SAFE_FREE(old_items); + + return &added_item; } -bNodeSocket *nodeFunctionSignatureCopySocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const bNode *from_node, - const bNodeSocket *from_sock) +void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, + bNodeFunctionParameter *item) { - return nodeFunctionSignatureCopySocketEx( - ntree, sig, from_node, from_sock, from_sock->idname, from_sock->name); -} - -bNodeSocket *nodeFunctionSignatureCopySocketEx(bNodeTree *ntree, - bNodeFunctionSignature *sig, - const bNode *from_node, - const bNodeSocket *from_sock, - const char *idname, - const char *name) -{ - bNodeSocket *iosock = nodeFunctionSignatureAddSocket( - ntree, sig, static_cast(from_sock->in_out), idname, DATA_(name)); - if (iosock) { - if (iosock->typeinfo->interface_from_socket) { - iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); - } + const int index = item - sim->items; + if (index < 0 || index >= sim->items_num) { + return; } - return iosock; -} -bNodeSocket *nodeFunctionSignatureCopyInsertSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - bNodeSocket *next_sock, - const bNode *from_node, - const bNodeSocket *from_sock) -{ - bNodeSocket *iosock = nodeFunctionSignatureInsertSocket( - ntree, - sig, - static_cast(from_sock->in_out), - from_sock->idname, - next_sock, - from_sock->name); - if (iosock) { - if (iosock->typeinfo->interface_from_socket) { - iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); - } + NodeSimulationItem *old_items = sim->items; + sim->items = MEM_cnew_array(sim->items_num - 1, __func__); + for (const int i : blender::IndexRange(0, index)) { + sim->items[i] = old_items[i]; } - return iosock; -} - -void nodeFunctionSignatureRemoveSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - bNodeSocket *sock) -{ - /* this is fast, this way we don't need an in_out argument */ - BLI_remlink(&sig->inputs, sock); - BLI_remlink(&sig->outputs, sock); - - node_socket_interface_free(ntree, sock, true); - MEM_freeN(sock); - - BKE_ntree_update_tag_signature_changed(ntree, sig); -} - -void nodeFunctionSignatureClear(bNodeTree *ntree, - bNodeFunctionSignature *sig, - eNodeSocketInOut in_out) -{ - if (in_out == SOCK_IN) { - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { - node_socket_interface_free(ntree, sock, true); - } - BLI_freelistN(&sig->inputs); + for (const int i : blender::IndexRange(index, sim->items_num - index).drop_front(1)) { + sim->items[i - 1] = old_items[i]; } - else if (in_out == SOCK_OUT) { - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { - node_socket_interface_free(ntree, sock, true); - } - BLI_freelistN(&sig->outputs); - } - BKE_ntree_update_tag_signature_changed(ntree, sig); + + MEM_SAFE_FREE(old_items[index].name); + + sim->items_num--; + MEM_SAFE_FREE(old_items); } -void nodeFunctionSignatureMoveSocket(bNodeTree *ntree, - bNodeFunctionSignature *sig, - eNodeSocketInOut in_out, - int from_index, - int to_index) +void nodeFunctionSignatureClearParameters(bNodeFunctionSignature *sig) { - ListBase *socket_list = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs; + for (NodeSimulationItem &item : blender::MutableSpan(sim->items, sim->items_num)) { + MEM_SAFE_FREE(item.name); + } + MEM_SAFE_FREE(sim->items); + sim->items = nullptr; + sim->items_num = 0; +} + +void nodeFunctionSignatureMoveParameter(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + int from_index, + int to_index) +{ + BLI_assert(from_index >= 0 && from_index < sim->items_num); + BLI_assert(to_index >= 0 && to_index < sim->items_num); if (from_index == to_index) { return; } - if (from_index < 0 || to_index < 0) { - return; - } - - bNodeSocket *sock = (bNodeSocket *)BLI_findlink(socket_list, from_index); - if (to_index < from_index) { - bNodeSocket *nextsock = (bNodeSocket *)BLI_findlink(socket_list, to_index); - if (nextsock) { - BLI_remlink(socket_list, sock); - BLI_insertlinkbefore(socket_list, nextsock, sock); + else if (from_index < to_index) { + const NodeSimulationItem tmp = sim->items[from_index]; + for (int i = from_index; i < to_index; ++i) { + sim->items[i] = sim->items[i + 1]; } + sim->items[to_index] = tmp; } - else { - bNodeSocket *prevsock = (bNodeSocket *)BLI_findlink(socket_list, to_index); - if (prevsock) { - BLI_remlink(socket_list, sock); - BLI_insertlinkafter(socket_list, prevsock, sock); + else /* from_index > to_index */ { + const NodeSimulationItem tmp = sim->items[from_index]; + for (int i = from_index; i > to_index; --i) { + sim->items[i] = sim->items[i - 1]; } + sim->items[to_index] = tmp; } - BKE_ntree_update_tag_signature_changed(ntree, sig); } static void ntree_init_data(ID *id) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d8508cfec5f..61bf717db30 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1630,6 +1630,8 @@ typedef struct NodeShaderMix { typedef struct bNodeFunctionParameter { char name[64]; /* MAX_NAME */ int socket_type; + int identifier; + int _pad; } bNodeFunctionParameter; typedef struct bNodeFunctionSignature { @@ -1639,6 +1641,8 @@ typedef struct bNodeFunctionSignature { int outputs_num; int active_input; int active_output; + int next_identifier; + int _pad; } bNodeFunctionSignature; typedef struct NodeFunctionEvaluate { -- 2.30.2 From bc693c0f07983b176a0fb4cef937db4563a27b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sat, 15 Apr 2023 10:39:29 +0200 Subject: [PATCH 13/33] Improved API for signatures using some C++ support methods. --- source/blender/blenkernel/BKE_node.h | 10 +- source/blender/blenkernel/intern/node.cc | 308 ++++++++++++++++------- source/blender/makesdna/DNA_node_types.h | 23 +- 3 files changed, 243 insertions(+), 98 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 4d7e8aa9ba8..c294540757b 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -228,11 +228,6 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, /** \name Node Function Signature * \{ */ -enum eNodeFunctionParameterType { - NODE_FUNC_PARAM_IN, - NODE_FUNC_PARAM_OUT, - }; - /** Set a unique parameter name. * @return True if the unique name differs from the original name. */ @@ -248,7 +243,8 @@ struct bNode *nodeFunctionParameterFindNode(struct bNodeTree *ntree, struct bNode *nodeFunctionSignatureFindNode(struct bNodeTree *ntree, const struct bNodeFunctionSignature *sig); bool nodeFunctionSignatureContainsParameter(const struct bNodeFunctionSignature *sig, - const struct bNodeFunctionParameter *param); + const struct bNodeFunctionParameter *param, + eNodeFunctionParameterType *r_param_type); struct bNodeFunctionParameter *nodeFunctionSignatureGetActiveParameter( struct bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type); void nodeFunctionSignatureSetActiveParameter(struct bNodeFunctionSignature *sig, @@ -268,7 +264,7 @@ struct bNodeFunctionParameter *nodeFunctionSignatureInsertParameter( const char *name, int index); void nodeFunctionSignatureRemoveParameter(struct bNodeFunctionSignature *sig, - struct bNodeFunctionParameter *item); + struct bNodeFunctionParameter *param); void nodeFunctionSignatureClearParameters(struct bNodeFunctionSignature *sig); void nodeFunctionSignatureMoveParameter(struct bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index b5290cab92a..3bc6a36c21c 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -128,36 +128,80 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, /* ************ NODE FUNCTION SIGNATURE *************** */ +blender::Span bNodeFunctionSignature::inputs_span() const +{ + return blender::Span(inputs, inputs_num); +} + +blender::MutableSpan bNodeFunctionSignature::inputs_span() +{ + return blender::MutableSpan(inputs, inputs_num); +} + +blender::IndexRange bNodeFunctionSignature::inputs_range() const +{ + return blender::IndexRange(inputs_num); +} + +blender::Span bNodeFunctionSignature::outputs_span() const +{ + return blender::Span(outputs, outputs_num); +} + +blender::MutableSpan bNodeFunctionSignature::outputs_span() +{ + return blender::MutableSpan(outputs, outputs_num); +} + +blender::IndexRange bNodeFunctionSignature::outputs_range() const +{ + return blender::IndexRange(outputs_num); +} + +blender::Span bNodeFunctionSignature::params_span( + eNodeFunctionParameterType param_type) const +{ + switch (param_type) { + case NODE_FUNC_PARAM_IN: + return inputs_span(); + case NODE_FUNC_PARAM_OUT: + return outputs_span(); + } + return {}; +} + +blender::MutableSpan bNodeFunctionSignature::params_span( + eNodeFunctionParameterType param_type) +{ + switch (param_type) { + case NODE_FUNC_PARAM_IN: + return inputs_span(); + case NODE_FUNC_PARAM_OUT: + return outputs_span(); + } + return {}; +} + +blender::IndexRange bNodeFunctionSignature::params_range( + eNodeFunctionParameterType param_type) const +{ + switch (param_type) { + case NODE_FUNC_PARAM_IN: + return inputs_range(); + case NODE_FUNC_PARAM_OUT: + return outputs_range(); + } + return {}; +} + namespace blender::nodes { -static Span nodeFunctionSignatureGetParams( - const bNodeFunctionSignature *sig, const eNodeFunctionParameterType param_type) -{ - if (param_type == NODE_FUNC_PARAM_IN) { - return Span(sig->inputs, sig->inputs_num); - } - else { - return Span(sig->outputs, sig->outputs_num); - } -} - -static MutableSpan nodeFunctionSignatureGetParams( - bNodeFunctionSignature *sig, const eNodeFunctionParameterType param_type) -{ - if (param_type == NODE_FUNC_PARAM_IN) { - return MutableSpan(sig->inputs, sig->inputs_num); - } - else { - return MutableSpan(sig->outputs, sig->outputs_num); - } -} - struct NodeFunctionSignatureUniqueNameArgs { Span params_span; const bNodeFunctionParameter *param; }; -static bool function_signature_unique_name_check(void *arg, const char *name) +static bool nodeFunctionSignatureUniqueNameCheck(void *arg, const char *name) { const NodeFunctionSignatureUniqueNameArgs &args = *static_cast(arg); @@ -175,7 +219,14 @@ static bool function_signature_unique_name_check(void *arg, const char *name) bNode *nodeFunctionParameterFindNode(bNodeTree *ntree, const bNodeFunctionParameter *param) { - /** TODO */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == FN_NODE_EVALUATE) { + NodeFunctionEvaluate *data = static_cast(node->storage); + if (nodeFunctionSignatureContainsParameter(&data->signature, param, nullptr)) { + return node; + } + } + } return nullptr; } @@ -186,36 +237,66 @@ bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig, { char unique_name[MAX_NAME + 4]; BLI_strncpy(unique_name, name, sizeof(unique_name)); + bool name_changed = false; - blender::nodes::SimulationItemsUniqueNameArgs args{sim, item}; - const bool name_changed = BLI_uniquename_cb(blender::nodes::simulation_items_unique_name_check, - &args, - defname, - '.', - unique_name, - ARRAY_SIZE(unique_name)); - item->name = BLI_strdup(unique_name); + eNodeFunctionParameterType param_type; + if (nodeFunctionSignatureContainsParameter(sig, param, ¶m_type)) { + blender::nodes::NodeFunctionSignatureUniqueNameArgs args{sig->params_span(param_type), param}; + name_changed = BLI_uniquename_cb(blender::nodes::nodeFunctionSignatureUniqueNameCheck, + &args, + defname, + '.', + unique_name, + ARRAY_SIZE(unique_name)); + } + param->name = BLI_strdup(unique_name); return name_changed; } bNode *nodeFunctionSignatureFindNode(bNodeTree *ntree, const bNodeFunctionSignature *sig) { - /** TODO */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == FN_NODE_EVALUATE) { + NodeFunctionEvaluate *data = static_cast(node->storage); + if (sig == &data->signature) { + return node; + } + } + } return nullptr; } bool nodeFunctionSignatureContainsParameter(const bNodeFunctionSignature *sig, - const bNodeFunctionParameter *param) + const bNodeFunctionParameter *param, + eNodeFunctionParameterType *r_param_type) { - const int index = item - sim->items; - return index >= 0 && index < sim->items_num; + if (sig->inputs_span().contains_ptr(param)) { + if (r_param_type) { + *r_param_type = NODE_FUNC_PARAM_IN; + } + return true; + } + if (sig->outputs_span().contains_ptr(param)) { + if (r_param_type) { + *r_param_type = NODE_FUNC_PARAM_OUT; + } + return true; + } + return false; } bNodeFunctionParameter *nodeFunctionSignatureGetActiveParameter( bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type) { - if (sim->active_index >= 0 && sim->active_index < sim->items_num) { - return &sim->items[sim->active_index]; + switch (param_type) { + case NODE_FUNC_PARAM_IN: + if (sig->inputs_range().contains(sig->active_input)) { + return &sig->inputs[sig->active_input]; + } + case NODE_FUNC_PARAM_OUT: + if (sig->outputs_range().contains(sig->active_output)) { + return &sig->outputs[sig->active_output]; + } } return nullptr; } @@ -224,18 +305,28 @@ void nodeFunctionSignatureSetActiveParameter(bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, bNodeFunctionParameter *param) { - const int index = item - sim->items; - if (index >= 0 && index < sim->items_num) { - sim->active_index = index; + switch (param_type) { + case NODE_FUNC_PARAM_IN: { + const int index = param - sig->inputs; + if (sig->inputs_range().contains(index)) { + sig->active_input = index; + } + } + case NODE_FUNC_PARAM_OUT: { + const int index = param - sig->outputs; + if (sig->outputs_range().contains(index)) { + sig->active_output = index; + } + } } } bNodeFunctionParameter *nodeFunctionSignatureFindParameterByName( bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, const char *name) { - for (const int i : blender::IndexRange(sim->items_num)) { - if (STREQ(sim->items[i].name, name)) { - return &sim->items[i]; + for (bNodeFunctionParameter ¶m : sig->params_span(param_type)) { + if (STREQ(param.name, name)) { + return ¶m; } } return nullptr; @@ -246,7 +337,7 @@ bNodeFunctionParameter *nodeFunctionSignatureAddParameter(bNodeFunctionSignature short socket_type, const char *name) { - return NOD_geometry_simulation_output_insert_item(sim, socket_type, name, sim->items_num); + return nodeFunctionSignatureInsertParameter(sig, param_type, socket_type, name, sig->params_range(param_type).size()); } bNodeFunctionParameter *nodeFunctionSignatureInsertParameter(bNodeFunctionSignature *sig, @@ -255,58 +346,94 @@ bNodeFunctionParameter *nodeFunctionSignatureInsertParameter(bNodeFunctionSignat const char *name, int index) { - NodeSimulationItem *old_items = sim->items; - sim->items = MEM_cnew_array(sim->items_num + 1, __func__); - for (const int i : blender::IndexRange(0, index)) { - sim->items[i] = old_items[i]; + const Span old_params = sig->params_span(param_type); + bNodeFunctionParameter *new_params = MEM_cnew_array( + old_params.size() + 1, __func__); + for (const int i : old_params.index_range().take_front(index)) { + new_params[i] = old_params[i]; } - for (const int i : blender::IndexRange(index, sim->items_num - index)) { - sim->items[i + 1] = old_items[i]; + for (const int i : old_params.index_range().drop_front(index)) { + new_params[i + 1] = old_params[i]; } const char *defname = nodeStaticSocketLabel(socket_type, 0); - NodeSimulationItem &added_item = sim->items[index]; - added_item.identifier = sim->next_identifier++; - NOD_geometry_simulation_output_item_set_unique_name(sim, &added_item, name, defname); - added_item.socket_type = socket_type; + bNodeFunctionParameter &added_param = new_params[index]; + added_param.identifier = sig->next_identifier++; + nodeFunctionParameterSetUniqueName(sig, &added_param, name, defname); + added_param.socket_type = socket_type; - sim->items_num++; - MEM_SAFE_FREE(old_items); + switch (param_type) { + case NODE_FUNC_PARAM_IN: { + MEM_SAFE_FREE(sig->inputs); + sig->inputs = new_params; + sig->inputs_num++; + } + case NODE_FUNC_PARAM_OUT: { + MEM_SAFE_FREE(sig->outputs); + sig->outputs = new_params; + sig->outputs_num++; + } + } - return &added_item; + return &added_param; +} + +static void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type, + bNodeFunctionParameter *param) +{ + const Span old_params = sig->params_span(param_type); + if (!old_params.contains_ptr(param)) { + return; + } + const int index = param - old_params.data(); + + bNodeFunctionParameter *new_params = MEM_cnew_array( + old_params.size() - 1, __func__); + for (const int i : old_params.index_range().take_front(index)) { + new_params[i] = old_params[i]; + } + for (const int i : old_params.index_range().drop_front(index + 1)) { + new_params[i - 1] = old_params[i]; + } + + MEM_SAFE_FREE(old_params[index].name); + + switch (param_type) { + case NODE_FUNC_PARAM_IN: { + MEM_SAFE_FREE(sig->inputs); + sig->inputs = new_params; + sig->inputs_num--; + } + case NODE_FUNC_PARAM_OUT: { + MEM_SAFE_FREE(sig->outputs); + sig->outputs = new_params; + sig->outputs_num--; + } + } } void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, - bNodeFunctionParameter *item) + bNodeFunctionParameter *param) { - const int index = item - sim->items; - if (index < 0 || index >= sim->items_num) { - return; - } - - NodeSimulationItem *old_items = sim->items; - sim->items = MEM_cnew_array(sim->items_num - 1, __func__); - for (const int i : blender::IndexRange(0, index)) { - sim->items[i] = old_items[i]; - } - for (const int i : blender::IndexRange(index, sim->items_num - index).drop_front(1)) { - sim->items[i - 1] = old_items[i]; - } - - MEM_SAFE_FREE(old_items[index].name); - - sim->items_num--; - MEM_SAFE_FREE(old_items); + nodeFunctionSignatureRemoveParameter(sig, NODE_FUNC_PARAM_IN, param); + nodeFunctionSignatureRemoveParameter(sig, NODE_FUNC_PARAM_OUT, param); } void nodeFunctionSignatureClearParameters(bNodeFunctionSignature *sig) { - for (NodeSimulationItem &item : blender::MutableSpan(sim->items, sim->items_num)) { - MEM_SAFE_FREE(item.name); + for (bNodeFunctionParameter ¶m : sig->params_span(NODE_FUNC_PARAM_IN)) { + MEM_SAFE_FREE(param.name); } - MEM_SAFE_FREE(sim->items); - sim->items = nullptr; - sim->items_num = 0; + for (bNodeFunctionParameter ¶m : sig->params_span(NODE_FUNC_PARAM_OUT)) { + MEM_SAFE_FREE(param.name); + } + MEM_SAFE_FREE(sig->inputs); + MEM_SAFE_FREE(sig->outputs); + sig->inputs = nullptr; + sig->outputs = nullptr; + sig->inputs_num = 0; + sig->outputs_num = 0; } void nodeFunctionSignatureMoveParameter(bNodeFunctionSignature *sig, @@ -314,25 +441,26 @@ void nodeFunctionSignatureMoveParameter(bNodeFunctionSignature *sig, int from_index, int to_index) { - BLI_assert(from_index >= 0 && from_index < sim->items_num); - BLI_assert(to_index >= 0 && to_index < sim->items_num); + const MutableSpan params = sig->params_span(param_type); + BLI_assert(params.index_range().contains(from_index)); + BLI_assert(params.index_range().contains(to_index)); if (from_index == to_index) { return; } else if (from_index < to_index) { - const NodeSimulationItem tmp = sim->items[from_index]; + const bNodeFunctionParameter tmp = params[from_index]; for (int i = from_index; i < to_index; ++i) { - sim->items[i] = sim->items[i + 1]; + params[i] = params[i + 1]; } - sim->items[to_index] = tmp; + params[to_index] = tmp; } else /* from_index > to_index */ { - const NodeSimulationItem tmp = sim->items[from_index]; + const bNodeFunctionParameter tmp = params[from_index]; for (int i = from_index; i > to_index; --i) { - sim->items[i] = sim->items[i - 1]; + params[i] = params[i - 1]; } - sim->items[to_index] = tmp; + params[to_index] = tmp; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 61bf717db30..297627682ad 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -16,6 +16,8 @@ #ifdef __cplusplus namespace blender { template class Span; +template class MutableSpan; +class IndexRange; class StringRef; class StringRefNull; } // namespace blender @@ -1628,12 +1630,17 @@ typedef struct NodeShaderMix { /* Input or output in a bNodeFunctionSignature. */ typedef struct bNodeFunctionParameter { - char name[64]; /* MAX_NAME */ + char *name; int socket_type; int identifier; int _pad; } bNodeFunctionParameter; +enum eNodeFunctionParameterType { + NODE_FUNC_PARAM_IN, + NODE_FUNC_PARAM_OUT, +}; + typedef struct bNodeFunctionSignature { bNodeFunctionParameter *inputs; bNodeFunctionParameter *outputs; @@ -1643,6 +1650,20 @@ typedef struct bNodeFunctionSignature { int active_output; int next_identifier; int _pad; + +#ifdef __cplusplus + blender::Span inputs_span() const; + blender::MutableSpan inputs_span(); + blender::IndexRange inputs_range() const; + + blender::Span outputs_span() const; + blender::MutableSpan outputs_span(); + blender::IndexRange outputs_range() const; + + blender::Span params_span(eNodeFunctionParameterType param_type) const; + blender::MutableSpan params_span(eNodeFunctionParameterType param_type); + blender::IndexRange params_range(eNodeFunctionParameterType param_type) const; +#endif } bNodeFunctionSignature; typedef struct NodeFunctionEvaluate { -- 2.30.2 From de13c479667086fd4991e9e96db7b07b5faf9292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sat, 15 Apr 2023 14:16:07 +0200 Subject: [PATCH 14/33] RNA for node signatures. --- source/blender/blenkernel/BKE_node.h | 14 +- source/blender/blenkernel/intern/node.cc | 88 ++-- source/blender/editors/include/ED_node.h | 1 + source/blender/editors/space_node/drawnode.cc | 17 + source/blender/makesdna/DNA_node_types.h | 5 +- source/blender/makesrna/intern/rna_nodetree.c | 381 +++++++++++------- source/blender/nodes/NOD_socket.h | 2 + source/blender/nodes/intern/node_socket.cc | 7 + 8 files changed, 338 insertions(+), 177 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index c294540757b..059488dbd6e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -236,12 +236,15 @@ bool nodeFunctionParameterSetUniqueName(struct bNodeFunctionSignature *sig, const char *name, const char *defname); /** Find the node owning this parameter. */ -struct bNode *nodeFunctionParameterFindNode(struct bNodeTree *ntree, - const struct bNodeFunctionParameter *param); +bool nodeFunctionParameterFindNode(struct bNodeTree *ntree, + const struct bNodeFunctionParameter *param, + struct bNode **r_node, + struct bNodeFunctionSignature **r_sig); /** Find the node owning this signature. */ -struct bNode *nodeFunctionSignatureFindNode(struct bNodeTree *ntree, - const struct bNodeFunctionSignature *sig); +bool nodeFunctionSignatureFindNode(struct bNodeTree *ntree, + const struct bNodeFunctionSignature *sig, + struct bNode **r_node); bool nodeFunctionSignatureContainsParameter(const struct bNodeFunctionSignature *sig, const struct bNodeFunctionParameter *param, eNodeFunctionParameterType *r_param_type); @@ -265,7 +268,8 @@ struct bNodeFunctionParameter *nodeFunctionSignatureInsertParameter( int index); void nodeFunctionSignatureRemoveParameter(struct bNodeFunctionSignature *sig, struct bNodeFunctionParameter *param); -void nodeFunctionSignatureClearParameters(struct bNodeFunctionSignature *sig); +void nodeFunctionSignatureClearParameters(struct bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type); void nodeFunctionSignatureMoveParameter(struct bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, int from_index, diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 3bc6a36c21c..ad2ba17c41a 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -217,17 +217,26 @@ static bool nodeFunctionSignatureUniqueNameCheck(void *arg, const char *name) } // namespace blender::nodes -bNode *nodeFunctionParameterFindNode(bNodeTree *ntree, const bNodeFunctionParameter *param) +bool nodeFunctionParameterFindNode(bNodeTree *ntree, + const bNodeFunctionParameter *param, + bNode **r_node, + bNodeFunctionSignature **r_sig) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == FN_NODE_EVALUATE) { NodeFunctionEvaluate *data = static_cast(node->storage); if (nodeFunctionSignatureContainsParameter(&data->signature, param, nullptr)) { - return node; + if (r_node) { + *r_node = node; + } + if (r_sig) { + *r_sig = &data->signature; + } + return true; } } } - return nullptr; + return false; } bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig, @@ -253,17 +262,22 @@ bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig, return name_changed; } -bNode *nodeFunctionSignatureFindNode(bNodeTree *ntree, const bNodeFunctionSignature *sig) +bool nodeFunctionSignatureFindNode(bNodeTree *ntree, + const bNodeFunctionSignature *sig, + bNode **r_node) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == FN_NODE_EVALUATE) { NodeFunctionEvaluate *data = static_cast(node->storage); if (sig == &data->signature) { - return node; + if (r_node) { + *r_node = node; + } + return true; } } } - return nullptr; + return false; } bool nodeFunctionSignatureContainsParameter(const bNodeFunctionSignature *sig, @@ -293,10 +307,12 @@ bNodeFunctionParameter *nodeFunctionSignatureGetActiveParameter( if (sig->inputs_range().contains(sig->active_input)) { return &sig->inputs[sig->active_input]; } + break; case NODE_FUNC_PARAM_OUT: if (sig->outputs_range().contains(sig->active_output)) { return &sig->outputs[sig->active_output]; } + break; } return nullptr; } @@ -311,12 +327,14 @@ void nodeFunctionSignatureSetActiveParameter(bNodeFunctionSignature *sig, if (sig->inputs_range().contains(index)) { sig->active_input = index; } + break; } case NODE_FUNC_PARAM_OUT: { const int index = param - sig->outputs; if (sig->outputs_range().contains(index)) { sig->active_output = index; } + break; } } } @@ -367,11 +385,13 @@ bNodeFunctionParameter *nodeFunctionSignatureInsertParameter(bNodeFunctionSignat MEM_SAFE_FREE(sig->inputs); sig->inputs = new_params; sig->inputs_num++; + break; } case NODE_FUNC_PARAM_OUT: { MEM_SAFE_FREE(sig->outputs); sig->outputs = new_params; sig->outputs_num++; + break; } } @@ -404,11 +424,13 @@ static void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, MEM_SAFE_FREE(sig->inputs); sig->inputs = new_params; sig->inputs_num--; + break; } case NODE_FUNC_PARAM_OUT: { MEM_SAFE_FREE(sig->outputs); sig->outputs = new_params; sig->outputs_num--; + break; } } } @@ -420,20 +442,27 @@ void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, nodeFunctionSignatureRemoveParameter(sig, NODE_FUNC_PARAM_OUT, param); } -void nodeFunctionSignatureClearParameters(bNodeFunctionSignature *sig) +void nodeFunctionSignatureClearParameters(bNodeFunctionSignature *sig, + eNodeFunctionParameterType param_type) { - for (bNodeFunctionParameter ¶m : sig->params_span(NODE_FUNC_PARAM_IN)) { - MEM_SAFE_FREE(param.name); + switch (param_type) { + case NODE_FUNC_PARAM_IN: + for (bNodeFunctionParameter ¶m : sig->inputs_span()) { + MEM_SAFE_FREE(param.name); + } + MEM_SAFE_FREE(sig->inputs); + sig->inputs = nullptr; + sig->inputs_num = 0; + break; + case NODE_FUNC_PARAM_OUT: + for (bNodeFunctionParameter ¶m : sig->outputs_span()) { + MEM_SAFE_FREE(param.name); + } + MEM_SAFE_FREE(sig->outputs); + sig->outputs = nullptr; + sig->outputs_num = 0; + break; } - for (bNodeFunctionParameter ¶m : sig->params_span(NODE_FUNC_PARAM_OUT)) { - MEM_SAFE_FREE(param.name); - } - MEM_SAFE_FREE(sig->inputs); - MEM_SAFE_FREE(sig->outputs); - sig->inputs = nullptr; - sig->outputs = nullptr; - sig->inputs_num = 0; - sig->outputs_num = 0; } void nodeFunctionSignatureMoveParameter(bNodeFunctionSignature *sig, @@ -844,11 +873,13 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) static void write_node_function_signature(BlendWriter *writer, bNodeFunctionSignature *sig) { BLO_write_struct(writer, bNodeFunctionSignature, sig); - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { - write_node_socket_interface(writer, sock); + BLO_write_struct_array(writer, bNodeFunctionParameter, sig->inputs_num, sig->inputs); + BLO_write_struct_array(writer, bNodeFunctionParameter, sig->outputs_num, sig->outputs); + for (const bNodeFunctionParameter ¶m : sig->inputs_span()) { + BLO_write_string(writer, param.name); } - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { - write_node_socket_interface(writer, sock); + for (const bNodeFunctionParameter ¶m : sig->outputs_span()) { + BLO_write_string(writer, param.name); } } @@ -1008,13 +1039,13 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) static void direct_link_node_function_signature(BlendDataReader *reader, bNodeFunctionSignature *sig) { - BLO_read_list(reader, &sig->inputs); - BLO_read_list(reader, &sig->outputs); - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) { - direct_link_node_socket(reader, sock); + BLO_read_data_address(reader, &sig->inputs); + BLO_read_data_address(reader, &sig->outputs); + for (bNodeFunctionParameter ¶m : sig->inputs_span()) { + BLO_read_data_address(reader, ¶m.name); } - LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) { - direct_link_node_socket(reader, sock); + for (bNodeFunctionParameter ¶m : sig->outputs_span()) { + BLO_read_data_address(reader, ¶m.name); } } @@ -2110,6 +2141,7 @@ void nodeModifySocketType(bNodeTree *ntree, case SOCK_COLLECTION: case SOCK_TEXTURE: case SOCK_MATERIAL: + case SOCK_FUNCTION: break; } } diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 5ae213afa36..cd5d1a06d7a 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -73,6 +73,7 @@ void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype); void ED_node_sample_set(const float col[4]); void ED_node_draw_snap( struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos); +void ED_node_type_draw_color(const char *idname, float *r_color); /* node_draw.cc */ diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index d353df7657a..e39be3fae98 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1498,6 +1498,23 @@ void ED_init_node_socket_type_virtual(bNodeSocketType *stype) stype->draw_color = node_socket_virtual_draw_color; } +void ED_node_type_draw_color(const char *idname, float *r_color) +{ + using namespace blender::ed::space_node; + + const bNodeSocketType *typeinfo = nodeSocketTypeFind(idname); + if (!typeinfo || typeinfo->type == SOCK_CUSTOM) { + r_color[0] = 0.0f; + r_color[1] = 0.0f; + r_color[2] = 0.0f; + r_color[3] = 0.0f; + return; + } + + BLI_assert(typeinfo->type < ARRAY_SIZE(std_node_socket_colors)); + copy_v4_v4(r_color, std_node_socket_colors[typeinfo->type]); +} + namespace blender::ed::space_node { /* ************** Generic drawing ************** */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 297627682ad..873d0798119 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1633,13 +1633,12 @@ typedef struct bNodeFunctionParameter { char *name; int socket_type; int identifier; - int _pad; } bNodeFunctionParameter; -enum eNodeFunctionParameterType { +typedef enum eNodeFunctionParameterType { NODE_FUNC_PARAM_IN, NODE_FUNC_PARAM_OUT, -}; +} eNodeFunctionParameterType; typedef struct bNodeFunctionSignature { bNodeFunctionParameter *inputs; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 6199180dac7..045cee37459 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -52,6 +52,7 @@ #include "RE_texture.h" #include "NOD_composite.h" +#include "NOD_socket.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -3282,148 +3283,205 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, /* ******** Node Function Signature ******** */ -static bNodeSocket *rna_NodeFunctionSignature_inputs_new(ID *id, - bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports, - const char *type, - const char *name) +static void rna_NodeFunctionParameter_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return NULL; - } - - bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_IN, type, name); - - if (sock == NULL) { - BKE_report(reports, RPT_ERROR, "Unable to create socket"); - } - else { + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNodeFunctionParameter *param = (bNodeFunctionParameter *)ptr->data; + bNode *node; + if (nodeFunctionParameterFindNode(ntree, param, &node, NULL)) { + BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } - - return sock; } -static bNodeSocket *rna_NodeFunctionSignature_outputs_new(ID *id, - bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports, - const char *type, - const char *name) +static void rna_NodeFunctionParameter_name_set(PointerRNA *ptr, const char *value) { - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return NULL; + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNodeFunctionParameter *param = (bNodeFunctionParameter *)ptr->data; + bNode *node; + bNodeFunctionSignature *sig; + if (nodeFunctionParameterFindNode(ntree, param, &node, &sig)) { + const char *defname = nodeStaticSocketLabel(param->socket_type, 0); + nodeFunctionParameterSetUniqueName(sig, param, value, defname); } - - bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_OUT, type, name); - - if (sock == NULL) { - BKE_report(reports, RPT_ERROR, "Unable to create socket"); - } - else { - ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); - } - - return sock; } -static void rna_NodeFunctionSignature_socket_remove(ID *id, +static void rna_NodeFunctionParameter_color_get(PointerRNA *ptr, float *values) +{ + bNodeFunctionParameter *param = (bNodeFunctionParameter *)ptr->data; + + const char *socket_type_idname = nodeStaticSocketType(param->socket_type, 0); + node_type_draw_color(socket_type_idname, values); +} + +static bNodeFunctionParameter *rna_NodeFunctionSignature_inputs_new(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + int socket_type, + const char *name) +{ + bNodeFunctionParameter *param = nodeFunctionSignatureAddParameter(sig, NODE_FUNC_PARAM_IN, (short)socket_type, name); + + if (param == NULL) { + BKE_report(reports, RPT_ERROR, "Unable to create input parameter"); + } + else { + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } + } + + return param; +} + +static bNodeFunctionParameter *rna_NodeFunctionSignature_outputs_new(ID *id, + bNodeFunctionSignature *sig, + Main *bmain, + ReportList *reports, + int socket_type, + const char *name) +{ + bNodeFunctionParameter *param = nodeFunctionSignatureAddParameter( + sig, NODE_FUNC_PARAM_OUT, (short)socket_type, name); + + if (param == NULL) { + BKE_report(reports, RPT_ERROR, "Unable to create output parameter"); + } + else { + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } + } + + return param; +} + +static void rna_NodeFunctionSignature_params_remove(ID *id, bNodeFunctionSignature *sig, Main *bmain, ReportList *reports, - bNodeSocket *sock) + bNodeFunctionParameter *param) { - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return; - } - - if (BLI_findindex(&sig->inputs, sock) == -1 && BLI_findindex(&sig->outputs, sock) == -1) { - BKE_reportf(reports, RPT_ERROR, "Unable to locate socket '%s' in node", sock->identifier); + if (!nodeFunctionSignatureContainsParameter(sig, param, NULL)) { + BKE_reportf(reports, RPT_ERROR, "Unable to remove parameter '%s' from signature", param->name); } else { - nodeFunctionSignatureRemoveSocket(ntree, sig, sock); + nodeFunctionSignatureRemoveParameter(sig, param); + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } + } +} + +static void rna_NodeFunctionSignature_inputs_clear(ID *id, bNodeFunctionSignature *sig, Main *bmain) +{ + nodeFunctionSignatureClearParameters(sig, NODE_FUNC_PARAM_IN); + + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } } -static void rna_NodeFunctionSignature_inputs_clear(ID *id, - bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports) -{ - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return; - } - - nodeFunctionSignatureClear(ntree, sig, SOCK_IN); - - ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); -} - static void rna_NodeFunctionSignature_outputs_clear(ID *id, - bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports) -{ - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return; - } - - nodeFunctionSignatureClear(ntree, sig, SOCK_OUT); - - ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); -} - -static void rna_NodeFunctionSignature_inputs_move(ID *id, - bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports, - int from_index, - int to_index) -{ - bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { - return; - } - - nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_IN, from_index, to_index); - - BKE_ntree_update_tag_interface(ntree); - - ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); -} - -static void rna_NodeFunctionSignature_outputs_move(ID *id, bNodeFunctionSignature *sig, - Main *bmain, - ReportList *reports, - int from_index, - int to_index) + Main *bmain) { + nodeFunctionSignatureClearParameters(sig, NODE_FUNC_PARAM_OUT); + bNodeTree *ntree = (bNodeTree *)id; - if (!rna_NodeTree_check(ntree, reports)) { + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } +} + +static void rna_NodeFunctionSignature_inputs_move( + ID *id, bNodeFunctionSignature *sig, Main *bmain, int from_index, int to_index) +{ + if (from_index < 0 || from_index >= sig->inputs_num || to_index < 0 || + to_index >= sig->inputs_num) { return; } - nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_OUT, from_index, to_index); + nodeFunctionSignatureMoveParameter(sig, NODE_FUNC_PARAM_IN, from_index, to_index); - BKE_ntree_update_tag_interface(ntree); + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } +} - ED_node_tree_propagate_change(NULL, bmain, ntree); - WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); +static void rna_NodeFunctionSignature_outputs_move( + ID *id, bNodeFunctionSignature *sig, Main *bmain, int from_index, int to_index) +{ + if (from_index < 0 || from_index >= sig->outputs_num || to_index < 0 || + to_index >= sig->outputs_num) { + return; + } + + nodeFunctionSignatureMoveParameter(sig, NODE_FUNC_PARAM_OUT, from_index, to_index); + + bNodeTree *ntree = (bNodeTree *)id; + bNode *node; + if (nodeFunctionSignatureFindNode(ntree, sig, &node)) { + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + } +} + +static PointerRNA rna_NodeFunctionSignature_active_input_get(PointerRNA *ptr) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + bNodeFunctionParameter *param = nodeFunctionSignatureGetActiveParameter(sig, NODE_FUNC_PARAM_IN); + PointerRNA r_ptr; + RNA_pointer_create(ptr->owner_id, &RNA_NodeFunctionParameter, param, &r_ptr); + return r_ptr; +} + +static void rna_NodeFunctionSignature_active_input_set(PointerRNA *ptr, PointerRNA value) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + nodeFunctionSignatureSetActiveParameter(sig, NODE_FUNC_PARAM_IN, (bNodeFunctionParameter *)value.data); +} + +static PointerRNA rna_NodeFunctionSignature_active_output_get(PointerRNA *ptr) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + bNodeFunctionParameter *param = nodeFunctionSignatureGetActiveParameter(sig, NODE_FUNC_PARAM_OUT); + PointerRNA r_ptr; + RNA_pointer_create(ptr->owner_id, &RNA_NodeFunctionParameter, param, &r_ptr); + return r_ptr; +} + +static void rna_NodeFunctionSignature_active_output_set(PointerRNA *ptr, PointerRNA value) +{ + bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data; + nodeFunctionSignatureSetActiveParameter( + sig, NODE_FUNC_PARAM_OUT, (bNodeFunctionParameter *)value.data); } /* ******** Node Types ******** */ @@ -5406,6 +5464,32 @@ static void def_fn_bind(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNodeBind_update"); } +static void rna_def_node_function_parameter(BlenderRNA *brna) +{ + PropertyRNA *prop; + + StructRNA *srna = RNA_def_struct(brna, "NodeFunctionParameter", NULL); + RNA_def_struct_ui_text(srna, "Node Function Parameter", "Input or output declaration of a node function"); + RNA_def_struct_sdna(srna, "bNodeFunctionParameter"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeFunctionParameter_name_set"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); + + prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, node_socket_data_type_items); + RNA_def_property_ui_text(prop, "Socket Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_float_funcs(prop, "rna_NodeFunctionParameter_color_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Color", "Socket color"); +} + static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) { StructRNA *srna; @@ -5415,7 +5499,7 @@ static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *c const char *uiname = (in_out == SOCK_IN ? "Node Function Signature Inputs" : "Node Function Signature Outputs"); const char *newfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_new" : "rna_NodeFunctionSignature_outputs_new"); - const char *removefunc = "rna_NodeFunctionSignature_socket_remove"; + const char *removefunc = "rna_NodeFunctionSignature_params_remove"; const char *clearfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_clear" : "rna_NodeFunctionSignature_outputs_clear"); const char *movefunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_move" : @@ -5424,37 +5508,37 @@ static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *c RNA_def_property_srna(cprop, structtype); srna = RNA_def_struct(brna, structtype, NULL); RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); - RNA_def_struct_ui_text(srna, uiname, "Collection of Node Socket Declarations"); + RNA_def_struct_ui_text(srna, uiname, "Collection of node function parameters"); func = RNA_def_function(srna, "new", newfunc); - RNA_def_function_ui_description(func, "Add a socket to this signature"); + RNA_def_function_ui_description(func, "Add a parameter to this signature"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ - parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket"); + parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "New parameter"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", removefunc); - RNA_def_function_ui_description(func, "Remove a socket from this signature"); + RNA_def_function_ui_description(func, "Remove a parameter from this signature"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove"); + parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "The parameter to remove"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", clearfunc); - RNA_def_function_ui_description(func, "Remove all sockets from this signature"); + RNA_def_function_ui_description(func, "Remove all parameters from this collection"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); func = RNA_def_function(srna, "move", movefunc); - RNA_def_function_ui_description(func, "Move a socket to another position"); + RNA_def_function_ui_description(func, "Move a parameter to another position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_int( - func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); + func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the parameter to move", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int( - func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); + func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the parameter", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } @@ -5468,36 +5552,50 @@ static void rna_def_node_function_signature(BlenderRNA *brna) RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); - RNA_def_property_struct_type(prop, "NodeSocketInterface"); + RNA_def_property_collection_sdna(prop, NULL, "inputs", "inputs_num"); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Inputs", "Function inputs"); rna_def_node_function_signature_api(brna, prop, SOCK_IN); - prop = RNA_def_property(srna, "active_input", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_NodeFunctionSignature_active_input_get", - "rna_NodeFunctionSignature_active_input_set", - NULL); - RNA_def_property_ui_text(prop, "Active Input", "Index of the active input"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_NODE, NULL); - prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); - RNA_def_property_struct_type(prop, "NodeSocketInterface"); + RNA_def_property_collection_sdna(prop, NULL, "outputs", "outputs_num"); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Outputs", "Function outputs"); rna_def_node_function_signature_api(brna, prop, SOCK_OUT); - prop = RNA_def_property(srna, "active_output", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_NodeFunctionSignature_active_output_get", - "rna_NodeFunctionSignature_active_output_set", - NULL); - RNA_def_property_ui_text(prop, "Active Output", "Index of the active output"); + prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "active_input"); + RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "active_output_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "active_output"); + RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "active_input", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_pointer_funcs(prop, + "rna_NodeFunctionSignature_active_input_get", + "rna_NodeFunctionSignature_active_input_set", + NULL, + NULL); + RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input"); + RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "active_output", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_pointer_funcs(prop, + "rna_NodeFunctionSignature_active_output_get", + "rna_NodeFunctionSignature_active_output_set", + NULL, + NULL); + RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output"); + RNA_def_property_update(prop, NC_NODE, NULL); } static void def_fn_evaluate(StructRNA *srna) @@ -13418,6 +13516,7 @@ void RNA_def_nodetree(BlenderRNA *brna) rna_def_node_socket(brna); rna_def_node_socket_interface(brna); + rna_def_node_function_parameter(brna); rna_def_node_function_signature(brna); rna_def_node(brna); diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h index a03dfc8b3ee..510ef378224 100644 --- a/source/blender/nodes/NOD_socket.h +++ b/source/blender/nodes/NOD_socket.h @@ -22,6 +22,8 @@ struct bNodeTree; extern "C" { #endif +void node_type_draw_color(const char *idname, float *r_color); + struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 47a8e47cc90..4ced21594dc 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -40,6 +40,13 @@ using namespace blender; using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; +extern "C" void ED_node_type_draw_color(const char *idname, float *r_color); + +void node_type_draw_color(const char *idname, float *r_color) +{ + ED_node_type_draw_color(idname, r_color); +} + struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, -- 2.30.2 From 249bb47f5a1167d1adf05f7c10925b2e4ba7ac88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sat, 15 Apr 2023 17:55:50 +0200 Subject: [PATCH 15/33] Implemented UI for the Evaluate node signature. --- scripts/startup/bl_operators/node.py | 100 ++++++++++++++++++ scripts/startup/bl_ui/space_node.py | 95 +++++++++++++++++ source/blender/blenkernel/intern/node.cc | 4 + source/blender/makesrna/intern/rna_nodetree.c | 87 +++++++-------- source/blender/nodes/intern/node_common.cc | 4 +- 5 files changed, 243 insertions(+), 47 deletions(-) diff --git a/scripts/startup/bl_operators/node.py b/scripts/startup/bl_operators/node.py index c57f482146f..31e1aa0ff5c 100644 --- a/scripts/startup/bl_operators/node.py +++ b/scripts/startup/bl_operators/node.py @@ -9,6 +9,7 @@ from bpy.types import ( from bpy.props import ( BoolProperty, CollectionProperty, + EnumProperty, StringProperty, ) @@ -198,10 +199,109 @@ class NODE_OT_tree_path_parent(Operator): return {'FINISHED'} +class NodeFunctionSignatureOperator(): + # Dictionary of node types with methods to get the signature + signature_nodes = { + 'FunctionNodeEvaluate' : lambda node: node.signature, + } + + param_type: EnumProperty( + name = "Parameter Type", + items = [ + ('INPUT', "Input", ""), + ('OUTPUT', "Output", ""), + ] + ) + + def params_get(self, signature): + return signature.inputs if self.param_type == 'INPUT' else signature.outputs + + @classmethod + def poll(cls, context): + snode = context.space_data + if snode is None: + return False + node = context.active_node + if node is None or node.bl_idname not in cls.signature_nodes: + return False + return True + + +class NODE_OT_function_parameter_add(NodeFunctionSignatureOperator, Operator): + '''Add a parameter to the function signature''' + bl_idname = "node.function_parameter_add" + bl_label = "Add Parameter" + bl_options = {'REGISTER', 'UNDO'} + + default_socket_type = 'FLOAT' + + def execute(self, context): + node = context.active_node + signature = self.signature_nodes[node.bl_idname](node) + params = self.params_get(signature) + + # Remember index to move the item + dst_index = min(params.active_index + 1, len(params)) + # Empty name so it is based on the type only + params.new(self.default_socket_type, "") + params.move(len(params) - 1, dst_index) + params.active_index = dst_index + + return {'FINISHED'} + + +class NODE_OT_function_parameter_remove(NodeFunctionSignatureOperator, Operator): + '''Remove a parameter from the function signature''' + bl_idname = "node.function_parameter_remove" + bl_label = "Remove Parameter" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + node = context.active_node + signature = self.signature_nodes[node.bl_idname](node) + params = self.params_get(signature) + + if params.active: + params.remove(params.active) + params.active_index = min(params.active_index, len(params) - 1) + + return {'FINISHED'} + + +class NODE_OT_function_parameter_move(NodeFunctionSignatureOperator, Operator): + '''Move a parameter item up or down in the signature''' + bl_idname = "node.function_parameter_move" + bl_label = "Move Parameter" + bl_options = {'REGISTER', 'UNDO'} + + direction: EnumProperty( + name="Direction", + items=[('UP', "Up", ""), ('DOWN', "Down", "")], + default = 'UP', + ) + + def execute(self, context): + node = context.active_node + signature = self.signature_nodes[node.bl_idname](node) + params = self.params_get(signature) + + if self.direction == 'UP' and params.active_index > 0: + params.move(params.active_index, params.active_index - 1) + params.active_index -= 1 + elif self.direction == 'DOWN' and params.active_index < len(params) - 1: + params.move(params.active_index, params.active_index + 1) + params.active_index += 1 + + return {'FINISHED'} + + classes = ( NodeSetting, NODE_OT_add_node, NODE_OT_collapse_hide_unused_toggle, NODE_OT_tree_path_parent, + NODE_OT_function_parameter_add, + NODE_OT_function_parameter_remove, + NODE_OT_function_parameter_move, ) diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index e16c6e1e77c..a55e5570ebb 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -955,6 +955,98 @@ class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel): self.draw_socket_list(context, "OUT", "outputs", "active_output") +class NODE_UL_function_parameters(bpy.types.UIList): + def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index): + if self.layout_type in {'DEFAULT', 'COMPACT'}: + row = layout.row(align=True) + + row.template_node_socket(color=item.color) + row.prop(item, "name", text="", emboss=False, icon_value=icon) + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.template_node_socket(color=item.color) + + +class FunctionSignaturePanel(): + # Must be defined by subclasses + param_type = None + params_prop = None + + # Dictionary of node types with methods to get the signature + signature_nodes = { + 'FunctionNodeEvaluate' : lambda node: node.signature, + } + + @classmethod + def poll(cls, context): + snode = context.space_data + if snode is None: + return False + node = context.active_node + if node is None or node.bl_idname not in cls.signature_nodes: + return False + return True + + def draw(self, context): + layout = self.layout + node = context.active_node + signature = self.signature_nodes[node.bl_idname](node) + params = getattr(signature, self.params_prop) + + split = layout.row() + + split.template_list( + "NODE_UL_function_parameters", + self.params_prop, + signature, + self.params_prop, + params, + "active_index") + + ops_col = split.column() + + add_remove_col = ops_col.column(align=True) + props = add_remove_col.operator("node.function_parameter_add", icon='ADD', text="") + props.param_type = self.param_type + props = add_remove_col.operator("node.function_parameter_remove", icon='REMOVE', text="") + props.param_type = self.param_type + + ops_col.separator() + + up_down_col = ops_col.column(align=True) + props = up_down_col.operator("node.function_parameter_move", icon='TRIA_UP', text="") + props.param_type = self.param_type + props.direction = 'UP' + props = up_down_col.operator("node.function_parameter_move", icon='TRIA_DOWN', text="") + props.param_type = self.param_type + props.direction = 'DOWN' + + active_param = params.active + if active_param is not None: + layout.prop(active_param, "socket_type") + layout.prop(active_param, "name") + + +class NODE_PT_function_signature_inputs(FunctionSignaturePanel, Panel): + bl_space_type = 'NODE_EDITOR' + bl_region_type = 'UI' + bl_category = "Node" + bl_label = "Function Signature Inputs" + + param_type = 'INPUT' + params_prop = "inputs" + + +class NODE_PT_function_signature_outputs(FunctionSignaturePanel, Panel): + bl_space_type = 'NODE_EDITOR' + bl_region_type = 'UI' + bl_category = "Node" + bl_label = "Function Signature Outputs" + + param_type = 'OUTPUT' + params_prop = "outputs" + + # Grease Pencil properties class NODE_PT_annotation(AnnotationDataPanel, Panel): bl_space_type = 'NODE_EDITOR' @@ -1019,6 +1111,9 @@ classes = ( NODE_UL_interface_sockets, NODE_PT_node_tree_interface_inputs, NODE_PT_node_tree_interface_outputs, + NODE_UL_function_parameters, + NODE_PT_function_signature_inputs, + NODE_PT_function_signature_outputs, node_panel(EEVEE_MATERIAL_PT_settings), node_panel(MATERIAL_PT_viewport), diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index ad2ba17c41a..a2361943261 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -258,6 +258,10 @@ bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig, unique_name, ARRAY_SIZE(unique_name)); } + else if (unique_name[0] == '\0') { + /* Should use default if name is empty, same as BLI_uniquename_cb behavior. */ + BLI_strncpy(unique_name, defname, sizeof(unique_name)); + } param->name = BLI_strdup(unique_name); return name_changed; } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 045cee37459..8a3b718953d 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5490,30 +5490,57 @@ static void rna_def_node_function_parameter(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Color", "Socket color"); } -static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) +static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, eNodeFunctionParameterType param_type) { StructRNA *srna; + PropertyRNA *prop; PropertyRNA *parm; FunctionRNA *func; - const char *structtype = (in_out == SOCK_IN ? "NodeFunctionSignatureInputs" : "NodeFunctionSignatureOutputs"); - const char *uiname = (in_out == SOCK_IN ? "Node Function Signature Inputs" : "Node Function Signature Outputs"); - const char *newfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_new" : - "rna_NodeFunctionSignature_outputs_new"); + const char *structtype = (param_type == NODE_FUNC_PARAM_IN ? "NodeFunctionSignatureInputs" : + "NodeFunctionSignatureOutputs"); + const char *uiname = (param_type == NODE_FUNC_PARAM_IN ? "Node Function Signature Inputs" : + "Node Function Signature Outputs"); + const char *active_index_sdna = (param_type == NODE_FUNC_PARAM_IN ? "active_input" : + "active_output"); + const char *active_param_get = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_active_input_get" : + "rna_NodeFunctionSignature_active_output_get"); + const char *active_param_set = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_active_input_set" : + "rna_NodeFunctionSignature_active_output_set"); + const char *newfunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_new" : + "rna_NodeFunctionSignature_outputs_new"); const char *removefunc = "rna_NodeFunctionSignature_params_remove"; - const char *clearfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_clear" : - "rna_NodeFunctionSignature_outputs_clear"); - const char *movefunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_move" : - "rna_NodeFunctionSignature_outputs_move"); + const char *clearfunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_clear" : + "rna_NodeFunctionSignature_outputs_clear"); + const char *movefunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_move" : + "rna_NodeFunctionSignature_outputs_move"); RNA_def_property_srna(cprop, structtype); srna = RNA_def_struct(brna, structtype, NULL); RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); RNA_def_struct_ui_text(srna, uiname, "Collection of node function parameters"); + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, active_index_sdna); + RNA_def_property_ui_text(prop, "Active Index", "Index of the active parameter"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_pointer_funcs(prop, active_param_get, active_param_set, NULL, NULL); + RNA_def_property_ui_text(prop, "Active", "Active parameter"); + RNA_def_property_update(prop, NC_NODE, NULL); + func = RNA_def_function(srna, "new", newfunc); RNA_def_function_ui_description(func, "Add a parameter to this signature"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); + parm = RNA_def_enum( + func, "socket_type", node_socket_data_type_items, SOCK_FLOAT, "Type", "Data type"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); @@ -5529,11 +5556,11 @@ static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *c func = RNA_def_function(srna, "clear", clearfunc); RNA_def_function_ui_description(func, "Remove all parameters from this collection"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); func = RNA_def_function(srna, "move", movefunc); RNA_def_function_ui_description(func, "Move a parameter to another position"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); parm = RNA_def_int( func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the parameter to move", 0, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); @@ -5556,46 +5583,14 @@ static void rna_def_node_function_signature(BlenderRNA *brna) RNA_def_property_struct_type(prop, "NodeFunctionParameter"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Inputs", "Function inputs"); - rna_def_node_function_signature_api(brna, prop, SOCK_IN); + rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_IN); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", "outputs_num"); RNA_def_property_struct_type(prop, "NodeFunctionParameter"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Outputs", "Function outputs"); - rna_def_node_function_signature_api(brna, prop, SOCK_OUT); - - prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "active_input"); - RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_NODE, NULL); - - prop = RNA_def_property(srna, "active_output_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "active_output"); - RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_NODE, NULL); - - prop = RNA_def_property(srna, "active_input", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "NodeFunctionParameter"); - RNA_def_property_pointer_funcs(prop, - "rna_NodeFunctionSignature_active_input_get", - "rna_NodeFunctionSignature_active_input_set", - NULL, - NULL); - RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input"); - RNA_def_property_update(prop, NC_NODE, NULL); - - prop = RNA_def_property(srna, "active_output", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "NodeFunctionParameter"); - RNA_def_property_pointer_funcs(prop, - "rna_NodeFunctionSignature_active_output_get", - "rna_NodeFunctionSignature_active_output_set", - NULL, - NULL); - RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output"); - RNA_def_property_update(prop, NC_NODE, NULL); + rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_OUT); } static void def_fn_evaluate(StructRNA *srna) diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index 2a0a6d75a19..085ffc7f29c 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -342,7 +342,9 @@ SocketDeclarationPtr declaration_for_signature_parameter(const bNodeFunctionPara dst = std::make_unique(); break; } - dst->name = param.name; + dst->name = param.name ? param.name : ""; + char buf[MAX_NAME]; + dst->identifier = BLI_snprintf(buf, sizeof(buf), "Item_%d", param.identifier); dst->in_out = in_out; dst->hide_value = true; dst->compact = false; -- 2.30.2 From 1deb83b208f48e26c3db33db35af34f246221273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sat, 15 Apr 2023 19:09:55 +0200 Subject: [PATCH 16/33] Moved the bind and evaluate nodes into the geometry category. These are going to need geometry exec functions and not just multifunctions. --- scripts/startup/bl_operators/node.py | 2 +- .../startup/bl_ui/node_add_menu_geometry.py | 4 +- scripts/startup/bl_ui/space_node.py | 2 +- source/blender/blenkernel/BKE_node.h | 5 +- source/blender/blenkernel/intern/node.cc | 16 +- source/blender/makesdna/DNA_node_types.h | 4 +- source/blender/makesrna/intern/rna_nodetree.c | 275 +++++++++--------- source/blender/nodes/NOD_static_types.h | 4 +- source/blender/nodes/function/CMakeLists.txt | 2 - .../nodes/function/node_function_register.cc | 2 - .../nodes/function/node_function_register.hh | 2 - source/blender/nodes/geometry/CMakeLists.txt | 2 + .../nodes/geometry/node_geometry_register.cc | 2 + .../nodes/geometry/node_geometry_register.hh | 2 + .../nodes/node_geo_bind_function.cc} | 29 +- .../nodes/node_geo_evaluate_function.cc} | 20 +- 16 files changed, 199 insertions(+), 174 deletions(-) rename source/blender/nodes/{function/nodes/node_fn_bind.cc => geometry/nodes/node_geo_bind_function.cc} (64%) rename source/blender/nodes/{function/nodes/node_fn_evaluate.cc => geometry/nodes/node_geo_evaluate_function.cc} (64%) diff --git a/scripts/startup/bl_operators/node.py b/scripts/startup/bl_operators/node.py index 31e1aa0ff5c..032c036758d 100644 --- a/scripts/startup/bl_operators/node.py +++ b/scripts/startup/bl_operators/node.py @@ -202,7 +202,7 @@ class NODE_OT_tree_path_parent(Operator): class NodeFunctionSignatureOperator(): # Dictionary of node types with methods to get the signature signature_nodes = { - 'FunctionNodeEvaluate' : lambda node: node.signature, + 'GeometryNodeEvaluateFunction' : lambda node: node.signature, } param_type: EnumProperty( diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index 2a5b072df69..81e846dc494 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -623,8 +623,8 @@ class NODE_MT_category_GEO_FUNCTION(Menu): def draw(self, context): layout = self.layout - node_add_menu.add_node_type(layout, "FunctionNodeBind") - node_add_menu.add_node_type(layout, "FunctionNodeEvaluate") + node_add_menu.add_node_type(layout, "GeometryNodeBindFunction") + node_add_menu.add_node_type(layout, "GeometryNodeEvaluateFunction") class NODE_MT_category_GEO_LAYOUT(Menu): diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index a55e5570ebb..616fd130ece 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -974,7 +974,7 @@ class FunctionSignaturePanel(): # Dictionary of node types with methods to get the signature signature_nodes = { - 'FunctionNodeEvaluate' : lambda node: node.signature, + 'GeometryNodeEvaluateFunction' : lambda node: node.signature, } @classmethod diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 059488dbd6e..ad1d59b2ffe 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1635,6 +1635,9 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197 #define GEO_NODE_OFFSET_SDF_VOLUME 1198 #define GEO_NODE_INDEX_OF_NEAREST 1199 +/* 1199 is last valid geometry node type ID, continuing at 11000. */ +#define GEO_NODE_BIND_FUNCTION 11000 +#define GEO_NODE_EVALUATE_FUNCTION 11001 /** \} */ @@ -1661,8 +1664,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define FN_NODE_INPUT_INT 1220 #define FN_NODE_SEPARATE_COLOR 1221 #define FN_NODE_COMBINE_COLOR 1222 -#define FN_NODE_BIND 1223 -#define FN_NODE_EVALUATE 1224 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a2361943261..3986bc73b1f 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -223,8 +223,8 @@ bool nodeFunctionParameterFindNode(bNodeTree *ntree, bNodeFunctionSignature **r_sig) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->type == FN_NODE_EVALUATE) { - NodeFunctionEvaluate *data = static_cast(node->storage); + if (node->type == GEO_NODE_EVALUATE_FUNCTION) { + NodeGeometryEvaluateFunction *data = static_cast(node->storage); if (nodeFunctionSignatureContainsParameter(&data->signature, param, nullptr)) { if (r_node) { *r_node = node; @@ -271,8 +271,8 @@ bool nodeFunctionSignatureFindNode(bNodeTree *ntree, bNode **r_node) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->type == FN_NODE_EVALUATE) { - NodeFunctionEvaluate *data = static_cast(node->storage); + if (node->type == GEO_NODE_EVALUATE_FUNCTION) { + NodeGeometryEvaluateFunction *data = static_cast(node->storage); if (sig == &data->signature) { if (r_node) { *r_node = node; @@ -970,8 +970,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); } - else if (node->type == FN_NODE_EVALUATE) { - NodeFunctionEvaluate *storage = (NodeFunctionEvaluate *)node->storage; + else if (node->type == GEO_NODE_EVALUATE_FUNCTION) { + NodeGeometryEvaluateFunction *storage = (NodeGeometryEvaluateFunction *)node->storage; BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); write_node_function_signature(writer, &storage->signature); } @@ -1186,8 +1186,8 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &storage->string); break; } - case FN_NODE_EVALUATE: { - NodeFunctionEvaluate *storage = (NodeFunctionEvaluate *)node->storage; + case GEO_NODE_EVALUATE_FUNCTION: { + NodeGeometryEvaluateFunction *storage = (NodeGeometryEvaluateFunction *)node->storage; direct_link_node_function_signature(reader, &storage->signature); break; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 873d0798119..2cf0f303ba3 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1665,10 +1665,10 @@ typedef struct bNodeFunctionSignature { #endif } bNodeFunctionSignature; -typedef struct NodeFunctionEvaluate { +typedef struct NodeGeometryEvaluateFunction { /* Expected signature of the function. */ bNodeFunctionSignature signature; -} NodeFunctionEvaluate; +} NodeGeometryEvaluateFunction; /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 8a3b718953d..d3152c87014 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5449,7 +5449,7 @@ static void def_fn_combsep_color(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } -static void def_fn_bind(StructRNA *srna) +static void def_geo_bind_function(StructRNA *srna) { PropertyRNA *prop; @@ -5464,140 +5464,11 @@ static void def_fn_bind(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNodeBind_update"); } -static void rna_def_node_function_parameter(BlenderRNA *brna) +static void def_geo_evaluate_function(StructRNA *srna) { PropertyRNA *prop; - StructRNA *srna = RNA_def_struct(brna, "NodeFunctionParameter", NULL); - RNA_def_struct_ui_text(srna, "Node Function Parameter", "Input or output declaration of a node function"); - RNA_def_struct_sdna(srna, "bNodeFunctionParameter"); - - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeFunctionParameter_name_set"); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); - - prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, node_socket_data_type_items); - RNA_def_property_ui_text(prop, "Socket Type", ""); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); - - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 4); - RNA_def_property_float_funcs(prop, "rna_NodeFunctionParameter_color_get", NULL, NULL); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Color", "Socket color"); -} - -static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, eNodeFunctionParameterType param_type) -{ - StructRNA *srna; - PropertyRNA *prop; - PropertyRNA *parm; - FunctionRNA *func; - const char *structtype = (param_type == NODE_FUNC_PARAM_IN ? "NodeFunctionSignatureInputs" : - "NodeFunctionSignatureOutputs"); - const char *uiname = (param_type == NODE_FUNC_PARAM_IN ? "Node Function Signature Inputs" : - "Node Function Signature Outputs"); - const char *active_index_sdna = (param_type == NODE_FUNC_PARAM_IN ? "active_input" : - "active_output"); - const char *active_param_get = (param_type == NODE_FUNC_PARAM_IN ? - "rna_NodeFunctionSignature_active_input_get" : - "rna_NodeFunctionSignature_active_output_get"); - const char *active_param_set = (param_type == NODE_FUNC_PARAM_IN ? - "rna_NodeFunctionSignature_active_input_set" : - "rna_NodeFunctionSignature_active_output_set"); - const char *newfunc = (param_type == NODE_FUNC_PARAM_IN ? - "rna_NodeFunctionSignature_inputs_new" : - "rna_NodeFunctionSignature_outputs_new"); - const char *removefunc = "rna_NodeFunctionSignature_params_remove"; - const char *clearfunc = (param_type == NODE_FUNC_PARAM_IN ? - "rna_NodeFunctionSignature_inputs_clear" : - "rna_NodeFunctionSignature_outputs_clear"); - const char *movefunc = (param_type == NODE_FUNC_PARAM_IN ? - "rna_NodeFunctionSignature_inputs_move" : - "rna_NodeFunctionSignature_outputs_move"); - - RNA_def_property_srna(cprop, structtype); - srna = RNA_def_struct(brna, structtype, NULL); - RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); - RNA_def_struct_ui_text(srna, uiname, "Collection of node function parameters"); - - prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, active_index_sdna); - RNA_def_property_ui_text(prop, "Active Index", "Index of the active parameter"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_NODE, NULL); - - prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "NodeFunctionParameter"); - RNA_def_property_pointer_funcs(prop, active_param_get, active_param_set, NULL, NULL); - RNA_def_property_ui_text(prop, "Active", "Active parameter"); - RNA_def_property_update(prop, NC_NODE, NULL); - - func = RNA_def_function(srna, "new", newfunc); - RNA_def_function_ui_description(func, "Add a parameter to this signature"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_enum( - func, "socket_type", node_socket_data_type_items, SOCK_FLOAT, "Type", "Data type"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - /* return value */ - parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "New parameter"); - RNA_def_function_return(func, parm); - - func = RNA_def_function(srna, "remove", removefunc); - RNA_def_function_ui_description(func, "Remove a parameter from this signature"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "The parameter to remove"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - - func = RNA_def_function(srna, "clear", clearfunc); - RNA_def_function_ui_description(func, "Remove all parameters from this collection"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); - - func = RNA_def_function(srna, "move", movefunc); - RNA_def_function_ui_description(func, "Move a parameter to another position"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); - parm = RNA_def_int( - func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the parameter to move", 0, 10000); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - parm = RNA_def_int( - func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the parameter", 0, 10000); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); -} - -static void rna_def_node_function_signature(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "NodeFunctionSignature", NULL); - RNA_def_struct_ui_text(srna, "Node Function Signature", "Declaration of inputs and outputs of a node function"); - RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); - - prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "inputs", "inputs_num"); - RNA_def_property_struct_type(prop, "NodeFunctionParameter"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Inputs", "Function inputs"); - rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_IN); - - prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "outputs", "outputs_num"); - RNA_def_property_struct_type(prop, "NodeFunctionParameter"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Outputs", "Function outputs"); - rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_OUT); -} - -static void def_fn_evaluate(StructRNA *srna) -{ - PropertyRNA *prop; - - RNA_def_struct_sdna_from(srna, "NodeFunctionEvaluate", "storage"); + RNA_def_struct_sdna_from(srna, "NodeGeometryEvaluateFunction", "storage"); prop = RNA_def_property(srna, "signature", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "signature"); @@ -11792,6 +11663,146 @@ static void rna_def_node_socket_interface(BlenderRNA *brna) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); } +static void rna_def_node_function_parameter(BlenderRNA *brna) +{ + PropertyRNA *prop; + + StructRNA *srna = RNA_def_struct(brna, "NodeFunctionParameter", NULL); + RNA_def_struct_ui_text( + srna, "Node Function Parameter", "Input or output declaration of a node function"); + RNA_def_struct_sdna(srna, "bNodeFunctionParameter"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeFunctionParameter_name_set"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); + + prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, node_socket_data_type_items); + RNA_def_property_ui_text(prop, "Socket Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeFunctionParameter_update"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_float_funcs(prop, "rna_NodeFunctionParameter_color_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Color", "Socket color"); +} + +static void rna_def_node_function_signature_api(BlenderRNA *brna, + PropertyRNA *cprop, + eNodeFunctionParameterType param_type) +{ + StructRNA *srna; + PropertyRNA *prop; + PropertyRNA *parm; + FunctionRNA *func; + const char *structtype = (param_type == NODE_FUNC_PARAM_IN ? "NodeFunctionSignatureInputs" : + "NodeFunctionSignatureOutputs"); + const char *uiname = (param_type == NODE_FUNC_PARAM_IN ? "Node Function Signature Inputs" : + "Node Function Signature Outputs"); + const char *active_index_sdna = (param_type == NODE_FUNC_PARAM_IN ? "active_input" : + "active_output"); + const char *active_param_get = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_active_input_get" : + "rna_NodeFunctionSignature_active_output_get"); + const char *active_param_set = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_active_input_set" : + "rna_NodeFunctionSignature_active_output_set"); + const char *newfunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_new" : + "rna_NodeFunctionSignature_outputs_new"); + const char *removefunc = "rna_NodeFunctionSignature_params_remove"; + const char *clearfunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_clear" : + "rna_NodeFunctionSignature_outputs_clear"); + const char *movefunc = (param_type == NODE_FUNC_PARAM_IN ? + "rna_NodeFunctionSignature_inputs_move" : + "rna_NodeFunctionSignature_outputs_move"); + + RNA_def_property_srna(cprop, structtype); + srna = RNA_def_struct(brna, structtype, NULL); + RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); + RNA_def_struct_ui_text(srna, uiname, "Collection of node function parameters"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, active_index_sdna); + RNA_def_property_ui_text(prop, "Active Index", "Index of the active parameter"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_NODE, NULL); + + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_pointer_funcs(prop, active_param_get, active_param_set, NULL, NULL); + RNA_def_property_ui_text(prop, "Active", "Active parameter"); + RNA_def_property_update(prop, NC_NODE, NULL); + + func = RNA_def_function(srna, "new", newfunc); + RNA_def_function_ui_description(func, "Add a parameter to this signature"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_enum( + func, "socket_type", node_socket_data_type_items, SOCK_FLOAT, "Type", "Data type"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return value */ + parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "New parameter"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", removefunc); + RNA_def_function_ui_description(func, "Remove a parameter from this signature"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "param", "NodeFunctionParameter", "", "The parameter to remove"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "clear", clearfunc); + RNA_def_function_ui_description(func, "Remove all parameters from this collection"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + + func = RNA_def_function(srna, "move", movefunc); + RNA_def_function_ui_description(func, "Move a parameter to another position"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + parm = RNA_def_int(func, + "from_index", + -1, + 0, + INT_MAX, + "From Index", + "Index of the parameter to move", + 0, + 10000); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int( + func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the parameter", 0, 10000); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); +} + +static void rna_def_node_function_signature(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "NodeFunctionSignature", NULL); + RNA_def_struct_ui_text( + srna, "Node Function Signature", "Declaration of inputs and outputs of a node function"); + RNA_def_struct_sdna(srna, "bNodeFunctionSignature"); + + prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "inputs", "inputs_num"); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Inputs", "Function inputs"); + rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_IN); + + prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "outputs", "outputs_num"); + RNA_def_property_struct_type(prop, "NodeFunctionParameter"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Outputs", "Function outputs"); + rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_OUT); +} + static void rna_def_node_socket_float(BlenderRNA *brna, const char *idname, const char *interface_idname, diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index df611a3166f..b0be6dc0e28 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -279,12 +279,11 @@ DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_CO 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", "") -DefNode(FunctionNode, FN_NODE_BIND, def_fn_bind, "BIND", Bind, "Bind", "") -DefNode(FunctionNode, FN_NODE_EVALUATE, def_fn_evaluate, "EVALUATE", Evaluate, "Evaluate", "") DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "Retrieve the number of elements in a geometry for each attribute domain") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC",AttributeStatistic, "Attribute Statistic","Calculate statistics about a data set from a field evaluated on a geometry") +DefNode(GeometryNode, GEO_NODE_BIND_FUNCTION, def_geo_bind_function, "BIND_FUNCTION", BindFunction, "Bind Function", "") DefNode(GeometryNode, GEO_NODE_BLUR_ATTRIBUTE, def_geo_blur_attribute, "BLUR_ATTRIBUTE", BlurAttribute, "Blur Attribute", "Mix attribute values of neighboring elements") DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "Calculate the limits of a geometry's positions and generate a box mesh with those dimensions") DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture,"CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "Store the result of a field on a geometry and output the data as a node socket. Allows remembering or interpolating data as the geometry changes, such as positions before deformation") @@ -318,6 +317,7 @@ DefNode(GeometryNode, GEO_NODE_EDGE_PATHS_TO_CURVES, 0, "EDGE_PATHS_TO_CURVES", DefNode(GeometryNode, GEO_NODE_EDGE_PATHS_TO_SELECTION, 0, "EDGE_PATHS_TO_SELECTION", EdgePathsToSelection, "Edge Paths to Selection", "") DefNode(GeometryNode, GEO_NODE_EDGES_TO_FACE_GROUPS, 0, "EDGES_TO_FACE_GROUPS", EdgesToFaceGroups, "Edges to Face Groups", "Group faces into regions surrounded by the selected boundary edges") DefNode(GeometryNode, GEO_NODE_EVALUATE_AT_INDEX, def_geo_evaluate_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Evaluate at Index", "Retrieve data of other elements in the context's geometry") +DefNode(GeometryNode, GEO_NODE_EVALUATE_FUNCTION, def_geo_evaluate_function, "EVALUATE_FUNCTION", EvaluateFunction, "Evaluate Function", "") DefNode(GeometryNode, GEO_NODE_EVALUATE_ON_DOMAIN, def_geo_evaluate_on_domain, "FIELD_ON_DOMAIN", FieldOnDomain, "Evaluate on Domain", "Retrieve values from a field on a different domain besides the domain from the context") DefNode(GeometryNode, GEO_NODE_EXTRUDE_MESH, def_geo_extrude_mesh, "EXTRUDE_MESH", ExtrudeMesh, "Extrude Mesh", "Generate new vertices, edges, or faces from selected elements and move them based on an offset while keeping them connected by their boundary") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "Generate a mesh on the XY plane with faces on the inside of input curves") diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt index 045abed94a5..756178ffe5a 100644 --- a/source/blender/nodes/function/CMakeLists.txt +++ b/source/blender/nodes/function/CMakeLists.txt @@ -21,11 +21,9 @@ set(INC_SYS set(SRC nodes/node_fn_align_euler_to_vector.cc - nodes/node_fn_bind.cc nodes/node_fn_boolean_math.cc nodes/node_fn_combine_color.cc nodes/node_fn_compare.cc - nodes/node_fn_evaluate.cc nodes/node_fn_float_to_int.cc nodes/node_fn_input_bool.cc nodes/node_fn_input_color.cc diff --git a/source/blender/nodes/function/node_function_register.cc b/source/blender/nodes/function/node_function_register.cc index 62feda8a0ee..8c5ce489832 100644 --- a/source/blender/nodes/function/node_function_register.cc +++ b/source/blender/nodes/function/node_function_register.cc @@ -7,11 +7,9 @@ void register_function_nodes() { register_node_type_fn_align_euler_to_vector(); - register_node_type_fn_bind(); register_node_type_fn_boolean_math(); register_node_type_fn_combine_color(); register_node_type_fn_compare(); - register_node_type_fn_evaluate(); register_node_type_fn_float_to_int(); register_node_type_fn_input_bool(); register_node_type_fn_input_color(); diff --git a/source/blender/nodes/function/node_function_register.hh b/source/blender/nodes/function/node_function_register.hh index b78548fb221..7f3e7c1cd8c 100644 --- a/source/blender/nodes/function/node_function_register.hh +++ b/source/blender/nodes/function/node_function_register.hh @@ -3,11 +3,9 @@ #pragma once void register_node_type_fn_align_euler_to_vector(); -void register_node_type_fn_bind(); void register_node_type_fn_boolean_math(); void register_node_type_fn_combine_color(); void register_node_type_fn_compare(); -void register_node_type_fn_evaluate(); void register_node_type_fn_float_to_int(); void register_node_type_fn_input_bool(); void register_node_type_fn_input_color(); diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 93c7165e839..1adcab7f9ec 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRC nodes/node_geo_attribute_capture.cc nodes/node_geo_attribute_domain_size.cc nodes/node_geo_attribute_statistic.cc + nodes/node_geo_bind_function.cc nodes/node_geo_blur_attribute.cc nodes/node_geo_boolean.cc nodes/node_geo_bounding_box.cc @@ -71,6 +72,7 @@ set(SRC nodes/node_geo_edge_split.cc nodes/node_geo_edges_to_face_groups.cc nodes/node_geo_evaluate_at_index.cc + nodes/node_geo_evaluate_function.cc nodes/node_geo_evaluate_on_domain.cc nodes/node_geo_extrude_mesh.cc nodes/node_geo_flip_faces.cc diff --git a/source/blender/nodes/geometry/node_geometry_register.cc b/source/blender/nodes/geometry/node_geometry_register.cc index ef78585a132..ac2ca41a9f9 100644 --- a/source/blender/nodes/geometry/node_geometry_register.cc +++ b/source/blender/nodes/geometry/node_geometry_register.cc @@ -14,6 +14,7 @@ void register_geometry_nodes() register_node_type_geo_attribute_capture(); register_node_type_geo_attribute_domain_size(); register_node_type_geo_attribute_statistic(); + register_node_type_geo_bind_function(); register_node_type_geo_blur_attribute(); register_node_type_geo_boolean(); register_node_type_geo_bounding_box(); @@ -55,6 +56,7 @@ void register_geometry_nodes() register_node_type_geo_edge_split(); register_node_type_geo_edges_to_face_groups(); register_node_type_geo_evaluate_at_index(); + register_node_type_geo_evaluate_function(); register_node_type_geo_evaluate_on_domain(); register_node_type_geo_extrude_mesh(); register_node_type_geo_flip_faces(); diff --git a/source/blender/nodes/geometry/node_geometry_register.hh b/source/blender/nodes/geometry/node_geometry_register.hh index d3a77f9bb93..dd8cbe73019 100644 --- a/source/blender/nodes/geometry/node_geometry_register.hh +++ b/source/blender/nodes/geometry/node_geometry_register.hh @@ -11,6 +11,7 @@ void register_node_type_geo_attribute_capture(); void register_node_type_geo_attribute_domain_size(); void register_node_type_geo_attribute_separate_xyz(); void register_node_type_geo_attribute_statistic(); +void register_node_type_geo_bind_function(); void register_node_type_geo_blur_attribute(); void register_node_type_geo_boolean(); void register_node_type_geo_bounding_box(); @@ -52,6 +53,7 @@ void register_node_type_geo_edge_paths_to_selection(); void register_node_type_geo_edge_split(); void register_node_type_geo_edges_to_face_groups(); void register_node_type_geo_evaluate_at_index(); +void register_node_type_geo_evaluate_function(); void register_node_type_geo_evaluate_on_domain(); void register_node_type_geo_extrude_mesh(); void register_node_type_geo_flip_faces(); diff --git a/source/blender/nodes/function/nodes/node_fn_bind.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc similarity index 64% rename from source/blender/nodes/function/nodes/node_fn_bind.cc rename to source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index e326fca0c53..27d95283777 100644 --- a/source/blender/nodes/function/nodes/node_fn_bind.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -11,10 +11,9 @@ #include "NOD_node_declaration.hh" #include "node_common.h" -#include "node_function_util.hh" -#include "node_function_util.hh" +#include "node_geometry_util.hh" -namespace blender::nodes::node_fn_bind_cc { +namespace blender::nodes::node_geo_bind_function_cc { static void node_declare(const bNodeTree &node_tree, const bNode &node, @@ -50,17 +49,31 @@ static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr) layout, C, ptr, "node_tree", nullptr, nullptr, nullptr, UI_TEMPLATE_ID_FILTER_ALL, nullptr); } -} // namespace blender::nodes::node_fn_bind_cc - -void register_node_type_fn_bind() +static void node_geo_exec(GeoNodeExecParams params) { - namespace file_ns = blender::nodes::node_fn_bind_cc; + //GeometrySet geometry_set = params.extract_input("Curve"); + + //const NodeGeometryCurveFill &storage = node_storage(params.node()); + //const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode; + + //geometry_set.modify_geometry_sets( + // [&](GeometrySet &geometry_set) { curve_fill_calculate(geometry_set, mode); }); + + //params.set_output("Mesh", std::move(geometry_set)); +} + +} // namespace blender::nodes::node_geo_bind_function_cc + +void register_node_type_geo_bind_function() +{ + namespace file_ns = blender::nodes::node_geo_bind_function_cc; static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_BIND, "Bind", NODE_CLASS_GROUP); + geo_node_type_base(&ntype, GEO_NODE_BIND_FUNCTION, "Bind Function", NODE_CLASS_GROUP); ntype.declare_dynamic = file_ns::node_declare; ntype.poll_instance = node_group_poll_instance; ntype.draw_buttons = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_evaluate.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc similarity index 64% rename from source/blender/nodes/function/nodes/node_fn_evaluate.cc rename to source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc index b6727d82455..33bd6fad722 100644 --- a/source/blender/nodes/function/nodes/node_fn_evaluate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc @@ -10,11 +10,11 @@ #include "UI_resources.h" #include "NOD_common.h" -#include "node_function_util.hh" +#include "node_geometry_util.hh" -namespace blender::nodes::node_fn_evaluate_cc { +namespace blender::nodes::node_geo_evaluate_function_cc { -NODE_STORAGE_FUNCS(NodeFunctionEvaluate) +NODE_STORAGE_FUNCS(NodeGeometryEvaluateFunction) static void node_declare(const bNodeTree &node_tree, const bNode &node, @@ -24,7 +24,7 @@ static void node_declare(const bNodeTree &node_tree, if (node.storage == nullptr) { return; } - const NodeFunctionEvaluate &storage = node_storage(node); + const NodeGeometryEvaluateFunction &storage = node_storage(node); NodeDeclarationBuilder builder(r_declaration); builder.add_input(N_("Function")); @@ -35,7 +35,7 @@ static void node_declare(const bNodeTree &node_tree, static void node_init(bNodeTree * /*tree*/, bNode *node) { - NodeFunctionEvaluate *data = MEM_cnew(__func__); + NodeGeometryEvaluateFunction *data = MEM_cnew(__func__); node->storage = data; } @@ -47,20 +47,20 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) { } -} // namespace blender::nodes::node_fn_evaluate_cc +} // namespace blender::nodes::node_geo_evaluate_function_cc -void register_node_type_fn_evaluate() +void register_node_type_geo_evaluate_function() { - namespace file_ns = blender::nodes::node_fn_evaluate_cc; + namespace file_ns = blender::nodes::node_geo_evaluate_function_cc; static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_EVALUATE, "Evaluate", NODE_CLASS_GROUP); + geo_node_type_base(&ntype, GEO_NODE_EVALUATE_FUNCTION, "Evaluate Function", NODE_CLASS_GROUP); ntype.declare_dynamic = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; ntype.initfunc = file_ns::node_init; ntype.updatefunc = file_ns::node_update; node_type_storage( - &ntype, "NodeFunctionEvaluate", node_free_standard_storage, node_copy_standard_storage); + &ntype, "NodeGeometryEvaluateFunction", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); } -- 2.30.2 From 5cf33e914d74c59fc58fc1adee3a345a8972213b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sat, 15 Apr 2023 23:15:53 +0200 Subject: [PATCH 17/33] Exec function for the bind node that stores a graph reference in the output. --- source/blender/functions/FN_closure.hh | 11 +++-- source/blender/functions/intern/closure.cc | 6 ++- .../geometry/nodes/node_geo_bind_function.cc | 19 ++++--- .../nodes/node_geo_evaluate_function.cc | 2 + .../intern/geometry_nodes_lazy_function.cc | 49 +++++++++++++++++++ 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/source/blender/functions/FN_closure.hh b/source/blender/functions/FN_closure.hh index 16b58e94ba1..577926b1008 100644 --- a/source/blender/functions/FN_closure.hh +++ b/source/blender/functions/FN_closure.hh @@ -8,19 +8,20 @@ #include "BLI_cpp_type.hh" -#include "FN_lazy_function.hh" -#include "FN_lazy_function_graph_executor.hh" - namespace blender::fn { +namespace lazy_function { +class Graph; +} + class Closure { private: - std::shared_ptr function_; + const lazy_function::Graph *graph_; public: Closure() = default; Closure(const Closure &other) = default; - explicit Closure(const lf::GraphExecutor &function); + explicit Closure(const lazy_function::Graph &graph); ~Closure() = default; Closure &operator=(const Closure &other) = default; diff --git a/source/blender/functions/intern/closure.cc b/source/blender/functions/intern/closure.cc index 24d7c8da7c3..c8913024598 100644 --- a/source/blender/functions/intern/closure.cc +++ b/source/blender/functions/intern/closure.cc @@ -6,10 +6,12 @@ #include "FN_closure.hh" +#include "FN_lazy_function_graph.hh" + namespace blender::fn { -Closure::Closure(const lf::GraphExecutor &function) - : function_(std::make_shared(function)) +Closure::Closure(const lf::Graph &graph) + : graph_(&graph) { } diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index 27d95283777..f260170a52f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -4,6 +4,9 @@ #include "BKE_node_runtime.hh" +#include "FN_closure.hh" +#include "FN_lazy_function_graph.hh" + #include "UI_interface.h" #include "UI_resources.h" @@ -51,15 +54,17 @@ static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr) static void node_geo_exec(GeoNodeExecParams params) { - //GeometrySet geometry_set = params.extract_input("Curve"); + if (params.node().id) { + const bNodeTree &bind_tree = *reinterpret_cast(params.node().id); + const std::unique_ptr &lf_graph_info_ptr = + bind_tree.runtime->geometry_nodes_lazy_function_graph_info; + BLI_assert(lf_graph_info_ptr); - //const NodeGeometryCurveFill &storage = node_storage(params.node()); - //const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode; + fn::Closure closure(lf_graph_info_ptr->graph); + params.set_output("Function", std::move(closure)); + } - //geometry_set.modify_geometry_sets( - // [&](GeometrySet &geometry_set) { curve_fill_calculate(geometry_set, mode); }); - - //params.set_output("Mesh", std::move(geometry_set)); + params.set_default_remaining_outputs(); } } // namespace blender::nodes::node_geo_bind_function_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc index 33bd6fad722..5ec7c3b7f1e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc @@ -4,6 +4,8 @@ #include "BLI_math_vector.h" #include "BLI_string.h" +#include "FN_closure.hh" + #include "RNA_enum_types.h" #include "UI_interface.h" diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 1761dbda733..fc9c1b7fce0 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1507,6 +1507,10 @@ struct GeometryNodesLazyFunctionGraphBuilder { this->handle_switch_node(*bnode); break; } + case GEO_NODE_BIND_FUNCTION: { + this->handle_bind_function_node(*bnode); + break; + } default: { if (node_type->geometry_node_execute) { this->handle_geometry_node(*bnode); @@ -1805,6 +1809,51 @@ struct GeometryNodesLazyFunctionGraphBuilder { } } + void handle_bind_function_node(const bNode &bnode) + { + const bNodeTree *group_btree = reinterpret_cast(bnode.id); + if (group_btree == nullptr) { + return; + } + const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = + ensure_geometry_nodes_lazy_function_graph(*group_btree); + if (group_lf_graph_info == nullptr) { + return; + } + + //auto lazy_function = std::make_unique(bnode, *group_lf_graph_info); + //lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); + + //for (const int i : bnode.input_sockets().index_range()) { + // const bNodeSocket &bsocket = bnode.input_socket(i); + // BLI_assert(!bsocket.is_multi_input()); + // lf::InputSocket &lf_socket = lf_node.input(i); + // input_socket_map_.add(&bsocket, &lf_socket); + // mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + //} + //for (const int i : bnode.output_sockets().index_range()) { + // const bNodeSocket &bsocket = bnode.output_socket(i); + // lf::OutputSocket &lf_socket = lf_node.output(i); + // output_socket_map_.add_new(&bsocket, &lf_socket); + // mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + //} + //mapping_->group_node_map.add(&bnode, &lf_node); + //lf_graph_info_->num_inline_nodes_approximate += + // group_lf_graph_info->num_inline_nodes_approximate; + //static const bool static_false = false; + //for (const int i : lazy_function->lf_input_for_output_bsocket_usage_.values()) { + // lf_node.input(i).set_default_value(&static_false); + // socket_usage_inputs_.add(&lf_node.input(i)); + //} + ///* Keep track of attribute set inputs that need to be populated later. */ + //for (const auto [output_index, lf_input_index] : + // lazy_function->lf_input_for_attribute_propagation_to_output_.items()) { + // attribute_set_propagation_map_.add(&bnode.output_socket(output_index), + // &lf_node.input(lf_input_index)); + //} + //lf_graph_info_->functions.append(std::move(lazy_function)); + } + void handle_undefined_node(const bNode &bnode) { auto lazy_function = std::make_unique( -- 2.30.2 From 4a2b5a30e41e9357a008057c7611c17efa85c628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 16 Apr 2023 09:06:14 +0200 Subject: [PATCH 18/33] Fix crash on load: skip socket verification of node has a bNodeTree dependency. --- source/blender/blenkernel/BKE_node_runtime.hh | 7 +++++++ source/blender/blenkernel/intern/node.cc | 4 +--- source/blender/makesdna/DNA_node_types.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index 17f8665c1b9..35a24574754 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -634,6 +634,13 @@ inline bool bNode::is_group_output() const return this->type == NODE_GROUP_OUTPUT; } +inline bool bNode::can_verify_sockets_on_read() const +{ + /* Don't update node groups here because they may depend on other node groups which are not + * fully versioned yet and don't have `typeinfo` pointers set. */ + return !is_group() && !ELEM(this->type, GEO_NODE_BIND_FUNCTION); +} + inline blender::Span bNode::internal_links() const { return this->runtime->internal_links; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 3986bc73b1f..31a82f2a46e 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -1340,9 +1340,7 @@ void ntreeBlendReadLib(BlendLibReader *reader, bNodeTree *ntree) * to match the static layout. */ if (!BLO_read_lib_is_undo(reader)) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - /* Don't update node groups here because they may depend on other node groups which are not - * fully versioned yet and don't have `typeinfo` pointers set. */ - if (!node->is_group()) { + if (node->can_verify_sockets_on_read()) { node_verify_sockets(ntree, node, false); } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 2cf0f303ba3..3e681c1238a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -383,6 +383,7 @@ typedef struct bNode { bool is_group() const; bool is_group_input() const; bool is_group_output() const; + bool can_verify_sockets_on_read() const; const blender::nodes::NodeDeclaration *declaration() const; /** A span containing all internal links when the node is muted. */ blender::Span internal_links() const; -- 2.30.2 From 419fb98fd27ebbb705a8139562351ab0e4f8b3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 16 Apr 2023 09:53:12 +0200 Subject: [PATCH 19/33] Ensure the bind node exec function is registered. --- .../intern/geometry_nodes_lazy_function.cc | 40 ++----------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index fc9c1b7fce0..a013178f3e6 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1815,43 +1815,11 @@ struct GeometryNodesLazyFunctionGraphBuilder { if (group_btree == nullptr) { return; } - const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info = - ensure_geometry_nodes_lazy_function_graph(*group_btree); - if (group_lf_graph_info == nullptr) { - return; - } + /* Tree graph is needed by the bind node. */ + ensure_geometry_nodes_lazy_function_graph(*group_btree); - //auto lazy_function = std::make_unique(bnode, *group_lf_graph_info); - //lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); - - //for (const int i : bnode.input_sockets().index_range()) { - // const bNodeSocket &bsocket = bnode.input_socket(i); - // BLI_assert(!bsocket.is_multi_input()); - // lf::InputSocket &lf_socket = lf_node.input(i); - // input_socket_map_.add(&bsocket, &lf_socket); - // mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); - //} - //for (const int i : bnode.output_sockets().index_range()) { - // const bNodeSocket &bsocket = bnode.output_socket(i); - // lf::OutputSocket &lf_socket = lf_node.output(i); - // output_socket_map_.add_new(&bsocket, &lf_socket); - // mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); - //} - //mapping_->group_node_map.add(&bnode, &lf_node); - //lf_graph_info_->num_inline_nodes_approximate += - // group_lf_graph_info->num_inline_nodes_approximate; - //static const bool static_false = false; - //for (const int i : lazy_function->lf_input_for_output_bsocket_usage_.values()) { - // lf_node.input(i).set_default_value(&static_false); - // socket_usage_inputs_.add(&lf_node.input(i)); - //} - ///* Keep track of attribute set inputs that need to be populated later. */ - //for (const auto [output_index, lf_input_index] : - // lazy_function->lf_input_for_attribute_propagation_to_output_.items()) { - // attribute_set_propagation_map_.add(&bnode.output_socket(output_index), - // &lf_node.input(lf_input_index)); - //} - //lf_graph_info_->functions.append(std::move(lazy_function)); + /* Continue as regular node. */ + handle_geometry_node(bnode); } void handle_undefined_node(const bNode &bnode) -- 2.30.2 From 91ff2c10d979ba41b3914d968abfa73757ff5135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 16 Apr 2023 22:49:18 +0200 Subject: [PATCH 20/33] WIP: adding a lazy function for evaluating function sockets. --- .../nodes/node_geo_evaluate_function.cc | 6 + .../intern/geometry_nodes_lazy_function.cc | 225 ++++++++++++++++++ 2 files changed, 231 insertions(+) diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc index 5ec7c3b7f1e..78790aef7ac 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc @@ -49,6 +49,11 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) { } +static void node_geo_exec(GeoNodeExecParams params) +{ + params.set_default_remaining_outputs(); +} + } // namespace blender::nodes::node_geo_evaluate_function_cc void register_node_type_geo_evaluate_function() @@ -64,5 +69,6 @@ void register_node_type_geo_evaluate_function() ntype.updatefunc = file_ns::node_update; node_type_storage( &ntype, "NodeGeometryEvaluateFunction", node_free_standard_storage, node_copy_standard_storage); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index a013178f3e6..f851c8236ab 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1140,6 +1140,192 @@ class LazyFunctionForSwitchSocketUsage : public lf::LazyFunction { } }; +/** + * Evaluates the function input and then executes it. + */ +class LazyFunctionForEvaluateFunctionNode : public LazyFunction { + private: + const bNode &eval_node_; + //bool has_many_nodes_ = false; + std::optional lf_logger_; + std::optional lf_side_effect_provider_; + std::optional graph_executor_; + + struct Storage { + void *graph_executor_storage = nullptr; + /* To avoid computing the hash more than once. */ + std::optional context_hash_cache; + }; + + public: + /** + * For every input bsocket there is a corresponding boolean output that indicates whether that + * input is used. + */ + Map lf_output_for_input_bsocket_usage_; + /** + * For every output bsocket there is a corresponding boolean input that indicates whether the + * output is used. + */ + Map lf_input_for_output_bsocket_usage_; + /** + * For every geometry output that can propagate attributes from an input, there is an attribute + * set input. It indicates which attributes should be propagated to the output. + */ + Map lf_input_for_attribute_propagation_to_output_; + + LazyFunctionForEvaluateFunctionNode(const bNode &eval_node) : eval_node_(eval_node) + { + debug_name_ = eval_node.name; + allow_missing_requested_inputs_ = true; + + Vector tmp_inputs; + Vector tmp_outputs; + lazy_function_interface_from_node(eval_node, tmp_inputs, tmp_outputs, inputs_, outputs_); + } + + void execute_impl(lf::Params ¶ms, const lf::Context &context) const override + { + + // has_many_nodes_ = lf_graph_info.num_inline_nodes_approximate > 1000; + + Vector graph_inputs; + /* Add inputs that also exist on the bnode. */ + graph_inputs.extend(lf_graph_info.mapping.group_input_sockets); + + /* Add a boolean input for every output bsocket that indicates whether that socket is used. */ + for (const int i : group_node.output_sockets().index_range()) { + lf_input_for_output_bsocket_usage_.add_new( + i, + graph_inputs.append_and_get_index(lf_graph_info.mapping.group_output_used_sockets[i])); + inputs_.append_as("Output is Used", CPPType::get(), lf::ValueUsage::Maybe); + } + graph_inputs.extend(lf_graph_info.mapping.group_output_used_sockets); + + /* Add an attribute set input for every output geometry socket that can propagate attributes + * from inputs. */ + for (auto [output_index, lf_socket] : + lf_graph_info.mapping.attribute_set_by_geometry_output.items()) { + const int lf_index = inputs_.append_and_get_index_as( + "Attribute Set", CPPType::get(), lf::ValueUsage::Maybe); + graph_inputs.append(lf_socket); + lf_input_for_attribute_propagation_to_output_.add(output_index, lf_index); + } + + Vector graph_outputs; + /* Add outputs that also exist on the bnode. */ + graph_outputs.extend(lf_graph_info.mapping.standard_group_output_sockets); + /* Add a boolean output for every input bsocket that indicates whether that socket is used. */ + for (const int i : group_node.input_sockets().index_range()) { + const InputUsageHint &input_usage_hint = lf_graph_info.mapping.group_input_usage_hints[i]; + if (input_usage_hint.type == InputUsageHintType::DynamicSocket) { + const lf::InputSocket *lf_socket = lf_graph_info.mapping.group_input_usage_sockets[i]; + lf_output_for_input_bsocket_usage_.add_new(i, + graph_outputs.append_and_get_index(lf_socket)); + outputs_.append_as("Input is Used", CPPType::get()); + } + } + + lf_logger_.emplace(lf_graph_info); + lf_side_effect_provider_.emplace(); + graph_executor_.emplace(lf_graph_info.graph, + std::move(graph_inputs), + std::move(graph_outputs), + &*lf_logger_, + &*lf_side_effect_provider_); + + GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); + BLI_assert(user_data != nullptr); + + //if (has_many_nodes_) { + // /* If the called node group has many nodes, it's likely that executing it takes a while even + // * if every individual node is very small. */ + // lazy_threading::send_hint(); + //} + + Storage *storage = static_cast(context.storage); + + /* The compute context changes when entering a node group. */ + bke::NodeGroupComputeContext compute_context{ + user_data->compute_context, group_node_.identifier, storage->context_hash_cache}; + storage->context_hash_cache = compute_context.hash(); + + GeoNodesLFUserData group_user_data = *user_data; + group_user_data.compute_context = &compute_context; + if (user_data->modifier_data->socket_log_contexts) { + group_user_data.log_socket_values = user_data->modifier_data->socket_log_contexts->contains( + compute_context.hash()); + } + + lf::Context group_context = context; + group_context.user_data = &group_user_data; + group_context.storage = storage->graph_executor_storage; + + graph_executor_->execute(params, group_context); + } + + void *init_storage(LinearAllocator<> &allocator) const override + { + Storage *s = allocator.construct().release(); + s->graph_executor_storage = graph_executor_->init_storage(allocator); + return s; + } + + void destruct_storage(void *storage) const override + { + Storage *s = static_cast(storage); + graph_executor_->destruct_storage(s->graph_executor_storage); + std::destroy_at(s); + } + + std::string name() const override + { + std::stringstream ss; + ss << "Group '" << (group_node_.id->name + 2) << "' (" << group_node_.name << ")"; + return ss.str(); + } + + std::string input_name(const int i) const override + { + if (i < group_node_.input_sockets().size()) { + return group_node_.input_socket(i).name; + } + for (const auto [bsocket_index, lf_socket_index] : + lf_input_for_output_bsocket_usage_.items()) { + if (i == lf_socket_index) { + std::stringstream ss; + ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used"; + return ss.str(); + } + } + for (const auto [bsocket_index, lf_index] : + lf_input_for_attribute_propagation_to_output_.items()) { + if (i == lf_index) { + std::stringstream ss; + ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'"; + return ss.str(); + } + } + return inputs_[i].debug_name; + } + + std::string output_name(const int i) const override + { + if (i < group_node_.output_sockets().size()) { + return group_node_.output_socket(i).name; + } + for (const auto [bsocket_index, lf_socket_index] : + lf_output_for_input_bsocket_usage_.items()) { + if (i == lf_socket_index) { + std::stringstream ss; + ss << "'" << group_node_.input_socket(bsocket_index).name << "' input is used"; + return ss.str(); + } + } + return outputs_[i].debug_name; + } +}; + /** * Takes a field as input and extracts the set of anonymous attributes that it references. */ @@ -1511,6 +1697,10 @@ struct GeometryNodesLazyFunctionGraphBuilder { this->handle_bind_function_node(*bnode); break; } + case GEO_NODE_EVALUATE_FUNCTION: { + this->handle_evaluate_function_node(*bnode); + break; + } default: { if (node_type->geometry_node_execute) { this->handle_geometry_node(*bnode); @@ -1822,6 +2012,41 @@ struct GeometryNodesLazyFunctionGraphBuilder { handle_geometry_node(bnode); } + void handle_evaluate_function_node(const bNode &bnode) + { + auto lazy_function = std::make_unique(bnode); + lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); + + for (const int i : bnode.input_sockets().index_range()) { + const bNodeSocket &bsocket = bnode.input_socket(i); + BLI_assert(!bsocket.is_multi_input()); + lf::InputSocket &lf_socket = lf_node.input(i); + input_socket_map_.add(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + } + for (const int i : bnode.output_sockets().index_range()) { + const bNodeSocket &bsocket = bnode.output_socket(i); + lf::OutputSocket &lf_socket = lf_node.output(i); + output_socket_map_.add_new(&bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + } + mapping_->group_node_map.add(&bnode, &lf_node); + //lf_graph_info_->num_inline_nodes_approximate += + // group_lf_graph_info->num_inline_nodes_approximate; + static const bool static_false = false; + for (const int i : lazy_function->lf_input_for_output_bsocket_usage_.values()) { + lf_node.input(i).set_default_value(&static_false); + socket_usage_inputs_.add(&lf_node.input(i)); + } + /* Keep track of attribute set inputs that need to be populated later. */ + for (const auto [output_index, lf_input_index] : + lazy_function->lf_input_for_attribute_propagation_to_output_.items()) { + attribute_set_propagation_map_.add(&bnode.output_socket(output_index), + &lf_node.input(lf_input_index)); + } + lf_graph_info_->functions.append(std::move(lazy_function)); + } + void handle_undefined_node(const bNode &bnode) { auto lazy_function = std::make_unique( -- 2.30.2 From 132bf55c481955aa160792c1abe92e586ccf4a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 17 Apr 2023 08:59:27 +0200 Subject: [PATCH 21/33] Moved closure to the nodes module so it can store the graph info. --- source/blender/functions/CMakeLists.txt | 2 - source/blender/functions/FN_closure.hh | 31 ------------ source/blender/functions/intern/closure.cc | 18 ------- source/blender/nodes/CMakeLists.txt | 2 + source/blender/nodes/NOD_closure.hh | 31 ++++++++++++ source/blender/nodes/intern/closure.cc | 23 +++++++++ .../intern/geometry_nodes_lazy_function.cc | 50 +++++++++++-------- source/blender/nodes/intern/node_socket.cc | 2 +- 8 files changed, 86 insertions(+), 73 deletions(-) delete mode 100644 source/blender/functions/FN_closure.hh delete mode 100644 source/blender/functions/intern/closure.cc create mode 100644 source/blender/nodes/NOD_closure.hh create mode 100644 source/blender/nodes/intern/closure.cc diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index b2237f333a8..54f67122907 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -11,7 +11,6 @@ set(INC_SYS ) set(SRC - intern/closure.cc intern/cpp_types.cc intern/field.cc intern/field_cpp_type.cc @@ -27,7 +26,6 @@ set(SRC intern/multi_function_procedure_executor.cc intern/multi_function_procedure_optimization.cc - FN_closure.hh FN_field.hh FN_field_cpp_type.hh FN_field_cpp_type_make.hh diff --git a/source/blender/functions/FN_closure.hh b/source/blender/functions/FN_closure.hh deleted file mode 100644 index 577926b1008..00000000000 --- a/source/blender/functions/FN_closure.hh +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup fn - */ - -#include "BLI_cpp_type.hh" - -namespace blender::fn { - -namespace lazy_function { -class Graph; -} - -class Closure { - private: - const lazy_function::Graph *graph_; - - public: - Closure() = default; - Closure(const Closure &other) = default; - explicit Closure(const lazy_function::Graph &graph); - ~Closure() = default; - - Closure &operator=(const Closure &other) = default; -}; - - -} // namespace blender::fn diff --git a/source/blender/functions/intern/closure.cc b/source/blender/functions/intern/closure.cc deleted file mode 100644 index c8913024598..00000000000 --- a/source/blender/functions/intern/closure.cc +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup fn - */ - -#include "FN_closure.hh" - -#include "FN_lazy_function_graph.hh" - -namespace blender::fn { - -Closure::Closure(const lf::Graph &graph) - : graph_(&graph) -{ -} - -} // namespace blender::fn diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 29212a6c246..e4575ce7eea 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -40,6 +40,7 @@ set(INC set(SRC intern/add_node_search.cc + intern/closure.cc intern/derived_node_tree.cc intern/geometry_nodes_lazy_function.cc intern/geometry_nodes_log.cc @@ -56,6 +57,7 @@ set(SRC intern/socket_search_link.cc NOD_add_node_search.hh + NOD_closure.hh NOD_common.h NOD_composite.h NOD_derived_node_tree.hh diff --git a/source/blender/nodes/NOD_closure.hh b/source/blender/nodes/NOD_closure.hh new file mode 100644 index 00000000000..061566cbc0b --- /dev/null +++ b/source/blender/nodes/NOD_closure.hh @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup nodes + */ + +#include "BLI_cpp_type.hh" + +namespace blender::nodes { + +struct GeometryNodesLazyFunctionGraphInfo; + +class Closure { + private: + const GeometryNodesLazyFunctionGraphInfo *lf_graph_info_; + + public: + Closure() = default; + Closure(const Closure &other) = default; + explicit Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info); + ~Closure() = default; + + Closure &operator=(const Closure &other) = default; + + const GeometryNodesLazyFunctionGraphInfo *lf_graph_info() const; +}; + + +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc new file mode 100644 index 00000000000..4c228ceb900 --- /dev/null +++ b/source/blender/nodes/intern/closure.cc @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup fn + */ + +#include "NOD_closure.hh" + +#include "NOD_geometry_nodes_lazy_function.hh" + +namespace blender::nodes { + +Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info) + : lf_graph_info_(&lf_graph_info) +{ +} + +const GeometryNodesLazyFunctionGraphInfo *Closure::lf_graph_info() const +{ + return *lf_graph_info_; +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index f851c8236ab..3435108fd71 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -13,6 +13,7 @@ * complexity. So far, this does not seem to be a performance issue. */ +#include "NOD_closure.hh" #include "NOD_geometry_exec.hh" #include "NOD_geometry_nodes_lazy_function.hh" #include "NOD_multi_function.hh" @@ -1158,21 +1159,6 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { }; public: - /** - * For every input bsocket there is a corresponding boolean output that indicates whether that - * input is used. - */ - Map lf_output_for_input_bsocket_usage_; - /** - * For every output bsocket there is a corresponding boolean input that indicates whether the - * output is used. - */ - Map lf_input_for_output_bsocket_usage_; - /** - * For every geometry output that can propagate attributes from an input, there is an attribute - * set input. It indicates which attributes should be propagated to the output. - */ - Map lf_input_for_attribute_propagation_to_output_; LazyFunctionForEvaluateFunctionNode(const bNode &eval_node) : eval_node_(eval_node) { @@ -1186,6 +1172,11 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { void execute_impl(lf::Params ¶ms, const lf::Context &context) const override { + const Closure *closure = params.get_input(0); + if (!closure->lf_graph_info()) { + return; + } + const GeometryNodesLazyFunctionGraphInfo &lf_graph_info = *closure->lf_graph_info(); // has_many_nodes_ = lf_graph_info.num_inline_nodes_approximate > 1000; @@ -1193,12 +1184,29 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { /* Add inputs that also exist on the bnode. */ graph_inputs.extend(lf_graph_info.mapping.group_input_sockets); + /** + * For every input bsocket there is a corresponding boolean output that indicates whether that + * input is used. + */ + Map lf_output_for_input_bsocket_usage; + /** + * For every output bsocket there is a corresponding boolean input that indicates whether the + * output is used. + */ + Map lf_input_for_output_bsocket_usage; + /** + * For every geometry output that can propagate attributes from an input, there is an attribute + * set input. It indicates which attributes should be propagated to the output. + */ + Map lf_input_for_attribute_propagation_to_output; + /* Add a boolean input for every output bsocket that indicates whether that socket is used. */ - for (const int i : group_node.output_sockets().index_range()) { - lf_input_for_output_bsocket_usage_.add_new( + //const NodeGeometryEvaluateFunction &node_data = params. + for (const int i : group_node.output_sockets().index_range()) { + lf_input_for_output_bsocket_usage.add_new( i, graph_inputs.append_and_get_index(lf_graph_info.mapping.group_output_used_sockets[i])); - inputs_.append_as("Output is Used", CPPType::get(), lf::ValueUsage::Maybe); + //inputs_.append_as("Output is Used", CPPType::get(), lf::ValueUsage::Maybe); } graph_inputs.extend(lf_graph_info.mapping.group_output_used_sockets); @@ -1209,7 +1217,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { const int lf_index = inputs_.append_and_get_index_as( "Attribute Set", CPPType::get(), lf::ValueUsage::Maybe); graph_inputs.append(lf_socket); - lf_input_for_attribute_propagation_to_output_.add(output_index, lf_index); + lf_input_for_attribute_propagation_to_output.add(output_index, lf_index); } Vector graph_outputs; @@ -1220,9 +1228,9 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { const InputUsageHint &input_usage_hint = lf_graph_info.mapping.group_input_usage_hints[i]; if (input_usage_hint.type == InputUsageHintType::DynamicSocket) { const lf::InputSocket *lf_socket = lf_graph_info.mapping.group_input_usage_sockets[i]; - lf_output_for_input_bsocket_usage_.add_new(i, + lf_output_for_input_bsocket_usage.add_new(i, graph_outputs.append_and_get_index(lf_socket)); - outputs_.append_as("Input is Used", CPPType::get()); + //outputs_.append_as("Input is Used", CPPType::get()); } } diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 4ced21594dc..79d87a431fd 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -30,10 +30,10 @@ #include "MEM_guardedalloc.h" +#include "NOD_closure.hh" #include "NOD_node_declaration.hh" #include "NOD_socket.h" -#include "FN_closure.hh" #include "FN_field.hh" using namespace blender; -- 2.30.2 From 7801c27ba6217e1136507ab1ce7599426b27bd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 17 Apr 2023 12:11:47 +0200 Subject: [PATCH 22/33] Own parameters for the closure invocation because mapping needs to happen. --- .../intern/geometry_nodes_lazy_function.cc | 124 +++++++++--------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 3435108fd71..9d86fdd7d29 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -35,6 +35,7 @@ #include "BKE_type_conversions.hh" #include "FN_field_cpp_type.hh" +#include "FN_lazy_function_execute.hh" #include "FN_lazy_function_graph_executor.hh" #include "DEG_depsgraph_query.h" @@ -1148,9 +1149,6 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { private: const bNode &eval_node_; //bool has_many_nodes_ = false; - std::optional lf_logger_; - std::optional lf_side_effect_provider_; - std::optional graph_executor_; struct Storage { void *graph_executor_storage = nullptr; @@ -1228,19 +1226,18 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { const InputUsageHint &input_usage_hint = lf_graph_info.mapping.group_input_usage_hints[i]; if (input_usage_hint.type == InputUsageHintType::DynamicSocket) { const lf::InputSocket *lf_socket = lf_graph_info.mapping.group_input_usage_sockets[i]; - lf_output_for_input_bsocket_usage.add_new(i, - graph_outputs.append_and_get_index(lf_socket)); + lf_output_for_input_bsocket_usage.add_new(i, graph_outputs.append_and_get_index(lf_socket)); //outputs_.append_as("Input is Used", CPPType::get()); } } - lf_logger_.emplace(lf_graph_info); - lf_side_effect_provider_.emplace(); - graph_executor_.emplace(lf_graph_info.graph, - std::move(graph_inputs), - std::move(graph_outputs), - &*lf_logger_, - &*lf_side_effect_provider_); + GeometryNodesLazyFunctionLogger lf_logger(lf_graph_info); + GeometryNodesLazyFunctionSideEffectProvider lf_side_effect_provider; + lf::GraphExecutor graph_executor(lf_graph_info.graph, + std::move(graph_inputs), + std::move(graph_outputs), + &lf_logger, + &lf_side_effect_provider); GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); BLI_assert(user_data != nullptr); @@ -1265,11 +1262,16 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { compute_context.hash()); } - lf::Context group_context = context; - group_context.user_data = &group_user_data; - group_context.storage = storage->graph_executor_storage; - - graph_executor_->execute(params, group_context); + lf::Context func_context = context; + func_context.user_data = &group_user_data; + func_context.storage = storage->graph_executor_storage; + lf::BasicParams func_params{graph_executor, + param_inputs, + param_outputs, + param_input_usages, + param_output_usages, + param_set_outputs}; + graph_executor->execute(params, func_context); } void *init_storage(LinearAllocator<> &allocator) const override @@ -1286,52 +1288,52 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { std::destroy_at(s); } - std::string name() const override - { - std::stringstream ss; - ss << "Group '" << (group_node_.id->name + 2) << "' (" << group_node_.name << ")"; - return ss.str(); - } +// std::string name() const override +// { +// std::stringstream ss; +// ss << "Group '" << (group_node_.id->name + 2) << "' (" << group_node_.name << ")"; +// return ss.str(); +// } - std::string input_name(const int i) const override - { - if (i < group_node_.input_sockets().size()) { - return group_node_.input_socket(i).name; - } - for (const auto [bsocket_index, lf_socket_index] : - lf_input_for_output_bsocket_usage_.items()) { - if (i == lf_socket_index) { - std::stringstream ss; - ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used"; - return ss.str(); - } - } - for (const auto [bsocket_index, lf_index] : - lf_input_for_attribute_propagation_to_output_.items()) { - if (i == lf_index) { - std::stringstream ss; - ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'"; - return ss.str(); - } - } - return inputs_[i].debug_name; - } +// std::string input_name(const int i) const override +// { +// if (i < group_node_.input_sockets().size()) { +// return group_node_.input_socket(i).name; +// } +// for (const auto [bsocket_index, lf_socket_index] : +// lf_input_for_output_bsocket_usage_.items()) { +// if (i == lf_socket_index) { +// std::stringstream ss; +// ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used"; +// return ss.str(); +// } +// } +// for (const auto [bsocket_index, lf_index] : +// lf_input_for_attribute_propagation_to_output_.items()) { +// if (i == lf_index) { +// std::stringstream ss; +// ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'"; +// return ss.str(); +// } +// } +// return inputs_[i].debug_name; +// } - std::string output_name(const int i) const override - { - if (i < group_node_.output_sockets().size()) { - return group_node_.output_socket(i).name; - } - for (const auto [bsocket_index, lf_socket_index] : - lf_output_for_input_bsocket_usage_.items()) { - if (i == lf_socket_index) { - std::stringstream ss; - ss << "'" << group_node_.input_socket(bsocket_index).name << "' input is used"; - return ss.str(); - } - } - return outputs_[i].debug_name; - } +// std::string output_name(const int i) const override +// { +// if (i < group_node_.output_sockets().size()) { +// return group_node_.output_socket(i).name; +// } +// for (const auto [bsocket_index, lf_socket_index] : +// lf_output_for_input_bsocket_usage_.items()) { +// if (i == lf_socket_index) { +// std::stringstream ss; +// ss << "'" << group_node_.input_socket(bsocket_index).name << "' input is used"; +// return ss.str(); +// } +// } +// return outputs_[i].debug_name; +// } }; /** -- 2.30.2 From a7ba495a82deaacaf09dd4752502d5739b833bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Sun, 7 May 2023 14:26:21 +0200 Subject: [PATCH 23/33] Set up parameters for the internal graph executor. --- source/blender/blenkernel/intern/cpp_types.cc | 8 +++----- source/blender/nodes/NOD_socket.h | 2 ++ .../nodes/geometry/nodes/node_geo_bind_function.cc | 4 ++-- .../geometry/nodes/node_geo_evaluate_function.cc | 3 +-- source/blender/nodes/intern/closure.cc | 2 +- .../nodes/intern/geometry_nodes_lazy_function.cc | 12 ++++++------ source/blender/nodes/intern/node_socket.cc | 12 ++++++++++-- 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/source/blender/blenkernel/intern/cpp_types.cc b/source/blender/blenkernel/intern/cpp_types.cc index b502c3506b4..e401dc5ade5 100644 --- a/source/blender/blenkernel/intern/cpp_types.cc +++ b/source/blender/blenkernel/intern/cpp_types.cc @@ -9,9 +9,10 @@ #include "DNA_meshdata_types.h" -#include "FN_closure.hh" #include "FN_init.h" +#include "NOD_socket.h" + struct Tex; struct Image; struct Material; @@ -31,12 +32,11 @@ BLI_CPP_TYPE_MAKE(MStringProperty, CPPTypeFlags::None); BLI_CPP_TYPE_MAKE(blender::bke::AnonymousAttributeSet, CPPTypeFlags::None); -BLI_CPP_TYPE_MAKE(blender::fn::Closure, CPPTypeFlags::None); - void BKE_cpp_types_init() { blender::register_cpp_types(); FN_register_cpp_types(); + blender::nodes::register_cpp_types(); BLI_CPP_TYPE_REGISTER(GeometrySet); BLI_CPP_TYPE_REGISTER(blender::bke::InstanceReference); @@ -52,6 +52,4 @@ void BKE_cpp_types_init() BLI_CPP_TYPE_REGISTER(MStringProperty); BLI_CPP_TYPE_REGISTER(blender::bke::AnonymousAttributeSet); - - BLI_CPP_TYPE_REGISTER(blender::fn::Closure); } diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h index 510ef378224..392cbf013e0 100644 --- a/source/blender/nodes/NOD_socket.h +++ b/source/blender/nodes/NOD_socket.h @@ -43,6 +43,8 @@ void register_standard_node_socket_types(void); namespace blender::nodes { +void register_cpp_types(); + void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node); } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index f260170a52f..08f46889d71 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -4,12 +4,12 @@ #include "BKE_node_runtime.hh" -#include "FN_closure.hh" #include "FN_lazy_function_graph.hh" #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_closure.hh" #include "NOD_common.h" #include "NOD_node_declaration.hh" @@ -60,7 +60,7 @@ static void node_geo_exec(GeoNodeExecParams params) bind_tree.runtime->geometry_nodes_lazy_function_graph_info; BLI_assert(lf_graph_info_ptr); - fn::Closure closure(lf_graph_info_ptr->graph); + Closure closure(*lf_graph_info_ptr); params.set_output("Function", std::move(closure)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc index 78790aef7ac..fd9c4c582bd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_function.cc @@ -4,13 +4,12 @@ #include "BLI_math_vector.h" #include "BLI_string.h" -#include "FN_closure.hh" - #include "RNA_enum_types.h" #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_closure.hh" #include "NOD_common.h" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index 4c228ceb900..6f3daf8a139 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -17,7 +17,7 @@ Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info) const GeometryNodesLazyFunctionGraphInfo *Closure::lf_graph_info() const { - return *lf_graph_info_; + return lf_graph_info_; } } // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 9d86fdd7d29..24a46792a3d 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1158,14 +1158,14 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { public: - LazyFunctionForEvaluateFunctionNode(const bNode &eval_node) : eval_node_(eval_node) + LazyFunctionForEvaluateFunctionNode(const bNode &eval_node, + MutableSpan r_lf_index_by_bsocket) + : eval_node_(eval_node) { debug_name_ = eval_node.name; allow_missing_requested_inputs_ = true; - Vector tmp_inputs; - Vector tmp_outputs; - lazy_function_interface_from_node(eval_node, tmp_inputs, tmp_outputs, inputs_, outputs_); + lazy_function_interface_from_node(eval_node, inputs_, outputs_, r_lf_index_by_bsocket); } void execute_impl(lf::Params ¶ms, const lf::Context &context) const override @@ -1252,7 +1252,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { /* The compute context changes when entering a node group. */ bke::NodeGroupComputeContext compute_context{ - user_data->compute_context, group_node_.identifier, storage->context_hash_cache}; + user_data->compute_context, eval_node_.identifier, storage->context_hash_cache}; storage->context_hash_cache = compute_context.hash(); GeoNodesLFUserData group_user_data = *user_data; @@ -1271,7 +1271,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { param_input_usages, param_output_usages, param_set_outputs}; - graph_executor->execute(params, func_context); + graph_executor.execute(func_params, func_context); } void *init_storage(LinearAllocator<> &allocator) const override diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 79d87a431fd..c09b4f5dd7f 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -10,6 +10,7 @@ #include "DNA_node_types.h" #include "BLI_color.hh" +#include "BLI_cpp_type_make.hh" #include "BLI_listbase.h" #include "BLI_math_vector.h" #include "BLI_math_vector_types.hh" @@ -181,8 +182,15 @@ static void verify_socket_template_list(bNodeTree *ntree, } } +BLI_CPP_TYPE_MAKE(blender::nodes::Closure, CPPTypeFlags::None); + namespace blender::nodes { +void register_cpp_types() +{ + BLI_CPP_TYPE_REGISTER(blender::nodes::Closure); +} + static void refresh_socket_list(bNodeTree &ntree, bNode &node, ListBase &sockets, @@ -789,9 +797,9 @@ static bNodeSocketType *make_socket_type_material() static bNodeSocketType *make_socket_type_function() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FUNCTION, PROP_NONE); - socktype->base_cpp_type = &blender::CPPType::get(); + socktype->base_cpp_type = &blender::CPPType::get(); socktype->get_base_cpp_value = [](const bNodeSocket &/*socket*/, void *r_value) { - new (r_value) fn::Closure(); + new (r_value) blender::nodes::Closure(); }; socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; -- 2.30.2 From eec81de7b437dc339b18c363c1db9a7982f1c6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 11 May 2023 13:41:41 +0200 Subject: [PATCH 24/33] Remove duplicate graph_output entries in the node group lazy function. --- source/blender/nodes/intern/geometry_nodes_lazy_function.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 9dfed68ce7b..dba699ffcae 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -908,7 +908,6 @@ class LazyFunctionForGroupNode : public LazyFunction { group_lf_graph_info.mapping.group_output_used_sockets[i]); inputs_.append_as("Output is Used", CPPType::get(), lf::ValueUsage::Maybe); } - graph_inputs.extend(group_lf_graph_info.mapping.group_output_used_sockets); /* Add an attribute set input for every output geometry socket that can propagate attributes * from inputs. */ -- 2.30.2 From ff155163f5a1aa4849ffcf12447185c88777c286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 11 May 2023 17:55:33 +0200 Subject: [PATCH 25/33] Create correct lazy function inputs/outputs for the node and graph. --- source/blender/blenkernel/intern/node.cc | 21 +- source/blender/nodes/NOD_closure.hh | 3 +- source/blender/nodes/NOD_node_declaration.hh | 3 +- .../geometry/nodes/node_geo_bind_function.cc | 2 +- .../intern/geometry_nodes_lazy_function.cc | 455 ++++++++++++------ 5 files changed, 316 insertions(+), 168 deletions(-) diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a20dc26a7a0..b8f3a9d530a 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -226,7 +226,8 @@ bool nodeFunctionParameterFindNode(bNodeTree *ntree, { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == GEO_NODE_EVALUATE_FUNCTION) { - NodeGeometryEvaluateFunction *data = static_cast(node->storage); + NodeGeometryEvaluateFunction *data = static_cast( + node->storage); if (nodeFunctionSignatureContainsParameter(&data->signature, param, nullptr)) { if (r_node) { *r_node = node; @@ -274,7 +275,8 @@ bool nodeFunctionSignatureFindNode(bNodeTree *ntree, { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == GEO_NODE_EVALUATE_FUNCTION) { - NodeGeometryEvaluateFunction *data = static_cast(node->storage); + NodeGeometryEvaluateFunction *data = static_cast( + node->storage); if (sig == &data->signature) { if (r_node) { *r_node = node; @@ -361,7 +363,8 @@ bNodeFunctionParameter *nodeFunctionSignatureAddParameter(bNodeFunctionSignature short socket_type, const char *name) { - return nodeFunctionSignatureInsertParameter(sig, param_type, socket_type, name, sig->params_range(param_type).size()); + return nodeFunctionSignatureInsertParameter( + sig, param_type, socket_type, name, sig->params_range(param_type).size()); } bNodeFunctionParameter *nodeFunctionSignatureInsertParameter(bNodeFunctionSignature *sig, @@ -408,8 +411,8 @@ static void nodeFunctionSignatureRemoveParameter(bNodeFunctionSignature *sig, eNodeFunctionParameterType param_type, bNodeFunctionParameter *param) { - const Span old_params = sig->params_span(param_type); - if (!old_params.contains_ptr(param)) { + const MutableSpan old_params = sig->params_span(param_type); + if (!old_params.as_span().contains_ptr(param)) { return; } const int index = param - old_params.data(); @@ -1420,7 +1423,7 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: + case SOCK_FUNCTION: break; } } @@ -3024,7 +3027,8 @@ bNodeLink *nodeAddLink( bNodeLink *link = nullptr; if (eNodeSocketInOut(fromsock->in_out) == SOCK_OUT && - eNodeSocketInOut(tosock->in_out) == SOCK_IN) { + eNodeSocketInOut(tosock->in_out) == SOCK_IN) + { link = MEM_cnew("link"); if (ntree) { BLI_addtail(&ntree->links, link); @@ -3152,7 +3156,8 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node) /* remove the link that would be the same as the relinked one */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link_to_compare, &ntree->links) { if (link_to_compare->fromsock == fromlink->fromsock && - link_to_compare->tosock == link->tosock) { + link_to_compare->tosock == link->tosock) + { adjust_multi_input_indices_after_removed_link( ntree, link_to_compare->tosock, link_to_compare->multi_input_socket_index); duplicate_links_to_remove.append_non_duplicates(link_to_compare); diff --git a/source/blender/nodes/NOD_closure.hh b/source/blender/nodes/NOD_closure.hh index 061566cbc0b..89840c7e28b 100644 --- a/source/blender/nodes/NOD_closure.hh +++ b/source/blender/nodes/NOD_closure.hh @@ -14,7 +14,7 @@ struct GeometryNodesLazyFunctionGraphInfo; class Closure { private: - const GeometryNodesLazyFunctionGraphInfo *lf_graph_info_; + const GeometryNodesLazyFunctionGraphInfo *lf_graph_info_ = nullptr; public: Closure() = default; @@ -27,5 +27,4 @@ class Closure { const GeometryNodesLazyFunctionGraphInfo *lf_graph_info() const; }; - } // namespace blender::nodes diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index 8c7a446cf09..a63bba1746c 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -753,6 +753,7 @@ inline Span NodeDeclaration::sockets(eNodeSocketInOut in_o /** \} */ -SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket); +SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree, + const bNodeSocket &io_socket); } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index 08f46889d71..fda0b9fa4aa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -37,7 +37,7 @@ static void node_declare(const bNodeTree &node_tree, r_declaration.skip_updating_sockets = false; LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) { - r_declaration.inputs.append(declaration_for_interface_socket(*input)); + r_declaration.inputs.append(declaration_for_interface_socket(node_tree, *input)); } const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface; diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index dba699ffcae..f179656abfd 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1152,35 +1152,183 @@ class LazyFunctionForSwitchSocketUsage : public lf::LazyFunction { } }; +/* Specialized Params class that passes parameters to a graph executor + * and communicates input requests back to the evaluation node. */ +class EvaluateFunctionNodeParams final : public lf::Params { + private: + Params &outer_params_; + /* Index of outer parameter used for a groph parameter, + * or -1 if the bound value must be used instead. */ + const Span outer_input_indices_; + const Span outer_output_indices_; + + const Span bound_inputs_; + const Span bound_outputs_; + MutableSpan> bound_input_usages_; + Span bound_output_usages_; + MutableSpan set_bound_outputs_; + + public: + EvaluateFunctionNodeParams(const lf::LazyFunction &fn, + const Span bound_inputs, + const Span bound_outputs, + MutableSpan> bound_input_usages, + Span bound_output_usages, + MutableSpan set_bound_outputs, + Params &outer_params, + Span outer_input_indices, + Span outer_output_indices) + : lf::Params(fn, outer_params.allow_multi_threading_), + outer_params_(outer_params), + outer_input_indices_(outer_input_indices), + outer_output_indices_(outer_output_indices), + bound_inputs_(bound_inputs), + bound_outputs_(bound_outputs), + bound_input_usages_(bound_input_usages), + bound_output_usages_(bound_output_usages), + set_bound_outputs_(set_bound_outputs) + { + } + + private: + void *try_get_input_data_ptr_impl(const int index) const override + { + const int outer_index = outer_input_indices_[index]; + if (outer_index >= 0) { + return outer_params_.try_get_input_data_ptr(outer_index); + } + else { + return bound_inputs_[index].get(); + } + } + + void *try_get_input_data_ptr_or_request_impl(const int index) override + { + const int outer_index = outer_input_indices_[index]; + if (outer_index >= 0) { + return outer_params_.try_get_input_data_ptr_or_request(outer_index); + } + else { + void *value = bound_inputs_[index].get(); + if (value == nullptr) { + bound_input_usages_[index] = lf::ValueUsage::Used; + } + return value; + } + } + + void *get_output_data_ptr_impl(const int index) override + { + const int outer_index = outer_output_indices_[index]; + if (outer_index >= 0) { + return outer_params_.get_output_data_ptr(outer_index); + } + else { + return bound_outputs_[index].get(); + } + } + + void output_set_impl(const int index) override + { + const int outer_index = outer_output_indices_[index]; + if (outer_index >= 0) { + return outer_params_.output_set(outer_index); + } + else { + set_bound_outputs_[index] = true; + } + } + + bool output_was_set_impl(const int index) const override + { + const int outer_index = outer_output_indices_[index]; + if (outer_index >= 0) { + return outer_params_.output_was_set(outer_index); + } + else { + return set_bound_outputs_[index]; + } + } + + lf::ValueUsage get_output_usage_impl(const int index) const override + { + const int outer_index = outer_output_indices_[index]; + if (outer_index >= 0) { + return outer_params_.get_output_usage(outer_index); + } + else { + return bound_output_usages_[index]; + } + } + + void set_input_unused_impl(const int index) override + { + const int outer_index = outer_input_indices_[index]; + if (outer_index >= 0) { + return outer_params_.set_input_unused(outer_index); + } + else { + bound_input_usages_[index] = lf::ValueUsage::Unused; + } + } + + bool try_enable_multi_threading_impl() override + { + return outer_params_.try_enable_multi_threading(); + } +}; + /** * Evaluates the function input and then executes it. */ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { private: const bNode &eval_node_; - //bool has_many_nodes_ = false; - - struct Storage { - void *graph_executor_storage = nullptr; - /* To avoid computing the hash more than once. */ - std::optional context_hash_cache; - }; + // bool has_many_nodes_ = false; public: - LazyFunctionForEvaluateFunctionNode(const bNode &eval_node, - MutableSpan r_lf_index_by_bsocket) + GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info) : eval_node_(eval_node) { debug_name_ = eval_node.name; allow_missing_requested_inputs_ = true; - lazy_function_interface_from_node(eval_node, inputs_, outputs_, r_lf_index_by_bsocket); + lazy_function_interface_from_node( + eval_node, inputs_, outputs_, own_lf_graph_info.mapping.lf_index_by_bsocket); + for (lf::Input &input : inputs_) { + input.usage = lf::ValueUsage::Maybe; + } + /* Add a boolean input for every output bsocket that indicates whether that socket is used. */ + for (const int i : eval_node.output_sockets().index_range()) { + own_lf_graph_info.mapping.lf_input_index_for_output_bsocket_usage + [eval_node.output_socket(i).index_in_all_outputs()] = inputs_.append_and_get_index_as( + "Output is Used", CPPType::get(), lf::ValueUsage::Maybe); + } + /* Add an attribute set input for every output geometry socket that can propagate attributes + * from inputs. */ + for (const int i : eval_node.output_sockets().index_range()) { + own_lf_graph_info.mapping.lf_input_index_for_attribute_propagation_to_output + [eval_node.output_socket(i).index_in_all_outputs()] = inputs_.append_and_get_index_as( + "Attribute Set", CPPType::get(), lf::ValueUsage::Maybe); + } + + /* Add a boolean output for every input bsocket that indicates whether that socket is used. */ + for (const int i : eval_node.input_sockets().index_range()) { + /* Treat all sockets as dynamic, i.e. their usage is undetermined at this point + * and a usage output is added. */ + outputs_.append_as("Input is Used", CPPType::get()); + UNUSED_VARS(i); + } } void execute_impl(lf::Params ¶ms, const lf::Context &context) const override { - const Closure *closure = params.get_input(0); + Closure *closure = params.try_get_input_data_ptr_or_request(0); + if (!closure) { + return; + } + if (!closure->lf_graph_info()) { return; } @@ -1191,55 +1339,22 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { Vector graph_inputs; /* Add inputs that also exist on the bnode. */ graph_inputs.extend(lf_graph_info.mapping.group_input_sockets); - - /** - * For every input bsocket there is a corresponding boolean output that indicates whether that - * input is used. - */ - Map lf_output_for_input_bsocket_usage; - /** - * For every output bsocket there is a corresponding boolean input that indicates whether the - * output is used. - */ - Map lf_input_for_output_bsocket_usage; - /** - * For every geometry output that can propagate attributes from an input, there is an attribute - * set input. It indicates which attributes should be propagated to the output. - */ - Map lf_input_for_attribute_propagation_to_output; - - /* Add a boolean input for every output bsocket that indicates whether that socket is used. */ - //const NodeGeometryEvaluateFunction &node_data = params. - for (const int i : group_node.output_sockets().index_range()) { - lf_input_for_output_bsocket_usage.add_new( - i, - graph_inputs.append_and_get_index(lf_graph_info.mapping.group_output_used_sockets[i])); - //inputs_.append_as("Output is Used", CPPType::get(), lf::ValueUsage::Maybe); - } + /* Add a boolean input for every output bsocket that indicates whether that socket is + * used. */ graph_inputs.extend(lf_graph_info.mapping.group_output_used_sockets); - /* Add an attribute set input for every output geometry socket that can propagate attributes * from inputs. */ - for (auto [output_index, lf_socket] : - lf_graph_info.mapping.attribute_set_by_geometry_output.items()) { - const int lf_index = inputs_.append_and_get_index_as( - "Attribute Set", CPPType::get(), lf::ValueUsage::Maybe); + for (const lf::OutputSocket *lf_socket : + lf_graph_info.mapping.attribute_set_by_geometry_output.values()) + { graph_inputs.append(lf_socket); - lf_input_for_attribute_propagation_to_output.add(output_index, lf_index); } Vector graph_outputs; /* Add outputs that also exist on the bnode. */ graph_outputs.extend(lf_graph_info.mapping.standard_group_output_sockets); /* Add a boolean output for every input bsocket that indicates whether that socket is used. */ - for (const int i : group_node.input_sockets().index_range()) { - const InputUsageHint &input_usage_hint = lf_graph_info.mapping.group_input_usage_hints[i]; - if (input_usage_hint.type == InputUsageHintType::DynamicSocket) { - const lf::InputSocket *lf_socket = lf_graph_info.mapping.group_input_usage_sockets[i]; - lf_output_for_input_bsocket_usage.add_new(i, graph_outputs.append_and_get_index(lf_socket)); - //outputs_.append_as("Input is Used", CPPType::get()); - } - } + graph_outputs.extend(lf_graph_info.mapping.group_input_usage_sockets); GeometryNodesLazyFunctionLogger lf_logger(lf_graph_info); GeometryNodesLazyFunctionSideEffectProvider lf_side_effect_provider; @@ -1252,98 +1367,113 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); BLI_assert(user_data != nullptr); - //if (has_many_nodes_) { - // /* If the called node group has many nodes, it's likely that executing it takes a while even - // * if every individual node is very small. */ - // lazy_threading::send_hint(); - //} + // if (has_many_nodes_) { + // /* If the called node group has many nodes, it's likely that executing it takes a while + // * even if every individual node is very small. */ + // lazy_threading::send_hint(); + // } - Storage *storage = static_cast(context.storage); + Array bound_inputs(graph_inputs.size()); + Array bound_outputs(graph_outputs.size()); + Array> bound_input_usages(graph_inputs.size()); + Array bound_output_usages(graph_outputs.size(), lf::ValueUsage::Used); + Array bound_set_outputs(graph_outputs.size(), false); + Array outer_input_indices(graph_inputs.size()); + Array outer_output_indices(graph_outputs.size()); + + // TODO fill those arrays + + LinearAllocator allocator; + void *graph_executor_storage = graph_executor.init_storage(allocator); /* The compute context changes when entering a node group. */ + std::optional context_hash_cache; bke::NodeGroupComputeContext compute_context{ - user_data->compute_context, eval_node_.identifier, storage->context_hash_cache}; - storage->context_hash_cache = compute_context.hash(); + user_data->compute_context, eval_node_.identifier, context_hash_cache}; + context_hash_cache = compute_context.hash(); - GeoNodesLFUserData group_user_data = *user_data; - group_user_data.compute_context = &compute_context; + GeoNodesLFUserData func_user_data = *user_data; + func_user_data.compute_context = &compute_context; if (user_data->modifier_data->socket_log_contexts) { - group_user_data.log_socket_values = user_data->modifier_data->socket_log_contexts->contains( + func_user_data.log_socket_values = user_data->modifier_data->socket_log_contexts->contains( compute_context.hash()); } lf::Context func_context = context; - func_context.user_data = &group_user_data; - func_context.storage = storage->graph_executor_storage; - lf::BasicParams func_params{graph_executor, - param_inputs, - param_outputs, - param_input_usages, - param_output_usages, - param_set_outputs}; + func_context.user_data = &func_user_data; + func_context.storage = graph_executor_storage; + EvaluateFunctionNodeParams func_params{graph_executor, + bound_inputs, + bound_outputs, + bound_input_usages, + bound_output_usages, + bound_set_outputs, + params, + outer_input_indices, + outer_output_indices}; graph_executor.execute(func_params, func_context); } - void *init_storage(LinearAllocator<> &allocator) const override - { - Storage *s = allocator.construct().release(); - s->graph_executor_storage = graph_executor_->init_storage(allocator); - return s; - } + // void *init_storage(LinearAllocator<> &allocator) const override + // { + // Storage *s = allocator.construct().release(); + // s->graph_executor_storage = graph_executor_->init_storage(allocator); + // return s; + // } - void destruct_storage(void *storage) const override - { - Storage *s = static_cast(storage); - graph_executor_->destruct_storage(s->graph_executor_storage); - std::destroy_at(s); - } + // void destruct_storage(void *storage) const override + // { + // Storage *s = static_cast(storage); + // graph_executor_->destruct_storage(s->graph_executor_storage); + // std::destroy_at(s); + // } -// std::string name() const override -// { -// std::stringstream ss; -// ss << "Group '" << (group_node_.id->name + 2) << "' (" << group_node_.name << ")"; -// return ss.str(); -// } + // std::string name() const override + // { + // std::stringstream ss; + // ss << "Group '" << (group_node_.id->name + 2) << "' (" << group_node_.name << ")"; + // return ss.str(); + // } -// std::string input_name(const int i) const override -// { -// if (i < group_node_.input_sockets().size()) { -// return group_node_.input_socket(i).name; -// } -// for (const auto [bsocket_index, lf_socket_index] : -// lf_input_for_output_bsocket_usage_.items()) { -// if (i == lf_socket_index) { -// std::stringstream ss; -// ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used"; -// return ss.str(); -// } -// } -// for (const auto [bsocket_index, lf_index] : -// lf_input_for_attribute_propagation_to_output_.items()) { -// if (i == lf_index) { -// std::stringstream ss; -// ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'"; -// return ss.str(); -// } -// } -// return inputs_[i].debug_name; -// } + // std::string input_name(const int i) const override + // { + // if (i < group_node_.input_sockets().size()) { + // return group_node_.input_socket(i).name; + // } + // for (const auto [bsocket_index, lf_socket_index] : + // lf_input_for_output_bsocket_usage_.items()) { + // if (i == lf_socket_index) { + // std::stringstream ss; + // ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used"; + // return ss.str(); + // } + // } + // for (const auto [bsocket_index, lf_index] : + // lf_input_for_attribute_propagation_to_output_.items()) { + // if (i == lf_index) { + // std::stringstream ss; + // ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'"; + // return ss.str(); + // } + // } + // return inputs_[i].debug_name; + // } -// std::string output_name(const int i) const override -// { -// if (i < group_node_.output_sockets().size()) { -// return group_node_.output_socket(i).name; -// } -// for (const auto [bsocket_index, lf_socket_index] : -// lf_output_for_input_bsocket_usage_.items()) { -// if (i == lf_socket_index) { -// std::stringstream ss; -// ss << "'" << group_node_.input_socket(bsocket_index).name << "' input is used"; -// return ss.str(); -// } -// } -// return outputs_[i].debug_name; -// } + // std::string output_name(const int i) const override + // { + // if (i < group_node_.output_sockets().size()) { + // return group_node_.output_socket(i).name; + // } + // for (const auto [bsocket_index, lf_socket_index] : + // lf_output_for_input_bsocket_usage_.items()) { + // if (i == lf_socket_index) { + // std::stringstream ss; + // ss << "'" << group_node_.input_socket(bsocket_index).name << "' input is used"; + // return ss.str(); + // } + // } + // return outputs_[i].debug_name; + // } }; /** @@ -1564,8 +1694,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { */ Map attribute_set_propagation_map_; /** - * Boolean inputs that tell a node if some socket (of the same or another node) is used. If this - * socket is in a link-cycle, its input can become a constant true. + * Boolean inputs that tell a node if some socket (of the same or another node) is used. If + * this socket is in a link-cycle, its input can become a constant true. */ Set socket_usage_inputs_; @@ -2102,7 +2232,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { void handle_evaluate_function_node(const bNode &bnode) { - auto lazy_function = std::make_unique(bnode); + auto lazy_function = std::make_unique(bnode, + *lf_graph_info_); lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); for (const int i : bnode.input_sockets().index_range()) { @@ -2118,19 +2249,27 @@ struct GeometryNodesLazyFunctionGraphBuilder { output_socket_map_.add_new(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); } - mapping_->group_node_map.add(&bnode, &lf_node); - //lf_graph_info_->num_inline_nodes_approximate += - // group_lf_graph_info->num_inline_nodes_approximate; + static const bool static_false = false; - for (const int i : lazy_function->lf_input_for_output_bsocket_usage_.values()) { - lf_node.input(i).set_default_value(&static_false); - socket_usage_inputs_.add(&lf_node.input(i)); - } - /* Keep track of attribute set inputs that need to be populated later. */ - for (const auto [output_index, lf_input_index] : - lazy_function->lf_input_for_attribute_propagation_to_output_.items()) { - attribute_set_propagation_map_.add(&bnode.output_socket(output_index), - &lf_node.input(lf_input_index)); + for (const bNodeSocket *bsocket : bnode.output_sockets()) { + { + const int lf_input_index = + mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()]; + if (lf_input_index != -1) { + lf::InputSocket &lf_input = lf_node.input(lf_input_index); + lf_input.set_default_value(&static_false); + socket_usage_inputs_.add(&lf_input); + } + } + { + /* Keep track of attribute set inputs that need to be populated later. */ + const int lf_input_index = mapping_->lf_input_index_for_attribute_propagation_to_output + [bsocket->index_in_all_outputs()]; + if (lf_input_index != -1) { + lf::InputSocket &lf_input = lf_node.input(lf_input_index); + attribute_set_propagation_map_.add(bsocket, &lf_input); + } + } } lf_graph_info_->functions.append(std::move(lazy_function)); } @@ -2338,8 +2477,9 @@ struct GeometryNodesLazyFunctionGraphBuilder { } /** - * Every output geometry socket that may propagate attributes has to know which attributes should - * be propagated. Therefore, every one of these outputs gets a corresponding attribute set input. + * Every output geometry socket that may propagate attributes has to know which attributes + * should be propagated. Therefore, every one of these outputs gets a corresponding attribute + * set input. */ void build_attribute_propagation_input_node() { @@ -2695,7 +2835,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { Vector output_usages; for (const int i : input_usage_hint.output_dependencies) { if (lf::OutputSocket *lf_socket = - socket_is_used_map_[bnode.output_socket(i).index_in_tree()]) { + socket_is_used_map_[bnode.output_socket(i).index_in_tree()]) + { output_usages.append(lf_socket); } } @@ -2718,7 +2859,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { BLI_assert(lf_input_index >= 0); lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index); if (lf::OutputSocket *lf_output_is_used = - socket_is_used_map_[output_bsocket->index_in_tree()]) { + socket_is_used_map_[output_bsocket->index_in_tree()]) + { lf_graph_->add_link(*lf_output_is_used, lf_socket); } else { @@ -2825,8 +2967,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { const int sockets_num = btree_.all_sockets().size(); const int attribute_references_num = attribute_reference_keys.size(); - /* The code below uses #BitGroupVector to store a set of attribute references per socket. Each - * socket has a bit span where each bit corresponds to one attribute reference. */ + /* The code below uses #BitGroupVector to store a set of attribute references per socket. + * Each socket has a bit span where each bit corresponds to one attribute reference. */ BitGroupVector<> referenced_by_field_socket(sockets_num, attribute_references_num, false); BitGroupVector<> propagated_to_geometry_socket(sockets_num, attribute_references_num, false); this->gather_referenced_and_potentially_propagated_data(relations_by_node, @@ -3181,15 +3323,15 @@ struct GeometryNodesLazyFunctionGraphBuilder { } /** - * By depending on "the future" (whether a specific socket is used in the future), it is possible - * to introduce cycles in the graph. This function finds those cycles and breaks them by removing - * specific links. + * By depending on "the future" (whether a specific socket is used in the future), it is + * possible to introduce cycles in the graph. This function finds those cycles and breaks them + * by removing specific links. * * Example for a cycle: There is a `Distribute Points on Faces` node and its `Normal` output is - * only used when the number of generated points is larger than 1000 because of some switch node - * later in the tree. In this case, to know whether the `Normal` output is needed, one first has - * to compute the points, but for that one has to know whether the normal information has to be - * added to the points. The fix is to always add the normal information in this case. + * only used when the number of generated points is larger than 1000 because of some switch + * node later in the tree. In this case, to know whether the `Normal` output is needed, one + * first has to compute the points, but for that one has to know whether the normal information + * has to be added to the points. The fix is to always add the normal information in this case. */ void fix_link_cycles() { @@ -3260,8 +3402,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { * computation later, but does not change correctness. * * After the cycle is broken, the cycle-detection is "rolled back" to the socket where - * the first socket of the cycle was found. This is necessary in case another cycle goes - * through this socket. */ + * the first socket of the cycle was found. This is necessary in case another cycle + * goes through this socket. */ detected_cycle = true; const int index_in_socket_stack = lf_socket_stack.first_index_of(lf_origin_socket); @@ -3273,7 +3415,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { bool broke_cycle = false; for (lf::Socket *lf_cycle_socket : cycle) { if (lf_cycle_socket->is_input() && - socket_usage_inputs_.contains(&lf_cycle_socket->as_input())) { + socket_usage_inputs_.contains(&lf_cycle_socket->as_input())) + { lf::InputSocket &lf_cycle_input_socket = lf_cycle_socket->as_input(); lf_graph_->clear_origin(lf_cycle_input_socket); static const bool static_true = true; -- 2.30.2 From c80eec293e058f82e1d6fb22701eef7569c827c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 12 May 2023 09:42:15 +0200 Subject: [PATCH 26/33] WIP: store bound values in the closure. --- source/blender/nodes/NOD_closure.hh | 10 +++- .../geometry/nodes/node_geo_bind_function.cc | 60 ++++++++++++++----- source/blender/nodes/intern/closure.cc | 17 +++++- .../intern/geometry_nodes_lazy_function.cc | 3 + 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/source/blender/nodes/NOD_closure.hh b/source/blender/nodes/NOD_closure.hh index 89840c7e28b..5878dcd276a 100644 --- a/source/blender/nodes/NOD_closure.hh +++ b/source/blender/nodes/NOD_closure.hh @@ -7,6 +7,7 @@ */ #include "BLI_cpp_type.hh" +#include "BLI_generic_pointer.hh" namespace blender::nodes { @@ -15,16 +16,21 @@ struct GeometryNodesLazyFunctionGraphInfo; class Closure { private: const GeometryNodesLazyFunctionGraphInfo *lf_graph_info_ = nullptr; + Vector bound_values_; public: Closure() = default; Closure(const Closure &other) = default; - explicit Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info); - ~Closure() = default; + explicit Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, + MutableSpan &&bound_values); + ~Closure(); Closure &operator=(const Closure &other) = default; const GeometryNodesLazyFunctionGraphInfo *lf_graph_info() const; + + Span bound_values() const; + MutableSpan bound_values(); }; } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index fda0b9fa4aa..e851e1f0bf4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -37,12 +37,10 @@ static void node_declare(const bNodeTree &node_tree, r_declaration.skip_updating_sockets = false; LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) { - r_declaration.inputs.append(declaration_for_interface_socket(node_tree, *input)); - } - - const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface; - for (const int i : r_declaration.inputs.index_range()) { - r_declaration.inputs[i]->input_field_type = field_interface.inputs[i]; + SocketDeclarationPtr decl = declaration_for_interface_socket(node_tree, *input); + /* Need single values to bind. */ + decl->input_field_type = InputSocketFieldType::None; + r_declaration.inputs.append(std::move(decl)); } } @@ -54,16 +52,50 @@ static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr) static void node_geo_exec(GeoNodeExecParams params) { - if (params.node().id) { - const bNodeTree &bind_tree = *reinterpret_cast(params.node().id); - const std::unique_ptr &lf_graph_info_ptr = - bind_tree.runtime->geometry_nodes_lazy_function_graph_info; - BLI_assert(lf_graph_info_ptr); - - Closure closure(*lf_graph_info_ptr); - params.set_output("Function", std::move(closure)); + if (params.node().id == nullptr) { + params.set_default_remaining_outputs(); + return; } + const bNodeTree &bind_tree = *reinterpret_cast(params.node().id); + const std::unique_ptr &lf_graph_info_ptr = + bind_tree.runtime->geometry_nodes_lazy_function_graph_info; + BLI_assert(lf_graph_info_ptr); + + Array bound_values(params.node().input_sockets().size()); + for (const int i : params.node().input_sockets().index_range()) { + const bNodeSocket *socket = params.node().input_sockets()[i]; + const CPPType *cpptype = socket->typeinfo->geometry_nodes_cpp_type; + BLI_assert(cpptype != nullptr); + + void *bound_value_buffer = MEM_mallocN_aligned( + cpptype->size(), cpptype->alignment(), "function bound value"); + switch (socket->type) { + case SOCK_FLOAT: + float value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + case SOCK_VECTOR: + case SOCK_RGBA: + case SOCK_BOOLEAN: + case SOCK_INT: + case SOCK_STRING: + case SOCK_OBJECT: + case SOCK_IMAGE: + case SOCK_GEOMETRY: + case SOCK_COLLECTION: + case SOCK_TEXTURE: + case SOCK_MATERIAL: + case SOCK_FUNCTION: + BLI_assert_unreachable(); + } + + bound_values[i] = {cpptype, bound_value_buffer}; + } + + Closure closure(*lf_graph_info_ptr, bound_values); + params.set_output("Function", std::move(closure)); + params.set_default_remaining_outputs(); } diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index 6f3daf8a139..d5444ce1cfd 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -10,14 +10,27 @@ namespace blender::nodes { -Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info) - : lf_graph_info_(&lf_graph_info) +Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, + MutableSpan &&bound_values) + : lf_graph_info_(&lf_graph_info), bound_values_(std::move(bound_values)) { } +Closure::~Closure() {} + const GeometryNodesLazyFunctionGraphInfo *Closure::lf_graph_info() const { return lf_graph_info_; } +Span Closure::bound_values() const +{ + return bound_values_; +} + +MutableSpan Closure::bound_values() +{ + return bound_values_; +} + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index f179656abfd..46528287293 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1382,6 +1382,9 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { Array outer_output_indices(graph_outputs.size()); // TODO fill those arrays + // for (const int i :) { + // bound_inputs[i] = params.try_get_input_data_ptr_or_request; + //} LinearAllocator allocator; void *graph_executor_storage = graph_executor.init_storage(allocator); -- 2.30.2 From 3b73a1fdba23b8faface74d8f65cd7d565f728f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 15 May 2023 16:00:20 +0200 Subject: [PATCH 27/33] Make the function evaluation work. --- source/blender/nodes/NOD_closure.hh | 14 ++- .../geometry/nodes/node_geo_bind_function.cc | 5 +- source/blender/nodes/intern/closure.cc | 27 +++- .../intern/geometry_nodes_lazy_function.cc | 119 ++++++++++++++++-- 4 files changed, 148 insertions(+), 17 deletions(-) diff --git a/source/blender/nodes/NOD_closure.hh b/source/blender/nodes/NOD_closure.hh index 5878dcd276a..51b76dc4875 100644 --- a/source/blender/nodes/NOD_closure.hh +++ b/source/blender/nodes/NOD_closure.hh @@ -13,10 +13,22 @@ namespace blender::nodes { struct GeometryNodesLazyFunctionGraphInfo; +class ClosureInputValues { + private: + Vector values_; + + public: + ClosureInputValues(const Span &values); + ~ClosureInputValues(); + + Span values() const; + MutableSpan values(); +}; + class Closure { private: const GeometryNodesLazyFunctionGraphInfo *lf_graph_info_ = nullptr; - Vector bound_values_; + std::shared_ptr bound_values_; public: Closure() = default; diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index e851e1f0bf4..34845edd8e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -71,10 +71,11 @@ static void node_geo_exec(GeoNodeExecParams params) void *bound_value_buffer = MEM_mallocN_aligned( cpptype->size(), cpptype->alignment(), "function bound value"); switch (socket->type) { - case SOCK_FLOAT: - float value = params.get_input(socket->identifier); + case SOCK_FLOAT: { + ValueOrField value = params.get_input(socket->identifier); cpptype->move_construct(&value, bound_value_buffer); break; + } case SOCK_VECTOR: case SOCK_RGBA: case SOCK_BOOLEAN: diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index d5444ce1cfd..3b6b48b642e 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -10,9 +10,30 @@ namespace blender::nodes { +ClosureInputValues::ClosureInputValues(const Span &values) : values_(values) {} + +ClosureInputValues::~ClosureInputValues() +{ + for (GMutablePointer &ptr : values_) { + ptr.destruct(); + MEM_freeN(ptr.get()); + } +} + +Span ClosureInputValues::values() const +{ + return values_; +} + +MutableSpan ClosureInputValues::values() +{ + return values_; +} + Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, MutableSpan &&bound_values) - : lf_graph_info_(&lf_graph_info), bound_values_(std::move(bound_values)) + : lf_graph_info_(&lf_graph_info), + bound_values_(std::make_shared(bound_values)) { } @@ -25,12 +46,12 @@ const GeometryNodesLazyFunctionGraphInfo *Closure::lf_graph_info() const Span Closure::bound_values() const { - return bound_values_; + return bound_values_->values(); } MutableSpan Closure::bound_values() { - return bound_values_; + return bound_values_->values(); } } // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 46528287293..adca14520fe 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1324,18 +1324,52 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { void execute_impl(lf::Params ¶ms, const lf::Context &context) const override { + GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); + BLI_assert(user_data != nullptr); + geo_eval_log::GeoTreeLogger *tree_logger = + (user_data->modifier_data->eval_log != nullptr) ? + &user_data->modifier_data->eval_log->get_local_tree_logger( + *user_data->compute_context) : + nullptr; + Closure *closure = params.try_get_input_data_ptr_or_request(0); if (!closure) { + /* Wait for closure request. */ return; } if (!closure->lf_graph_info()) { + if (tree_logger) { + tree_logger->node_warnings.append( + {eval_node_.identifier, + {NodeWarningType::Info, + tree_logger->allocator->copy_string("Function graph undefined")}}); + } + params.set_default_remaining_outputs(); return; } const GeometryNodesLazyFunctionGraphInfo &lf_graph_info = *closure->lf_graph_info(); // has_many_nodes_ = lf_graph_info.num_inline_nodes_approximate > 1000; + /* There is a bound value for each regular graph input. */ + const IndexRange input_values_range{0, lf_graph_info.mapping.group_input_sockets.size()}; + /* There is a bound value for each "output used" flag. */ + const IndexRange output_used_range{lf_graph_info.mapping.group_input_sockets.size(), + lf_graph_info.mapping.group_output_used_sockets.size()}; + /* There is a bound value for each output attribute set. */ + const IndexRange attribute_set_range( + lf_graph_info.mapping.group_output_used_sockets.size(), + lf_graph_info.mapping.attribute_set_by_geometry_output.size()); + const IndexRange output_values_range{ + 0, lf_graph_info.mapping.standard_group_output_sockets.size()}; + const IndexRange input_usage_range{lf_graph_info.mapping.standard_group_output_sockets.size(), + lf_graph_info.mapping.group_input_usage_sockets.size()}; + /* We make a few assumptions below about the size of these ranges. */ + BLI_assert(closure->bound_values().size() == input_values_range.size()); + BLI_assert(lf_graph_info.mapping.group_input_usage_sockets.size() == + input_values_range.size()); + Vector graph_inputs; /* Add inputs that also exist on the bnode. */ graph_inputs.extend(lf_graph_info.mapping.group_input_sockets); @@ -1364,9 +1398,6 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { &lf_logger, &lf_side_effect_provider); - GeoNodesLFUserData *user_data = dynamic_cast(context.user_data); - BLI_assert(user_data != nullptr); - // if (has_many_nodes_) { // /* If the called node group has many nodes, it's likely that executing it takes a while // * even if every individual node is very small. */ @@ -1374,17 +1405,83 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { // } Array bound_inputs(graph_inputs.size()); - Array bound_outputs(graph_outputs.size()); + bound_inputs.as_mutable_span().slice(input_values_range).copy_from(closure->bound_values()); + Array bound_input_for_output_used(output_used_range.size(), false); + for (const int i : bound_input_for_output_used.index_range()) { + bound_inputs[output_used_range[i]] = {CPPType::get(), &bound_input_for_output_used[i]}; + } + Array bound_input_for_attribute_set(attribute_set_range.size()); + for (const int i : bound_input_for_attribute_set.index_range()) { + bound_inputs[attribute_set_range[i]] = {CPPType::get(), + &bound_input_for_attribute_set[i]}; + } + + /* These are written to if the graph outputs a value that is not captured by the evaluation + * node. + * XXX Could find a better way to handle this. */ + Array unused_outputs(graph_outputs.size()); + for (const int i : unused_outputs.index_range()) { + const CPPType &cpptype = graph_outputs[i]->type(); + void *buffer = MEM_mallocN_aligned( + cpptype.size(), cpptype.alignment(), "unused graph output buffer"); + unused_outputs[i] = {&cpptype, buffer}; + } Array> bound_input_usages(graph_inputs.size()); Array bound_output_usages(graph_outputs.size(), lf::ValueUsage::Used); Array bound_set_outputs(graph_outputs.size(), false); - Array outer_input_indices(graph_inputs.size()); - Array outer_output_indices(graph_outputs.size()); - // TODO fill those arrays - // for (const int i :) { - // bound_inputs[i] = params.try_get_input_data_ptr_or_request; - //} + Array outer_input_indices(graph_inputs.size(), -1); + Array outer_output_indices(graph_outputs.size(), -1); + /* Find a socket in the evaluation node that matches the graph socket. */ + auto find_matching_socket = [](const Span &sockets, + const StringRef name, + const CPPType &type) -> int { + for (const int socket_i : sockets.index_range()) { + const bNodeSocket *socket = sockets[socket_i]; + BLI_assert(socket->typeinfo->geometry_nodes_cpp_type != nullptr); + if (socket->name == name && *socket->typeinfo->geometry_nodes_cpp_type == type) { + /* Index relative to the socket list (ignore the Function input socket). */ + return socket_i - sockets.index_range().start(); + } + } + return -1; + }; + for (const int i : lf_graph_info.mapping.group_input_sockets.index_range()) { + const lf::OutputSocket *graph_input = lf_graph_info.mapping.group_input_sockets[i]; + /* Drop the Function output socket at the start of the list. */ + const int matching_socket_index = find_matching_socket( + eval_node_.input_sockets().drop_front(1), graph_input->name(), graph_input->type()); + outer_input_indices[input_values_range[i]] = matching_socket_index; + } + for (const int i : lf_graph_info.mapping.standard_group_output_sockets.index_range()) { + const lf::InputSocket *graph_output = lf_graph_info.mapping.standard_group_output_sockets[i]; + const int matching_socket_index = find_matching_socket( + eval_node_.output_sockets(), graph_output->name(), graph_output->type()); + outer_output_indices[output_values_range[i]] = matching_socket_index; + } + for (const int i : lf_graph_info.mapping.group_output_used_sockets.index_range()) { + outer_input_indices[output_used_range[i]] = + outer_output_indices[i] >= 0 ? + lf_graph_info.mapping.group_input_sockets.size() + outer_output_indices[i] : + -1; + } + for (const int i : lf_graph_info.mapping.group_input_usage_sockets.index_range()) { + outer_output_indices[input_usage_range[i]] = + outer_input_indices[i] >= 0 ? + lf_graph_info.mapping.standard_group_output_sockets.size() + outer_input_indices[i] : + -1; + } + // XXX TODO + // { + // int i = 0; + // for (auto [output_index, lf_socket] : + // lf_graph_info.mapping.attribute_set_by_geometry_output.items()) + // { + // const int lf_socket_index = lf_graph_info.mapping.group_ + // outer_input_indices[attribute_set_range[i]] = ; + // ++i; + // } + // } LinearAllocator allocator; void *graph_executor_storage = graph_executor.init_storage(allocator); @@ -1407,7 +1504,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { func_context.storage = graph_executor_storage; EvaluateFunctionNodeParams func_params{graph_executor, bound_inputs, - bound_outputs, + unused_outputs, bound_input_usages, bound_output_usages, bound_set_outputs, -- 2.30.2 From 034f3deaf0208ddb04b2753c64a7089be39a6170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 15 May 2023 18:07:35 +0200 Subject: [PATCH 28/33] Support node tree ID default_value values for function sockets. --- source/blender/blenkernel/intern/node.cc | 41 +++++++++++++++---- .../intern/builder/deg_builder_nodes.cc | 6 ++- .../intern/builder/deg_builder_relations.cc | 6 +++ source/blender/editors/space_node/drawnode.cc | 10 ++++- source/blender/makesdna/DNA_node_types.h | 4 ++ source/blender/makesrna/intern/rna_nodetree.c | 40 ++++++++++++++++++ source/blender/modifiers/intern/MOD_nodes.cc | 25 +++++++++++ source/blender/nodes/NOD_closure.hh | 11 +++-- source/blender/nodes/intern/closure.cc | 36 ++++++++++++++-- source/blender/nodes/intern/node_common.cc | 13 ++++-- source/blender/nodes/intern/node_socket.cc | 24 +++++++++-- 11 files changed, 191 insertions(+), 25 deletions(-) diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index b8f3a9d530a..ab4f356d14e 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -694,6 +694,12 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value.value, IDWALK_CB_USER); break; } + case SOCK_FUNCTION: { + bNodeSocketValueFunction &default_value = + *sock->default_value_typed(); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, default_value.value, IDWALK_CB_USER); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -704,7 +710,6 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: break; } } @@ -844,13 +849,15 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so case SOCK_MATERIAL: BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value); break; + case SOCK_FUNCTION: + BLO_write_struct(writer, bNodeSocketValueFunction, sock->default_value); + break; case SOCK_CUSTOM: /* Custom node sockets where default_value is defined uses custom properties for storage. */ break; case __SOCK_MESH: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: BLI_assert_unreachable(); break; } @@ -1319,6 +1326,11 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock reader, lib, &sock->default_value_typed()->value); break; } + case SOCK_FUNCTION: { + BLO_read_id_address( + reader, lib, &sock->default_value_typed()->value); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -1329,7 +1341,6 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: break; } } @@ -1413,6 +1424,10 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) BLO_expand(expander, sock->default_value_typed()->value); break; } + case SOCK_FUNCTION: { + BLO_expand(expander, sock->default_value_typed()->value); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -1423,7 +1438,6 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: break; } } @@ -2070,6 +2084,12 @@ static void socket_id_user_increment(bNodeSocket *sock) id_us_plus(reinterpret_cast(default_value.value)); break; } + case SOCK_FUNCTION: { + bNodeSocketValueFunction &default_value = + *sock->default_value_typed(); + id_us_plus(reinterpret_cast(default_value.value)); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -2080,7 +2100,6 @@ static void socket_id_user_increment(bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: break; } } @@ -2117,6 +2136,12 @@ static bool socket_id_user_decrement(bNodeSocket *sock) id_us_min(reinterpret_cast(default_value.value)); return default_value.value != nullptr; } + case SOCK_FUNCTION: { + bNodeSocketValueFunction &default_value = + *sock->default_value_typed(); + id_us_min(reinterpret_cast(default_value.value)); + return default_value.value != nullptr; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -2127,7 +2152,6 @@ static bool socket_id_user_decrement(bNodeSocket *sock) case SOCK_CUSTOM: case SOCK_SHADER: case SOCK_GEOMETRY: - case SOCK_FUNCTION: break; } return false; @@ -2935,6 +2959,8 @@ static void *socket_value_storage(bNodeSocket &socket) return &socket.default_value_typed()->value; case SOCK_MATERIAL: return &socket.default_value_typed()->value; + case SOCK_FUNCTION: + return &socket.default_value_typed()->value; case SOCK_STRING: /* We don't want do this now! */ return nullptr; @@ -2992,7 +3018,8 @@ void node_socket_move_default_value(Main & /*bmain*/, SOCK_IMAGE, SOCK_MATERIAL, SOCK_TEXTURE, - SOCK_OBJECT)) + SOCK_OBJECT, + SOCK_FUNCTION)) { src_type.value_initialize(src_value); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 4a7f0c36973..5640bef4350 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -915,7 +915,8 @@ void DepsgraphNodeBuilder::build_object_modifiers(Object *object) } if (modifier_node->flag & DEPSOP_FLAG_USER_MODIFIED) { if (nmd->simulation_cache && - nmd->simulation_cache->cache_state() == bke::sim::CacheState::Valid) { + nmd->simulation_cache->cache_state() == bke::sim::CacheState::Valid) + { nmd->simulation_cache->invalidate(); } } @@ -1767,6 +1768,9 @@ void DepsgraphNodeBuilder::build_nodetree_socket(bNodeSocket *socket) else if (socket->type == SOCK_MATERIAL) { build_id((ID *)((bNodeSocketValueMaterial *)socket->default_value)->value); } + else if (socket->type == SOCK_FUNCTION) { + build_id((ID *)((bNodeSocketValueFunction *)socket->default_value)->value); + } } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 9a9aec2243f..32634c95099 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2647,6 +2647,12 @@ void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket) build_material(material); } } + else if (socket->type == SOCK_FUNCTION) { + bNodeTree *ntree = ((bNodeSocketValueFunction *)socket->default_value)->value; + if (ntree != nullptr) { + build_nodetree(ntree); + } + } } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 8100ec6f559..6f1758dbf13 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1294,7 +1294,8 @@ static void std_node_socket_draw( } if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_IS_LINKED) || - (sock->flag & SOCK_HIDE_VALUE)) { + (sock->flag & SOCK_HIDE_VALUE)) + { node_socket_button_label(C, layout, ptr, node_ptr, text); return; } @@ -1416,6 +1417,10 @@ static void std_node_socket_draw( uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } + case SOCK_FUNCTION: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); + break; + } default: node_socket_button_label(C, layout, ptr, node_ptr, text); break; @@ -1458,7 +1463,8 @@ static void std_node_socket_interface_draw(bContext * /*C*/, uiLayout *layout, P case SOCK_COLLECTION: case SOCK_IMAGE: case SOCK_TEXTURE: - case SOCK_MATERIAL: { + case SOCK_MATERIAL: + case SOCK_FUNCTION: { uiItemR(col, ptr, "default_value", DEFAULT_FLAGS, IFACE_("Default"), 0); break; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6e05fa30c88..2317c28cdce 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -756,6 +756,10 @@ typedef struct bNodeSocketValueMaterial { struct Material *value; } bNodeSocketValueMaterial; +typedef struct bNodeSocketValueFunction { + struct bNodeTree *value; +} bNodeSocketValueFunction; + /* Data structs, for `node->storage`. */ typedef enum CMPNodeMaskType { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 404c1c5e92a..fa296e62dd6 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4865,6 +4865,20 @@ bool rna_NodeSocketMaterial_default_value_poll(PointerRNA *UNUSED(ptr), PointerR return ma->gp_style == NULL; } +bool rna_NodeSocketFunction_default_value_poll(PointerRNA *ptr, PointerRNA value) +{ + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + bNodeTree *ngroup = value.data; + + /* only allow node trees of the same type as the group node's tree */ + if (ngroup->type != ntree->type) { + return false; + } + + const char *disabled_hint = NULL; + return nodeGroupPoll(ntree, ngroup, &disabled_hint); +} + static int rna_NodeConvertColorSpace_from_color_space_get(struct PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; @@ -12666,14 +12680,40 @@ static void rna_def_node_socket_function(BlenderRNA *brna, const char *interface_idname) { StructRNA *srna; + PropertyRNA *prop; srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); RNA_def_struct_ui_text(srna, "Function Node Socket", "Function socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); + RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value"); + + prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "value"); + RNA_def_property_struct_type(prop, "NodeTree"); + RNA_def_property_pointer_funcs( + prop, NULL, NULL, NULL, "rna_NodeSocketFunction_default_value_poll"); + RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); + RNA_def_property_update( + prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); RNA_def_struct_ui_text(srna, "Function Node Socket Interface", "Function socket of a node"); RNA_def_struct_sdna(srna, "bNodeSocket"); + + RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value"); + + prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "value"); + RNA_def_property_struct_type(prop, "NodeTree"); + RNA_def_property_pointer_funcs( + prop, NULL, NULL, NULL, "rna_NodeSocketFunction_default_value_poll"); + RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); } static void rna_def_node_socket_standard_types(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index aaf43482184..e6bfe236410 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -85,6 +85,7 @@ #include "ED_undo.h" #include "ED_viewer_path.hh" +#include "NOD_closure.hh" #include "NOD_geometry.h" #include "NOD_geometry_nodes_lazy_function.hh" #include "NOD_node_declaration.hh" @@ -144,6 +145,12 @@ static void add_used_ids_from_sockets(const ListBase &sockets, Set &ids) } break; } + case SOCK_FUNCTION: { + if (bNodeTree *ntree = ((bNodeSocketValueFunction *)socket->default_value)->value) { + ids.add(&ntree->id); + } + break; + } } } } @@ -508,6 +515,11 @@ static std::unique_ptr id_property_c socket.default_value); return bke::idprop::create(socket.identifier, reinterpret_cast(value->value)); } + case SOCK_FUNCTION: { + const bNodeSocketValueFunction *value = static_cast( + socket.default_value); + return bke::idprop::create(socket.identifier, reinterpret_cast(value->value)); + } } return nullptr; } @@ -532,6 +544,7 @@ static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDP case SOCK_TEXTURE: case SOCK_IMAGE: case SOCK_MATERIAL: + case SOCK_FUNCTION: return property.type == IDP_ID; } BLI_assert_unreachable(); @@ -611,6 +624,14 @@ static void init_socket_cpp_value_from_property(const IDProperty &property, *(Material **)r_value = material; break; } + case SOCK_FUNCTION: { + using Closure = blender::nodes::Closure; + + ID *id = IDP_Id(&property); + bNodeTree *ntree = (id && GS(id->name) == ID_NT) ? (bNodeTree *)id : nullptr; + new (r_value) Closure(Closure::make_from_node_tree(ntree)); + break; + } default: { BLI_assert_unreachable(); break; @@ -1792,6 +1813,10 @@ static void draw_property_for_socket(const bContext &C, uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE); break; } + case SOCK_FUNCTION: { + uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "node_groups", socket.name, ICON_NODETREE); + break; + } default: { if (input_has_attribute_toggle(*nmd->node_group, socket_index)) { add_attribute_search_or_value_buttons(C, row, *nmd, md_ptr, socket); diff --git a/source/blender/nodes/NOD_closure.hh b/source/blender/nodes/NOD_closure.hh index 51b76dc4875..82593066842 100644 --- a/source/blender/nodes/NOD_closure.hh +++ b/source/blender/nodes/NOD_closure.hh @@ -6,9 +6,10 @@ * \ingroup nodes */ -#include "BLI_cpp_type.hh" #include "BLI_generic_pointer.hh" +struct bNodeTree; + namespace blender::nodes { struct GeometryNodesLazyFunctionGraphInfo; @@ -31,11 +32,11 @@ class Closure { std::shared_ptr bound_values_; public: - Closure() = default; - Closure(const Closure &other) = default; + Closure(); + Closure(const Closure &other); explicit Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, MutableSpan &&bound_values); - ~Closure(); + ~Closure() = default; Closure &operator=(const Closure &other) = default; @@ -43,6 +44,8 @@ class Closure { Span bound_values() const; MutableSpan bound_values(); + + static Closure make_from_node_tree(const bNodeTree *node_tree); }; } // namespace blender::nodes diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index 3b6b48b642e..808a868b827 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -6,6 +6,10 @@ #include "NOD_closure.hh" +#include "DNA_node_types.h" + +#include "BKE_node_runtime.hh" + #include "NOD_geometry_nodes_lazy_function.hh" namespace blender::nodes { @@ -15,8 +19,10 @@ ClosureInputValues::ClosureInputValues(const Span &values) : va ClosureInputValues::~ClosureInputValues() { for (GMutablePointer &ptr : values_) { - ptr.destruct(); - MEM_freeN(ptr.get()); + if (ptr.get()) { + ptr.destruct(); + MEM_freeN(ptr.get()); + } } } @@ -30,6 +36,13 @@ MutableSpan ClosureInputValues::values() return values_; } +Closure::Closure() : bound_values_(nullptr) {} + +Closure::Closure(const Closure &other) + : lf_graph_info_(other.lf_graph_info_), bound_values_(other.bound_values_) +{ +} + Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, MutableSpan &&bound_values) : lf_graph_info_(&lf_graph_info), @@ -37,8 +50,6 @@ Closure::Closure(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info, { } -Closure::~Closure() {} - const GeometryNodesLazyFunctionGraphInfo *Closure::lf_graph_info() const { return lf_graph_info_; @@ -54,4 +65,21 @@ MutableSpan Closure::bound_values() return bound_values_->values(); } +Closure Closure ::make_from_node_tree(const bNodeTree *node_tree) +{ + if (node_tree == nullptr) { + return Closure(); + } + + BLI_assert(node_tree->runtime); + const std::unique_ptr &lf_graph_info_ptr = + node_tree->runtime->geometry_nodes_lazy_function_graph_info; + BLI_assert(lf_graph_info_ptr); + + Array bound_values(node_tree->interface_inputs().size()); + // TODO fill with default values of the tree + + return Closure(*lf_graph_info_ptr.get(), bound_values); +} + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index 2ef7eab82a1..eefd83c5c3b 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -256,9 +256,12 @@ SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree, dst = std::move(value); break; } - case SOCK_FUNCTION: - dst = std::make_unique(); + case SOCK_FUNCTION: { + auto value = std::make_unique(); + value->default_value_fn = get_default_id_getter(ntree, io_socket); + dst = std::move(value); break; + } case SOCK_CUSTOM: std::unique_ptr decl = std::make_unique(); decl->idname_ = io_socket.idname; @@ -368,7 +371,8 @@ void node_function_signature_declare(const bNodeFunctionSignature &sig, r_declaration.inputs.append(std::move(decl)); } for (const int socket_i : IndexRange(sig.outputs_num)) { - SocketDeclarationPtr decl = declaration_for_signature_parameter(sig.outputs[socket_i], SOCK_OUT); + SocketDeclarationPtr decl = declaration_for_signature_parameter(sig.outputs[socket_i], + SOCK_OUT); if (field_interface) { decl->output_field_dependency = field_interface->outputs[socket_i]; } @@ -543,7 +547,8 @@ bool BKE_node_is_connected_to_output(const bNodeTree *ntree, const bNode *node) for (const bNodeSocket *socket : next_node->output_sockets()) { for (const bNodeLink *link : socket->directly_linked_links()) { if (link->tonode->typeinfo->nclass == NODE_CLASS_OUTPUT && - link->tonode->flag & NODE_DO_OUTPUT) { + link->tonode->flag & NODE_DO_OUTPUT) + { return true; } nodes_to_check.push(link->tonode); diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 36e29d4858a..e3b5c29987d 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -418,6 +418,14 @@ void node_socket_init_default_value(bNodeSocket *sock) "node socket value material"); dval->value = nullptr; + sock->default_value = dval; + break; + } + case SOCK_FUNCTION: { + bNodeSocketValueFunction *dval = MEM_cnew( + "node socket value function"); + dval->value = nullptr; + sock->default_value = dval; break; } @@ -514,6 +522,13 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) id_us_plus(&toval->value->id); break; } + case SOCK_FUNCTION: { + bNodeSocketValueFunction *toval = (bNodeSocketValueFunction *)to->default_value; + bNodeSocketValueFunction *fromval = (bNodeSocketValueFunction *)from->default_value; + *toval = *fromval; + id_us_plus(&toval->value->id); + break; + } } to->flag |= (from->flag & SOCK_HIDE_VALUE); @@ -796,10 +811,13 @@ static bNodeSocketType *make_socket_type_material() static bNodeSocketType *make_socket_type_function() { + using Closure = blender::nodes::Closure; + bNodeSocketType *socktype = make_standard_socket_type(SOCK_FUNCTION, PROP_NONE); - socktype->base_cpp_type = &blender::CPPType::get(); - socktype->get_base_cpp_value = [](const bNodeSocket &/*socket*/, void *r_value) { - new (r_value) blender::nodes::Closure(); + socktype->base_cpp_type = &blender::CPPType::get(); + socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { + const bNodeTree *ntree = ((bNodeSocketValueFunction *)socket.default_value)->value; + new (r_value) Closure(Closure::make_from_node_tree(ntree)); }; socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; -- 2.30.2 From d4759b1503f22284a7e561993fb8ed6a9db38eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 15 May 2023 20:49:52 +0200 Subject: [PATCH 29/33] Ensure the node group graph info exists even if the group isn't used elsewhere. --- .../nodes/geometry/nodes/node_geo_bind_function.cc | 8 ++++---- source/blender/nodes/intern/closure.cc | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index 34845edd8e7..994a14d8c06 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -58,9 +58,9 @@ static void node_geo_exec(GeoNodeExecParams params) } const bNodeTree &bind_tree = *reinterpret_cast(params.node().id); - const std::unique_ptr &lf_graph_info_ptr = - bind_tree.runtime->geometry_nodes_lazy_function_graph_info; - BLI_assert(lf_graph_info_ptr); + const GeometryNodesLazyFunctionGraphInfo *lf_graph_info = + ensure_geometry_nodes_lazy_function_graph(bind_tree); + BLI_assert(lf_graph_info); Array bound_values(params.node().input_sockets().size()); for (const int i : params.node().input_sockets().index_range()) { @@ -94,7 +94,7 @@ static void node_geo_exec(GeoNodeExecParams params) bound_values[i] = {cpptype, bound_value_buffer}; } - Closure closure(*lf_graph_info_ptr, bound_values); + Closure closure(*lf_graph_info, bound_values); params.set_output("Function", std::move(closure)); params.set_default_remaining_outputs(); diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index 808a868b827..79d39011bd4 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -72,14 +72,14 @@ Closure Closure ::make_from_node_tree(const bNodeTree *node_tree) } BLI_assert(node_tree->runtime); - const std::unique_ptr &lf_graph_info_ptr = - node_tree->runtime->geometry_nodes_lazy_function_graph_info; - BLI_assert(lf_graph_info_ptr); + const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info = + ensure_geometry_nodes_lazy_function_graph(*node_tree); + BLI_assert(lf_graph_info); Array bound_values(node_tree->interface_inputs().size()); // TODO fill with default values of the tree - return Closure(*lf_graph_info_ptr.get(), bound_values); + return Closure(*lf_graph_info, bound_values); } } // namespace blender::nodes -- 2.30.2 From 693190a24ce79f7626752430495a106d4b7c1400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Mon, 15 May 2023 22:40:04 +0200 Subject: [PATCH 30/33] Fill default input values for node trees. --- source/blender/nodes/intern/closure.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/nodes/intern/closure.cc b/source/blender/nodes/intern/closure.cc index 79d39011bd4..71606cb910b 100644 --- a/source/blender/nodes/intern/closure.cc +++ b/source/blender/nodes/intern/closure.cc @@ -77,7 +77,16 @@ Closure Closure ::make_from_node_tree(const bNodeTree *node_tree) BLI_assert(lf_graph_info); Array bound_values(node_tree->interface_inputs().size()); - // TODO fill with default values of the tree + for (const int i : node_tree->interface_inputs().index_range()) { + const bNodeSocket *socket = node_tree->interface_inputs()[i]; + const CPPType *cpptype = socket->typeinfo->geometry_nodes_cpp_type; + if (cpptype && socket->typeinfo->get_geometry_nodes_cpp_value) { + void *buffer = MEM_mallocN_aligned( + cpptype->size(), cpptype->alignment(), "default graph input buffer"); + socket->typeinfo->get_geometry_nodes_cpp_value(*socket, buffer); + bound_values[i] = {cpptype, buffer}; + } + } return Closure(*lf_graph_info, bound_values); } -- 2.30.2 From 33413b3ff6a5cb3de8884113a3eb5280ca94ee78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 16 May 2023 09:25:16 +0200 Subject: [PATCH 31/33] Support all socket types in the bind node. --- .../geometry/nodes/node_geo_bind_function.cc | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc index 994a14d8c06..c9162dd85e2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bind_function.cc @@ -76,17 +76,62 @@ static void node_geo_exec(GeoNodeExecParams params) cpptype->move_construct(&value, bound_value_buffer); break; } - case SOCK_VECTOR: - case SOCK_RGBA: - case SOCK_BOOLEAN: - case SOCK_INT: - case SOCK_STRING: - case SOCK_OBJECT: - case SOCK_IMAGE: - case SOCK_GEOMETRY: - case SOCK_COLLECTION: - case SOCK_TEXTURE: - case SOCK_MATERIAL: + case SOCK_VECTOR: { + ValueOrField value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_RGBA: { + ValueOrField value = params.get_input( + socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_BOOLEAN: { + ValueOrField value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_INT: { + ValueOrField value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_STRING: { + ValueOrField value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_OBJECT: { + Object *value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_IMAGE: { + Image *value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_GEOMETRY: { + GeometrySet value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_COLLECTION: { + Collection *value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_TEXTURE: { + Tex *value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } + case SOCK_MATERIAL: { + Material *value = params.get_input(socket->identifier); + cpptype->move_construct(&value, bound_value_buffer); + break; + } case SOCK_FUNCTION: BLI_assert_unreachable(); } -- 2.30.2 From ef2966c8963616e4a5cc47faa2e512e9c1444da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 16 May 2023 18:02:11 +0200 Subject: [PATCH 32/33] Warning if the node graph does not provide all outputs. --- .../intern/geometry_nodes_lazy_function.cc | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index adca14520fe..160aa6e60c0 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1342,7 +1342,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { if (tree_logger) { tree_logger->node_warnings.append( {eval_node_.identifier, - {NodeWarningType::Info, + {NodeWarningType::Warning, tree_logger->allocator->copy_string("Function graph undefined")}}); } params.set_default_remaining_outputs(); @@ -1417,8 +1417,7 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { } /* These are written to if the graph outputs a value that is not captured by the evaluation - * node. - * XXX Could find a better way to handle this. */ + * node. */ Array unused_outputs(graph_outputs.size()); for (const int i : unused_outputs.index_range()) { const CPPType &cpptype = graph_outputs[i]->type(); @@ -1434,11 +1433,19 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { Array outer_output_indices(graph_outputs.size(), -1); /* Find a socket in the evaluation node that matches the graph socket. */ auto find_matching_socket = [](const Span &sockets, + const Span matched_sockets, const StringRef name, const CPPType &type) -> int { + BLI_assert(matched_sockets.size() == sockets.index_range().one_after_last()); for (const int socket_i : sockets.index_range()) { const bNodeSocket *socket = sockets[socket_i]; BLI_assert(socket->typeinfo->geometry_nodes_cpp_type != nullptr); + + /* Skip sockets that have been matched already. */ + if (matched_sockets[socket_i] >= 0) { + continue; + } + if (socket->name == name && *socket->typeinfo->geometry_nodes_cpp_type == type) { /* Index relative to the socket list (ignore the Function input socket). */ return socket_i - sockets.index_range().start(); @@ -1446,17 +1453,24 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { } return -1; }; + Array matched_inputs(eval_node_.input_sockets().size(), -1); for (const int i : lf_graph_info.mapping.group_input_sockets.index_range()) { const lf::OutputSocket *graph_input = lf_graph_info.mapping.group_input_sockets[i]; /* Drop the Function output socket at the start of the list. */ const int matching_socket_index = find_matching_socket( - eval_node_.input_sockets().drop_front(1), graph_input->name(), graph_input->type()); + eval_node_.input_sockets().drop_front(1), + matched_inputs, + graph_input->name(), + graph_input->type()); outer_input_indices[input_values_range[i]] = matching_socket_index; } + Array matched_outputs(eval_node_.output_sockets().size(), -1); for (const int i : lf_graph_info.mapping.standard_group_output_sockets.index_range()) { const lf::InputSocket *graph_output = lf_graph_info.mapping.standard_group_output_sockets[i]; - const int matching_socket_index = find_matching_socket( - eval_node_.output_sockets(), graph_output->name(), graph_output->type()); + const int matching_socket_index = find_matching_socket(eval_node_.output_sockets(), + matched_outputs, + graph_output->name(), + graph_output->type()); outer_output_indices[output_values_range[i]] = matching_socket_index; } for (const int i : lf_graph_info.mapping.group_output_used_sockets.index_range()) { @@ -1483,6 +1497,20 @@ class LazyFunctionForEvaluateFunctionNode : public LazyFunction { // } // } + /* If any output is not mapped the graph is considered invalid. */ + for (const int matched_graph_output : matched_outputs) { + if (matched_graph_output < 0) { + if (tree_logger) { + tree_logger->node_warnings.append( + {eval_node_.identifier, + {NodeWarningType::Warning, + tree_logger->allocator->copy_string("Missing output in graph")}}); + } + params.set_default_remaining_outputs(); + return; + } + } + LinearAllocator allocator; void *graph_executor_storage = graph_executor.init_storage(allocator); -- 2.30.2 From d7a6067f0a2f5130a903a0f7a0c3b8d3bd57f524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 19 May 2023 18:02:36 +0200 Subject: [PATCH 33/33] Fix merge errors. --- source/blender/blenkernel/intern/node.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 77bd0e44af9..7e992c98622 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -135,6 +135,8 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo); +} // namespace blender::bke + /* ************ NODE FUNCTION SIGNATURE *************** */ blender::Span bNodeFunctionSignature::inputs_span() const @@ -509,6 +511,8 @@ void nodeFunctionSignatureMoveParameter(bNodeFunctionSignature *sig, } } +namespace blender::bke { + static void ntree_init_data(ID *id) { bNodeTree *ntree = reinterpret_cast(id); @@ -1340,7 +1344,7 @@ static void lib_link_node_socket(BlendLibReader *reader, ID *self_id, bNodeSocke } case SOCK_FUNCTION: { BLO_read_id_address( - reader, lib, &sock->default_value_typed()->value); + reader, self_id, &sock->default_value_typed()->value); break; } case SOCK_FLOAT: @@ -3253,7 +3257,8 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node) /* remove the link that would be the same as the relinked one */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link_to_compare, &ntree->links) { if (link_to_compare->fromsock == fromlink->fromsock && - link_to_compare->tosock == link->tosock) { + link_to_compare->tosock == link->tosock) + { blender::bke::adjust_multi_input_indices_after_removed_link( ntree, link_to_compare->tosock, link_to_compare->multi_input_socket_index); duplicate_links_to_remove.append_non_duplicates(link_to_compare); -- 2.30.2