Blender V5.0
node_geo_evaluate_closure.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6#include "UI_resources.hh"
7
8#include "NOD_geo_closure.hh"
13#include "NOD_sync_sockets.hh"
14
15#include "BKE_idprop.hh"
16
17#include "BLO_read_write.hh"
18
19#include "node_geometry_util.hh"
21
23
25
27{
28 b.use_custom_socket_order();
29 b.allow_any_socket_order();
30
31 b.add_input<decl::Closure>("Closure");
32
33 const bNode *node = b.node_or_null();
34 auto &panel = b.add_panel("Interface");
35 if (node) {
36 const auto &storage = node_storage(*node);
37 for (const int i : IndexRange(storage.output_items.items_num)) {
38 const NodeEvaluateClosureOutputItem &item = storage.output_items.items[i];
39 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
40 const std::string identifier =
42 auto &decl = panel.add_output(socket_type, item.name, identifier);
44 decl.structure_type(StructureType(item.structure_type));
45 }
46 else {
47 decl.structure_type(StructureType::Dynamic);
48 }
49 }
50 panel.add_output<decl::Extend>("", "__extend__");
51 for (const int i : IndexRange(storage.input_items.items_num)) {
52 const NodeEvaluateClosureInputItem &item = storage.input_items.items[i];
53 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
55 item);
56 auto &decl = panel.add_input(socket_type, item.name, identifier);
58 decl.structure_type(StructureType(item.structure_type));
59 }
60 else {
61 decl.structure_type(StructureType::Dynamic);
62 }
63 }
64 panel.add_input<decl::Extend>("", "__extend__");
65 }
66}
67
68static void node_init(bNodeTree * /*tree*/, bNode *node)
69{
70 auto *storage = MEM_callocN<NodeEvaluateClosure>(__func__);
71 node->storage = storage;
72}
73
74static void node_copy_storage(bNodeTree * /*tree*/, bNode *dst_node, const bNode *src_node)
75{
76 const NodeEvaluateClosure &src_storage = node_storage(*src_node);
77 auto *dst_storage = MEM_dupallocN<NodeEvaluateClosure>(__func__, src_storage);
78 dst_node->storage = dst_storage;
79
82}
83
90
92{
93 if (params.C && params.link.tosock == params.node.inputs.first &&
94 params.link.fromsock->type == SOCK_CLOSURE)
95 {
96 const NodeEvaluateClosure &storage = node_storage(params.node);
97 if (storage.input_items.items_num == 0 && storage.output_items.items_num == 0) {
99 if (snode && snode->edittree == &params.ntree) {
100 sync_sockets_evaluate_closure(*snode, params.node, nullptr, params.link.fromsock);
101 }
102 }
103 return true;
104 }
105 if (params.link.tonode == &params.node) {
107 params.ntree, params.node, params.node, params.link);
108 }
110 params.ntree, params.node, params.node, params.link);
111}
112
114{
115 bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
116 bNode &node = *static_cast<bNode *>(ptr->data);
117
118 layout->use_property_split_set(true);
119 layout->use_property_decorate_set(false);
120
121 layout->op("node.sockets_sync", IFACE_("Sync"), ICON_FILE_REFRESH);
122 layout->prop(ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
123
124 if (uiLayout *panel = layout->panel(C, "input_items", false, IFACE_("Input Items"))) {
126 C, panel, tree, node);
128 tree, node, [&](PointerRNA *item_ptr) {
129 const auto &item = *item_ptr->data_as<NodeEvaluateClosureInputItem>();
130 panel->use_property_split_set(true);
131 panel->use_property_decorate_set(false);
132 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
133 if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
134 panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, IFACE_("Shape"), ICON_NONE);
135 }
136 });
137 }
138 if (uiLayout *panel = layout->panel(C, "output_items", false, IFACE_("Output Items"))) {
140 C, panel, tree, node);
142 tree, node, [&](PointerRNA *item_ptr) {
143 const auto &item = *item_ptr->data_as<NodeEvaluateClosureOutputItem>();
144 panel->use_property_split_set(true);
145 panel->use_property_decorate_set(false);
146 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
147 if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
148 panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, IFACE_("Shape"), ICON_NONE);
149 }
150 });
151 }
152}
153
155 const bNode & /*node*/,
156 const bNodeSocket &output_socket)
157{
159}
160
162{
163 const bNodeSocket &other_socket = params.other_socket();
164 if (other_socket.in_out == SOCK_IN) {
165 params.add_item(IFACE_("Item"), [](LinkSearchOpParams &params) {
166 bNode &node = params.add_node("NodeEvaluateClosure");
167 const auto *item =
169 params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
170 params.update_and_connect_available_socket(node, item->name);
171 });
172 return;
173 }
174 if (other_socket.type == SOCK_CLOSURE) {
175 params.add_item(IFACE_("Closure"), [](LinkSearchOpParams &params) {
176 bNode &node = params.add_node("NodeEvaluateClosure");
177 params.connect_available_socket(node, "Closure");
178
179 SpaceNode &snode = *CTX_wm_space_node(&params.C);
180 sync_sockets_evaluate_closure(snode, node, nullptr);
181 });
182 }
184 params.node_tree().type))
185 {
186 params.add_item(
187 IFACE_("Item"),
189 bNode &node = params.add_node("NodeEvaluateClosure");
190 const auto *item =
192 params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
194 params.connect_available_socket_by_identifier(
196 },
197 other_socket.type == SOCK_CLOSURE ? -1 : 0);
198 }
199}
200
206
212
218
219static void node_register()
220{
221 static blender::bke::bNodeType ntype;
222
223 sh_geo_node_type_base(&ntype, "NodeEvaluateClosure", NODE_EVALUATE_CLOSURE);
224 ntype.ui_name = "Evaluate Closure";
225 ntype.ui_description = "Execute a given closure";
227 ntype.declare = node_declare;
228 ntype.initfunc = node_init;
236 bke::node_type_storage(ntype, "NodeEvaluateClosure", node_free_storage, node_copy_storage);
238}
240
241} // namespace blender::nodes::node_geo_evaluate_closure_cc
242
243namespace blender::nodes {
244
245StructRNA *EvaluateClosureInputItemsAccessor::item_srna = &RNA_NodeEvaluateClosureInputItem;
246
248{
249 BLO_write_string(writer, item.name);
250}
251
256
257StructRNA *EvaluateClosureOutputItemsAccessor::item_srna = &RNA_NodeEvaluateClosureOutputItem;
258
263
268
270{
271 const bNode &node = output_socket.owner_node();
272 const bNodeTree &tree = node.owner_tree();
273 BLI_assert(node.is_type("NodeEvaluateClosure"));
274 const auto &storage = *static_cast<const NodeEvaluateClosure *>(node.storage);
275 if (output_socket.index() >= storage.output_items.items_num) {
276 return nullptr;
277 }
278 const NodeEvaluateClosureOutputItem &output_item =
279 storage.output_items.items[output_socket.index()];
280 const StringRef output_key = output_item.name;
281 for (const int i : IndexRange(storage.input_items.items_num)) {
282 const NodeEvaluateClosureInputItem &input_item = storage.input_items.items[i];
283 const StringRef input_key = input_item.name;
284 if (output_key == input_key) {
285 if (!tree.typeinfo->validate_link ||
286 tree.typeinfo->validate_link(eNodeSocketDatatype(input_item.socket_type),
287 eNodeSocketDatatype(output_item.socket_type)))
288 {
289 return &node.input_socket(i + 1);
290 }
291 }
292 }
293 return nullptr;
294}
295
296} // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_EVALUATE_CLOSURE
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define IFACE_(msgid)
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_CLOSURE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
KDTree_3d * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
static void node_declare(NodeDeclarationBuilder &b)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static const bNodeSocket * node_internally_linked_input(const bNodeTree &, const bNode &, const bNodeSocket &output_socket)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_init(bNodeTree *, bNode *node)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
void blend_read_data(BlendDataReader *reader, bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNodeTree &ntree, bNode &node, const eNodeSocketDatatype socket_type, const char *name, std::optional< int > dimensions=std::nullopt)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt, typename Accessor::ItemT **r_new_item=nullptr)
void sync_sockets_evaluate_closure(SpaceNode &snode, bNode &evaluate_closure_node, ReportList *reports, const bNodeSocket *src_closure_socket)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
const bNodeSocket * evaluate_closure_node_internally_linked_input(const bNodeSocket &output_socket)
bool socket_type_always_single(const eNodeSocketDatatype socket_type)
void sh_geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
NodeEvaluateClosureInputItems input_items
NodeEvaluateClosureOutputItems output_items
T * data_as() const
Definition RNA_types.hh:124
struct bNodeTree * edittree
bNodeSocketTypeHandle * typeinfo
char name[64]
void * storage
Defines a node type.
Definition BKE_node.hh:238
NodeInternallyLinkedInputFunction internally_linked_input
Definition BKE_node.hh:384
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:390
std::string ui_description
Definition BKE_node.hh:244
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:391
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:261
bool(* insert_link)(NodeInsertLinkParams &params)
Definition BKE_node.hh:333
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* register_operators)()
Definition BKE_node.hh:417
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static bool supports_socket_type(const eNodeSocketDatatype socket_type, const int ntree_type)
static std::string socket_identifier_for_item(const ItemT &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static std::string socket_identifier_for_item(const ItemT &item)
void use_property_decorate_set(bool is_sep)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238