Blender V4.3
NOD_socket_items.hh
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#pragma once
6
20#include "BLI_string.h"
21#include "BLI_string_utils.hh"
22
23#include "BKE_node.hh"
24#include "BKE_node_runtime.hh"
25
26#include "DNA_array_utils.hh"
27
28#include "NOD_socket.hh"
29
31
36template<typename T> struct SocketItemsRef {
37 T **items;
40};
41
45template<typename Accessor>
46inline bNode *find_node_by_item(bNodeTree &ntree, const typename Accessor::ItemT &item)
47{
48 ntree.ensure_topology_cache();
49 for (bNode *node : ntree.nodes_by_type(Accessor::node_idname)) {
50 SocketItemsRef array = Accessor::get_items_from_node(*node);
51 if (&item >= *array.items && &item < *array.items + *array.items_num) {
52 return node;
53 }
54 }
55 return nullptr;
56}
57
61template<typename Accessor> inline void destruct_array(bNode &node)
62{
63 using ItemT = typename Accessor::ItemT;
64 SocketItemsRef ref = Accessor::get_items_from_node(node);
65 for (const int i : IndexRange(*ref.items_num)) {
66 ItemT &item = (*ref.items)[i];
67 Accessor::destruct_item(&item);
68 }
69 MEM_SAFE_FREE(*ref.items);
70}
71
75template<typename Accessor> inline void copy_array(const bNode &src_node, bNode &dst_node)
76{
77 using ItemT = typename Accessor::ItemT;
78 SocketItemsRef src_ref = Accessor::get_items_from_node(const_cast<bNode &>(src_node));
79 SocketItemsRef dst_ref = Accessor::get_items_from_node(dst_node);
80 const int items_num = *src_ref.items_num;
81 *dst_ref.items = MEM_cnew_array<ItemT>(items_num, __func__);
82 for (const int i : IndexRange(items_num)) {
83 Accessor::copy_item((*src_ref.items)[i], (*dst_ref.items)[i]);
84 }
85}
86
91template<typename Accessor>
93 typename Accessor::ItemT &item,
94 const char *value)
95{
96 using ItemT = typename Accessor::ItemT;
97 SocketItemsRef array = Accessor::get_items_from_node(node);
98 const char *default_name = "Item";
99 if constexpr (Accessor::has_type) {
100 default_name = bke::node_static_socket_label(Accessor::get_socket_type(item), 0);
101 }
102
103 char unique_name[MAX_NAME + 4];
104 STRNCPY(unique_name, value);
105
106 struct Args {
108 ItemT *item;
109 } args = {array, &item};
111 [](void *arg, const char *name) {
112 const Args &args = *static_cast<Args *>(arg);
113 for (ItemT &item : blender::MutableSpan(*args.array.items, *args.array.items_num)) {
114 if (&item != args.item) {
115 if (STREQ(*Accessor::get_name(item), name)) {
116 return true;
117 }
118 }
119 }
120 return false;
121 },
122 &args,
123 default_name,
124 '.',
127
128 char **item_name = Accessor::get_name(item);
129 MEM_SAFE_FREE(*item_name);
130 *item_name = BLI_strdup(unique_name);
131}
132
133namespace detail {
134
135template<typename Accessor> inline typename Accessor::ItemT &add_item_to_array(bNode &node)
136{
137 using ItemT = typename Accessor::ItemT;
138 SocketItemsRef array = Accessor::get_items_from_node(node);
139
140 ItemT *old_items = *array.items;
141 const int old_items_num = *array.items_num;
142 const int new_items_num = old_items_num + 1;
143
144 ItemT *new_items = MEM_cnew_array<ItemT>(new_items_num, __func__);
145 std::copy_n(old_items, old_items_num, new_items);
146 ItemT &new_item = new_items[old_items_num];
147
148 MEM_SAFE_FREE(old_items);
149 *array.items = new_items;
150 *array.items_num = new_items_num;
151 if (array.active_index) {
152 *array.active_index = old_items_num;
153 }
154
155 return new_item;
156}
157
158} // namespace detail
159
163template<typename Accessor>
164inline typename Accessor::ItemT *add_item_with_socket_type_and_name(
165 bNode &node, const eNodeSocketDatatype socket_type, const char *name)
166{
167 using ItemT = typename Accessor::ItemT;
168 BLI_assert(Accessor::supports_socket_type(socket_type));
169 ItemT &new_item = detail::add_item_to_array<Accessor>(node);
170 Accessor::init_with_socket_type_and_name(node, new_item, socket_type, name);
171 return &new_item;
172}
173
177template<typename Accessor>
178inline typename Accessor::ItemT *add_item_with_name(bNode &node, const char *name)
179{
180 using ItemT = typename Accessor::ItemT;
181 ItemT &new_item = detail::add_item_to_array<Accessor>(node);
182 Accessor::init_with_name(node, new_item, name);
183 return &new_item;
184}
185
189template<typename Accessor> inline typename Accessor::ItemT *add_item(bNode &node)
190{
191 using ItemT = typename Accessor::ItemT;
192 ItemT &new_item = detail::add_item_to_array<Accessor>(node);
193 Accessor::init(node, new_item);
194 return &new_item;
195}
196
197template<typename Accessor>
198inline std::string get_socket_identifier(const typename Accessor::ItemT &item,
199 const eNodeSocketInOut in_out)
200{
201 if constexpr (Accessor::has_single_identifier_str) {
202 return Accessor::socket_identifier_for_item(item);
203 }
204 else {
205 if (in_out == SOCK_IN) {
206 return Accessor::input_socket_identifier_for_item(item);
207 }
208 else {
209 return Accessor::output_socket_identifier_for_item(item);
210 }
211 }
212}
213
219template<typename Accessor>
220[[nodiscard]] inline bool try_add_item_via_extend_socket(bNodeTree &ntree,
221 bNode &extend_node,
222 bNodeSocket &extend_socket,
223 bNode &storage_node,
224 bNodeLink &link)
225{
226 using ItemT = typename Accessor::ItemT;
227 bNodeSocket *src_socket = nullptr;
228 if (link.tosock == &extend_socket) {
229 src_socket = link.fromsock;
230 }
231 else if (link.fromsock == &extend_socket) {
232 src_socket = link.tosock;
233 }
234 else {
235 return false;
236 }
237
238 const ItemT *item = nullptr;
239 if constexpr (Accessor::has_name && Accessor::has_type) {
240 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(src_socket->type);
241 if (!Accessor::supports_socket_type(socket_type)) {
242 return false;
243 }
245 storage_node, socket_type, src_socket->name);
246 }
247 else if constexpr (Accessor::has_name && !Accessor::has_type) {
248 item = add_item_with_name<Accessor>(storage_node, src_socket->name);
249 }
250 else {
251 item = add_item<Accessor>(storage_node);
252 }
253 if (item == nullptr) {
254 return false;
255 }
256
257 update_node_declaration_and_sockets(ntree, extend_node);
258 if (extend_socket.is_input()) {
259 const std::string item_identifier = get_socket_identifier<Accessor>(*item, SOCK_IN);
261 &extend_node, SOCK_IN, item_identifier.c_str());
262 link.tosock = new_socket;
263 }
264 else {
265 const std::string item_identifier = get_socket_identifier<Accessor>(*item, SOCK_OUT);
267 &extend_node, SOCK_OUT, item_identifier.c_str());
268 link.fromsock = new_socket;
269 }
270 return true;
271}
272
277template<typename Accessor>
278[[nodiscard]] inline bool try_add_item_via_any_extend_socket(
279 bNodeTree &ntree,
280 bNode &extend_node,
281 bNode &storage_node,
282 bNodeLink &link,
283 const std::optional<StringRef> socket_identifier = std::nullopt)
284{
285 bNodeSocket *possible_extend_socket = nullptr;
286 if (link.fromnode == &extend_node) {
287 possible_extend_socket = link.fromsock;
288 }
289 if (link.tonode == &extend_node) {
290 possible_extend_socket = link.tosock;
291 }
292 if (possible_extend_socket == nullptr) {
293 return true;
294 }
295 if (!STREQ(possible_extend_socket->idname, "NodeSocketVirtual")) {
296 return true;
297 }
298 if (socket_identifier.has_value()) {
299 if (possible_extend_socket->identifier != socket_identifier) {
300 return true;
301 }
302 }
304 ntree, extend_node, *possible_extend_socket, storage_node, link);
305}
306
307} // namespace blender::nodes::socket_items
#define BLI_assert(a)
Definition BLI_assert.h:50
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
size_t void BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(1
#define ARRAY_SIZE(arr)
#define STREQ(a, b)
#define MAX_NAME
Definition DNA_defs.h:50
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
eNodeSocketDatatype
#define MEM_SAFE_FREE(v)
OperationNode * node
const char * node_static_socket_label(int type, int subtype)
Definition node.cc:2318
bNodeSocket * node_find_socket(bNode *node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:1829
Accessor::ItemT & add_item_to_array(bNode &node)
void set_item_name_and_make_unique(bNode &node, typename Accessor::ItemT &item, const char *value)
Accessor::ItemT * add_item_with_name(bNode &node, const char *name)
Accessor::ItemT * add_item(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)
bool try_add_item_via_extend_socket(bNodeTree &ntree, bNode &extend_node, bNodeSocket &extend_socket, bNode &storage_node, bNodeLink &link)
bNode * find_node_by_item(bNodeTree &ntree, const typename Accessor::ItemT &item)
std::string get_socket_identifier(const typename Accessor::ItemT &item, const eNodeSocketInOut in_out)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
static void unique_name(bNode *node)
char identifier[64]
char idname[64]