Blender V4.3
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"
11
12#include "BLO_read_write.hh"
13
14#include "BLI_string_utils.hh"
15
16#include "RNA_access.hh"
17#include "RNA_prototypes.hh"
18
19#include "BKE_screen.hh"
20
21#include "WM_api.hh"
22
23#include "UI_interface.hh"
24
25#include "node_geometry_util.hh"
26
28
29static void draw_repeat_state_item(uiList * /*ui_list*/,
30 const bContext *C,
31 uiLayout *layout,
32 PointerRNA * /*idataptr*/,
33 PointerRNA *itemptr,
34 int /*icon*/,
35 PointerRNA * /*active_dataptr*/,
36 const char * /*active_propname*/,
37 int /*index*/,
38 int /*flt_flag*/)
39{
40 uiLayout *row = uiLayoutRow(layout, true);
41 float4 color;
42 RNA_float_get_array(itemptr, "color", color);
43 uiTemplateNodeSocket(row, const_cast<bContext *>(C), color);
45 uiItemR(row, itemptr, "name", UI_ITEM_NONE, "", ICON_NONE);
46}
47
49static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
50{
51 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(current_node_ptr->owner_id);
52 bNode *current_node = static_cast<bNode *>(current_node_ptr->data);
53
54 const bke::bNodeTreeZones *zones = ntree.zones();
55 if (!zones) {
56 return;
57 }
58 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(current_node->identifier);
59 if (!zone) {
60 return;
61 }
62 if (!zone->output_node) {
63 return;
64 }
65 bNode &output_node = const_cast<bNode &>(*zone->output_node);
66 PointerRNA output_node_ptr = RNA_pointer_create(
67 current_node_ptr->owner_id, &RNA_Node, &output_node);
68
69 static const uiListType *state_items_list = []() {
70 uiListType *list = MEM_cnew<uiListType>(__func__);
71 STRNCPY(list->idname, "DATA_UL_repeat_zone_state");
72 list->draw_item = draw_repeat_state_item;
74 return list;
75 }();
76
77 if (uiLayout *panel = uiLayoutPanel(C, layout, "repeat_items", false, TIP_("Repeat Items"))) {
78 uiLayout *row = uiLayoutRow(panel, false);
80 C,
81 state_items_list->idname,
82 "",
83 &output_node_ptr,
84 "repeat_items",
85 &output_node_ptr,
86 "active_index",
87 nullptr,
88 3,
89 5,
91 0,
93 {
94 uiLayout *ops_col = uiLayoutColumn(row, false);
95 {
96 uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
97 uiItemO(add_remove_col, "", ICON_ADD, "node.repeat_zone_item_add");
98 uiItemO(add_remove_col, "", ICON_REMOVE, "node.repeat_zone_item_remove");
99 }
100 {
101 uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
102 uiItemEnumO(up_down_col, "node.repeat_zone_item_move", "", ICON_TRIA_UP, "direction", 0);
103 uiItemEnumO(up_down_col, "node.repeat_zone_item_move", "", ICON_TRIA_DOWN, "direction", 1);
104 }
105 }
106 auto &storage = *static_cast<NodeGeometryRepeatOutput *>(output_node.storage);
107 if (storage.active_index >= 0 && storage.active_index < storage.items_num) {
108 NodeRepeatItem &active_item = storage.items[storage.active_index];
110 output_node_ptr.owner_id, RepeatItemsAccessor::item_srna, &active_item);
111 uiLayoutSetPropSep(panel, true);
112 uiLayoutSetPropDecorate(panel, false);
113 uiItemR(panel, &item_ptr, "socket_type", UI_ITEM_NONE, nullptr, ICON_NONE);
114 }
115 }
116
117 uiItemR(layout, &output_node_ptr, "inspection_index", UI_ITEM_NONE, nullptr, ICON_NONE);
118}
119
120namespace repeat_input_node {
121
123
125{
126 b.use_custom_socket_order();
127 b.allow_any_socket_order();
128 b.add_output<decl::Int>("Iteration")
129 .description("Index of the current iteration. Starts counting at zero");
130 b.add_input<decl::Int>("Iterations").min(0).default_value(1);
131
132 const bNode *node = b.node_or_null();
133 const bNodeTree *tree = b.tree_or_null();
134 if (node && tree) {
135 const NodeGeometryRepeatInput &storage = node_storage(*node);
136 const bNode *output_node = tree->node_by_id(storage.output_node_id);
137 if (output_node) {
138 const auto &output_storage = *static_cast<const NodeGeometryRepeatOutput *>(
139 output_node->storage);
140 for (const int i : IndexRange(output_storage.items_num)) {
141 const NodeRepeatItem &item = output_storage.items[i];
142 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
143 const StringRef name = item.name ? item.name : "";
144 const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
145 auto &input_decl = b.add_input(socket_type, name, identifier)
146 .socket_name_ptr(
147 &tree->id, RepeatItemsAccessor::item_srna, &item, "name");
148 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
149 if (socket_type_supports_fields(socket_type)) {
150 input_decl.supports_field();
151 output_decl.dependent_field({input_decl.index()});
152 }
153 }
154 }
155 }
156 b.add_input<decl::Extend>("", "__extend__");
157 b.add_output<decl::Extend>("", "__extend__").align_with_previous();
158}
159
160static void node_init(bNodeTree * /*tree*/, bNode *node)
161{
162 NodeGeometryRepeatInput *data = MEM_cnew<NodeGeometryRepeatInput>(__func__);
163 /* Needs to be initialized for the node to work. */
164 data->output_node_id = 0;
165 node->storage = data;
166}
167
168static void node_label(const bNodeTree * /*ntree*/,
169 const bNode * /*node*/,
170 char *label,
171 const int label_maxncpy)
172{
173 BLI_strncpy_utf8(label, IFACE_("Repeat"), label_maxncpy);
174}
175
176static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
177{
178 bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
179 if (!output_node) {
180 return true;
181 }
183 *ntree, *node, *output_node, *link);
184}
185
186static void node_register()
187{
188 static blender::bke::bNodeType ntype;
189 geo_node_type_base(&ntype, GEO_NODE_REPEAT_INPUT, "Repeat Input", NODE_CLASS_INTERFACE);
190 ntype.initfunc = node_init;
191 ntype.declare = node_declare;
192 ntype.labelfunc = node_label;
193 ntype.gather_link_search_ops = nullptr;
195 ntype.no_muting = true;
198 &ntype, "NodeGeometryRepeatInput", node_free_standard_storage, node_copy_standard_storage);
200}
202
203} // namespace repeat_input_node
204
205namespace repeat_output_node {
206
208
210{
211 b.use_custom_socket_order();
212 b.allow_any_socket_order();
213 const bNodeTree *tree = b.tree_or_null();
214 const bNode *node = b.node_or_null();
215 if (node) {
216 const NodeGeometryRepeatOutput &storage = node_storage(*node);
217 for (const int i : IndexRange(storage.items_num)) {
218 const NodeRepeatItem &item = storage.items[i];
219 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
220 const StringRef name = item.name ? item.name : "";
221 const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item);
222 auto &input_decl = b.add_input(socket_type, name, identifier)
223 .socket_name_ptr(
224 &tree->id, RepeatItemsAccessor::item_srna, &item, "name");
225 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
226 if (socket_type_supports_fields(socket_type)) {
227 input_decl.supports_field();
228 output_decl.dependent_field({input_decl.index()});
229 }
230 }
231 }
232 b.add_input<decl::Extend>("", "__extend__");
233 b.add_output<decl::Extend>("", "__extend__").align_with_previous();
234}
235
236static void node_init(bNodeTree * /*tree*/, bNode *node)
237{
238 NodeGeometryRepeatOutput *data = MEM_cnew<NodeGeometryRepeatOutput>(__func__);
239
240 data->next_identifier = 0;
241
242 data->items = MEM_cnew_array<NodeRepeatItem>(1, __func__);
243 data->items[0].name = BLI_strdup(DATA_("Geometry"));
244 data->items[0].socket_type = SOCK_GEOMETRY;
245 data->items[0].identifier = data->next_identifier++;
246 data->items_num = 1;
247
248 node->storage = data;
249}
250
251static void node_free_storage(bNode *node)
252{
254 MEM_freeN(node->storage);
255}
256
257static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
258{
259 const NodeGeometryRepeatOutput &src_storage = node_storage(*src_node);
260 auto *dst_storage = MEM_cnew<NodeGeometryRepeatOutput>(__func__, src_storage);
261 dst_node->storage = dst_storage;
262
264}
265
266static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
267{
269 *ntree, *node, *node, *link);
270}
271
273{
275 ot, "Remove Repeat Zone Item", __func__, "Remove active repeat zone item");
276}
277
279{
281 ot, "Add Repeat Zone Item", __func__, "Add repeat zone item");
282}
283
285{
287 ot, "Move Repeat Zone Item", __func__, "Move active repeat zone item");
288}
289
296
297static void node_register()
298{
299 static blender::bke::bNodeType ntype;
300 geo_node_type_base(&ntype, GEO_NODE_REPEAT_OUTPUT, "Repeat Output", NODE_CLASS_INTERFACE);
301 ntype.initfunc = node_init;
302 ntype.declare = node_declare;
305 ntype.no_muting = true;
309 &ntype, "NodeGeometryRepeatOutput", node_free_storage, node_copy_storage);
311}
313
314} // namespace repeat_output_node
315
316} // namespace blender::nodes::node_geo_repeat_cc
317
318namespace blender::nodes {
319
322
324{
325 const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(node.storage);
326 BLO_write_struct_array(writer, NodeRepeatItem, storage.items_num, storage.items);
327 for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) {
328 BLO_write_string(writer, item.name);
329 }
330}
331
333{
334 auto &storage = *static_cast<NodeGeometryRepeatOutput *>(node.storage);
335 BLO_read_struct_array(reader, NodeRepeatItem, storage.items_num, &storage.items);
336 for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) {
337 BLO_read_string(reader, &item.name);
338 }
339}
340
341} // namespace blender::nodes
342
343blender::Span<NodeRepeatItem> NodeGeometryRepeatOutput::items_span() const
344{
345 return blender::Span<NodeRepeatItem>(items, items_num);
346}
347
348blender::MutableSpan<NodeRepeatItem> NodeGeometryRepeatOutput::items_span()
349{
350 return blender::MutableSpan<NodeRepeatItem>(items, items_num);
351}
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:416
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define GEO_NODE_REPEAT_OUTPUT
Definition BKE_node.hh:1338
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
eNodeSocketDatatype
@ SOCK_GEOMETRY
@ UILST_LAYOUT_DEFAULT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ UI_EMBOSS_NONE
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
void uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
#define UI_ITEM_NONE
PanelLayout uiLayoutPanel(const bContext *C, uiLayout *layout, const char *idname, bool default_closed)
void uiTemplateNodeSocket(uiLayout *layout, bContext *C, const float color[4])
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
@ UI_TEMPLATE_LIST_FLAG_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
local_group_size(16, 16) .push_constant(Type b
const char * label
KDTree_3d * tree
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static void node_init(bNodeTree *, bNode *node)
static void node_label(const bNodeTree *, const bNode *, char *label, const int label_maxncpy)
static void node_declare(NodeDeclarationBuilder &b)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void NODE_OT_repeat_zone_item_move(wmOperatorType *ot)
static void NODE_OT_repeat_zone_item_remove(wmOperatorType *ot)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void NODE_OT_repeat_zone_item_add(wmOperatorType *ot)
static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *, bNode *node)
static void draw_repeat_state_item(uiList *, const bContext *C, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
void move_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void remove_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void add_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
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)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
#define min(a, b)
Definition sort.c:32
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
void * storage
int32_t identifier
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:249
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:240
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:309
NodeDeclareFunction declare
Definition BKE_node.hh:347
void(* register_operators)()
Definition BKE_node.hh:392
static void blend_write(BlendWriter *writer, const bNode &node)
static void blend_read_data(BlendDataReader *reader, bNode &node)
static std::string socket_identifier_for_item(const NodeRepeatItem &item)
char idname[BKE_ST_MAXNAME]
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_uilisttype_add(uiListType *ult)