Blender V5.0
node_geo_repeat.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_string.h"
6#include "BLI_string_utf8.h"
7
8#include "NOD_geo_repeat.hh"
9#include "NOD_socket.hh"
14
15#include "BLO_read_write.hh"
16
17#include "RNA_access.hh"
18#include "RNA_prototypes.hh"
19
20#include "BKE_screen.hh"
21
22#include "WM_api.hh"
23
25
26#include "node_geometry_util.hh"
28
30
32static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
33{
34 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(current_node_ptr->owner_id);
35 bNode *current_node = static_cast<bNode *>(current_node_ptr->data);
36
37 const bke::bNodeTreeZones *zones = ntree.zones();
38 if (!zones) {
39 return;
40 }
41 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(current_node->identifier);
42 if (!zone) {
43 return;
44 }
45 if (!zone->output_node_id) {
46 return;
47 }
48 bNode &output_node = const_cast<bNode &>(*zone->output_node());
50 current_node_ptr->owner_id, &RNA_Node, &output_node);
51
52 if (uiLayout *panel = layout->panel(C, "repeat_items", false, IFACE_("Repeat Items"))) {
54 C, panel, ntree, output_node);
56 ntree, output_node, [&](PointerRNA *item_ptr) {
57 panel->use_property_split_set(true);
58 panel->use_property_decorate_set(false);
59 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
60 });
61 }
62
63 layout->prop(&output_node_ptr, "inspection_index", UI_ITEM_NONE, std::nullopt, ICON_NONE);
64}
65
67
69
71{
72 b.use_custom_socket_order();
73 b.allow_any_socket_order();
74 b.add_output<decl::Int>("Iteration")
75 .description("Index of the current iteration. Starts counting at zero");
76 b.add_input<decl::Int>("Iterations").min(0).default_value(1);
77
78 const bNode *node = b.node_or_null();
79 const bNodeTree *tree = b.tree_or_null();
80 if (node && tree) {
81 const NodeGeometryRepeatInput &storage = node_storage(*node);
82 if (const bNode *output_node = tree->node_by_id(storage.output_node_id)) {
83 const auto &output_storage = *static_cast<const NodeGeometryRepeatOutput *>(
84 output_node->storage);
85 for (const int i : IndexRange(output_storage.items_num)) {
86 const NodeRepeatItem &item = output_storage.items[i];
87 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
88 const StringRef name = item.name ? item.name : "";
89 const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
90 auto &input_decl = b.add_input(socket_type, name, identifier)
91 .socket_name_ptr(
92 &tree->id, RepeatItemsAccessor::item_srna, &item, "name");
93 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
94 if (socket_type_supports_fields(socket_type)) {
95 input_decl.supports_field();
96 output_decl.dependent_field({input_decl.index()});
97 }
98 input_decl.structure_type(StructureType::Dynamic);
99 output_decl.structure_type(StructureType::Dynamic);
100 }
101 }
102 }
103 b.add_input<decl::Extend>("", "__extend__").structure_type(StructureType::Dynamic);
104 b.add_output<decl::Extend>("", "__extend__")
105 .structure_type(StructureType::Dynamic)
106 .align_with_previous();
107}
108
109static void node_init(bNodeTree * /*tree*/, bNode *node)
110{
112 /* Needs to be initialized for the node to work. */
113 data->output_node_id = 0;
114 node->storage = data;
115}
116
117static void node_label(const bNodeTree * /*ntree*/,
118 const bNode * /*node*/,
119 char *label,
120 const int label_maxncpy)
121{
122 BLI_strncpy_utf8(label, CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, "Repeat"), label_maxncpy);
123}
124
126{
127 bNode *output_node = params.ntree.node_by_id(node_storage(params.node).output_node_id);
128 if (!output_node) {
129 return true;
130 }
132 params.ntree, params.node, *output_node, params.link);
133}
134
136 bNode *node,
137 bNodeExecData * /*execdata*/,
140{
141 int zone_id = node_storage(*node).output_node_id;
142 return GPU_stack_link_zone(mat, node, "REPEAT_BEGIN", in, out, zone_id, false, 1, 1);
143}
144
145static void node_register()
146{
147 static blender::bke::bNodeType ntype;
148 sh_geo_node_type_base(&ntype, "GeometryNodeRepeatInput", GEO_NODE_REPEAT_INPUT);
149 ntype.ui_name = "Repeat Input";
150 ntype.enum_name_legacy = "REPEAT_INPUT";
152 ntype.initfunc = node_init;
153 ntype.declare = node_declare;
154 ntype.labelfunc = node_label;
155 ntype.gather_link_search_ops = nullptr;
157 ntype.no_muting = true;
159 ntype.gpu_fn = node_shader_fn;
161 ntype, "NodeGeometryRepeatInput", node_free_standard_storage, node_copy_standard_storage);
163}
165
166} // namespace repeat_input_node
167
169
171
173{
174 b.use_custom_socket_order();
175 b.allow_any_socket_order();
176 const bNodeTree *tree = b.tree_or_null();
177 const bNode *node = b.node_or_null();
178 if (node) {
179 const NodeGeometryRepeatOutput &storage = node_storage(*node);
180 for (const int i : IndexRange(storage.items_num)) {
181 const NodeRepeatItem &item = storage.items[i];
182 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
183 const StringRef name = item.name ? item.name : "";
184 const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
185 auto &input_decl = b.add_input(socket_type, name, identifier)
186 .socket_name_ptr(
187 &tree->id, RepeatItemsAccessor::item_srna, &item, "name");
188 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
189 if (socket_type_supports_fields(socket_type)) {
190 input_decl.supports_field();
191 output_decl.dependent_field({input_decl.index()});
192 }
193 input_decl.structure_type(StructureType::Dynamic);
194 output_decl.structure_type(StructureType::Dynamic);
195 }
196 }
197 b.add_input<decl::Extend>("", "__extend__").structure_type(StructureType::Dynamic);
198 b.add_output<decl::Extend>("", "__extend__")
199 .structure_type(StructureType::Dynamic)
200 .align_with_previous();
201}
202
203static void node_init(bNodeTree *tree, bNode *node)
204{
206
207 data->next_identifier = 0;
208
209 if (tree->type == NTREE_GEOMETRY) {
210 data->items = MEM_calloc_arrayN<NodeRepeatItem>(1, __func__);
211 data->items[0].name = BLI_strdup(DATA_("Geometry"));
212 data->items[0].socket_type = SOCK_GEOMETRY;
213 data->items[0].identifier = data->next_identifier++;
214 data->items_num = 1;
215 }
216
217 node->storage = data;
218}
219
225
226static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
227{
228 const NodeGeometryRepeatOutput &src_storage = node_storage(*src_node);
229 auto *dst_storage = MEM_dupallocN<NodeGeometryRepeatOutput>(__func__, src_storage);
230 dst_node->storage = dst_storage;
231
233}
234
240
245
247{
248 const bNodeSocket &other_socket = params.other_socket();
250 params.node_tree().type))
251 {
252 return;
253 }
254 params.add_item_full_name(IFACE_("Repeat"), [](LinkSearchOpParams &params) {
255 bNode &input_node = params.add_node("GeometryNodeRepeatInput");
256 bNode &output_node = params.add_node("GeometryNodeRepeatOutput");
257 output_node.location[0] = 300;
258
259 auto &input_storage = *static_cast<NodeGeometryRepeatInput *>(input_node.storage);
260 input_storage.output_node_id = output_node.identifier;
261
264 params.node_tree,
265 output_node,
266 eNodeSocketDatatype(params.socket.type),
267 params.socket.name);
268 update_node_declaration_and_sockets(params.node_tree, input_node);
269 update_node_declaration_and_sockets(params.node_tree, output_node);
270 if (params.socket.in_out == SOCK_IN) {
271 params.connect_available_socket(output_node, params.socket.name);
272 }
273 else {
274 params.connect_available_socket(input_node, params.socket.name);
275 }
276 params.node_tree.ensure_topology_cache();
277 bke::node_add_link(params.node_tree,
278 input_node,
279 input_node.output_socket(1),
280 output_node,
281 output_node.input_socket(0));
282 });
283}
284
285static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
286{
288}
289
290static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader &reader)
291{
293}
294
296 bNode *node,
297 bNodeExecData * /*execdata*/,
300{
301 int zone_id = node->identifier;
302 return GPU_stack_link_zone(mat, node, "REPEAT_END", in, out, zone_id, true, 0, 0);
303}
304
305static void node_register()
306{
307 static blender::bke::bNodeType ntype;
308 sh_geo_node_type_base(&ntype, "GeometryNodeRepeatOutput", GEO_NODE_REPEAT_OUTPUT);
309 ntype.ui_name = "Repeat Output";
310 ntype.enum_name_legacy = "REPEAT_OUTPUT";
312 ntype.initfunc = node_init;
313 ntype.declare = node_declare;
317 ntype.no_muting = true;
322 ntype.gpu_fn = node_shader_fn;
324 ntype, "NodeGeometryRepeatOutput", node_free_storage, node_copy_storage);
326}
328
329} // namespace repeat_output_node
330
331} // namespace blender::nodes::node_geo_repeat_cc
332
333namespace blender::nodes {
334
336
338{
339 BLO_write_string(writer, item.name);
340}
341
343{
344 BLO_read_string(reader, &item.name);
345}
346
347} // namespace blender::nodes
348
349blender::Span<NodeRepeatItem> NodeGeometryRepeatOutput::items_span() const
350{
351 return blender::Span<NodeRepeatItem>(items, items_num);
352}
353
354blender::MutableSpan<NodeRepeatItem> NodeGeometryRepeatOutput::items_span()
355{
356 return blender::MutableSpan<NodeRepeatItem>(items, items_num);
357}
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:459
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define GEO_NODE_REPEAT_OUTPUT
#define GEO_NODE_REPEAT_INPUT
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
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)
#define DATA_(msgid)
@ NTREE_GEOMETRY
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_GEOMETRY
bool GPU_stack_link_zone(GPUMaterial *material, const bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, int zone_index, bool is_zone_end, int in_argument_count, int out_argument_count)
#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
KDTree_3d * tree
#define in
#define out
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
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
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
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 int node_shader_fn(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_label(const bNodeTree *, const bNode *, char *label, const int label_maxncpy)
static void node_declare(NodeDeclarationBuilder &b)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static int node_shader_fn(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_declare(NodeDeclarationBuilder &b)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void node_init(bNodeTree *tree, bNode *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(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 update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
bool socket_type_supports_fields(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
const char * name
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
#define min(a, b)
Definition sort.cc:36
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
float location[2]
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
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:261
const char * enum_name_legacy
Definition BKE_node.hh:247
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_write_item(BlendWriter *writer, const ItemT &item)
static bool supports_socket_type(const eNodeSocketDatatype socket_type, const int ntree_type)
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static std::string socket_identifier_for_item(const NodeRepeatItem &item)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
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