Blender V5.0
node_geo_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
7#include "BLI_string_utf8.h"
8
9#include "BKE_idprop.hh"
10
11#include "NOD_geo_closure.hh"
16#include "NOD_sync_sockets.hh"
17
18#include "BLO_read_write.hh"
20
22
24static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
25{
26 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(current_node_ptr->owner_id);
27 bNode *current_node = static_cast<bNode *>(current_node_ptr->data);
28
29 const bke::bNodeTreeZones *zones = ntree.zones();
30 if (!zones) {
31 return;
32 }
33 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(current_node->identifier);
34 if (!zone) {
35 return;
36 }
37 if (!zone->output_node_id) {
38 return;
39 }
40 bNode &output_node = const_cast<bNode &>(*zone->output_node());
41
42 layout->use_property_split_set(true);
43 layout->use_property_decorate_set(false);
44
45 PointerRNA output_node_ptr = RNA_pointer_create_discrete(&ntree.id, &RNA_Node, &output_node);
46
47 layout->op("node.sockets_sync", IFACE_("Sync"), ICON_FILE_REFRESH);
48 layout->prop(&output_node_ptr, "define_signature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
49 if (current_node->type_legacy == NODE_CLOSURE_INPUT) {
50 if (uiLayout *panel = layout->panel(C, "input_items", false, IFACE_("Input Items"))) {
52 C, panel, ntree, output_node);
54 ntree, output_node, [&](PointerRNA *item_ptr) {
55 const auto &item = *item_ptr->data_as<NodeClosureInputItem>();
56 panel->use_property_split_set(true);
57 panel->use_property_decorate_set(false);
58 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
59 if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
60 panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, IFACE_("Shape"), ICON_NONE);
61 }
62 });
63 }
64 }
65 else {
66 if (uiLayout *panel = layout->panel(C, "output_items", false, IFACE_("Output Items"))) {
68 C, panel, ntree, output_node);
70 ntree, output_node, [&](PointerRNA *item_ptr) {
71 const auto &item = *item_ptr->data_as<NodeClosureOutputItem>();
72 panel->use_property_split_set(true);
73 panel->use_property_decorate_set(false);
74 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
75 if (!socket_type_always_single(eNodeSocketDatatype(item.socket_type))) {
76 panel->prop(item_ptr, "structure_type", UI_ITEM_NONE, IFACE_("Shape"), ICON_NONE);
77 }
78 });
79 }
80 }
81}
82
83namespace input_node {
84
86
88{
89 const bNode *node = b.node_or_null();
90 const bNodeTree *tree = b.tree_or_null();
91 if (node && tree) {
92 const NodeClosureInput &storage = node_storage(*node);
93 const bNode *output_node = tree->node_by_id(storage.output_node_id);
94 if (output_node) {
95 const auto &output_storage = *static_cast<const NodeClosureOutput *>(output_node->storage);
96 for (const int i : IndexRange(output_storage.input_items.items_num)) {
97 const NodeClosureInputItem &item = output_storage.input_items.items[i];
98 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
99 const std::string identifier = ClosureInputItemsAccessor::socket_identifier_for_item(item);
100 auto &decl = b.add_output(socket_type, item.name, identifier);
102 decl.structure_type(StructureType(item.structure_type));
103 }
104 else {
105 decl.structure_type(StructureType::Dynamic);
106 }
107 }
108 }
109 }
110 b.add_output<decl::Extend>("", "__extend__");
111}
112
113static void node_label(const bNodeTree * /*ntree*/,
114 const bNode * /*node*/,
115 char *label,
116 const int label_maxncpy)
117{
118 BLI_strncpy_utf8(label, CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, "Closure"), label_maxncpy);
119}
120
121static void node_init(bNodeTree * /*tree*/, bNode *node)
122{
124 node->storage = data;
125}
126
128{
129 bNode *output_node = params.ntree.node_by_id(node_storage(params.node).output_node_id);
130 if (!output_node) {
131 return true;
132 }
134 params.ntree, params.node, *output_node, params.link);
135}
136
137static void node_register()
138{
139 static blender::bke::bNodeType ntype;
140 sh_geo_node_type_base(&ntype, "NodeClosureInput", NODE_CLOSURE_INPUT);
141 ntype.ui_name = "Closure Input";
143 ntype.declare = node_declare;
144 ntype.gather_link_search_ops = nullptr;
145 ntype.initfunc = node_init;
146 ntype.labelfunc = node_label;
147 ntype.no_muting = true;
151 ntype, "NodeClosureInput", node_free_standard_storage, node_copy_standard_storage);
153}
155
156} // namespace input_node
157
158namespace output_node {
159
161
163{
164 const bNodeTree *tree = b.tree_or_null();
165 const bNode *node = b.node_or_null();
166 if (node && tree) {
167 const NodeClosureOutput &storage = node_storage(*node);
168 for (const int i : IndexRange(storage.output_items.items_num)) {
169 const NodeClosureOutputItem &item = storage.output_items.items[i];
170 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
171 const std::string identifier = ClosureOutputItemsAccessor::socket_identifier_for_item(item);
172 auto &decl = b.add_input(socket_type, item.name, identifier).supports_field();
174 decl.structure_type(StructureType(item.structure_type));
175 }
176 else {
177 decl.structure_type(StructureType::Dynamic);
178 }
179 }
180 }
181 b.add_input<decl::Extend>("", "__extend__");
182 b.add_output<decl::Closure>("Closure");
183}
184
185static void node_init(bNodeTree * /*tree*/, bNode *node)
186{
188 node->storage = data;
189}
190
191static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
192{
193 const NodeClosureOutput &src_storage = node_storage(*src_node);
194 auto *dst_storage = MEM_dupallocN<NodeClosureOutput>(__func__, src_storage);
195 dst_node->storage = dst_storage;
196
199}
200
207
209{
210 if (params.C && params.link.fromnode == &params.node && params.link.tosock->type == SOCK_CLOSURE)
211 {
212 const NodeClosureOutput &storage = node_storage(params.node);
213 if (storage.input_items.items_num == 0 && storage.output_items.items_num == 0) {
215 if (snode && snode->edittree == &params.ntree) {
218 if (input_node) {
219 sync_sockets_closure(*snode, *input_node, params.node, nullptr, params.link.tosock);
220 }
221 }
222 }
223 return true;
224 }
226 params.ntree, params.node, params.node, params.link);
227}
228
234
236{
237 const bNodeSocket &other_socket = params.other_socket();
238 if (other_socket.type != SOCK_CLOSURE) {
239 return;
240 }
241 if (other_socket.in_out == SOCK_OUT) {
242 return;
243 }
244 params.add_item_full_name(IFACE_("Closure"), [](LinkSearchOpParams &params) {
245 bNode &input_node = params.add_node("NodeClosureInput");
246 bNode &output_node = params.add_node("NodeClosureOutput");
247 output_node.location[0] = 300;
248
249 auto &input_storage = *static_cast<NodeClosureInput *>(input_node.storage);
250 input_storage.output_node_id = output_node.identifier;
251
252 params.connect_available_socket(output_node, "Closure");
253
254 SpaceNode &snode = *CTX_wm_space_node(&params.C);
256 });
257}
258
259static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
260{
263}
264
270
291
292} // namespace output_node
293
294} // namespace blender::nodes::node_geo_closure_cc
295
296namespace blender::nodes {
297
298StructRNA *ClosureInputItemsAccessor::item_srna = &RNA_NodeClosureInputItem;
299
301{
302 BLO_write_string(writer, item.name);
303}
304
309
310StructRNA *ClosureOutputItemsAccessor::item_srna = &RNA_NodeClosureOutputItem;
311
313{
314 BLO_write_string(writer, item.name);
315}
316
321
322} // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:459
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_CLOSURE_OUTPUT
#define NODE_CLOSURE_INPUT
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLT_I18NCONTEXT_ID_NODETREE
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO
@ SOCK_OUT
eNodeSocketDatatype
@ SOCK_CLOSURE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
BMesh const char void * data
std::optional< int > output_node_id
const bNode * output_node() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
const bNode * get_corresponding_input(const bNodeTree &tree, const bNode &output_bnode) const
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
const bNodeZoneType * zone_type_by_node_type(const int node_type)
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_init(bNodeTree *, bNode *node)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void node_label(const bNodeTree *, const bNode *, char *label, const int label_maxncpy)
static void node_declare(NodeDeclarationBuilder &b)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void node_init(bNodeTree *, bNode *node)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_declare(NodeDeclarationBuilder &b)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
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)
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_closure(SpaceNode &snode, bNode &closure_input_node, bNode &closure_output_node, ReportList *reports, const bNodeSocket *src_closure_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)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
NodeClosureOutputItem * items
NodeClosureOutputItems output_items
NodeClosureInputItems input_items
T * data_as() const
Definition RNA_types.hh:124
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
struct bNodeTree * edittree
int16_t type_legacy
void * storage
int32_t identifier
Defines a node type.
Definition BKE_node.hh:238
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:390
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:391
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:270
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 std::string socket_identifier_for_item(const ItemT &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static std::string socket_identifier_for_item(const ItemT &item)
static void blend_read_data_item(BlendDataReader *reader, 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