Blender V4.5
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 "NOD_geo_closure.hh"
14
16
17#include "BLO_read_write.hh"
18
20
22static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
23{
24 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(current_node_ptr->owner_id);
25 bNode *current_node = static_cast<bNode *>(current_node_ptr->data);
26
27 const bke::bNodeTreeZones *zones = ntree.zones();
28 if (!zones) {
29 return;
30 }
31 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(current_node->identifier);
32 if (!zone) {
33 return;
34 }
35 if (!zone->output_node_id) {
36 return;
37 }
38 bNode &output_node = const_cast<bNode &>(*zone->output_node());
39
40 if (current_node->type_legacy == GEO_NODE_CLOSURE_INPUT) {
41 if (uiLayout *panel = layout->panel(C, "input_items", false, TIP_("Input Items"))) {
43 C, panel, ntree, output_node);
45 ntree, output_node, [&](PointerRNA *item_ptr) {
46 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
47 });
48 }
49 }
50 else {
51 if (uiLayout *panel = layout->panel(C, "output_items", false, TIP_("Output Items"))) {
53 C, panel, ntree, output_node);
55 ntree, output_node, [&](PointerRNA *item_ptr) {
56 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
57 });
58 }
59 }
60}
61
62namespace input_node {
63
65
67{
68 const bNode *node = b.node_or_null();
69 const bNodeTree *tree = b.tree_or_null();
70 if (node && tree) {
71 const NodeGeometryClosureInput &storage = node_storage(*node);
72 const bNode *output_node = tree->node_by_id(storage.output_node_id);
73 if (output_node) {
74 const auto &output_storage = *static_cast<const NodeGeometryClosureOutput *>(
75 output_node->storage);
76 for (const int i : IndexRange(output_storage.input_items.items_num)) {
77 const NodeGeometryClosureInputItem &item = output_storage.input_items.items[i];
78 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
79 const std::string identifier = ClosureInputItemsAccessor::socket_identifier_for_item(item);
80 b.add_output(socket_type, item.name, identifier);
81 }
82 }
83 }
84 b.add_output<decl::Extend>("", "__extend__");
85}
86
87static void node_label(const bNodeTree * /*ntree*/,
88 const bNode * /*node*/,
89 char *label,
90 const int label_maxncpy)
91{
92 BLI_strncpy_utf8(label, IFACE_("Closure"), label_maxncpy);
93}
94
95static void node_init(bNodeTree * /*tree*/, bNode *node)
96{
98 node->storage = data;
99}
100
101static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
102{
103 bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
104 if (!output_node) {
105 return true;
106 }
108 *ntree, *node, *output_node, *link);
109}
110
111static void node_register()
112{
113 static blender::bke::bNodeType ntype;
114 geo_node_type_base(&ntype, "GeometryNodeClosureInput", GEO_NODE_CLOSURE_INPUT);
115 ntype.ui_name = "Closure Input";
117 ntype.declare = node_declare;
118 ntype.gather_link_search_ops = nullptr;
119 ntype.initfunc = node_init;
120 ntype.labelfunc = node_label;
121 ntype.no_muting = true;
125 ntype, "NodeGeometryClosureInput", node_free_standard_storage, node_copy_standard_storage);
127}
129
130} // namespace input_node
131
132namespace output_node {
133
135
137{
138 const bNodeTree *tree = b.tree_or_null();
139 const bNode *node = b.node_or_null();
140 if (node && tree) {
141 const NodeGeometryClosureOutput &storage = node_storage(*node);
142 for (const int i : IndexRange(storage.output_items.items_num)) {
143 const NodeGeometryClosureOutputItem &item = storage.output_items.items[i];
144 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
145 const std::string identifier = ClosureOutputItemsAccessor::socket_identifier_for_item(item);
146 b.add_input(socket_type, item.name, identifier);
147 }
148 }
149 b.add_input<decl::Extend>("", "__extend__");
150 b.add_output<decl::Closure>("Closure");
151}
152
153static void node_init(bNodeTree * /*tree*/, bNode *node)
154{
156 node->storage = data;
157}
158
159static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
160{
161 const NodeGeometryClosureOutput &src_storage = node_storage(*src_node);
162 auto *dst_storage = MEM_dupallocN<NodeGeometryClosureOutput>(__func__, src_storage);
163 dst_node->storage = dst_storage;
164
167}
168
175
176static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
177{
179 *ntree, *node, *node, *link);
180}
181
187
189 bNode &closure_input_node,
190 bNode &closure_output_node)
191{
192 snode.edittree->ensure_topology_cache();
193 bNodeSocket &closure_socket = closure_output_node.output_socket(0);
194
195 bke::ComputeContextCache compute_context_cache;
197 snode, compute_context_cache, closure_socket);
198 if (!current_context) {
199 /* The current tree does not have a known context, e.g. it is pinned but the modifier has been
200 * removed. */
201 return;
202 }
203 const ComputeContext *evaluate_context_generic =
205 current_context, closure_socket, compute_context_cache, std::nullopt);
206 if (!evaluate_context_generic) {
207 /* No evaluation of the closure found. */
208 return;
209 }
210 const auto *evaluate_context = dynamic_cast<const bke::EvaluateClosureComputeContext *>(
211 evaluate_context_generic);
212 if (!evaluate_context) {
213 return;
214 }
215 const bNode *evaluate_node = evaluate_context->node();
216 if (!evaluate_node) {
217 return;
218 }
219 const auto *storage = static_cast<const NodeGeometryEvaluateClosure *>(evaluate_node->storage);
220
221 for (const int i : IndexRange(storage->input_items.items_num)) {
222 const NodeGeometryEvaluateClosureInputItem &evaluate_item = storage->input_items.items[i];
224 closure_output_node, eNodeSocketDatatype(evaluate_item.socket_type), evaluate_item.name);
225 }
226 for (const int i : IndexRange(storage->output_items.items_num)) {
227 const NodeGeometryEvaluateClosureOutputItem &evaluate_item = storage->output_items.items[i];
229 closure_output_node, eNodeSocketDatatype(evaluate_item.socket_type), evaluate_item.name);
230 }
231 BKE_ntree_update_tag_node_property(snode.edittree, &closure_input_node);
232 BKE_ntree_update_tag_node_property(snode.edittree, &closure_output_node);
233
234 update_node_declaration_and_sockets(*snode.edittree, closure_input_node);
235 update_node_declaration_and_sockets(*snode.edittree, closure_output_node);
236
237 snode.edittree->ensure_topology_cache();
239 for (const bNodeSocket *eval_output_socket : evaluate_node->output_sockets()) {
241 *eval_output_socket);
242 if (!eval_input_socket) {
243 continue;
244 }
245 internal_links.append({&closure_input_node.output_socket(eval_input_socket->index() - 1),
246 &closure_output_node.input_socket(eval_output_socket->index())});
247 }
248 for (auto &&[from_socket, to_socket] : internal_links) {
250 *snode.edittree, closure_input_node, *from_socket, closure_output_node, *to_socket);
251 }
252}
253
255{
256 const bNodeSocket &other_socket = params.other_socket();
257 if (other_socket.type != SOCK_CLOSURE) {
258 return;
259 }
260 if (other_socket.in_out == SOCK_OUT) {
261 return;
262 }
263 params.add_item_full_name(IFACE_("Closure"), [](LinkSearchOpParams &params) {
264 bNode &input_node = params.add_node("GeometryNodeClosureInput");
265 bNode &output_node = params.add_node("GeometryNodeClosureOutput");
266 output_node.location[0] = 300;
267
268 auto &input_storage = *static_cast<NodeGeometryClosureInput *>(input_node.storage);
269 input_storage.output_node_id = output_node.identifier;
270
271 params.connect_available_socket(output_node, "Closure");
272
273 SpaceNode &snode = *CTX_wm_space_node(&params.C);
275 });
276}
277
278static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
279{
282}
283
289
290static void node_register()
291{
292 static blender::bke::bNodeType ntype;
293 geo_node_type_base(&ntype, "GeometryNodeClosureOutput", GEO_NODE_CLOSURE_OUTPUT);
294 ntype.ui_name = "Closure Output";
296 ntype.declare = node_declare;
297 ntype.initfunc = node_init;
299 ntype.no_muting = true;
306 bke::node_type_storage(ntype, "NodeGeometryClosureOutput", node_free_storage, node_copy_storage);
308}
310
311} // namespace output_node
312
313} // namespace blender::nodes::node_geo_closure_cc
314
315namespace blender::nodes {
316
317StructRNA *ClosureInputItemsAccessor::item_srna = &RNA_NodeGeometryClosureInputItem;
318
320{
321 BLO_write_string(writer, item.name);
322}
323
328
329StructRNA *ClosureOutputItemsAccessor::item_srna = &RNA_NodeGeometryClosureOutputItem;
330
332{
333 BLO_write_string(writer, item.name);
334}
335
340
341} // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:445
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#define GEO_NODE_CLOSURE_OUTPUT
#define GEO_NODE_CLOSURE_INPUT
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
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:5351
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define TIP_(msgid)
#define IFACE_(msgid)
@ 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
void append(const T &value)
std::optional< int > output_node_id
const bNode * output_node() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) 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
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
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:5603
const ComputeContext * compute_context_for_edittree_socket(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNodeSocket &socket)
const ComputeContext * compute_context_for_closure_evaluation(const ComputeContext *closure_socket_context, const bNodeSocket &closure_socket, bke::ComputeContextCache &compute_context_cache, const std::optional< nodes::ClosureSourceLocation > &source_location)
static void node_init(bNodeTree *, bNode *node)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
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 void node_init(bNodeTree *, bNode *node)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void try_initialize_closure_from_evaluator(SpaceNode &snode, bNode &closure_input_node, bNode &closure_output_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)
Accessor::ItemT * add_item_with_socket_type_and_name(bNode &node, const eNodeSocketDatatype socket_type, const char *name)
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)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
const bNodeSocket * evaluate_closure_node_internally_linked_input(const bNodeSocket &output_socket)
void 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
NodeGeometryClosureOutputItem * items
NodeGeometryClosureOutputItems output_items
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:226
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:383
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:384
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:258
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:249
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:321
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* register_operators)()
Definition BKE_node.hh:410
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)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
i
Definition text_draw.cc:230