Blender V4.5
node.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "CLG_log.h"
10
11#include "MEM_guardedalloc.h"
12
13#include <cstddef>
14#include <cstdlib>
15#include <cstring>
16#include <optional>
17
18/* Allow using deprecated functionality for .blend file I/O. */
19#define DNA_DEPRECATED_ALLOW
20
23#include "DNA_light_types.h"
24#include "DNA_linestyle_types.h"
25#include "DNA_material_types.h"
26#include "DNA_node_types.h"
27#include "DNA_scene_types.h"
28#include "DNA_texture_types.h"
29#include "DNA_userdef_types.h"
30#include "DNA_world_types.h"
31
32#include "BLI_color.hh"
33#include "BLI_ghash.h"
34#include "BLI_listbase.h"
35#include "BLI_map.hh"
37#include "BLI_math_vector.h"
38#include "BLI_rand.hh"
39#include "BLI_set.hh"
40#include "BLI_string.h"
41#include "BLI_string_utf8.h"
42#include "BLI_string_utils.hh"
43#include "BLI_time.h"
44#include "BLI_utildefines.h"
45#include "BLI_vector_set.hh"
46#include "BLT_translation.hh"
47
48#include "IMB_imbuf.hh"
49
50#include "BKE_anim_data.hh"
51#include "BKE_animsys.h"
52#include "BKE_asset.hh"
53#include "BKE_bpath.hh"
54#include "BKE_colortools.hh"
55#include "BKE_context.hh"
56#include "BKE_global.hh"
57#include "BKE_idprop.hh"
58#include "BKE_idtype.hh"
59#include "BKE_image_format.hh"
60#include "BKE_lib_id.hh"
61#include "BKE_lib_query.hh"
62#include "BKE_main.hh"
63#include "BKE_node.hh"
64#include "BKE_node_enum.hh"
66#include "BKE_node_runtime.hh"
70#include "BKE_preview_image.hh"
74
75#include "RNA_access.hh"
76#include "RNA_define.hh"
77#include "RNA_enum_types.hh"
78#include "RNA_prototypes.hh"
79
80#include "NOD_common.hh"
81#include "NOD_composite.hh"
82#include "NOD_geo_bake.hh"
83#include "NOD_geo_bundle.hh"
85#include "NOD_geo_closure.hh"
89#include "NOD_geo_repeat.hh"
90#include "NOD_geo_simulation.hh"
95#include "NOD_register.hh"
96#include "NOD_shader.h"
97#include "NOD_socket.hh"
99#include "NOD_texture.h"
100
101#include "DEG_depsgraph.hh"
102#include "DEG_depsgraph_build.hh"
103
104#include "BLO_read_write.hh"
105
112
113static CLG_LogRef LOG = {"bke.node"};
114
115namespace blender::bke {
116
117/* Forward declaration. */
118static void write_node_socket_default_value(BlendWriter *writer, const bNodeSocket *sock);
119
120/* Fallback types for undefined tree, nodes, sockets. */
124
125static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo);
126static void node_socket_set_typeinfo(bNodeTree *ntree,
127 bNodeSocket *sock,
128 bNodeSocketType *typeinfo);
129static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag);
130static void free_localized_node_groups(bNodeTree *ntree);
131static bool socket_id_user_decrement(bNodeSocket *sock);
132
133static void ntree_init_data(ID *id)
134{
135 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
136 ntree->tree_interface.init_data();
137 ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
139 ntree_set_typeinfo(ntree, nullptr);
140}
141
142static void ntree_copy_data(Main * /*bmain*/,
143 std::optional<Library *> /*owner_library*/,
144 ID *id_dst,
145 const ID *id_src,
146 const int flag)
147{
148 bNodeTree *ntree_dst = reinterpret_cast<bNodeTree *>(id_dst);
149 const bNodeTree *ntree_src = reinterpret_cast<const bNodeTree *>(id_src);
150
151 /* We never handle user-count here for owned data. */
152 const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
153
154 ntree_dst->runtime = MEM_new<bNodeTreeRuntime>(__func__);
155 bNodeTreeRuntime &dst_runtime = *ntree_dst->runtime;
156
158
159 dst_runtime.nodes_by_id.reserve(ntree_src->all_nodes().size());
160 BLI_listbase_clear(&ntree_dst->nodes);
161 int i;
162 LISTBASE_FOREACH_INDEX (const bNode *, src_node, &ntree_src->nodes, i) {
163 /* Don't find a unique name for every node, since they should have valid names already. */
164 bNode *new_node = node_copy_with_mapping(
165 ntree_dst, *src_node, flag_subdata, false, socket_map);
166 dst_runtime.nodes_by_id.add_new(new_node);
167 new_node->runtime->index_in_tree = i;
168 }
169
170 /* copy links */
171 BLI_listbase_clear(&ntree_dst->links);
172 LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) {
173 bNodeLink *dst_link = static_cast<bNodeLink *>(MEM_dupallocN(src_link));
174 dst_link->fromnode = dst_runtime.nodes_by_id.lookup_key_as(src_link->fromnode->identifier);
175 dst_link->fromsock = socket_map.lookup(src_link->fromsock);
176 dst_link->tonode = dst_runtime.nodes_by_id.lookup_key_as(src_link->tonode->identifier);
177 dst_link->tosock = socket_map.lookup(src_link->tosock);
178 BLI_assert(dst_link->tosock);
179 dst_link->tosock->link = dst_link;
180 BLI_addtail(&ntree_dst->links, dst_link);
181 }
182
183 /* update node->parent pointers */
184 for (bNode *node : ntree_dst->all_nodes()) {
185 if (node->parent) {
186 node->parent = dst_runtime.nodes_by_id.lookup_key_as(node->parent->identifier);
187 }
188 }
189
190 for (bNode *node : ntree_dst->all_nodes()) {
191 node_declaration_ensure(*ntree_dst, *node);
192 }
193
194 ntree_dst->tree_interface.copy_data(ntree_src->tree_interface, flag);
195 /* copy preview hash */
196 if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
197 for (const auto &item : ntree_src->runtime->previews.items()) {
198 dst_runtime.previews.add_new(item.key, item.value);
199 }
200 }
201
202 if (ntree_src->runtime->field_inferencing_interface) {
203 dst_runtime.field_inferencing_interface = std::make_unique<FieldInferencingInterface>(
204 *ntree_src->runtime->field_inferencing_interface);
205 }
206 if (ntree_src->runtime->structure_type_interface) {
207 dst_runtime.structure_type_interface = std::make_unique<nodes::StructureTypeInterface>(
208 *ntree_src->runtime->structure_type_interface);
209 }
210 if (ntree_src->runtime->reference_lifetimes_info) {
211 using namespace node_tree_reference_lifetimes;
212 dst_runtime.reference_lifetimes_info = std::make_unique<ReferenceLifetimesInfo>(
213 *ntree_src->runtime->reference_lifetimes_info);
214 for (ReferenceSetInfo &reference_set : dst_runtime.reference_lifetimes_info->reference_sets) {
215 if (ELEM(reference_set.type,
216 ReferenceSetType::LocalReferenceSet,
217 ReferenceSetType::ClosureInputReferenceSet,
218 ReferenceSetType::ClosureOutputData))
219 {
220 reference_set.socket = socket_map.lookup(reference_set.socket);
221 }
222 for (auto &socket : reference_set.potential_data_origins) {
223 socket = socket_map.lookup(socket);
224 }
225 }
226 }
227
228 if (ntree_src->geometry_node_asset_traits) {
230 __func__, *ntree_src->geometry_node_asset_traits);
231 }
232
233 if (ntree_src->nested_node_refs) {
235 size_t(ntree_src->nested_node_refs_num), __func__);
237 ntree_src->nested_node_refs, ntree_src->nested_node_refs_num, ntree_dst->nested_node_refs);
238 }
239
241 ntree_dst->preview = nullptr;
242 }
243 else {
244 BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id);
245 }
246
247 ntree_dst->description = BLI_strdup_null(ntree_src->description);
248}
249
250static void ntree_free_data(ID *id)
251{
252 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
253
254 /* XXX hack! node trees should not store execution graphs at all.
255 * This should be removed when old tree types no longer require it.
256 * Currently the execution data for texture nodes remains in the tree
257 * after execution, until the node tree is updated or freed. */
258 if (ntree->runtime->execdata) {
259 switch (ntree->type) {
260 case NTREE_SHADER:
261 ntreeShaderEndExecTree(ntree->runtime->execdata);
262 break;
263 case NTREE_TEXTURE:
264 ntreeTexEndExecTree(ntree->runtime->execdata);
265 ntree->runtime->execdata = nullptr;
266 break;
267 }
268 }
269
270 /* XXX not nice, but needed to free localized node groups properly */
272
273 BLI_freelistN(&ntree->links);
274
275 LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
276 node_free_node(ntree, *node);
277 }
278
279 ntree->tree_interface.free_data();
280
281 if (ntree->id.tag & ID_TAG_LOCALIZED) {
282 BKE_libblock_free_data(&ntree->id, true);
283 }
284
285 if (ntree->geometry_node_asset_traits) {
287 }
288
289 if (ntree->nested_node_refs) {
291 }
292
295 MEM_delete(ntree->runtime);
296}
297
299{
302 BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data);
303 }));
304
305 switch (eNodeSocketDatatype(sock->type)) {
306 case SOCK_OBJECT: {
307 bNodeSocketValueObject &default_value = *sock->default_value_typed<bNodeSocketValueObject>();
309 break;
310 }
311 case SOCK_IMAGE: {
312 bNodeSocketValueImage &default_value = *sock->default_value_typed<bNodeSocketValueImage>();
314 break;
315 }
316 case SOCK_COLLECTION: {
317 bNodeSocketValueCollection &default_value =
318 *sock->default_value_typed<bNodeSocketValueCollection>();
320 break;
321 }
322 case SOCK_TEXTURE: {
323 bNodeSocketValueTexture &default_value =
324 *sock->default_value_typed<bNodeSocketValueTexture>();
326 break;
327 }
328 case SOCK_MATERIAL: {
329 bNodeSocketValueMaterial &default_value =
330 *sock->default_value_typed<bNodeSocketValueMaterial>();
332 break;
333 }
334 case SOCK_FLOAT:
335 case SOCK_VECTOR:
336 case SOCK_RGBA:
337 case SOCK_BOOLEAN:
338 case SOCK_ROTATION:
339 case SOCK_MATRIX:
340 case SOCK_INT:
341 case SOCK_STRING:
342 case SOCK_CUSTOM:
343 case SOCK_SHADER:
344 case SOCK_GEOMETRY:
345 case SOCK_MENU:
346 case SOCK_BUNDLE:
347 case SOCK_CLOSURE:
348 break;
349 }
350}
351
353{
355
358 BKE_lib_query_idpropertiesForeachIDLink_callback(prop, data);
359 }));
360 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
362 }
363 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
365 }
366
367 /* Note that this ID pointer is only a cache, it may be outdated. */
369}
370
372{
373 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
374
376 data,
377 ntree->owner_id,
379
381
382 for (bNode *node : ntree->all_nodes()) {
384 }
385
386 ntree->tree_interface.foreach_id(data);
387
388 if (ntree->runtime->geometry_nodes_eval_dependencies) {
389 for (ID *&id_ref : ntree->runtime->geometry_nodes_eval_dependencies->ids.values()) {
391 }
392 }
393}
394
395static void node_foreach_cache(ID *id,
396 IDTypeForeachCacheFunctionCallback function_callback,
397 void *user_data)
398{
399 bNodeTree *nodetree = reinterpret_cast<bNodeTree *>(id);
400 IDCacheKey key = {0};
401 key.id_session_uid = id->session_uid;
402
403 if (nodetree->type == NTREE_COMPOSIT) {
404 for (bNode *node : nodetree->all_nodes()) {
405 if (node->type_legacy == CMP_NODE_MOVIEDISTORTION) {
406 key.identifier = size_t(BLI_ghashutil_strhash_p(node->name));
407 function_callback(id, &key, (&node->storage), 0, user_data);
408 }
409 }
410 }
411}
412
413static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
414{
415 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
416
417 switch (ntree->type) {
418 case NTREE_SHADER: {
419 for (bNode *node : ntree->all_nodes()) {
420 if (node->type_legacy == SH_NODE_SCRIPT) {
421 NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
422 if (nss->mode == NODE_SCRIPT_EXTERNAL && nss->filepath[0]) {
423 BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath, sizeof(nss->filepath));
424 }
425 }
426 else if (node->type_legacy == SH_NODE_TEX_IES) {
427 NodeShaderTexIES *ies = static_cast<NodeShaderTexIES *>(node->storage);
428 if (ies->mode == NODE_IES_EXTERNAL && ies->filepath[0]) {
429 BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath, sizeof(ies->filepath));
430 }
431 }
432 }
433 break;
434 }
435 default:
436 break;
437 }
438}
439
440static ID **node_owner_pointer_get(ID *id, const bool debug_relationship_assert)
441{
442 if ((id->flag & ID_FLAG_EMBEDDED_DATA) == 0) {
443 return nullptr;
444 }
445 /* TODO: Sort this NO_MAIN or not for embedded node trees. See #86119. */
446 // BLI_assert((id->tag & ID_TAG_NO_MAIN) == 0);
447
448 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
449 if (debug_relationship_assert) {
450 BLI_assert(ntree->owner_id != nullptr);
451 BLI_assert(node_tree_from_id(ntree->owner_id) == ntree);
452 }
453
454 return &ntree->owner_id;
455}
456
457namespace forward_compat {
458
459static void write_node_socket_interface(BlendWriter *writer, const bNodeSocket *sock)
460{
461 BLO_write_struct(writer, bNodeSocket, sock);
462
463 if (sock->prop) {
464 IDP_BlendWrite(writer, sock->prop);
465 }
466
468
470}
471
472/* Construct a bNodeSocket that represents a node group socket the old way. */
474 const eNodeSocketInOut in_out,
475 const StringRef idname,
476 const StringRef name,
477 const StringRef identifier)
478{
479 bNodeSocketType *stype = node_socket_type_find(idname);
480 if (stype == nullptr) {
481 return nullptr;
482 }
483
484 bNodeSocket *sock = MEM_callocN<bNodeSocket>(__func__);
485 sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
487 sock->in_out = int(in_out);
488 sock->type = int(SOCK_CUSTOM); /* int type undefined by default */
489 node_socket_set_typeinfo(ntree, sock, stype);
490
491 sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
492
493 identifier.copy_utf8_truncated(sock->identifier);
494 name.copy_utf8_truncated(sock->name);
495 sock->storage = nullptr;
496 sock->flag |= SOCK_COLLAPSED;
497
498 return sock;
499}
500
501/* Include the subtype suffix for old socket idnames. */
502static StringRef get_legacy_socket_subtype_idname(StringRef idname, const void *socket_data)
503{
504 if (idname == "NodeSocketFloat") {
505 const bNodeSocketValueFloat &float_data = *static_cast<const bNodeSocketValueFloat *>(
506 socket_data);
507 switch (float_data.subtype) {
508 case PROP_UNSIGNED:
509 return "NodeSocketFloatUnsigned";
510 case PROP_PERCENTAGE:
511 return "NodeSocketFloatPercentage";
512 case PROP_FACTOR:
513 return "NodeSocketFloatFactor";
514 case PROP_ANGLE:
515 return "NodeSocketFloatAngle";
516 case PROP_TIME:
517 return "NodeSocketFloatTime";
519 return "NodeSocketFloatTimeAbsolute";
520 case PROP_DISTANCE:
521 return "NodeSocketFloatDistance";
522 case PROP_WAVELENGTH:
523 return "NodeSocketFloatWavelength";
525 return "NodeSocketFloatColorTemperature";
526 case PROP_FREQUENCY:
527 return "NodeSocketFloatFrequency";
528 }
529 }
530 if (idname == "NodeSocketInt") {
531 const bNodeSocketValueInt &int_data = *static_cast<const bNodeSocketValueInt *>(socket_data);
532 switch (int_data.subtype) {
533 case PROP_UNSIGNED:
534 return "NodeSocketIntUnsigned";
535 case PROP_PERCENTAGE:
536 return "NodeSocketIntPercentage";
537 case PROP_FACTOR:
538 return "NodeSocketIntFactor";
539 }
540 }
541 if (idname == "NodeSocketVector") {
542 const bNodeSocketValueVector &vector_data = *static_cast<const bNodeSocketValueVector *>(
543 socket_data);
544 switch (vector_data.subtype) {
545 case PROP_FACTOR:
546 return "NodeSocketVectorFactor";
547 case PROP_PERCENTAGE:
548 return "NodeSocketVectorPercentage";
549 case PROP_TRANSLATION:
550 return "NodeSocketVectorTranslation";
551 case PROP_DIRECTION:
552 return "NodeSocketVectorDirection";
553 case PROP_VELOCITY:
554 return "NodeSocketVectorVelocity";
556 return "NodeSocketVectorAcceleration";
557 case PROP_EULER:
558 return "NodeSocketVectorEuler";
559 }
560 }
561 return idname;
562}
563
572{
573 BLI_assert(BLI_listbase_is_empty(&ntree->inputs_legacy));
574 BLI_assert(BLI_listbase_is_empty(&ntree->outputs_legacy));
575
576 auto make_legacy_socket = [&](const bNodeTreeInterfaceSocket &socket,
577 eNodeSocketInOut in_out) -> bNodeSocket * {
578 bNodeSocket *iosock = make_socket(
579 ntree,
580 in_out,
582 socket.name ? socket.name : "",
583 socket.identifier);
584 if (!iosock) {
585 return nullptr;
586 }
587
588 if (socket.description) {
589 STRNCPY(iosock->description, socket.description);
590 }
592 iosock->typeinfo->type, iosock->default_value, socket.socket_data);
593 if (socket.properties) {
594 iosock->prop = IDP_CopyProperty(socket.properties);
595 }
600 iosock->attribute_domain = socket.attribute_domain;
602 return iosock;
603 };
604
605 /* Construct inputs/outputs socket lists in the node tree. */
606 ntree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
607 if (const bNodeTreeInterfaceSocket *socket =
609 {
610 if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
611 if (bNodeSocket *legacy_socket = make_legacy_socket(*socket, SOCK_IN)) {
612 BLI_addtail(&ntree->inputs_legacy, legacy_socket);
613 }
614 }
615 if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
616 if (bNodeSocket *legacy_socket = make_legacy_socket(*socket, SOCK_OUT)) {
617 BLI_addtail(&ntree->outputs_legacy, legacy_socket);
618 }
619 }
620 }
621 return true;
622 });
623}
624
625static void write_legacy_sockets(BlendWriter *writer, bNodeTree *ntree)
626{
627 /* Write inputs/outputs */
628 LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs_legacy) {
629 write_node_socket_interface(writer, sock);
630 }
631 LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs_legacy) {
632 write_node_socket_interface(writer, sock);
633 }
634}
635
637{
638 if (sock->prop) {
639 IDP_FreeProperty_ex(sock->prop, false);
640 }
641
642 if (sock->default_value) {
644 }
645 if (sock->default_attribute_name) {
647 }
648 MEM_delete(sock->runtime);
649}
650
652{
653 /* Clean up temporary inputs/outputs. */
654 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->inputs_legacy) {
656 MEM_freeN(socket);
657 }
658 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, socket, &ntree->outputs_legacy) {
660 MEM_freeN(socket);
661 }
662 BLI_listbase_clear(&ntree->inputs_legacy);
663 BLI_listbase_clear(&ntree->outputs_legacy);
664}
665
667{
668 for (bNode *node : ntree.all_nodes()) {
669 node->locx_legacy = node->location[0];
670 node->locy_legacy = node->location[1];
671 if (const bNode *parent = node->parent) {
672 node->locx_legacy -= parent->location[0];
673 node->locy_legacy -= parent->location[1];
674 }
675 }
676}
677
678/* Some node properties were turned into inputs, so we write the input values back to the
679 * properties upon write to maintain forward compatibility. */
681{
682 if (node_tree.type != NTREE_COMPOSIT) {
683 return;
684 }
685
686 for (bNode *node : node_tree.all_nodes()) {
687 auto write_input_to_property_bool_char =
688 [&](const char *identifier, char &property, const bool invert = false) {
689 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
690 if (invert) {
691 property = !input->default_value_typed<bNodeSocketValueBoolean>()->value;
692 }
693 else {
694 property = input->default_value_typed<bNodeSocketValueBoolean>()->value;
695 }
696 };
697
698 auto write_input_to_property_bool_short = [&](const char *identifier, short &property) {
699 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
700 property = input->default_value_typed<bNodeSocketValueBoolean>()->value;
701 };
702
703 auto write_input_to_property_bool_int16_flag = [&](const char *identifier,
704 int16_t &property,
705 const int flag,
706 const bool negative = false) {
707 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
708 if (bool(input->default_value_typed<bNodeSocketValueBoolean>()->value) != negative) {
709 property |= flag;
710 }
711 else {
712 property &= ~flag;
713 }
714 };
715
716 auto write_input_to_property_int = [&](const char *identifier, int &property) {
717 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
718 property = input->default_value_typed<bNodeSocketValueInt>()->value;
719 };
720
721 auto write_input_to_property_short = [&](const char *identifier, short &property) {
722 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
723 property = input->default_value_typed<bNodeSocketValueInt>()->value;
724 };
725
726 auto write_input_to_property_char = [&](const char *identifier, char &property) {
727 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
728 property = input->default_value_typed<bNodeSocketValueInt>()->value;
729 };
730
731 auto write_input_to_property_int16 = [&](const char *identifier, int16_t &property) {
732 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
733 property = int16_t(input->default_value_typed<bNodeSocketValueInt>()->value);
734 };
735
736 auto write_input_to_property_float = [&](const char *identifier, float &property) {
737 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
738 property = input->default_value_typed<bNodeSocketValueFloat>()->value;
739 };
740
741 auto write_input_to_property_float_vector =
742 [&](const char *identifier, const int index, float &property) {
743 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
744 property = input->default_value_typed<bNodeSocketValueVector>()->value[index];
745 };
746
747 auto write_input_to_property_float_color =
748 [&](const char *identifier, const int index, float &property) {
749 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, identifier);
750 property = input->default_value_typed<bNodeSocketValueRGBA>()->value[index];
751 };
752
753 if (node->type_legacy == CMP_NODE_GLARE) {
754 NodeGlare *storage = static_cast<NodeGlare *>(node->storage);
755 write_input_to_property_bool_char("Diagonal Star", storage->star_45);
756 }
757
758 if (node->type_legacy == CMP_NODE_BOKEHIMAGE) {
759 if (!node->storage) {
760 node->storage = MEM_callocN<NodeBokehImage>(__func__);
761 }
762 NodeBokehImage *storage = static_cast<NodeBokehImage *>(node->storage);
763 write_input_to_property_int("Flaps", storage->flaps);
764 write_input_to_property_float("Angle", storage->angle);
765 write_input_to_property_float("Roundness", storage->rounding);
766 write_input_to_property_float("Catadioptric Size", storage->catadioptric);
767 write_input_to_property_float("Color Shift", storage->lensshift);
768 }
769
770 if (node->type_legacy == CMP_NODE_TIME) {
771 write_input_to_property_int16("Start Frame", node->custom1);
772 write_input_to_property_int16("End Frame", node->custom2);
773 }
774
775 if (node->type_legacy == CMP_NODE_MASK) {
776 if (!node->storage) {
777 node->storage = MEM_callocN<NodeMask>(__func__);
778 }
779 NodeMask *storage = static_cast<NodeMask *>(node->storage);
780 write_input_to_property_int("Size X", storage->size_x);
781 write_input_to_property_int("Size Y", storage->size_y);
782 write_input_to_property_bool_int16_flag(
783 "Feather", node->custom1, CMP_NODE_MASK_FLAG_NO_FEATHER, true);
784 write_input_to_property_bool_int16_flag(
785 "Motion Blur", node->custom1, CMP_NODE_MASK_FLAG_MOTION_BLUR);
786 write_input_to_property_int16("Motion Blur Samples", node->custom2);
787 write_input_to_property_float("Motion Blur Shutter", node->custom3);
788 }
789
790 if (node->type_legacy == CMP_NODE_SWITCH) {
791 write_input_to_property_bool_int16_flag("Switch", node->custom1, 1 << 0);
792 }
793
794 if (node->type_legacy == CMP_NODE_SPLIT) {
795 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, "Factor");
796 node->custom1 = int(input->default_value_typed<bNodeSocketValueFloat>()->value * 100.0f);
797 }
798
799 if (node->type_legacy == CMP_NODE_INVERT) {
800 write_input_to_property_bool_int16_flag("Invert Color", node->custom1, CMP_CHAN_RGB);
801 write_input_to_property_bool_int16_flag("Invert Alpha", node->custom1, CMP_CHAN_A);
802 }
803
804 if (node->type_legacy == CMP_NODE_ZCOMBINE) {
805 write_input_to_property_bool_int16_flag("Use Alpha", node->custom1, 1 << 0);
806 write_input_to_property_bool_int16_flag("Anti-Alias", node->custom2, 1 << 0, true);
807 }
808
809 if (node->type_legacy == CMP_NODE_TONEMAP) {
810 NodeTonemap *storage = static_cast<NodeTonemap *>(node->storage);
811 write_input_to_property_float("Key", storage->key);
812 write_input_to_property_float("Balance", storage->offset);
813 write_input_to_property_float("Gamma", storage->gamma);
814 write_input_to_property_float("Intensity", storage->f);
815 write_input_to_property_float("Contrast", storage->m);
816 write_input_to_property_float("Light Adaptation", storage->a);
817 write_input_to_property_float("Chromatic Adaptation", storage->c);
818 }
819
820 if (node->type_legacy == CMP_NODE_DILATEERODE) {
821 write_input_to_property_int16("Size", node->custom2);
822 write_input_to_property_float("Falloff Size", node->custom3);
823 }
824
825 if (node->type_legacy == CMP_NODE_INPAINT) {
826 write_input_to_property_int16("Size", node->custom2);
827 }
828
829 if (node->type_legacy == CMP_NODE_PIXELATE) {
830 write_input_to_property_int16("Size", node->custom1);
831 }
832
833 if (node->type_legacy == CMP_NODE_KUWAHARA) {
834 NodeKuwaharaData *storage = static_cast<NodeKuwaharaData *>(node->storage);
835 write_input_to_property_bool_char("High Precision", storage->high_precision);
836 write_input_to_property_int("Uniformity", storage->uniformity);
837 write_input_to_property_float("Sharpness", storage->sharpness);
838 write_input_to_property_float("Eccentricity", storage->eccentricity);
839 }
840
841 if (node->type_legacy == CMP_NODE_DESPECKLE) {
842 write_input_to_property_float("Color Threshold", node->custom3);
843 write_input_to_property_float("Neighbor Threshold", node->custom4);
844 }
845
846 if (node->type_legacy == CMP_NODE_DENOISE) {
847 NodeDenoise *storage = static_cast<NodeDenoise *>(node->storage);
848 write_input_to_property_bool_char("HDR", storage->hdr);
849 }
850
851 if (node->type_legacy == CMP_NODE_ANTIALIASING) {
852 if (!node->storage) {
853 node->storage = MEM_callocN<NodeAntiAliasingData>(__func__);
854 }
855 NodeAntiAliasingData *storage = static_cast<NodeAntiAliasingData *>(node->storage);
856 write_input_to_property_float("Threshold", storage->threshold);
857 write_input_to_property_float("Corner Rounding", storage->corner_rounding);
858
859 /* Contrast limit was previously divided by 10. */
860 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, "Contrast Limit");
861 storage->contrast_limit = input->default_value_typed<bNodeSocketValueFloat>()->value / 10.0f;
862 }
863
864 if (node->type_legacy == CMP_NODE_VECBLUR) {
865 if (!node->storage) {
866 node->storage = MEM_callocN<NodeBlurData>(__func__);
867 }
868 NodeBlurData *storage = static_cast<NodeBlurData *>(node->storage);
869 write_input_to_property_short("Samples", storage->samples);
870
871 /* Shutter was previously divided by 2. */
872 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, "Shutter");
873 storage->fac = input->default_value_typed<bNodeSocketValueFloat>()->value / 2.0f;
874 }
875
876 if (node->type_legacy == CMP_NODE_CHANNEL_MATTE) {
877 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
878 write_input_to_property_float("Minimum", storage->t2);
879 write_input_to_property_float("Maximum", storage->t1);
880 }
881
882 if (node->type_legacy == CMP_NODE_CHROMA_MATTE) {
883 if (!node->storage) {
884 node->storage = MEM_callocN<NodeChroma>(__func__);
885 }
886 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
887 write_input_to_property_float("Minimum", storage->t2);
888 write_input_to_property_float("Maximum", storage->t1);
889 write_input_to_property_float("Falloff", storage->fstrength);
890 }
891
892 if (node->type_legacy == CMP_NODE_COLOR_MATTE) {
893 if (!node->storage) {
894 node->storage = MEM_callocN<NodeChroma>(__func__);
895 }
896 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
897 write_input_to_property_float("Hue", storage->t1);
898 write_input_to_property_float("Saturation", storage->t2);
899 write_input_to_property_float("Value", storage->t3);
900 }
901
902 if (node->type_legacy == CMP_NODE_DIFF_MATTE) {
903 if (!node->storage) {
904 node->storage = MEM_callocN<NodeChroma>(__func__);
905 }
906 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
907 write_input_to_property_float("Tolerance", storage->t1);
908 write_input_to_property_float("Falloff", storage->t2);
909 }
910
911 if (node->type_legacy == CMP_NODE_DIST_MATTE) {
912 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
913 write_input_to_property_float("Tolerance", storage->t1);
914 write_input_to_property_float("Falloff", storage->t2);
915 }
916
917 if (node->type_legacy == CMP_NODE_LUMA_MATTE) {
918 if (!node->storage) {
919 node->storage = MEM_callocN<NodeChroma>(__func__);
920 }
921 NodeChroma *storage = static_cast<NodeChroma *>(node->storage);
922 write_input_to_property_float("Minimum", storage->t2);
923 write_input_to_property_float("Maximum", storage->t1);
924 }
925
926 if (node->type_legacy == CMP_NODE_COLOR_SPILL) {
927 NodeColorspill *storage = static_cast<NodeColorspill *>(node->storage);
928 write_input_to_property_float("Limit Strength", storage->limscale);
929 write_input_to_property_bool_short("Use Spill Strength", storage->unspill);
930 write_input_to_property_float_color("Spill Strength", 0, storage->uspillr);
931 write_input_to_property_float_color("Spill Strength", 1, storage->uspillg);
932 write_input_to_property_float_color("Spill Strength", 2, storage->uspillb);
933 }
934
935 if (node->type_legacy == CMP_NODE_KEYINGSCREEN) {
936 NodeKeyingScreenData *storage = static_cast<NodeKeyingScreenData *>(node->storage);
937 write_input_to_property_float("Smoothness", storage->smoothness);
938 }
939
940 if (node->type_legacy == CMP_NODE_KEYING) {
941 NodeKeyingData *storage = static_cast<NodeKeyingData *>(node->storage);
942 write_input_to_property_int("Preprocess Blur Size", storage->blur_pre);
943 write_input_to_property_float("Key Balance", storage->screen_balance);
944 write_input_to_property_int("Edge Search Size", storage->edge_kernel_radius);
945 write_input_to_property_float("Edge Tolerance", storage->edge_kernel_tolerance);
946 write_input_to_property_float("Black Level", storage->clip_black);
947 write_input_to_property_float("White Level", storage->clip_white);
948 write_input_to_property_int("Postprocess Blur Size", storage->blur_post);
949 write_input_to_property_int("Postprocess Dilate Size", storage->dilate_distance);
950 write_input_to_property_int("Postprocess Feather Size", storage->feather_distance);
951 write_input_to_property_float("Despill Strength", storage->despill_factor);
952 write_input_to_property_float("Despill Balance", storage->despill_balance);
953 }
954
955 if (node->type_legacy == CMP_NODE_ID_MASK) {
956 write_input_to_property_short("Index", node->custom1);
957 write_input_to_property_bool_short("Anti-Alias", node->custom2);
958 }
959
960 if (node->type_legacy == CMP_NODE_STABILIZE2D) {
961 write_input_to_property_bool_short("Invert", node->custom2);
962 }
963
964 if (node->type_legacy == CMP_NODE_PLANETRACKDEFORM) {
965 NodePlaneTrackDeformData *storage = static_cast<NodePlaneTrackDeformData *>(node->storage);
966 write_input_to_property_bool_char("Motion Blur", storage->flag);
967 write_input_to_property_char("Motion Blur Samples", storage->motion_blur_samples);
968 write_input_to_property_float("Motion Blur Shutter", storage->motion_blur_shutter);
969 }
970
971 if (node->type_legacy == CMP_NODE_COLORCORRECTION) {
972 if (!node->storage) {
973 node->storage = MEM_callocN<NodeColorCorrection>(__func__);
974 }
975 NodeColorCorrection *storage = static_cast<NodeColorCorrection *>(node->storage);
976 write_input_to_property_float("Master Saturation", storage->master.saturation);
977 write_input_to_property_float("Master Contrast", storage->master.contrast);
978 write_input_to_property_float("Master Gamma", storage->master.gamma);
979 write_input_to_property_float("Master Gain", storage->master.gain);
980 write_input_to_property_float("Master Lift", storage->master.lift);
981 write_input_to_property_float("Shadows Saturation", storage->shadows.saturation);
982 write_input_to_property_float("Shadows Contrast", storage->shadows.contrast);
983 write_input_to_property_float("Shadows Gamma", storage->shadows.gamma);
984 write_input_to_property_float("Shadows Gain", storage->shadows.gain);
985 write_input_to_property_float("Shadows Lift", storage->shadows.lift);
986 write_input_to_property_float("Midtones Saturation", storage->midtones.saturation);
987 write_input_to_property_float("Midtones Contrast", storage->midtones.contrast);
988 write_input_to_property_float("Midtones Gamma", storage->midtones.gamma);
989 write_input_to_property_float("Midtones Gain", storage->midtones.gain);
990 write_input_to_property_float("Midtones Lift", storage->midtones.lift);
991 write_input_to_property_float("Highlights Saturation", storage->highlights.saturation);
992 write_input_to_property_float("Highlights Contrast", storage->highlights.contrast);
993 write_input_to_property_float("Highlights Gamma", storage->highlights.gamma);
994 write_input_to_property_float("Highlights Gain", storage->highlights.gain);
995 write_input_to_property_float("Highlights Lift", storage->highlights.lift);
996 write_input_to_property_float("Midtones Start", storage->startmidtones);
997 write_input_to_property_float("Midtones End", storage->endmidtones);
998 write_input_to_property_bool_int16_flag("Apply On Red", node->custom1, 1 << 0);
999 write_input_to_property_bool_int16_flag("Apply On Green", node->custom1, 1 << 1);
1000 write_input_to_property_bool_int16_flag("Apply On Blue", node->custom1, 1 << 2);
1001 }
1002
1003 if (node->type_legacy == CMP_NODE_LENSDIST) {
1004 NodeLensDist *storage = static_cast<NodeLensDist *>(node->storage);
1005 write_input_to_property_bool_short("Jitter", storage->jit);
1006 write_input_to_property_bool_short("Fit", storage->fit);
1007 storage->proj = storage->distortion_type == CMP_NODE_LENS_DISTORTION_HORIZONTAL;
1008 }
1009
1010 if (node->type_legacy == CMP_NODE_MASK_BOX) {
1011 if (!node->storage) {
1012 node->storage = MEM_callocN<NodeBoxMask>(__func__);
1013 }
1014 NodeBoxMask *storage = static_cast<NodeBoxMask *>(node->storage);
1015 write_input_to_property_float_vector("Position", 0, storage->x);
1016 write_input_to_property_float_vector("Position", 1, storage->y);
1017 write_input_to_property_float_vector("Size", 0, storage->width);
1018 write_input_to_property_float_vector("Size", 1, storage->height);
1019 write_input_to_property_float("Rotation", storage->rotation);
1020 }
1021
1022 if (node->type_legacy == CMP_NODE_MASK_ELLIPSE) {
1023 if (!node->storage) {
1024 node->storage = MEM_callocN<NodeEllipseMask>(__func__);
1025 }
1026 NodeEllipseMask *storage = static_cast<NodeEllipseMask *>(node->storage);
1027 write_input_to_property_float_vector("Position", 0, storage->x);
1028 write_input_to_property_float_vector("Position", 1, storage->y);
1029 write_input_to_property_float_vector("Size", 0, storage->width);
1030 write_input_to_property_float_vector("Size", 1, storage->height);
1031 write_input_to_property_float("Rotation", storage->rotation);
1032 }
1033
1034 if (node->type_legacy == CMP_NODE_SUNBEAMS) {
1035 if (!node->storage) {
1036 node->storage = MEM_callocN<NodeSunBeams>(__func__);
1037 }
1038 NodeSunBeams *storage = static_cast<NodeSunBeams *>(node->storage);
1039 write_input_to_property_float_vector("Source", 0, storage->source[0]);
1040 write_input_to_property_float_vector("Source", 1, storage->source[1]);
1041 write_input_to_property_float("Length", storage->ray_length);
1042 }
1043
1044 if (node->type_legacy == CMP_NODE_DBLUR) {
1045 if (!node->storage) {
1046 node->storage = MEM_callocN<NodeDBlurData>(__func__);
1047 }
1048 NodeDBlurData *storage = static_cast<NodeDBlurData *>(node->storage);
1049 write_input_to_property_short("Samples", storage->iter);
1050 write_input_to_property_float_vector("Center", 0, storage->center_x);
1051 write_input_to_property_float_vector("Center", 1, storage->center_y);
1052 write_input_to_property_float("Translation Amount", storage->distance);
1053 write_input_to_property_float("Translation Direction", storage->angle);
1054 write_input_to_property_float("Rotation", storage->spin);
1055
1056 /* Scale was previously minus 1. */
1057 const bNodeSocket *input = blender::bke::node_find_socket(*node, SOCK_IN, "Scale");
1058 storage->zoom = input->default_value_typed<bNodeSocketValueFloat>()->value - 1.0f;
1059 }
1060
1061 if (node->type_legacy == CMP_NODE_BILATERALBLUR) {
1062 if (!node->storage) {
1063 node->storage = MEM_callocN<NodeBilateralBlurData>(__func__);
1064 }
1065 NodeBilateralBlurData *storage = static_cast<NodeBilateralBlurData *>(node->storage);
1066
1067 /* The size input is `ceil(iterations + sigma_space)`. */
1068 const bNodeSocket *size_input = blender::bke::node_find_socket(*node, SOCK_IN, "Size");
1069 storage->iter = size_input->default_value_typed<bNodeSocketValueInt>()->value - 1;
1070 storage->sigma_space = 1.0f;
1071
1072 /* Threshold was previously multiplied by 3. */
1073 const bNodeSocket *threshold_input = blender::bke::node_find_socket(
1074 *node, SOCK_IN, "Threshold");
1075 storage->sigma_color = threshold_input->default_value_typed<bNodeSocketValueFloat>()->value *
1076 3.0f;
1077 }
1078
1079 if (node->type_legacy == CMP_NODE_ALPHAOVER) {
1080 if (!node->storage) {
1081 node->storage = MEM_callocN<NodeTwoFloats>(__func__);
1082 }
1083 write_input_to_property_bool_short("Straight Alpha", node->custom1);
1084 }
1085
1086 if (node->type_legacy == CMP_NODE_BOKEHBLUR) {
1087 write_input_to_property_bool_int16_flag("Extend Bounds", node->custom1, (1 << 1));
1088 }
1089
1090 if (node->type_legacy == CMP_NODE_CROP) {
1091 if (!node->storage) {
1092 node->storage = MEM_callocN<NodeTwoXYs>(__func__);
1093 }
1094 write_input_to_property_bool_int16_flag("Alpha Crop", node->custom1, (1 << 0), true);
1095
1096 NodeTwoXYs *storage = static_cast<NodeTwoXYs *>(node->storage);
1097 write_input_to_property_int16("X", storage->x1);
1098 write_input_to_property_int16("Y", storage->y2);
1099
1100 const bNodeSocket *x_input = blender::bke::node_find_socket(*node, SOCK_IN, "X");
1101 const bNodeSocket *width_input = blender::bke::node_find_socket(*node, SOCK_IN, "Width");
1102 storage->x2 = x_input->default_value_typed<bNodeSocketValueInt>()->value +
1103 width_input->default_value_typed<bNodeSocketValueInt>()->value;
1104
1105 const bNodeSocket *y_input = blender::bke::node_find_socket(*node, SOCK_IN, "Y");
1106 const bNodeSocket *height_input = blender::bke::node_find_socket(*node, SOCK_IN, "Height");
1107 storage->y1 = y_input->default_value_typed<bNodeSocketValueInt>()->value +
1108 height_input->default_value_typed<bNodeSocketValueInt>()->value;
1109 }
1110
1111 if (node->type_legacy == CMP_NODE_COLORBALANCE) {
1112 if (!node->storage) {
1113 node->storage = MEM_callocN<NodeColorBalance>(__func__);
1114 }
1115 NodeColorBalance *storage = static_cast<NodeColorBalance *>(node->storage);
1116
1117 {
1118 const bNodeSocket *base_input = blender::bke::node_find_socket(
1119 *node, SOCK_IN, "Base Lift");
1120 const bNodeSocket *color_input = blender::bke::node_find_socket(
1121 *node, SOCK_IN, "Color Lift");
1122 const float3 value = base_input->default_value_typed<bNodeSocketValueFloat>()->value +
1123 float3(
1124 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1125 copy_v3_v3(storage->lift, value);
1126 }
1127
1128 {
1129 const bNodeSocket *base_input = blender::bke::node_find_socket(
1130 *node, SOCK_IN, "Base Gamma");
1131 const bNodeSocket *color_input = blender::bke::node_find_socket(
1132 *node, SOCK_IN, "Color Gamma");
1133 const float3 value = base_input->default_value_typed<bNodeSocketValueFloat>()->value *
1134 float3(
1135 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1136 copy_v3_v3(storage->gamma, value);
1137 }
1138
1139 {
1140 const bNodeSocket *base_input = blender::bke::node_find_socket(
1141 *node, SOCK_IN, "Base Gain");
1142 const bNodeSocket *color_input = blender::bke::node_find_socket(
1143 *node, SOCK_IN, "Color Gain");
1144 const float3 value = base_input->default_value_typed<bNodeSocketValueFloat>()->value *
1145 float3(
1146 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1147 copy_v3_v3(storage->gain, value);
1148 }
1149
1150 {
1151 const bNodeSocket *base_input = blender::bke::node_find_socket(
1152 *node, SOCK_IN, "Base Power");
1153 const bNodeSocket *color_input = blender::bke::node_find_socket(
1154 *node, SOCK_IN, "Color Power");
1155 const float3 value = base_input->default_value_typed<bNodeSocketValueFloat>()->value *
1156 float3(
1157 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1158 copy_v3_v3(storage->power, value);
1159 }
1160
1161 {
1162 const bNodeSocket *base_input = blender::bke::node_find_socket(
1163 *node, SOCK_IN, "Base Slope");
1164 const bNodeSocket *color_input = blender::bke::node_find_socket(
1165 *node, SOCK_IN, "Color Slope");
1166 const float3 value = base_input->default_value_typed<bNodeSocketValueFloat>()->value *
1167 float3(
1168 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1169 copy_v3_v3(storage->slope, value);
1170 }
1171
1172 {
1173 const bNodeSocket *base_input = blender::bke::node_find_socket(
1174 *node, SOCK_IN, "Base Offset");
1175 const bNodeSocket *color_input = blender::bke::node_find_socket(
1176 *node, SOCK_IN, "Color Offset");
1177 storage->offset_basis = base_input->default_value_typed<bNodeSocketValueFloat>()->value;
1178 copy_v3_v3(storage->offset,
1179 color_input->default_value_typed<bNodeSocketValueRGBA>()->value);
1180 }
1181
1182 write_input_to_property_float("Input Temperature", storage->input_temperature);
1183 write_input_to_property_float("Input Tint", storage->input_tint);
1184 write_input_to_property_float("Output Temperature", storage->output_temperature);
1185 write_input_to_property_float("Output Tint", storage->output_tint);
1186 }
1187
1188 if (node->type_legacy == CMP_NODE_BLUR) {
1189 write_input_to_property_bool_int16_flag("Extend Bounds", node->custom1, (1 << 1));
1190
1191 NodeBlurData *storage = static_cast<NodeBlurData *>(node->storage);
1192 write_input_to_property_bool_char("Separable", storage->bokeh, true);
1193
1194 const bNodeSocket *size_input = blender::bke::node_find_socket(*node, SOCK_IN, "Size");
1195 storage->sizex = int(
1196 math::ceil(size_input->default_value_typed<bNodeSocketValueVector>()->value[0]));
1197 storage->sizey = int(
1198 math::ceil(size_input->default_value_typed<bNodeSocketValueVector>()->value[1]));
1199 }
1200
1201 if (node->type_legacy == CMP_NODE_FLIP) {
1202 const bNodeSocket *x_input = blender::bke::node_find_socket(*node, SOCK_IN, "Flip X");
1203 const bNodeSocket *y_input = blender::bke::node_find_socket(*node, SOCK_IN, "Flip Y");
1204 const bool flip_x = x_input->default_value_typed<bNodeSocketValueBoolean>()->value;
1205 const bool flip_y = y_input->default_value_typed<bNodeSocketValueBoolean>()->value;
1206 if (flip_x && flip_y) {
1207 node->custom1 = 2;
1208 }
1209 else if (flip_y) {
1210 node->custom1 = 1;
1211 }
1212 else {
1213 node->custom1 = 0;
1214 }
1215 }
1216 }
1217}
1218
1219/* The write_compositor_legacy_properties function might have allocated temporary storage for nodes
1220 * whose storage are no longer needed and therefore have no storage name in the node type info.
1221 * Such storage will not get saved due to the missing storage name, so we need to write them
1222 * manually and then free the storage. */
1224{
1225 if (!node.storage) {
1226 return;
1227 }
1228
1229 if (!node.typeinfo->storagename.empty()) {
1230 return;
1231 }
1232
1233 switch (node.type_legacy) {
1235 BLO_write_struct_by_name(writer, "NodeBokehImage", node.storage);
1236 MEM_freeN(static_cast<NodeBokehImage *>(node.storage));
1237 break;
1238 case CMP_NODE_MASK:
1239 BLO_write_struct_by_name(writer, "NodeMask", node.storage);
1240 MEM_freeN(static_cast<NodeMask *>(node.storage));
1241 break;
1243 BLO_write_struct_by_name(writer, "NodeAntiAliasingData", node.storage);
1244 MEM_freeN(static_cast<NodeAntiAliasingData *>(node.storage));
1245 break;
1246 case CMP_NODE_VECBLUR:
1247 BLO_write_struct_by_name(writer, "NodeBlurData", node.storage);
1248 MEM_freeN(static_cast<NodeBlurData *>(node.storage));
1249 break;
1254 BLO_write_struct_by_name(writer, "NodeChroma", node.storage);
1255 MEM_freeN(static_cast<NodeChroma *>(node.storage));
1256 break;
1258 BLO_write_struct_by_name(writer, "NodeColorCorrection", node.storage);
1259 MEM_freeN(static_cast<NodeColorCorrection *>(node.storage));
1260 break;
1261 case CMP_NODE_MASK_BOX:
1262 BLO_write_struct_by_name(writer, "NodeBoxMask", node.storage);
1263 MEM_freeN(static_cast<NodeBoxMask *>(node.storage));
1264 break;
1266 BLO_write_struct_by_name(writer, "NodeEllipseMask", node.storage);
1267 MEM_freeN(static_cast<NodeEllipseMask *>(node.storage));
1268 break;
1269 case CMP_NODE_SUNBEAMS:
1270 BLO_write_struct_by_name(writer, "NodeSunBeams", node.storage);
1271 MEM_freeN(static_cast<NodeSunBeams *>(node.storage));
1272 break;
1273 case CMP_NODE_DBLUR:
1274 BLO_write_struct_by_name(writer, "NodeDBlurData", node.storage);
1275 MEM_freeN(static_cast<NodeDBlurData *>(node.storage));
1276 break;
1278 BLO_write_struct_by_name(writer, "NodeBilateralBlurData", node.storage);
1279 MEM_freeN(static_cast<NodeBilateralBlurData *>(node.storage));
1280 break;
1281 case CMP_NODE_ALPHAOVER:
1282 BLO_write_struct_by_name(writer, "NodeTwoFloats", node.storage);
1283 MEM_freeN(static_cast<NodeTwoFloats *>(node.storage));
1284 break;
1285 case CMP_NODE_CROP:
1286 BLO_write_struct_by_name(writer, "NodeTwoXYs", node.storage);
1287 MEM_freeN(static_cast<NodeTwoXYs *>(node.storage));
1288 break;
1290 BLO_write_struct_by_name(writer, "NodeColorBalance", node.storage);
1291 MEM_freeN(static_cast<NodeColorBalance *>(node.storage));
1292 break;
1293 default:
1294 return;
1295 }
1296
1297 node.storage = nullptr;
1298}
1299
1300} // namespace forward_compat
1301
1303{
1304 if (sock->default_value == nullptr) {
1305 return;
1306 }
1307
1308 switch (eNodeSocketDatatype(sock->type)) {
1309 case SOCK_FLOAT:
1311 break;
1312 case SOCK_VECTOR:
1314 break;
1315 case SOCK_RGBA:
1317 break;
1318 case SOCK_BOOLEAN:
1320 break;
1321 case SOCK_INT:
1323 break;
1324 case SOCK_STRING:
1326 break;
1327 case SOCK_OBJECT:
1329 break;
1330 case SOCK_IMAGE:
1332 break;
1333 case SOCK_COLLECTION:
1335 break;
1336 case SOCK_TEXTURE:
1338 break;
1339 case SOCK_MATERIAL:
1341 break;
1342 case SOCK_ROTATION:
1344 break;
1345 case SOCK_MENU:
1347 break;
1348 case SOCK_MATRIX:
1349 /* Matrix sockets currently have no default value. */
1350 break;
1351 case SOCK_CUSTOM:
1352 /* Custom node sockets where default_value is defined use custom properties for storage. */
1353 break;
1354 case SOCK_SHADER:
1355 case SOCK_GEOMETRY:
1356 case SOCK_BUNDLE:
1357 case SOCK_CLOSURE:
1359 break;
1360 }
1361}
1362
1363static void write_node_socket(BlendWriter *writer, const bNodeSocket *sock)
1364{
1365 BLO_write_struct(writer, bNodeSocket, sock);
1366
1367 if (sock->prop) {
1368 IDP_BlendWrite(writer, sock->prop);
1369 }
1370
1371 /* This property should only be used for group node "interface" sockets. */
1372 BLI_assert(sock->default_attribute_name == nullptr);
1373
1374 write_node_socket_default_value(writer, sock);
1375}
1376
1377static void node_blend_write_storage(BlendWriter *writer, bNodeTree *ntree, bNode *node)
1378{
1379 if (!node->storage) {
1380 return;
1381 }
1382
1383 if (node->type_legacy == CMP_NODE_GLARE) {
1384 /* Simple forward compatibility for fix for #50736.
1385 * Not ideal (there is no ideal solution here), but should do for now. */
1386 NodeGlare *ndg = static_cast<NodeGlare *>(node->storage);
1387 /* Not in undo case. */
1388 if (!BLO_write_is_undo(writer)) {
1389 switch (ndg->type) {
1391 ndg->angle = ndg->streaks;
1392 break;
1394 ndg->angle = ndg->star_45;
1395 break;
1396 default:
1397 break;
1398 }
1399 }
1400 }
1401 else if (node->type_legacy == GEO_NODE_CAPTURE_ATTRIBUTE) {
1402 auto &storage = *static_cast<NodeGeometryAttributeCapture *>(node->storage);
1403 /* Improve forward compatibility. */
1405 for (const NodeGeometryAttributeCaptureItem &item :
1406 Span{storage.capture_items, storage.capture_items_num})
1407 {
1408 if (item.identifier == 0) {
1409 /* The sockets of this item have the same identifiers that have been used by older
1410 * Blender versions before the node supported capturing multiple attributes. */
1411 storage.data_type_legacy = item.data_type;
1412 break;
1413 }
1414 }
1415 }
1416
1417 const bNodeType *ntype = node->typeinfo;
1418 if (!ntype->storagename.empty()) {
1419 BLO_write_struct_by_name(writer, ntype->storagename.c_str(), node->storage);
1420 }
1421 else {
1422 if (!BLO_write_is_undo(writer)) {
1424 }
1425 }
1426 if (ntype->blend_write_storage_content) {
1427 ntype->blend_write_storage_content(*ntree, *node, *writer);
1428 return;
1429 }
1430
1431 /* These nodes don't use #blend_write_storage_content because their corresponding blend-read
1432 * can't use it since they were introduced before there were node idnames. */
1433 if (ELEM(node->type_legacy,
1443 {
1444 BKE_curvemapping_curves_blend_write(writer, static_cast<const CurveMapping *>(node->storage));
1445 }
1446 else if (node->type_legacy == SH_NODE_SCRIPT) {
1447 NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
1448 if (nss->bytecode) {
1449 BLO_write_string(writer, nss->bytecode);
1450 }
1451 }
1452 else if (node->type_legacy == CMP_NODE_MOVIEDISTORTION) {
1453 /* pass */
1454 }
1456 NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage);
1457 BLO_write_string(writer, nc->matte_id);
1458 LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
1459 BLO_write_struct(writer, CryptomatteEntry, entry);
1460 }
1461 }
1462}
1463
1465{
1466 BKE_id_blend_write(writer, &ntree->id);
1467 BLO_write_string(writer, ntree->description);
1468
1469 if (!BLO_write_is_undo(writer)) {
1472 }
1473
1474 for (bNode *node : ntree->all_nodes()) {
1475 if (ntree->type == NTREE_SHADER && node->type_legacy == SH_NODE_BSDF_HAIR_PRINCIPLED) {
1476 /* For Principeld Hair BSDF, also write to `node->custom1` for forward compatibility, because
1477 * prior to 4.0 `node->custom1` was used for color parametrization instead of
1478 * `node->storage->parametrization`. */
1479 NodeShaderHairPrincipled *data = static_cast<NodeShaderHairPrincipled *>(node->storage);
1480 node->custom1 = data->parametrization;
1481 }
1482
1483 BLO_write_struct(writer, bNode, node);
1484
1485 if (node->prop) {
1486 IDP_BlendWrite(writer, node->prop);
1487 }
1488
1489 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1490 write_node_socket(writer, sock);
1491 }
1492 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1493 write_node_socket(writer, sock);
1494 }
1496 writer, bNodePanelState, node->num_panel_states, node->panel_states_array);
1497
1498 if (node->storage) {
1499 node_blend_write_storage(writer, ntree, node);
1500 }
1501
1502 if (node->type_legacy == CMP_NODE_OUTPUT_FILE) {
1503 /* Inputs have their own storage data. */
1504 NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
1505 BKE_image_format_blend_write(writer, &nimf->format);
1506
1507 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
1508 NodeImageMultiFileSocket *sockdata = static_cast<NodeImageMultiFileSocket *>(
1509 sock->storage);
1510 BLO_write_struct(writer, NodeImageMultiFileSocket, sockdata);
1511 BKE_image_format_blend_write(writer, &sockdata->format);
1512 }
1513 }
1514 if (ELEM(node->type_legacy, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
1515 /* Write extra socket info. */
1516 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
1517 BLO_write_struct(writer, NodeImageLayer, sock->storage);
1518 }
1519 }
1520 }
1521
1522 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
1523 BLO_write_struct(writer, bNodeLink, link);
1524 }
1525
1526 ntree->tree_interface.write(writer);
1527 if (!BLO_write_is_undo(writer)) {
1529 }
1530
1532
1534 writer, bNestedNodeRef, ntree->nested_node_refs_num, ntree->nested_node_refs);
1535
1536 BKE_previewimg_blend_write(writer, ntree->preview);
1537}
1538
1539static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address)
1540{
1541 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
1542
1543 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
1544 ntree->typeinfo = nullptr;
1545 ntree->runtime->execdata = nullptr;
1546
1547 if (!BLO_write_is_undo(writer)) {
1548 /* Generate legacy inputs/outputs socket ListBase for forward compatibility.
1549 * NOTE: this has to happen before writing the ntree struct itself so that the ListBase
1550 * first/last pointers are valid. */
1552 }
1553
1554 BLO_write_id_struct(writer, bNodeTree, id_address, &ntree->id);
1555
1556 node_tree_blend_write(writer, ntree);
1557
1558 if (!BLO_write_is_undo(writer)) {
1560 }
1561}
1562
1569{
1570 switch (eNodeSocketDatatype(sock->type)) {
1571 case SOCK_FLOAT:
1572 case SOCK_VECTOR:
1573 case SOCK_RGBA:
1574 case SOCK_BOOLEAN:
1575 case SOCK_INT:
1576 case SOCK_STRING:
1577 case SOCK_CUSTOM:
1578 case SOCK_SHADER:
1579 case SOCK_GEOMETRY:
1580 case SOCK_OBJECT:
1581 case SOCK_IMAGE:
1582 case SOCK_COLLECTION:
1583 case SOCK_TEXTURE:
1584 case SOCK_MATERIAL:
1585 case SOCK_ROTATION:
1586 case SOCK_MENU:
1587 case SOCK_MATRIX:
1588 case SOCK_BUNDLE:
1589 case SOCK_CLOSURE:
1590 return true;
1591 }
1592 return false;
1593}
1594
1596
1597/* Specific code required to properly handle older blend-files (pre-2.83), where some node data
1598 * (like the sockets default values) were written as raw bytes buffer, without any DNA type
1599 * information. */
1600
1601/* Node socket default values were historically written and read as raw bytes buffers, without any
1602 * DNA typing information.
1603 *
1604 * The writing code was fixed in commit `50d5050e9c`, which is included in the 2.83 release.
1605 * However the matching reading code was only fixed in the 4.5 release.
1606 *
1607 * So currently, reading code assumes that any blend-file >= 3.0 has correct DNA info for these
1608 * default values, and it keeps previous 'raw buffer' reading code for older ones.
1609 *
1610 * This means that special care must be taken when the various DNA types used for these default
1611 * values are modified, as a 'manual' version of DNA internal versioning must be performed on data
1612 * from older blend-files (see also #direct_link_node_socket_default_value).
1613 */
1615
1616/* The `_404` structs below are copies of DNA structs as they were in Blender 4.4 and before. Their
1617 * data layout should never have to be modified in any way, as it matches the expected data layout
1618 * in the raw bytes buffers read from older blend-files.
1619 *
1620 * NOTE: There is _no_ need to protect DNA structs definition in any way to ensure forward
1621 * compatibility, for the following reasons:
1622 * - The DNA struct info _is_ properly written in blend-files since 2.83.
1623 * - When there is DNA info for a #BHead in the blend-file, even if that #BHead is ultimately
1624 * 'read'/used as raw bytes buffer through a call to `BLO_read_data_address`, the actual
1625 * reading of that #BHead from the blend-file will have already gone through the lower-level
1626 * 'DNA versioning' process, which means that DNA struct changes (like adding new properties,
1627 * increasing an array size, etc.) will be handled properly.
1628 * - Blender versions prior to 3.6 will not be able to load any 4.0+ blend-files without
1629 * immediate crash, so trying to preserve forward compatibility for versions older than
1630 * 2.83 would be totally pointless.
1631 */
1632
1639
1646
1650
1657
1661
1665
1668 char _pad[4];
1669 char value[/*FILE_MAX*/ 1024];
1671
1675
1679
1683
1687
1691
1693 /* Default input enum identifier. */
1695 /* #NodeSocketValueMenuRuntimeFlag */
1697 /* Immutable runtime enum definition. */
1700
1701/* Generic code handling the conversion between a legacy (pre-2.83) socket data, and its current
1702 * data. Currently used for `bNodeSocket.default_value`. */
1703template<typename T, typename T_404>
1705 void **dest_data, void **raw_data, blender::FunctionRef<void(T &dest, T_404 &source)> copy_fn)
1706{
1707 /* Cannot check for equality because of potential alignment offset. */
1708 BLI_assert(MEM_allocN_len(*raw_data) >= sizeof(T_404));
1709 T_404 *orig_data = static_cast<T_404 *>(*raw_data);
1710 *raw_data = nullptr;
1711 T *final_data = MEM_callocN<T>(__func__);
1712 /* Could use `memcpy` here, since we also require historic members of these DNA structs to
1713 * never be moved or re-ordered. But better be verbose and explicit here. */
1714 copy_fn(*final_data, *orig_data);
1715 *dest_data = final_data;
1716 MEM_freeN(orig_data);
1717}
1718
1719} // namespace versioning_internal
1720
1722{
1723 if (sock->default_value == nullptr) {
1724 return;
1725 }
1726
1727 if (sock->type == SOCK_CUSTOM) {
1728 /* There are some files around that have non-null default value for custom sockets. See e.g.
1729 * #140083.
1730 *
1731 * It is unclear how this could happen, but for now simply systematically set this pointer to
1732 * null. */
1733 sock->default_value = nullptr;
1734 return;
1735 }
1736
1737 if (BLO_read_fileversion_get(reader) >=
1739 {
1740 /* Modern, standard DNA-typed reading of sockets default values. */
1741 switch (eNodeSocketDatatype(sock->type)) {
1742 case SOCK_FLOAT:
1744 break;
1745 case SOCK_VECTOR:
1747 break;
1748 case SOCK_RGBA:
1750 break;
1751 case SOCK_BOOLEAN:
1753 break;
1754 case SOCK_INT:
1756 break;
1757 case SOCK_STRING:
1759 break;
1760 case SOCK_OBJECT:
1762 break;
1763 case SOCK_IMAGE:
1765 break;
1766 case SOCK_COLLECTION:
1768 break;
1769 case SOCK_TEXTURE:
1771 break;
1772 case SOCK_MATERIAL:
1774 break;
1775 case SOCK_ROTATION:
1777 break;
1778 case SOCK_MENU:
1780 break;
1781 case SOCK_MATRIX:
1782 /* Matrix sockets currently have no default value. */
1783 case SOCK_CUSTOM:
1784 /* Custom node sockets where default_value is defined use custom properties for storage. */
1785 case SOCK_SHADER:
1786 case SOCK_GEOMETRY:
1787 case SOCK_BUNDLE:
1788 case SOCK_CLOSURE:
1790 break;
1791 }
1792 }
1793 else {
1794 /* Legacy-compatible, raw-buffer-based reading of sockets default values. */
1795 void *temp_data = sock->default_value;
1796 BLO_read_data_address(reader, &temp_data);
1797 if (!temp_data) {
1798 sock->default_value = nullptr;
1799 return;
1800 }
1801
1802 switch (eNodeSocketDatatype(sock->type)) {
1803 case SOCK_FLOAT:
1807 &sock->default_value,
1808 &temp_data,
1810 dest.subtype = src.subtype;
1811 dest.value = src.value;
1812 dest.min = src.min;
1813 dest.max = src.max;
1814 });
1815 break;
1816 case SOCK_VECTOR:
1820 &sock->default_value,
1821 &temp_data,
1822 [](bNodeSocketValueVector &dest,
1824 dest.subtype = src.subtype;
1825 copy_v3_v3(dest.value, src.value);
1826 dest.min = src.min;
1827 dest.max = src.max;
1828 });
1829 break;
1830 case SOCK_RGBA:
1834 &sock->default_value,
1835 &temp_data,
1837 copy_v4_v4(dest.value, src.value);
1838 });
1839 break;
1840 case SOCK_BOOLEAN:
1844 &sock->default_value,
1845 &temp_data,
1846 [](bNodeSocketValueBoolean &dest,
1847 versioning_internal::bNodeSocketValueBoolean_404 &src) { dest.value = src.value; });
1848 break;
1849 case SOCK_INT:
1853 &sock->default_value,
1854 &temp_data,
1856 dest.subtype = src.subtype;
1857 dest.value = src.value;
1858 dest.min = src.min;
1859 dest.max = src.max;
1860 });
1861 break;
1862 case SOCK_STRING:
1866 &sock->default_value,
1867 &temp_data,
1868 [](bNodeSocketValueString &dest,
1870 dest.subtype = src.subtype;
1871 STRNCPY(dest.value, src.value);
1872 });
1873 break;
1874 case SOCK_OBJECT:
1878 &sock->default_value,
1879 &temp_data,
1880 [](bNodeSocketValueObject &dest,
1881 versioning_internal::bNodeSocketValueObject_404 &src) { dest.value = src.value; });
1882 break;
1883 case SOCK_IMAGE:
1887 &sock->default_value,
1888 &temp_data,
1890 dest.value = src.value;
1891 });
1892 break;
1893 case SOCK_COLLECTION:
1897 &sock->default_value,
1898 &temp_data,
1901 dest.value = src.value;
1902 });
1903 break;
1904 case SOCK_TEXTURE:
1908 &sock->default_value,
1909 &temp_data,
1910 [](bNodeSocketValueTexture &dest,
1911 versioning_internal::bNodeSocketValueTexture_404 &src) { dest.value = src.value; });
1912 break;
1913 case SOCK_MATERIAL:
1917 &sock->default_value,
1918 &temp_data,
1919 [](bNodeSocketValueMaterial &dest,
1921 dest.value = src.value;
1922 });
1923 break;
1924 case SOCK_ROTATION:
1928 &sock->default_value,
1929 &temp_data,
1930 [](bNodeSocketValueRotation &dest,
1932 copy_v3_v3(dest.value_euler, src.value_euler);
1933 });
1934 break;
1935 case SOCK_MENU:
1939 &sock->default_value,
1940 &temp_data,
1942 dest.value = src.value;
1943 /* Other members are runtime-only. */
1944 });
1945 break;
1946 case SOCK_MATRIX:
1947 /* Matrix sockets had no default value. */
1948 case SOCK_CUSTOM:
1949 /* Custom node sockets where default_value is defined were using custom properties for
1950 * storage. */
1951 case SOCK_SHADER:
1952 case SOCK_GEOMETRY:
1953 case SOCK_BUNDLE:
1954 case SOCK_CLOSURE:
1956 break;
1957 }
1958 }
1959
1960 /* Post-reading processing. */
1961 switch (eNodeSocketDatatype(sock->type)) {
1962 case SOCK_MENU: {
1963 bNodeSocketValueMenu &default_value = *sock->default_value_typed<bNodeSocketValueMenu>();
1964 /* Clear runtime data. */
1965 default_value.enum_items = nullptr;
1966 default_value.runtime_flag = 0;
1967 break;
1968 }
1969 default:
1970 break;
1971 }
1972}
1973
1975 const bNode *node,
1976 bNodeSocket *sock)
1977{
1978 if (!sock->storage) {
1979 return;
1980 }
1981 if (!node) {
1982 /* Sockets not owned by a node should never have storage data. */
1984 sock->storage = nullptr;
1985 return;
1986 }
1987
1988 /* Sockets storage data seem to have always been written with correct DNA type info (see
1989 * 3bae60d0c9 and 9d91bc38d3). So no need to use the same versioning work-around for old files as
1990 * done for default values. */
1991 switch (node->type_legacy) {
1994 if (sock->storage) {
1995 NodeImageMultiFileSocket *sockdata = static_cast<NodeImageMultiFileSocket *>(
1996 sock->storage);
1997 BKE_image_format_blend_read_data(reader, &sockdata->format);
1998 }
1999 break;
2000 case CMP_NODE_IMAGE:
2001 case CMP_NODE_R_LAYERS:
2002 BLO_read_struct(reader, NodeImageLayer, &sock->storage);
2003 break;
2004 default:
2006 sock->storage = nullptr;
2007 break;
2008 }
2009}
2010
2011static void direct_link_node_socket(BlendDataReader *reader, const bNode *node, bNodeSocket *sock)
2012{
2013 BLO_read_struct(reader, IDProperty, &sock->prop);
2014 IDP_BlendDataRead(reader, &sock->prop);
2015
2016 BLO_read_struct(reader, bNodeLink, &sock->link);
2017 sock->typeinfo = nullptr;
2018
2019 direct_link_node_socket_storage(reader, node, sock);
2020
2022
2024 sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
2025}
2026
2027static void remove_unsupported_sockets(ListBase *sockets, ListBase *links)
2028{
2029 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, sockets) {
2030 if (is_node_socket_supported(sock)) {
2031 continue;
2032 }
2033
2034 /* First remove any link pointing to the socket. */
2035 if (links) {
2036 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, links) {
2037 if (link->fromsock == sock || link->tosock == sock) {
2038 BLI_remlink(links, link);
2039 if (link->tosock) {
2040 link->tosock->link = nullptr;
2041 }
2042 MEM_freeN(link);
2043 }
2044 }
2045 }
2046
2047 BLI_remlink(sockets, sock);
2048 MEM_delete(sock->runtime);
2049 MEM_freeN(sock);
2050 }
2051}
2052
2054{
2055 if (!node->storage) {
2056 return;
2057 }
2059 /* Do nothing, this is a runtime cache and hence handled by generic code using
2060 * `IDTypeInfo.foreach_cache` callback. */
2061 return;
2062 }
2063
2064 /* This may not always find the type for legacy nodes when the idname did not exist yet or it was
2065 * changed. Versioning code will update the nodes with unknown types. */
2066 const bNodeType *ntype = node_type_find(node->idname);
2067
2068 if (ntype && !ntype->storagename.empty()) {
2070 reader, ntype->storagename.c_str(), 1, node->storage);
2071 }
2072 else {
2073 /* Untyped read because we don't know the type yet. */
2074 BLO_read_data_address(reader, &node->storage);
2075 }
2076
2077 if (ntype && ntype->blend_data_read_storage_content) {
2078 ntype->blend_data_read_storage_content(*ntree, *node, *reader);
2079 return;
2080 }
2081
2082 /* Some nodes don't use the callback above, because they were introduced before there were node
2083 * idnames. Therefore, we can't rely on the idname to lookup the node type. */
2084 switch (node->type_legacy) {
2085 case SH_NODE_CURVE_VEC:
2086 case SH_NODE_CURVE_RGB:
2088 case CMP_NODE_TIME:
2089 case CMP_NODE_CURVE_VEC:
2090 case CMP_NODE_CURVE_RGB:
2092 case TEX_NODE_CURVE_RGB:
2093 case TEX_NODE_CURVE_TIME: {
2094 BKE_curvemapping_blend_read(reader, static_cast<CurveMapping *>(node->storage));
2095 break;
2096 }
2097 case SH_NODE_SCRIPT: {
2098 NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
2099 BLO_read_string(reader, &nss->bytecode);
2100 break;
2101 }
2103 NodeShaderTexPointDensity *npd = static_cast<NodeShaderTexPointDensity *>(node->storage);
2104 npd->pd = dna::shallow_zero_initialize();
2105 break;
2106 }
2107 case SH_NODE_TEX_IMAGE: {
2108 NodeTexImage *tex = static_cast<NodeTexImage *>(node->storage);
2109 tex->iuser.scene = nullptr;
2110 break;
2111 }
2113 NodeTexEnvironment *tex = static_cast<NodeTexEnvironment *>(node->storage);
2114 tex->iuser.scene = nullptr;
2115 break;
2116 }
2117 case CMP_NODE_IMAGE:
2118 case CMP_NODE_VIEWER: {
2119 ImageUser *iuser = static_cast<ImageUser *>(node->storage);
2120 iuser->scene = nullptr;
2121 break;
2122 }
2124 case CMP_NODE_CRYPTOMATTE: {
2125 NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage);
2126 BLO_read_string(reader, &nc->matte_id);
2129 break;
2130 }
2131 case TEX_NODE_IMAGE: {
2132 ImageUser *iuser = static_cast<ImageUser *>(node->storage);
2133 iuser->scene = nullptr;
2134 break;
2135 }
2136 case CMP_NODE_OUTPUT_FILE: {
2137 NodeImageMultiFile *nimf = static_cast<NodeImageMultiFile *>(node->storage);
2139 break;
2140 }
2141 default:
2142 break;
2143 }
2144}
2145
2147{
2148 /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs
2149 * for do_versioning, and ensures coherence of data in any case.
2150 *
2151 * NOTE: Old versions are very often 'broken' here, just fix it silently in these cases.
2152 */
2153 if (BLO_read_fileversion_get(reader) > 300) {
2154 BLI_assert((ntree->id.flag & ID_FLAG_EMBEDDED_DATA) != 0 || owner_id == nullptr);
2155 }
2156 BLI_assert(owner_id == nullptr || owner_id->lib == ntree->id.lib);
2157 if (owner_id != nullptr && (ntree->id.flag & ID_FLAG_EMBEDDED_DATA) == 0) {
2158 /* This is unfortunate, but currently a lot of existing files (including startup ones) have
2159 * missing `ID_FLAG_EMBEDDED_DATA` flag.
2160 *
2161 * NOTE: Using do_version is not a solution here, since this code will be called before any
2162 * do_version takes place. Keeping it here also ensures future (or unknown existing) similar
2163 * bugs won't go easily unnoticed. */
2164 if (BLO_read_fileversion_get(reader) > 300) {
2165 CLOG_WARN(&LOG,
2166 "Fixing root node tree '%s' owned by '%s' missing EMBEDDED tag, please consider "
2167 "re-saving your (startup) file",
2168 ntree->id.name,
2169 owner_id->name);
2170 }
2171 ntree->id.flag |= ID_FLAG_EMBEDDED_DATA;
2172 }
2173 ntree->owner_id = owner_id;
2174
2175 /* NOTE: writing and reading goes in sync, for speed. */
2176 ntree->typeinfo = nullptr;
2177
2178 ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
2180
2181 BLO_read_string(reader, &ntree->description);
2182
2183 BLO_read_struct_list(reader, bNode, &ntree->nodes);
2184 int i;
2185 LISTBASE_FOREACH_INDEX (bNode *, node, &ntree->nodes, i) {
2186 node->runtime = MEM_new<bNodeRuntime>(__func__);
2187 node->typeinfo = nullptr;
2188 node->runtime->index_in_tree = i;
2189
2190 /* Create the `nodes_by_id` cache eagerly so it can be expected to be valid. Because
2191 * we create it here we also have to check for zero identifiers from previous versions. */
2192 if (node->identifier == 0 || ntree->runtime->nodes_by_id.contains_as(node->identifier)) {
2193 node_unique_id(*ntree, *node);
2194 }
2195 else {
2196 ntree->runtime->nodes_by_id.add_new(node);
2197 }
2198
2199 BLO_read_struct_list(reader, bNodeSocket, &node->inputs);
2200 BLO_read_struct_list(reader, bNodeSocket, &node->outputs);
2202 reader, bNodePanelState, node->num_panel_states, &node->panel_states_array);
2203
2204 BLO_read_struct(reader, IDProperty, &node->prop);
2205 IDP_BlendDataRead(reader, &node->prop);
2206
2207 node_blend_read_data_storage(reader, ntree, node);
2208 }
2209 BLO_read_struct_list(reader, bNodeLink, &ntree->links);
2210 BLI_assert(ntree->all_nodes().size() == BLI_listbase_count(&ntree->nodes));
2211
2212 /* and we connect the rest */
2213 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
2214 BLO_read_struct(reader, bNode, &node->parent);
2215
2216 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
2217 direct_link_node_socket(reader, node, sock);
2218 }
2219 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
2220 direct_link_node_socket(reader, node, sock);
2221 }
2222 }
2223
2224 /* Read legacy interface socket lists for versioning. */
2225 BLO_read_struct_list(reader, bNodeSocket, &ntree->inputs_legacy);
2226 BLO_read_struct_list(reader, bNodeSocket, &ntree->outputs_legacy);
2227 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &ntree->inputs_legacy) {
2228 direct_link_node_socket(reader, nullptr, sock);
2229 }
2230 LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &ntree->outputs_legacy) {
2231 direct_link_node_socket(reader, nullptr, sock);
2232 }
2233
2234 ntree->tree_interface.read_data(reader);
2235
2236 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
2237 BLO_read_struct(reader, bNode, &link->fromnode);
2238 BLO_read_struct(reader, bNode, &link->tonode);
2239 BLO_read_struct(reader, bNodeSocket, &link->fromsock);
2240 BLO_read_struct(reader, bNodeSocket, &link->tosock);
2241 }
2242
2243 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
2244 remove_unsupported_sockets(&node->inputs, &ntree->links);
2245 remove_unsupported_sockets(&node->outputs, &ntree->links);
2246 }
2247 remove_unsupported_sockets(&ntree->inputs_legacy, nullptr);
2248 remove_unsupported_sockets(&ntree->outputs_legacy, nullptr);
2249
2252 reader, bNestedNodeRef, ntree->nested_node_refs_num, &ntree->nested_node_refs);
2253
2254 BLO_read_struct(reader, PreviewImage, &ntree->preview);
2255 BKE_previewimg_blend_read(reader, ntree->preview);
2256
2257 /* type verification is in lib-link */
2258}
2259
2261{
2262 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
2263 node_tree_blend_read_data(reader, nullptr, ntree);
2264}
2265
2267{
2268 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
2269
2270 /* Set `node->typeinfo` pointers. This is done in lib linking, after the
2271 * first versioning that can change types still without functions that
2272 * update the `typeinfo` pointers. Versioning after lib linking needs
2273 * these top be valid. */
2274 node_tree_set_type(*ntree);
2275
2276 /* For nodes with static socket layout, add/remove sockets as needed
2277 * to match the static layout. */
2278 if (!BLO_read_lib_is_undo(reader)) {
2279 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
2280 /* Don't update node groups here because they may depend on other node groups which are not
2281 * fully versioned yet and don't have `typeinfo` pointers set. */
2282 if (!node->is_group()) {
2283 node_verify_sockets(ntree, node, false);
2284 }
2285 }
2286 }
2287}
2288
2290{
2291 AssetMetaData *asset_data = node_tree.id.asset_data;
2292 if (!asset_data) {
2293 return;
2294 }
2295
2296 BKE_asset_metadata_idprop_ensure(asset_data, idprop::create("type", node_tree.type).release());
2297 auto inputs = idprop::create_group("inputs");
2298 auto outputs = idprop::create_group("outputs");
2299 node_tree.ensure_interface_cache();
2300 for (const bNodeTreeInterfaceSocket *socket : node_tree.interface_inputs()) {
2301 auto *prop = idprop::create(socket->name ? socket->name : "", socket->socket_type).release();
2302 if (!IDP_AddToGroup(inputs.get(), prop)) {
2303 IDP_FreeProperty(prop);
2304 }
2305 }
2306 for (const bNodeTreeInterfaceSocket *socket : node_tree.interface_outputs()) {
2307 auto *prop = idprop::create(socket->name ? socket->name : "", socket->socket_type).release();
2308 if (!IDP_AddToGroup(outputs.get(), prop)) {
2309 IDP_FreeProperty(prop);
2310 }
2311 }
2312 BKE_asset_metadata_idprop_ensure(asset_data, inputs.release());
2313 BKE_asset_metadata_idprop_ensure(asset_data, outputs.release());
2314 if (node_tree.geometry_node_asset_traits) {
2315 auto property = idprop::create("geometry_node_asset_traits_flag",
2316 node_tree.geometry_node_asset_traits->flag);
2317 BKE_asset_metadata_idprop_ensure(asset_data, property.release());
2318 }
2319}
2320
2321static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData * /*asset_data*/)
2322{
2323 bNodeTree &ntree = *static_cast<bNodeTree *>(asset_ptr);
2325}
2326
2327static void node_tree_asset_on_mark_asset(void *asset_ptr, AssetMetaData *asset_data)
2328{
2329 bNodeTree &ntree = *static_cast<bNodeTree *>(asset_ptr);
2331
2332 /* Copy node tree description to asset description so that the user does not have to write it
2333 * again. */
2334 if (!asset_data->description) {
2335 asset_data->description = BLI_strdup_null(ntree.description);
2336 }
2337}
2338
2339static void node_tree_asset_on_clear_asset(void *asset_ptr, AssetMetaData *asset_data)
2340{
2341 bNodeTree &ntree = *static_cast<bNodeTree *>(asset_ptr);
2342
2343 /* Copy asset description to node tree description so that it is not lost when the asset data is
2344 * removed. */
2345 if (asset_data->description) {
2347 ntree.description = BLI_strdup_null(asset_data->description);
2348 }
2349}
2350
2351} // namespace blender::bke
2352
2358
2360 /*id_code*/ bNodeTree::id_type,
2361 /*id_filter*/ FILTER_ID_NT,
2362 /* IDProps of nodes, and #bNode.id, can use any type of ID. */
2363 /*dependencies_id_types*/ FILTER_ID_ALL,
2364 /*main_listbase_index*/ INDEX_ID_NT,
2365 /*struct_size*/ sizeof(bNodeTree),
2366 /*name*/ "NodeTree",
2367 /*name_plural*/ N_("node_groups"),
2368 /*translation_context*/ BLT_I18NCONTEXT_ID_NODETREE,
2370 /*asset_type_info*/ &AssetType_NT,
2371
2372 /*init_data*/ blender::bke::ntree_init_data,
2373 /*copy_data*/ blender::bke::ntree_copy_data,
2374 /*free_data*/ blender::bke::ntree_free_data,
2375 /*make_local*/ nullptr,
2376 /*foreach_id*/ blender::bke::node_foreach_id,
2377 /*foreach_cache*/ blender::bke::node_foreach_cache,
2378 /*foreach_path*/ blender::bke::node_foreach_path,
2379 /*owner_pointer_get*/ blender::bke::node_owner_pointer_get,
2380
2381 /*blend_write*/ blender::bke::ntree_blend_write,
2382 /*blend_read_data*/ blender::bke::ntree_blend_read_data,
2383 /*blend_read_after_liblink*/ blender::bke::ntree_blend_read_after_liblink,
2384
2385 /*blend_read_undo_preserve*/ nullptr,
2386
2387 /*lib_override_apply_post*/ nullptr,
2388};
2389
2390namespace blender::bke {
2391
2392static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
2393{
2394 if (ntype->declare) {
2395 node_verify_sockets(ntree, node, true);
2396 return;
2397 }
2398 bNodeSocketTemplate *sockdef;
2399
2400 if (ntype->inputs) {
2401 sockdef = ntype->inputs;
2402 while (sockdef->type != -1) {
2403 node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
2404 sockdef++;
2405 }
2406 }
2407 if (ntype->outputs) {
2408 sockdef = ntype->outputs;
2409 while (sockdef->type != -1) {
2410 node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
2411 sockdef++;
2412 }
2413 }
2414}
2415
2416/* NOTE: This function is called to initialize node data based on the type.
2417 * The #bNodeType may not be registered at creation time of the node,
2418 * so this can be delayed until the node type gets registered.
2419 */
2420static void node_init(const bContext *C, bNodeTree *ntree, bNode *node)
2421{
2422 BLI_assert(ntree != nullptr);
2423 bNodeType *ntype = node->typeinfo;
2424 if (ntype == &NodeTypeUndefined) {
2425 return;
2426 }
2427
2428 /* only do this once */
2429 if (node->flag & NODE_INIT) {
2430 return;
2431 }
2432
2433 node->flag = NODE_SELECT | NODE_OPTIONS | ntype->flag;
2434 node->width = ntype->width;
2435 node->height = ntype->height;
2436 node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */
2437 /* initialize the node name with the node label.
2438 * NOTE: do this after the initfunc so nodes get their data set which may be used in naming
2439 * (node groups for example) */
2440 /* XXX Do not use nodeLabel() here, it returns translated content for UI,
2441 * which should *only* be used in UI, *never* in data...
2442 * Data have their own translation option!
2443 * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
2444 * than adding "do_translate" flags to this func (and labelfunc() as well). */
2445 DATA_(ntype->ui_name).copy_utf8_truncated(node->name);
2446 node_unique_name(*ntree, *node);
2447
2448 /* Generally sockets should be added after the initialization, because the set of sockets might
2449 * depend on node properties. */
2450 const bool add_sockets_before_init = node->type_legacy == CMP_NODE_R_LAYERS;
2451 if (add_sockets_before_init) {
2452 node_add_sockets_from_type(ntree, node, ntype);
2453 }
2454
2455 if (ntype->initfunc != nullptr) {
2456 ntype->initfunc(ntree, node);
2457 }
2458
2459 if (ntree->typeinfo && ntree->typeinfo->node_add_init) {
2460 ntree->typeinfo->node_add_init(ntree, node);
2461 }
2462
2463 if (!add_sockets_before_init) {
2464 node_add_sockets_from_type(ntree, node, ntype);
2465 }
2466
2467 if (node->id) {
2468 id_us_plus(node->id);
2469 }
2470
2471 if (ntype->initfunc_api) {
2472 PointerRNA ptr = RNA_pointer_create_discrete(&ntree->id, &RNA_Node, node);
2473
2474 /* XXX WARNING: context can be nullptr in case nodes are added in do_versions.
2475 * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
2476 BLI_assert(C != nullptr);
2477 ntype->initfunc_api(C, &ptr);
2478 }
2479
2480 node->flag |= NODE_INIT;
2481}
2482
2483static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
2484{
2485 if (typeinfo) {
2486 ntree->typeinfo = typeinfo;
2487 }
2488 else {
2490 }
2491
2492 /* Deprecated integer type. */
2493 ntree->type = ntree->typeinfo->type;
2495}
2496
2497static void node_set_typeinfo(const bContext *C,
2498 bNodeTree *ntree,
2499 bNode *node,
2500 bNodeType *typeinfo)
2501{
2502 /* for nodes saved in older versions storage can get lost, make undefined then */
2503 if (node->flag & NODE_INIT) {
2504 if (typeinfo && typeinfo->storagename[0] && !node->storage) {
2505 typeinfo = nullptr;
2506 }
2507 }
2508
2509 if (typeinfo) {
2510 node->typeinfo = typeinfo;
2511
2512 /* deprecated integer type */
2513 node->type_legacy = typeinfo->type_legacy;
2514
2515 /* initialize the node if necessary */
2516 node_init(C, ntree, node);
2517 }
2518 else {
2519 node->typeinfo = &NodeTypeUndefined;
2520 }
2521 BKE_ntree_update_tag_node_type(ntree, node);
2522}
2523
2524/* WARNING: default_value must either be null or match the typeinfo at this point.
2525 * This function is called both for initializing new sockets and after loading files.
2526 */
2528 bNodeSocket *sock,
2529 bNodeSocketType *typeinfo)
2530{
2531 if (typeinfo) {
2532 sock->typeinfo = typeinfo;
2533
2534 /* deprecated integer type */
2535 sock->type = typeinfo->type;
2536
2537 if (sock->default_value == nullptr) {
2538 /* initialize the default_value pointer used by standard socket types */
2540 }
2541 }
2542 else {
2544 }
2546}
2547
2548/* Set specific typeinfo pointers in all node trees on register/unregister */
2549static void update_typeinfo(Main *bmain,
2550 bNodeTreeType *treetype,
2551 bNodeType *nodetype,
2552 bNodeSocketType *socktype,
2553 const bool unregister)
2554{
2555 if (!bmain) {
2556 return;
2557 }
2558
2559 FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
2560 if (treetype && ntree->idname == treetype->idname) {
2561 ntree_set_typeinfo(ntree, unregister ? nullptr : treetype);
2562 }
2563
2564 /* initialize nodes */
2565 for (bNode *node : ntree->all_nodes()) {
2566 if (nodetype && node->idname == nodetype->idname) {
2567 node_set_typeinfo(nullptr, ntree, node, unregister ? nullptr : nodetype);
2568 }
2569
2570 /* initialize node sockets */
2571 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
2572 if (socktype && sock->idname == socktype->idname) {
2573 node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype);
2574 }
2575 }
2576 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
2577 if (socktype && sock->idname == socktype->idname) {
2578 node_socket_set_typeinfo(ntree, sock, unregister ? nullptr : socktype);
2579 }
2580 }
2581 }
2582 }
2584}
2585
2587{
2589
2590 for (bNode *node : ntree.all_nodes()) {
2591 /* Set socket typeinfo first because node initialization may rely on socket typeinfo for
2592 * generating declarations. */
2593 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
2594 node_socket_set_typeinfo(&ntree, sock, node_socket_type_find(sock->idname));
2595 }
2596 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
2597 node_socket_set_typeinfo(&ntree, sock, node_socket_type_find(sock->idname));
2598 }
2599
2600 node_set_typeinfo(nullptr, &ntree, node, node_type_find(node->idname));
2601 }
2602}
2603
2604template<typename T> struct NodeStructIDNameGetter {
2605 StringRef operator()(const T *value) const
2606 {
2607 return StringRef(value->idname);
2608 }
2609};
2610
2616
2617static auto &get_node_type_map()
2618{
2620 return map;
2621}
2622
2624{
2626 return map;
2627}
2628
2634
2636{
2637 bNodeTreeType *const *value = get_node_tree_type_map().lookup_key_ptr_as(idname);
2638 if (!value) {
2639 return nullptr;
2640 }
2641 return *value;
2642}
2643
2645{
2646 static ResourceScope scope;
2647 scope.add_destruct_call([tree_type]() { MEM_delete(tree_type); });
2648}
2649
2651{
2652 static ResourceScope scope;
2653 scope.add_destruct_call([ntype]() {
2654 /* May be null if the type is statically allocated. */
2655 if (ntype->free_self) {
2656 ntype->free_self(ntype);
2657 }
2658 });
2659}
2660
2662{
2663 static ResourceScope scope;
2664 scope.add_destruct_call([stype]() {
2665 /* May be null if the type is statically allocated. */
2666 if (stype->free_self) {
2667 stype->free_self(stype);
2668 }
2669 });
2670}
2671
2673{
2674 get_node_tree_type_map().add(&nt);
2675 /* XXX pass Main to register function? */
2676 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2677 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2678 update_typeinfo(G_MAIN, &nt, nullptr, nullptr, false);
2679}
2680
2681static void ntree_free_type(void *treetype_v)
2682{
2683 bNodeTreeType *treetype = static_cast<bNodeTreeType *>(treetype_v);
2684 /* XXX pass Main to unregister function? */
2685 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2686 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2687 update_typeinfo(G_MAIN, treetype, nullptr, nullptr, true);
2688
2689 /* Defer freeing the tree type, because it may still be referenced by trees in depsgraph
2690 * copies. We can't just remove these tree types, because the depsgraph may exist completely
2691 * separately from original data. */
2692 defer_free_tree_type(treetype);
2693}
2694
2696{
2697 get_node_tree_type_map().remove(const_cast<bNodeTreeType *>(&nt));
2698 ntree_free_type(const_cast<bNodeTreeType *>(&nt));
2699}
2700
2702{
2703 return (ntree.typeinfo != &NodeTreeTypeUndefined);
2704}
2705
2710
2712{
2713 bNodeType *const *value = get_node_type_map().lookup_key_ptr_as(idname);
2714 if (!value) {
2715 return nullptr;
2716 }
2717 return *value;
2718}
2719
2721{
2722 const std::string *idname = get_node_type_alias_map().lookup_ptr_as(alias);
2723 if (!idname) {
2724 return alias;
2725 }
2726 return *idname;
2727}
2728
2729static void node_free_type(void *nodetype_v)
2730{
2731 bNodeType *nodetype = static_cast<bNodeType *>(nodetype_v);
2732 /* XXX pass Main to unregister function? */
2733 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2734 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2735 update_typeinfo(G_MAIN, nullptr, nodetype, nullptr, true);
2736
2737 /* Setting this to null is necessary for the case of static node types. When running tests,
2738 * they may be registered and unregistered multiple times. */
2739 delete nodetype->static_declaration;
2740 nodetype->static_declaration = nullptr;
2741
2742 /* Defer freeing the node type, because it may still be referenced by nodes in depsgraph
2743 * copies. We can't just remove these node types, because the depsgraph may exist completely
2744 * separate from original data. */
2745 defer_free_node_type(nodetype);
2746}
2747
2749{
2750 /* debug only: basic verification of registered types */
2751 BLI_assert(!nt.idname.empty());
2752 BLI_assert(nt.poll != nullptr);
2753
2754 RNA_def_struct_ui_text(nt.rna_ext.srna, nt.ui_name.c_str(), nt.ui_description.c_str());
2755
2756 if (!nt.enum_name_legacy) {
2757 /* For new nodes, use the idname as a unique identifier. */
2758 nt.enum_name_legacy = nt.idname.c_str();
2759 }
2760
2761 if (nt.declare) {
2763 nodes::build_node_declaration(nt, *nt.static_declaration, nullptr, nullptr);
2764 }
2765
2766 get_node_type_map().add_new(&nt);
2767 /* XXX pass Main to register function? */
2768 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2769 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2770 update_typeinfo(G_MAIN, nullptr, &nt, nullptr, false);
2771}
2772
2774{
2775 get_node_type_map().remove(&nt);
2776 node_free_type(&nt);
2777}
2778
2780{
2781 return get_node_type_map().as_span();
2782}
2783
2785{
2786 get_node_type_alias_map().add_new(alias, nt.idname);
2787}
2788
2793
2795{
2796 bNodeSocketType *const *value = get_socket_type_map().lookup_key_ptr_as(idname);
2797 if (!value) {
2798 return nullptr;
2799 }
2800 return *value;
2801}
2802
2803bNodeSocketType *node_socket_type_find_static(const int type, const int subtype)
2804{
2805 const std::optional<StringRefNull> idname = node_static_socket_type(type, subtype);
2806 if (!idname) {
2807 return nullptr;
2808 }
2809 return node_socket_type_find(*idname);
2810}
2811
2812static void node_free_socket_type(void *socktype_v)
2813{
2814 bNodeSocketType *socktype = static_cast<bNodeSocketType *>(socktype_v);
2815 /* XXX pass Main to unregister function? */
2816 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2817 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2818 update_typeinfo(G_MAIN, nullptr, nullptr, socktype, true);
2819
2820 /* Defer freeing the socket type, because it may still be referenced by nodes in depsgraph
2821 * copies. We can't just remove these socket types, because the depsgraph may exist completely
2822 * separate from original data. */
2823 defer_free_socket_type(socktype);
2824}
2825
2827{
2828 get_socket_type_map().add(&st);
2829 /* XXX pass Main to register function? */
2830 /* Probably not. It is pretty much expected we want to update G_MAIN here I think -
2831 * or we'd want to update *all* active Mains, which we cannot do anyway currently. */
2832 update_typeinfo(G_MAIN, nullptr, nullptr, &st, false);
2833}
2834
2840
2842{
2843 return (sock.typeinfo != &NodeSocketTypeUndefined);
2844}
2845
2847{
2848 /* Use socket type name as a fallback if label is undefined. */
2849 if (stype.label[0] == '\0') {
2850 return RNA_struct_ui_name(stype.ext_socket.srna);
2851 }
2852 return stype.label;
2853}
2854
2856{
2857 const char *name;
2858 if (RNA_enum_name(rna_enum_property_subtype_items, subtype, &name)) {
2859 return name;
2860 }
2861 return "";
2862}
2863
2865 const eNodeSocketInOut in_out,
2866 const StringRef identifier)
2867{
2868 const ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
2869 LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
2870 if (sock->identifier == identifier) {
2871 return sock;
2872 }
2873 }
2874 return nullptr;
2875}
2876
2878 const eNodeSocketInOut in_out,
2879 const StringRef identifier)
2880{
2881 /* Reuse the implementation of the mutable accessor. */
2882 return node_find_socket(*const_cast<bNode *>(&node), in_out, identifier);
2883}
2884
2886 const eNodeSocketInOut in_out,
2887 const StringRef name)
2888{
2889 ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
2890 LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
2891 if (socket->is_available() && socket->name == name) {
2892 return socket;
2893 }
2894 }
2895 return nullptr;
2896}
2897
2899{
2900 return node_find_enabled_socket(node, SOCK_IN, name);
2901}
2902
2904{
2905 return node_find_enabled_socket(node, SOCK_OUT, name);
2906}
2907
2909 bNode * /*node*/,
2910 const int in_out,
2911 ListBase *lb,
2912 const StringRefNull idname,
2913 const StringRefNull identifier,
2914 const StringRefNull name)
2915{
2916 char auto_identifier[MAX_NAME];
2917
2918 if (identifier[0] != '\0') {
2919 /* use explicit identifier */
2920 identifier.copy_utf8_truncated(auto_identifier);
2921 }
2922 else {
2923 /* if no explicit identifier is given, assign a unique identifier based on the name */
2924 name.copy_utf8_truncated(auto_identifier);
2925 }
2926 /* Make the identifier unique. */
2928 [&](const StringRef check_name) {
2929 LISTBASE_FOREACH (bNodeSocket *, sock, lb) {
2930 if (sock->identifier == check_name) {
2931 return true;
2932 }
2933 }
2934 return false;
2935 },
2936 "socket",
2937 '_',
2938 auto_identifier,
2939 sizeof(auto_identifier));
2940
2941 bNodeSocket *sock = MEM_callocN<bNodeSocket>(__func__);
2942 sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
2943 sock->in_out = in_out;
2944
2945 STRNCPY(sock->identifier, auto_identifier);
2946 sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
2947
2948 name.copy_utf8_truncated(sock->name);
2949 sock->storage = nullptr;
2950 sock->flag |= SOCK_COLLAPSED;
2951 sock->type = SOCK_CUSTOM; /* int type undefined by default */
2952
2953 idname.copy_utf8_truncated(sock->idname);
2954 node_socket_set_typeinfo(ntree, sock, node_socket_type_find(idname));
2955
2956 return sock;
2957}
2958
2960{
2961 switch (eNodeSocketDatatype(sock->type)) {
2962 case SOCK_OBJECT: {
2963 bNodeSocketValueObject &default_value = *sock->default_value_typed<bNodeSocketValueObject>();
2964 id_us_plus(reinterpret_cast<ID *>(default_value.value));
2965 break;
2966 }
2967 case SOCK_IMAGE: {
2968 bNodeSocketValueImage &default_value = *sock->default_value_typed<bNodeSocketValueImage>();
2969 id_us_plus(reinterpret_cast<ID *>(default_value.value));
2970 break;
2971 }
2972 case SOCK_COLLECTION: {
2973 bNodeSocketValueCollection &default_value =
2974 *sock->default_value_typed<bNodeSocketValueCollection>();
2975 id_us_plus(reinterpret_cast<ID *>(default_value.value));
2976 break;
2977 }
2978 case SOCK_TEXTURE: {
2979 bNodeSocketValueTexture &default_value =
2980 *sock->default_value_typed<bNodeSocketValueTexture>();
2981 id_us_plus(reinterpret_cast<ID *>(default_value.value));
2982 break;
2983 }
2984 case SOCK_MATERIAL: {
2985 bNodeSocketValueMaterial &default_value =
2986 *sock->default_value_typed<bNodeSocketValueMaterial>();
2987 id_us_plus(reinterpret_cast<ID *>(default_value.value));
2988 break;
2989 }
2990 case SOCK_FLOAT:
2991 case SOCK_VECTOR:
2992 case SOCK_RGBA:
2993 case SOCK_BOOLEAN:
2994 case SOCK_ROTATION:
2995 case SOCK_MATRIX:
2996 case SOCK_INT:
2997 case SOCK_STRING:
2998 case SOCK_MENU:
2999 case SOCK_CUSTOM:
3000 case SOCK_SHADER:
3001 case SOCK_GEOMETRY:
3002 case SOCK_BUNDLE:
3003 case SOCK_CLOSURE:
3004 break;
3005 }
3006}
3007
3010{
3011 switch (eNodeSocketDatatype(sock->type)) {
3012 case SOCK_OBJECT: {
3013 bNodeSocketValueObject &default_value = *sock->default_value_typed<bNodeSocketValueObject>();
3014 id_us_min(reinterpret_cast<ID *>(default_value.value));
3015 return default_value.value != nullptr;
3016 }
3017 case SOCK_IMAGE: {
3018 bNodeSocketValueImage &default_value = *sock->default_value_typed<bNodeSocketValueImage>();
3019 id_us_min(reinterpret_cast<ID *>(default_value.value));
3020 return default_value.value != nullptr;
3021 }
3022 case SOCK_COLLECTION: {
3023 bNodeSocketValueCollection &default_value =
3024 *sock->default_value_typed<bNodeSocketValueCollection>();
3025 id_us_min(reinterpret_cast<ID *>(default_value.value));
3026 return default_value.value != nullptr;
3027 }
3028 case SOCK_TEXTURE: {
3029 bNodeSocketValueTexture &default_value =
3030 *sock->default_value_typed<bNodeSocketValueTexture>();
3031 id_us_min(reinterpret_cast<ID *>(default_value.value));
3032 return default_value.value != nullptr;
3033 }
3034 case SOCK_MATERIAL: {
3035 bNodeSocketValueMaterial &default_value =
3036 *sock->default_value_typed<bNodeSocketValueMaterial>();
3037 id_us_min(reinterpret_cast<ID *>(default_value.value));
3038 return default_value.value != nullptr;
3039 }
3040 case SOCK_FLOAT:
3041 case SOCK_VECTOR:
3042 case SOCK_RGBA:
3043 case SOCK_BOOLEAN:
3044 case SOCK_ROTATION:
3045 case SOCK_MATRIX:
3046 case SOCK_INT:
3047 case SOCK_STRING:
3048 case SOCK_MENU:
3049 case SOCK_CUSTOM:
3050 case SOCK_SHADER:
3051 case SOCK_GEOMETRY:
3052 case SOCK_BUNDLE:
3053 case SOCK_CLOSURE:
3054 break;
3055 }
3056 return false;
3057}
3058
3060 bNode & /*node*/,
3061 bNodeSocket &sock,
3062 const StringRefNull idname)
3063{
3064 bNodeSocketType *socktype = node_socket_type_find(idname);
3065
3066 if (!socktype) {
3067 CLOG_ERROR(&LOG, "node socket type %s undefined", idname.c_str());
3068 return;
3069 }
3070
3071 if (sock.default_value) {
3072 if (sock.type != socktype->type) {
3073 /* Only reallocate the default value if the type changed so that UI data like min and max
3074 * isn't removed. This assumes that the default value is stored in the same format for all
3075 * socket types with the same #eNodeSocketDatatype. */
3078 sock.default_value = nullptr;
3079 }
3080 else {
3081 /* Update the socket subtype when the storage isn't freed and recreated. */
3082 switch (eNodeSocketDatatype(sock.type)) {
3083 case SOCK_FLOAT: {
3084 sock.default_value_typed<bNodeSocketValueFloat>()->subtype = socktype->subtype;
3085 break;
3086 }
3087 case SOCK_VECTOR: {
3088 sock.default_value_typed<bNodeSocketValueVector>()->subtype = socktype->subtype;
3089 break;
3090 }
3091 case SOCK_INT: {
3092 sock.default_value_typed<bNodeSocketValueInt>()->subtype = socktype->subtype;
3093 break;
3094 }
3095 case SOCK_STRING: {
3096 sock.default_value_typed<bNodeSocketValueString>()->subtype = socktype->subtype;
3097 break;
3098 }
3099 case SOCK_RGBA:
3100 case SOCK_SHADER:
3101 case SOCK_BOOLEAN:
3102 case SOCK_ROTATION:
3103 case SOCK_MATRIX:
3104 case SOCK_CUSTOM:
3105 case SOCK_OBJECT:
3106 case SOCK_IMAGE:
3107 case SOCK_GEOMETRY:
3108 case SOCK_COLLECTION:
3109 case SOCK_TEXTURE:
3110 case SOCK_MATERIAL:
3111 case SOCK_MENU:
3112 case SOCK_BUNDLE:
3113 case SOCK_CLOSURE:
3114 break;
3115 }
3116 }
3117 }
3118
3119 idname.copy_utf8_truncated(sock.idname);
3120 node_socket_set_typeinfo(&ntree, &sock, socktype);
3121}
3122
3124 bNodeTree *ntree, bNode *node, bNodeSocket *sock, const int type, const int subtype)
3125{
3126 const std::optional<StringRefNull> idname = node_static_socket_type(type, subtype);
3127
3128 if (!idname.has_value()) {
3129 CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
3130 return;
3131 }
3132
3133 node_modify_socket_type(*ntree, *node, *sock, *idname);
3134}
3135
3137 bNode &node,
3138 const eNodeSocketInOut in_out,
3139 const StringRefNull idname,
3140 const StringRefNull identifier,
3141 const StringRefNull name)
3142{
3143 BLI_assert(!node.is_frame());
3144 BLI_assert(!(in_out == SOCK_IN && node.is_group_input()));
3145 BLI_assert(!(in_out == SOCK_OUT && node.is_group_output()));
3146
3147 ListBase *lb = (in_out == SOCK_IN ? &node.inputs : &node.outputs);
3148 bNodeSocket *sock = make_socket(&ntree, &node, in_out, lb, idname, identifier, name);
3149
3150 BLI_remlink(lb, sock); /* does nothing for new socket */
3151 BLI_addtail(lb, sock);
3152
3153 BKE_ntree_update_tag_socket_new(&ntree, sock);
3154
3155 return sock;
3156}
3157
3159{
3160 /*
3161 * Cannot rely on type==SOCK_CUSTOM here, because type is 0 by default
3162 * and can be changed on custom sockets.
3163 */
3164 return RNA_struct_is_a(stype.ext_socket.srna, &RNA_NodeSocketStandard);
3165}
3166
3167std::optional<StringRefNull> node_static_socket_type(const int type,
3168 const int subtype,
3169 const std::optional<int> dimensions)
3170{
3171 BLI_assert(!(dimensions.has_value() && type != SOCK_VECTOR));
3172
3173 switch (eNodeSocketDatatype(type)) {
3174 case SOCK_FLOAT:
3175 switch (PropertySubType(subtype)) {
3176 case PROP_UNSIGNED:
3177 return "NodeSocketFloatUnsigned";
3178 case PROP_PERCENTAGE:
3179 return "NodeSocketFloatPercentage";
3180 case PROP_FACTOR:
3181 return "NodeSocketFloatFactor";
3182 case PROP_ANGLE:
3183 return "NodeSocketFloatAngle";
3184 case PROP_TIME:
3185 return "NodeSocketFloatTime";
3186 case PROP_TIME_ABSOLUTE:
3187 return "NodeSocketFloatTimeAbsolute";
3188 case PROP_DISTANCE:
3189 return "NodeSocketFloatDistance";
3190 case PROP_WAVELENGTH:
3191 return "NodeSocketFloatWavelength";
3193 return "NodeSocketFloatColorTemperature";
3194 case PROP_FREQUENCY:
3195 return "NodeSocketFloatFrequency";
3196 case PROP_NONE:
3197 default:
3198 return "NodeSocketFloat";
3199 }
3200 case SOCK_INT:
3201 switch (PropertySubType(subtype)) {
3202 case PROP_UNSIGNED:
3203 return "NodeSocketIntUnsigned";
3204 case PROP_PERCENTAGE:
3205 return "NodeSocketIntPercentage";
3206 case PROP_FACTOR:
3207 return "NodeSocketIntFactor";
3208 case PROP_NONE:
3209 default:
3210 return "NodeSocketInt";
3211 }
3212 case SOCK_BOOLEAN:
3213 return "NodeSocketBool";
3214 case SOCK_ROTATION:
3215 return "NodeSocketRotation";
3216 case SOCK_MATRIX:
3217 return "NodeSocketMatrix";
3218 case SOCK_VECTOR:
3219 if (!dimensions.has_value() || dimensions.value() == 3) {
3220 switch (PropertySubType(subtype)) {
3221 case PROP_FACTOR:
3222 return "NodeSocketVectorFactor";
3223 case PROP_PERCENTAGE:
3224 return "NodeSocketVectorPercentage";
3225 case PROP_TRANSLATION:
3226 return "NodeSocketVectorTranslation";
3227 case PROP_DIRECTION:
3228 return "NodeSocketVectorDirection";
3229 case PROP_VELOCITY:
3230 return "NodeSocketVectorVelocity";
3231 case PROP_ACCELERATION:
3232 return "NodeSocketVectorAcceleration";
3233 case PROP_EULER:
3234 return "NodeSocketVectorEuler";
3235 case PROP_XYZ:
3236 return "NodeSocketVectorXYZ";
3237 case PROP_NONE:
3238 default:
3239 return "NodeSocketVector";
3240 }
3241 }
3242 else if (dimensions.value() == 2) {
3243 switch (PropertySubType(subtype)) {
3244 case PROP_FACTOR:
3245 return "NodeSocketVectorFactor2D";
3246 case PROP_PERCENTAGE:
3247 return "NodeSocketVectorPercentage2D";
3248 case PROP_TRANSLATION:
3249 return "NodeSocketVectorTranslation2D";
3250 case PROP_DIRECTION:
3251 return "NodeSocketVectorDirection2D";
3252 case PROP_VELOCITY:
3253 return "NodeSocketVectorVelocity2D";
3254 case PROP_ACCELERATION:
3255 return "NodeSocketVectorAcceleration2D";
3256 case PROP_EULER:
3257 return "NodeSocketVectorEuler2D";
3258 case PROP_XYZ:
3259 return "NodeSocketVectorXYZ2D";
3260 case PROP_NONE:
3261 default:
3262 return "NodeSocketVector2D";
3263 }
3264 }
3265 else if (dimensions.value() == 4) {
3266 switch (PropertySubType(subtype)) {
3267 case PROP_FACTOR:
3268 return "NodeSocketVectorFactor4D";
3269 case PROP_PERCENTAGE:
3270 return "NodeSocketVectorPercentage4D";
3271 case PROP_TRANSLATION:
3272 return "NodeSocketVectorTranslation4D";
3273 case PROP_DIRECTION:
3274 return "NodeSocketVectorDirection4D";
3275 case PROP_VELOCITY:
3276 return "NodeSocketVectorVelocity4D";
3277 case PROP_ACCELERATION:
3278 return "NodeSocketVectorAcceleration4D";
3279 case PROP_EULER:
3280 return "NodeSocketVectorEuler4D";
3281 case PROP_XYZ:
3282 return "NodeSocketVectorXYZ4D";
3283 case PROP_NONE:
3284 default:
3285 return "NodeSocketVector4D";
3286 }
3287 }
3288 else {
3290 return "NodeSocketVector";
3291 }
3292 case SOCK_RGBA:
3293 return "NodeSocketColor";
3294 case SOCK_STRING:
3295 switch (PropertySubType(subtype)) {
3296 case PROP_FILEPATH:
3297 return "NodeSocketStringFilePath";
3298 default:
3299 return "NodeSocketString";
3300 }
3301 case SOCK_SHADER:
3302 return "NodeSocketShader";
3303 case SOCK_OBJECT:
3304 return "NodeSocketObject";
3305 case SOCK_IMAGE:
3306 return "NodeSocketImage";
3307 case SOCK_GEOMETRY:
3308 return "NodeSocketGeometry";
3309 case SOCK_COLLECTION:
3310 return "NodeSocketCollection";
3311 case SOCK_TEXTURE:
3312 return "NodeSocketTexture";
3313 case SOCK_MATERIAL:
3314 return "NodeSocketMaterial";
3315 case SOCK_MENU:
3316 return "NodeSocketMenu";
3317 case SOCK_BUNDLE:
3318 return "NodeSocketBundle";
3319 case SOCK_CLOSURE:
3320 return "NodeSocketClosure";
3321 case SOCK_CUSTOM:
3322 break;
3323 }
3324 return std::nullopt;
3325}
3326
3327std::optional<StringRefNull> node_static_socket_interface_type_new(
3328 const int type, const int subtype, const std::optional<int> dimensions)
3329{
3330 switch (eNodeSocketDatatype(type)) {
3331 case SOCK_FLOAT:
3332 switch (PropertySubType(subtype)) {
3333 case PROP_UNSIGNED:
3334 return "NodeTreeInterfaceSocketFloatUnsigned";
3335 case PROP_PERCENTAGE:
3336 return "NodeTreeInterfaceSocketFloatPercentage";
3337 case PROP_FACTOR:
3338 return "NodeTreeInterfaceSocketFloatFactor";
3339 case PROP_ANGLE:
3340 return "NodeTreeInterfaceSocketFloatAngle";
3341 case PROP_TIME:
3342 return "NodeTreeInterfaceSocketFloatTime";
3343 case PROP_TIME_ABSOLUTE:
3344 return "NodeTreeInterfaceSocketFloatTimeAbsolute";
3345 case PROP_DISTANCE:
3346 return "NodeTreeInterfaceSocketFloatDistance";
3347 case PROP_WAVELENGTH:
3348 return "NodeTreeInterfaceSocketFloatWavelength";
3350 return "NodeTreeInterfaceSocketFloatColorTemperature";
3351 case PROP_FREQUENCY:
3352 return "NodeTreeInterfaceSocketFloatFrequency";
3353 case PROP_NONE:
3354 default:
3355 return "NodeTreeInterfaceSocketFloat";
3356 }
3357 case SOCK_INT:
3358 switch (PropertySubType(subtype)) {
3359 case PROP_UNSIGNED:
3360 return "NodeTreeInterfaceSocketIntUnsigned";
3361 case PROP_PERCENTAGE:
3362 return "NodeTreeInterfaceSocketIntPercentage";
3363 case PROP_FACTOR:
3364 return "NodeTreeInterfaceSocketIntFactor";
3365 case PROP_NONE:
3366 default:
3367 return "NodeTreeInterfaceSocketInt";
3368 }
3369 case SOCK_BOOLEAN:
3370 return "NodeTreeInterfaceSocketBool";
3371 case SOCK_ROTATION:
3372 return "NodeTreeInterfaceSocketRotation";
3373 case SOCK_MATRIX:
3374 return "NodeTreeInterfaceSocketMatrix";
3375 case SOCK_VECTOR:
3376 if (!dimensions.has_value() || dimensions.value() == 3) {
3377 switch (PropertySubType(subtype)) {
3378 case PROP_FACTOR:
3379 return "NodeTreeInterfaceSocketVectorFactor";
3380 case PROP_PERCENTAGE:
3381 return "NodeTreeInterfaceSocketVectorPercentage";
3382 case PROP_TRANSLATION:
3383 return "NodeTreeInterfaceSocketVectorTranslation";
3384 case PROP_DIRECTION:
3385 return "NodeTreeInterfaceSocketVectorDirection";
3386 case PROP_VELOCITY:
3387 return "NodeTreeInterfaceSocketVectorVelocity";
3388 case PROP_ACCELERATION:
3389 return "NodeTreeInterfaceSocketVectorAcceleration";
3390 case PROP_EULER:
3391 return "NodeTreeInterfaceSocketVectorEuler";
3392 case PROP_XYZ:
3393 return "NodeTreeInterfaceSocketVectorXYZ";
3394 case PROP_NONE:
3395 default:
3396 return "NodeTreeInterfaceSocketVector";
3397 }
3398 }
3399 else if (dimensions.value() == 2) {
3400 switch (PropertySubType(subtype)) {
3401 case PROP_FACTOR:
3402 return "NodeTreeInterfaceSocketVectorFactor2D";
3403 case PROP_PERCENTAGE:
3404 return "NodeTreeInterfaceSocketVectorPercentage2D";
3405 case PROP_TRANSLATION:
3406 return "NodeTreeInterfaceSocketVectorTranslation2D";
3407 case PROP_DIRECTION:
3408 return "NodeTreeInterfaceSocketVectorDirection2D";
3409 case PROP_VELOCITY:
3410 return "NodeTreeInterfaceSocketVectorVelocity2D";
3411 case PROP_ACCELERATION:
3412 return "NodeTreeInterfaceSocketVectorAcceleration2D";
3413 case PROP_EULER:
3414 return "NodeTreeInterfaceSocketVectorEuler2D";
3415 case PROP_XYZ:
3416 return "NodeTreeInterfaceSocketVectorXYZ2D";
3417 case PROP_NONE:
3418 default:
3419 return "NodeTreeInterfaceSocketVector2D";
3420 }
3421 }
3422 else if (dimensions.value() == 4) {
3423 switch (PropertySubType(subtype)) {
3424 case PROP_FACTOR:
3425 return "NodeTreeInterfaceSocketVectorFactor4D";
3426 case PROP_PERCENTAGE:
3427 return "NodeTreeInterfaceSocketVectorPercentage4D";
3428 case PROP_TRANSLATION:
3429 return "NodeTreeInterfaceSocketVectorTranslation4D";
3430 case PROP_DIRECTION:
3431 return "NodeTreeInterfaceSocketVectorDirection4D";
3432 case PROP_VELOCITY:
3433 return "NodeTreeInterfaceSocketVectorVelocity4D";
3434 case PROP_ACCELERATION:
3435 return "NodeTreeInterfaceSocketVectorAcceleration4D";
3436 case PROP_EULER:
3437 return "NodeTreeInterfaceSocketVectorEuler4D";
3438 case PROP_XYZ:
3439 return "NodeTreeInterfaceSocketVectorXYZ4D";
3440 case PROP_NONE:
3441 default:
3442 return "NodeTreeInterfaceSocketVector4D";
3443 }
3444 }
3445 else {
3447 return "NodeTreeInterfaceSocketVector";
3448 }
3449 case SOCK_RGBA:
3450 return "NodeTreeInterfaceSocketColor";
3451 case SOCK_STRING:
3452 switch (PropertySubType(subtype)) {
3453 case PROP_FILEPATH:
3454 return "NodeTreeInterfaceSocketStringFilePath";
3455 default:
3456 return "NodeTreeInterfaceSocketString";
3457 }
3458 case SOCK_SHADER:
3459 return "NodeTreeInterfaceSocketShader";
3460 case SOCK_OBJECT:
3461 return "NodeTreeInterfaceSocketObject";
3462 case SOCK_IMAGE:
3463 return "NodeTreeInterfaceSocketImage";
3464 case SOCK_GEOMETRY:
3465 return "NodeTreeInterfaceSocketGeometry";
3466 case SOCK_COLLECTION:
3467 return "NodeTreeInterfaceSocketCollection";
3468 case SOCK_TEXTURE:
3469 return "NodeTreeInterfaceSocketTexture";
3470 case SOCK_MATERIAL:
3471 return "NodeTreeInterfaceSocketMaterial";
3472 case SOCK_MENU:
3473 return "NodeTreeInterfaceSocketMenu";
3474 case SOCK_BUNDLE:
3475 return "NodeTreeInterfaceSocketBundle";
3476 case SOCK_CLOSURE:
3477 return "NodeTreeInterfaceSocketClosure";
3478 case SOCK_CUSTOM:
3479 break;
3480 }
3481 return std::nullopt;
3482}
3483
3484std::optional<StringRefNull> node_static_socket_label(const int type, const int /*subtype*/)
3485{
3486 switch (eNodeSocketDatatype(type)) {
3487 case SOCK_FLOAT:
3488 return "Float";
3489 case SOCK_INT:
3490 return "Integer";
3491 case SOCK_BOOLEAN:
3492 return "Boolean";
3493 case SOCK_ROTATION:
3494 return "Rotation";
3495 case SOCK_MATRIX:
3496 return "Matrix";
3497 case SOCK_VECTOR:
3498 return "Vector";
3499 case SOCK_RGBA:
3500 return "Color";
3501 case SOCK_STRING:
3502 return "String";
3503 case SOCK_SHADER:
3504 return "Shader";
3505 case SOCK_OBJECT:
3506 return "Object";
3507 case SOCK_IMAGE:
3508 return "Image";
3509 case SOCK_GEOMETRY:
3510 return "Geometry";
3511 case SOCK_COLLECTION:
3512 return "Collection";
3513 case SOCK_TEXTURE:
3514 return "Texture";
3515 case SOCK_MATERIAL:
3516 return "Material";
3517 case SOCK_MENU:
3518 return "Menu";
3519 case SOCK_BUNDLE:
3520 return "Bundle";
3521 case SOCK_CLOSURE:
3522 return "Closure";
3523 case SOCK_CUSTOM:
3524 break;
3525 }
3526 return std::nullopt;
3527}
3528
3530 bNode &node,
3531 eNodeSocketInOut in_out,
3532 int type,
3533 int subtype,
3534 const StringRefNull identifier,
3535 const StringRefNull name)
3536{
3537 const std::optional<StringRefNull> idname = node_static_socket_type(type, subtype);
3538
3539 if (!idname.has_value()) {
3540 CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
3541 return nullptr;
3542 }
3543
3544 bNodeSocket *sock = node_add_socket(ntree, node, in_out, *idname, identifier, name);
3545 sock->type = type;
3546 return sock;
3547}
3548
3549static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
3550{
3551 if (sock->prop) {
3552 IDP_FreePropertyContent_ex(sock->prop, do_id_user);
3553 MEM_freeN(sock->prop);
3554 }
3555
3556 if (sock->default_value) {
3557 if (do_id_user) {
3559 }
3560 if (sock->type == SOCK_MENU) {
3561 auto &default_value_menu = *sock->default_value_typed<bNodeSocketValueMenu>();
3562 if (default_value_menu.enum_items) {
3563 /* Release shared data pointer. */
3564 default_value_menu.enum_items->remove_user_and_delete_if_last();
3565 }
3566 }
3567 MEM_freeN(sock->default_value);
3568 }
3569 if (sock->default_attribute_name) {
3571 }
3572 MEM_delete(sock->runtime);
3573}
3574
3576{
3577 node_remove_socket_ex(ntree, node, sock, true);
3578}
3579
3580void node_remove_socket_ex(bNodeTree &ntree, bNode &node, bNodeSocket &sock, const bool do_id_user)
3581{
3582 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
3583 if (link->fromsock == &sock || link->tosock == &sock) {
3584 node_remove_link(&ntree, *link);
3585 }
3586 }
3587
3588 for (const int64_t i : node.runtime->internal_links.index_range()) {
3589 const bNodeLink &link = node.runtime->internal_links[i];
3590 if (link.fromsock == &sock || link.tosock == &sock) {
3591 node.runtime->internal_links.remove_and_reorder(i);
3593 break;
3594 }
3595 }
3596
3597 /* this is fast, this way we don't need an in_out argument */
3598 BLI_remlink(&node.inputs, &sock);
3599 BLI_remlink(&node.outputs, &sock);
3600
3601 node_socket_free(&sock, do_id_user);
3602 MEM_freeN(&sock);
3603
3605}
3606
3608{
3609 return reinterpret_cast<bNode *>(
3610 BLI_findstring(&ntree.nodes, name.c_str(), offsetof(bNode, name)));
3611}
3612
3614{
3615 ntree.ensure_topology_cache();
3616 return socket.owner_node();
3617}
3618
3619const bNode &node_find_node(const bNodeTree &ntree, const bNodeSocket &socket)
3620{
3621 ntree.ensure_topology_cache();
3622 return socket.owner_node();
3623}
3624
3626{
3627 for (bNode *node : ntree.all_nodes()) {
3628 const ListBase *sockets = (socket.in_out == SOCK_IN) ? &node->inputs : &node->outputs;
3629 LISTBASE_FOREACH (const bNodeSocket *, socket_iter, sockets) {
3630 if (socket_iter == &socket) {
3631 return node;
3632 }
3633 }
3634 }
3635 return nullptr;
3636}
3637
3639 const StringRef identifier)
3640{
3641 ntree.ensure_interface_cache();
3642 for (const bNodeTreeInterfaceSocket *input : ntree.interface_inputs()) {
3643 if (input->identifier == identifier) {
3644 return input;
3645 }
3646 }
3647 return nullptr;
3648}
3649
3651{
3652 bNode *parent_iter = &node;
3653 while (parent_iter->parent != nullptr) {
3654 parent_iter = parent_iter->parent;
3655 }
3656 if (!parent_iter->is_frame()) {
3657 return nullptr;
3658 }
3659 return parent_iter;
3660}
3661
3662bool node_is_parent_and_child(const bNode &parent, const bNode &child)
3663{
3664 for (const bNode *child_iter = &child; child_iter; child_iter = child_iter->parent) {
3665 if (child_iter == &parent) {
3666 return true;
3667 }
3668 }
3669 return false;
3670}
3671
3673 const bNode *node_start,
3674 bool (*callback)(bNode *, bNode *, void *, const bool),
3675 void *userdata,
3676 const bool reversed)
3677{
3678 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
3679 if ((link->flag & NODE_LINK_VALID) == 0) {
3680 /* Skip links marked as cyclic. */
3681 continue;
3682 }
3683 /* Is the link part of the chain meaning node_start == fromnode
3684 * (or tonode for reversed case)? */
3685 if (!reversed) {
3686 if (link->fromnode != node_start) {
3687 continue;
3688 }
3689 }
3690 else {
3691 if (link->tonode != node_start) {
3692 continue;
3693 }
3694 }
3695
3696 if (!callback(link->fromnode, link->tonode, userdata, reversed)) {
3697 return;
3698 }
3700 ntree, reversed ? link->fromnode : link->tonode, callback, userdata, reversed);
3701 }
3702}
3703
3704static void iter_backwards_ex(const bNodeTree *ntree,
3705 const bNode *node_start,
3706 bool (*callback)(bNode *, bNode *, void *),
3707 void *userdata,
3708 const char recursion_mask)
3709{
3710 LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) {
3711 bNodeLink *link = sock->link;
3712 if (link == nullptr) {
3713 continue;
3714 }
3715 if ((link->flag & NODE_LINK_VALID) == 0) {
3716 /* Skip links marked as cyclic. */
3717 continue;
3718 }
3719 if (link->fromnode->runtime->iter_flag & recursion_mask) {
3720 continue;
3721 }
3722
3723 link->fromnode->runtime->iter_flag |= recursion_mask;
3724
3725 if (!callback(link->fromnode, link->tonode, userdata)) {
3726 return;
3727 }
3728 iter_backwards_ex(ntree, link->fromnode, callback, userdata, recursion_mask);
3729 }
3730}
3731
3733 const bNode *node_start,
3734 bool (*callback)(bNode *, bNode *, void *),
3735 void *userdata,
3736 const int recursion_lvl)
3737{
3738 if (!node_start) {
3739 return;
3740 }
3741
3742 /* Limited by iter_flag type. */
3743 BLI_assert(recursion_lvl < 8);
3744 const char recursion_mask = (1 << recursion_lvl);
3745
3746 /* Reset flag. */
3747 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
3748 node->runtime->iter_flag &= ~recursion_mask;
3749 }
3750
3751 iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask);
3752}
3753
3754void node_parents_iterator(bNode *node, bool (*callback)(bNode *, void *), void *userdata)
3755{
3756 if (node->parent) {
3757 if (!callback(node->parent, userdata)) {
3758 return;
3759 }
3760 node_parents_iterator(node->parent, callback, userdata);
3761 }
3762}
3763
3765{
3767 &ntree.nodes, &node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node.name));
3768}
3769
3770void node_unique_id(bNodeTree &ntree, bNode &node)
3771{
3772 /* Use a pointer cast to avoid overflow warnings. */
3773 const double time = BLI_time_now_seconds() * 1000000.0;
3774 RandomNumberGenerator id_rng{*reinterpret_cast<const uint32_t *>(&time)};
3775
3776 /* In the unlikely case that the random ID doesn't match, choose a new one until it does. */
3777 int32_t new_id = id_rng.get_int32();
3778 while (ntree.runtime->nodes_by_id.contains_as(new_id) || new_id <= 0) {
3779 new_id = id_rng.get_int32();
3780 }
3781
3782 node.identifier = new_id;
3783 ntree.runtime->nodes_by_id.add_new(&node);
3784 node.runtime->index_in_tree = ntree.runtime->nodes_by_id.index_range().last();
3785 BLI_assert(node.runtime->index_in_tree == ntree.runtime->nodes_by_id.index_of(&node));
3786}
3787
3788bNode *node_add_node(const bContext *C, bNodeTree &ntree, const StringRef idname)
3789{
3790 bNode *node = MEM_callocN<bNode>(__func__);
3791 node->runtime = MEM_new<bNodeRuntime>(__func__);
3792 BLI_addtail(&ntree.nodes, node);
3793 node_unique_id(ntree, *node);
3794 node->ui_order = ntree.all_nodes().size();
3795
3796 idname.copy_utf8_truncated(node->idname);
3797 node_set_typeinfo(C, &ntree, node, node_type_find(idname));
3798
3799 BKE_ntree_update_tag_node_new(&ntree, node);
3800
3801 return node;
3802}
3803
3804bNode *node_add_static_node(const bContext *C, bNodeTree &ntree, const int type)
3805{
3806 std::optional<StringRefNull> idname;
3807
3808 for (bNodeType *ntype : node_types_get()) {
3809 /* Do an extra poll here, because some int types are used
3810 * for multiple node types, this helps find the desired type. */
3811 if (ntype->type_legacy != type) {
3812 continue;
3813 }
3814
3815 const char *disabled_hint;
3816 if (ntype->poll && ntype->poll(ntype, &ntree, &disabled_hint)) {
3817 idname = ntype->idname;
3818 break;
3819 }
3820 }
3821 if (!idname) {
3822 CLOG_ERROR(&LOG, "static node type %d undefined", type);
3823 return nullptr;
3824 }
3825 return node_add_node(C, ntree, *idname);
3826}
3827
3828static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag)
3829{
3830 sock_dst->runtime = MEM_new<bNodeSocketRuntime>(__func__);
3831 if (sock_src->prop) {
3832 sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
3833 }
3834
3835 if (sock_src->default_value) {
3836 sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
3837
3838 if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
3839 socket_id_user_increment(sock_dst);
3840 }
3841
3842 if (sock_src->type == SOCK_MENU) {
3843 auto &default_value_menu = *sock_dst->default_value_typed<bNodeSocketValueMenu>();
3844 if (default_value_menu.enum_items) {
3845 /* Copy of shared data pointer. */
3846 default_value_menu.enum_items->add_user();
3847 }
3848 }
3849 }
3850
3851 sock_dst->default_attribute_name = static_cast<char *>(
3853
3854 sock_dst->stack_index = 0;
3855}
3856
3858 const bNode &node_src,
3859 const int flag,
3860 const bool use_unique,
3862{
3863 bNode *node_dst = MEM_mallocN<bNode>(__func__);
3864 *node_dst = node_src;
3865
3866 node_dst->runtime = MEM_new<bNodeRuntime>(__func__);
3867
3868 /* Can be called for nodes outside a node tree (e.g. clipboard). */
3869 if (dst_tree) {
3870 if (use_unique) {
3871 node_unique_name(*dst_tree, *node_dst);
3872 node_unique_id(*dst_tree, *node_dst);
3873 }
3874 BLI_addtail(&dst_tree->nodes, node_dst);
3875 }
3876
3877 BLI_listbase_clear(&node_dst->inputs);
3878 LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) {
3879 bNodeSocket *dst_socket = static_cast<bNodeSocket *>(MEM_dupallocN(src_socket));
3880 node_socket_copy(dst_socket, src_socket, flag);
3881 BLI_addtail(&node_dst->inputs, dst_socket);
3882 socket_map.add_new(src_socket, dst_socket);
3883 }
3884
3885 BLI_listbase_clear(&node_dst->outputs);
3886 LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) {
3887 bNodeSocket *dst_socket = static_cast<bNodeSocket *>(MEM_dupallocN(src_socket));
3888 node_socket_copy(dst_socket, src_socket, flag);
3889 BLI_addtail(&node_dst->outputs, dst_socket);
3890 socket_map.add_new(src_socket, dst_socket);
3891 }
3892
3893 if (node_src.prop) {
3894 node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag);
3895 }
3896
3897 node_dst->panel_states_array = static_cast<bNodePanelState *>(
3899
3900 node_dst->runtime->internal_links = node_src.runtime->internal_links;
3901 for (bNodeLink &dst_link : node_dst->runtime->internal_links) {
3902 dst_link.fromnode = node_dst;
3903 dst_link.tonode = node_dst;
3904 dst_link.fromsock = socket_map.lookup(dst_link.fromsock);
3905 dst_link.tosock = socket_map.lookup(dst_link.tosock);
3906 }
3907
3908 if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
3909 id_us_plus(node_dst->id);
3910 }
3911
3912 if (node_src.typeinfo->copyfunc) {
3913 node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src);
3914 }
3915
3916 if (dst_tree) {
3917 BKE_ntree_update_tag_node_new(dst_tree, node_dst);
3918 }
3919
3920 /* Only call copy function when a copy is made for the main database, not
3921 * for cases like the dependency graph and localization. */
3922 if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
3924 reinterpret_cast<ID *>(dst_tree), &RNA_Node, node_dst);
3925
3926 node_dst->typeinfo->copyfunc_api(&ptr, &node_src);
3927 }
3928
3929 return node_dst;
3930}
3931
3936static void *node_static_value_storage_for(bNode &node, const bNodeSocket &socket)
3937{
3938 if (!socket.is_output()) {
3939 return nullptr;
3940 }
3941
3942 switch (node.type_legacy) {
3943 case FN_NODE_INPUT_BOOL:
3944 return &reinterpret_cast<NodeInputBool *>(node.storage)->boolean;
3945 case SH_NODE_VALUE:
3946 /* The value is stored in the default value of the first output socket. */
3947 return &static_cast<bNodeSocket *>(node.outputs.first)
3948 ->default_value_typed<bNodeSocketValueFloat>()
3949 ->value;
3950 case FN_NODE_INPUT_INT:
3951 return &reinterpret_cast<NodeInputInt *>(node.storage)->integer;
3953 return &reinterpret_cast<NodeInputVector *>(node.storage)->vector;
3955 return &reinterpret_cast<NodeInputColor *>(node.storage)->color;
3956 case GEO_NODE_IMAGE:
3957 return &node.id;
3958 default:
3959 break;
3960 }
3961
3962 return nullptr;
3963}
3964
3966{
3967 switch (eNodeSocketDatatype(socket.type)) {
3968 case SOCK_BOOLEAN:
3969 return &socket.default_value_typed<bNodeSocketValueBoolean>()->value;
3970 case SOCK_INT:
3971 return &socket.default_value_typed<bNodeSocketValueInt>()->value;
3972 case SOCK_FLOAT:
3973 return &socket.default_value_typed<bNodeSocketValueFloat>()->value;
3974 case SOCK_VECTOR:
3975 return &socket.default_value_typed<bNodeSocketValueVector>()->value;
3976 case SOCK_RGBA:
3977 return &socket.default_value_typed<bNodeSocketValueRGBA>()->value;
3978 case SOCK_IMAGE:
3979 return &socket.default_value_typed<bNodeSocketValueImage>()->value;
3980 case SOCK_TEXTURE:
3981 return &socket.default_value_typed<bNodeSocketValueTexture>()->value;
3982 case SOCK_COLLECTION:
3983 return &socket.default_value_typed<bNodeSocketValueCollection>()->value;
3984 case SOCK_OBJECT:
3985 return &socket.default_value_typed<bNodeSocketValueObject>()->value;
3986 case SOCK_MATERIAL:
3987 return &socket.default_value_typed<bNodeSocketValueMaterial>()->value;
3988 case SOCK_ROTATION:
3989 return &socket.default_value_typed<bNodeSocketValueRotation>()->value_euler;
3990 case SOCK_MENU:
3991 return &socket.default_value_typed<bNodeSocketValueMenu>()->value;
3992 case SOCK_MATRIX:
3993 /* Matrix sockets currently have no default value. */
3994 return nullptr;
3995 case SOCK_STRING:
3996 /* We don't want do this now! */
3997 return nullptr;
3998 case SOCK_CUSTOM:
3999 case SOCK_SHADER:
4000 case SOCK_GEOMETRY:
4001 case SOCK_BUNDLE:
4002 case SOCK_CLOSURE:
4003 /* Unmovable types. */
4004 break;
4005 }
4006
4007 return nullptr;
4008}
4009
4011 bNodeTree &tree,
4012 bNodeSocket &src,
4013 bNodeSocket &dst)
4014{
4015 tree.ensure_topology_cache();
4016
4017 bNode &dst_node = dst.owner_node();
4018 bNode &src_node = src.owner_node();
4019
4020 const CPPType &src_type = *src.typeinfo->base_cpp_type;
4021 const CPPType &dst_type = *dst.typeinfo->base_cpp_type;
4022
4024
4025 if (src.is_multi_input()) {
4026 /* Multi input sockets no have value. */
4027 return;
4028 }
4029 if (dst_node.is_reroute() || src_node.is_reroute()) {
4030 /* Reroute node can't have ownership of socket value directly. */
4031 return;
4032 }
4033 if (&src_type != &dst_type) {
4034 if (!convert.is_convertible(src_type, dst_type)) {
4035 return;
4036 }
4037 }
4038
4039 /* Special handling for strings because the generic code below can't handle them. */
4040 if (src.type == SOCK_STRING && dst.type == SOCK_STRING &&
4041 dst_node.is_type("FunctionNodeInputString"))
4042 {
4043 auto *src_value = static_cast<bNodeSocketValueString *>(src.default_value);
4044 auto *dst_storage = static_cast<NodeInputString *>(dst_node.storage);
4045 MEM_SAFE_FREE(dst_storage->string);
4046 dst_storage->string = BLI_strdup_null(src_value->value);
4047 return;
4048 }
4049
4050 void *src_value = socket_value_storage(src);
4051 void *dst_value = node_static_value_storage_for(dst_node, dst);
4052 if (!dst_value || !src_value) {
4053 return;
4054 }
4055
4056 convert.convert_to_uninitialized(src_type, dst_type, src_value, dst_value);
4057
4058 src_type.destruct(src_value);
4059 if (ELEM(eNodeSocketDatatype(src.type),
4061 SOCK_IMAGE,
4064 SOCK_OBJECT))
4065 {
4066 src_type.value_initialize(src_value);
4067 }
4068}
4069
4070bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, const int flag, const bool use_unique)
4071{
4073 return node_copy_with_mapping(dst_tree, src_node, flag, use_unique, socket_map);
4074}
4075
4076static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
4077{
4078 int count = 0;
4079 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
4080 if (ELEM(socket, link->fromsock, link->tosock)) {
4081 count++;
4082 }
4083 }
4084 return count;
4085}
4086
4088 bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
4089{
4090 BLI_assert(ntree.all_nodes().contains(&fromnode));
4091 BLI_assert(ntree.all_nodes().contains(&tonode));
4092
4093 bNodeLink *link = nullptr;
4094 if (eNodeSocketInOut(fromsock.in_out) == SOCK_OUT && eNodeSocketInOut(tosock.in_out) == SOCK_IN)
4095 {
4096 link = MEM_callocN<bNodeLink>(__func__);
4097 BLI_addtail(&ntree.links, link);
4098 link->fromnode = &fromnode;
4099 link->fromsock = &fromsock;
4100 link->tonode = &tonode;
4101 link->tosock = &tosock;
4102 }
4103 else if (eNodeSocketInOut(fromsock.in_out) == SOCK_IN &&
4104 eNodeSocketInOut(tosock.in_out) == SOCK_OUT)
4105 {
4106 /* OK but flip */
4107 link = MEM_callocN<bNodeLink>(__func__);
4108 BLI_addtail(&ntree.links, link);
4109 link->fromnode = &tonode;
4110 link->fromsock = &tosock;
4111 link->tonode = &fromnode;
4112 link->tosock = &fromsock;
4113 }
4114
4115 BKE_ntree_update_tag_link_added(&ntree, link);
4116
4117 if (link != nullptr && link->tosock->is_multi_input()) {
4118 link->multi_input_sort_id = node_count_links(&ntree, link->tosock) - 1;
4119 }
4120
4121 return *link;
4122}
4123
4125{
4126 /* Can be called for links outside a node tree (e.g. clipboard). */
4127 if (ntree) {
4128 BLI_remlink(&ntree->links, &link);
4129 }
4130
4131 if (link.tosock) {
4132 link.tosock->link = nullptr;
4133 }
4134 MEM_freeN(&link);
4135
4136 if (ntree) {
4138 }
4139}
4140
4141void node_link_set_mute(bNodeTree &ntree, bNodeLink &link, const bool muted)
4142{
4143 const bool was_muted = link.is_muted();
4145 if (muted != was_muted) {
4146 BKE_ntree_update_tag_link_mute(&ntree, &link);
4147 }
4148}
4149
4151{
4152 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
4153 if (link->fromsock == &sock || link->tosock == &sock) {
4154 node_remove_link(&ntree, *link);
4155 }
4156 }
4157}
4158
4160{
4161 return !(link.fromsock->is_visible() && link.tosock->is_visible());
4162}
4163
4165{
4166 return (link.fromnode->flag & NODE_SELECT) || (link.tonode->flag & NODE_SELECT);
4167}
4168
4169/* Adjust the indices of links connected to the given multi input socket after deleting the link at
4170 * `deleted_index`. This function also works if the link has not yet been deleted. */
4172 const bNodeSocket *sock,
4173 const int deleted_index)
4174{
4175 LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
4176 /* We only need to adjust those with a greater index, because the others will have the same
4177 * index. */
4178 if (link->tosock != sock || link->multi_input_sort_id <= deleted_index) {
4179 continue;
4180 }
4181 link->multi_input_sort_id -= 1;
4182 }
4183}
4184
4186{
4187 /* store link pointers in output sockets, for efficient lookup */
4188 for (bNodeLink &link : node.runtime->internal_links) {
4189 link.tosock->link = &link;
4190 }
4191
4192 Vector<bNodeLink *> duplicate_links_to_remove;
4193
4194 /* redirect downstream links */
4195 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
4196 /* do we have internal link? */
4197 if (link->fromnode != &node) {
4198 continue;
4199 }
4200
4201 bNodeLink *internal_link = link->fromsock->link;
4202 bNodeLink *fromlink = internal_link ? internal_link->fromsock->link : nullptr;
4203
4204 if (fromlink == nullptr) {
4205 if (link->tosock->is_multi_input()) {
4207 &ntree, link->tosock, link->multi_input_sort_id);
4208 }
4209 node_remove_link(&ntree, *link);
4210 continue;
4211 }
4212
4213 if (link->tosock->is_multi_input()) {
4214 /* remove the link that would be the same as the relinked one */
4215 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link_to_compare, &ntree.links) {
4216 if (link_to_compare->fromsock == fromlink->fromsock &&
4217 link_to_compare->tosock == link->tosock)
4218 {
4220 &ntree, link_to_compare->tosock, link_to_compare->multi_input_sort_id);
4221 duplicate_links_to_remove.append_non_duplicates(link_to_compare);
4222 }
4223 }
4224 }
4225
4226 link->fromnode = fromlink->fromnode;
4227 link->fromsock = fromlink->fromsock;
4228
4229 /* if the up- or downstream link is invalid,
4230 * the replacement link will be invalid too.
4231 */
4232 if (!(fromlink->flag & NODE_LINK_VALID)) {
4233 link->flag &= ~NODE_LINK_VALID;
4234 }
4235
4236 if (fromlink->flag & NODE_LINK_MUTED) {
4237 link->flag |= NODE_LINK_MUTED;
4238 }
4239
4241 }
4242
4243 for (bNodeLink *link : duplicate_links_to_remove) {
4244 node_remove_link(&ntree, *link);
4245 }
4246
4247 /* remove remaining upstream links */
4248 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
4249 if (link->tonode == &node) {
4250 node_remove_link(&ntree, *link);
4251 }
4252 }
4253}
4254
4255void node_attach_node(bNodeTree &ntree, bNode &node, bNode &parent)
4256{
4257 BLI_assert(parent.is_frame());
4258 BLI_assert(!node_is_parent_and_child(parent, node));
4259 node.parent = &parent;
4261}
4262
4264{
4265 if (node.parent) {
4266 BLI_assert(node.parent->is_frame());
4267 node.parent = nullptr;
4269 }
4270}
4271
4273 const bNode &to_node,
4274 const bNodeSocket *from_sock,
4275 const bNodeSocket &to_sock)
4276{
4277 float offset_x;
4278 int tot_sock_idx;
4279
4280 /* Socket to plug into. */
4281 if (eNodeSocketInOut(to_sock.in_out) == SOCK_IN) {
4282 offset_x = -(from_node.typeinfo->width + 50);
4283 tot_sock_idx = BLI_listbase_count(&to_node.outputs);
4284 tot_sock_idx += BLI_findindex(&to_node.inputs, &to_sock);
4285 }
4286 else {
4287 offset_x = to_node.typeinfo->width + 50;
4288 tot_sock_idx = BLI_findindex(&to_node.outputs, &to_sock);
4289 }
4290
4291 BLI_assert(tot_sock_idx != -1);
4292
4293 float offset_y = U.widget_unit * tot_sock_idx;
4294
4295 /* Output socket. */
4296 if (from_sock) {
4297 if (eNodeSocketInOut(from_sock->in_out) == SOCK_IN) {
4298 tot_sock_idx = BLI_listbase_count(&from_node.outputs);
4299 tot_sock_idx += BLI_findindex(&from_node.inputs, from_sock);
4300 }
4301 else {
4302 tot_sock_idx = BLI_findindex(&from_node.outputs, from_sock);
4303 }
4304 }
4305
4306 BLI_assert(tot_sock_idx != -1);
4307
4308 offset_y -= U.widget_unit * tot_sock_idx;
4309
4310 from_node.location[0] = to_node.location[0] + offset_x;
4311 from_node.location[1] = to_node.location[1] - offset_y;
4312}
4313
4315{
4316 LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
4317 if (socket->link != nullptr) {
4318 bNodeLink *link = socket->link;
4319 node_position_relative(*link->fromnode, *link->tonode, link->fromsock, *link->tosock);
4321 }
4322 }
4323}
4324
4326 std::optional<Library *> owner_library,
4327 ID *owner_id,
4328 const bool is_embedded,
4329 const StringRef name,
4330 const StringRef idname)
4331{
4332 /* trees are created as local trees for compositor, material or texture nodes,
4333 * node groups and other tree types are created as library data.
4334 */
4335 int flag = 0;
4336 if (is_embedded || bmain == nullptr) {
4338 }
4339 BLI_assert_msg(!owner_library || !owner_id,
4340 "Embedded NTrees should never have a defined owner library here");
4341 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(
4342 BKE_libblock_alloc_in_lib(bmain, owner_library, ID_NT, std::string(name).c_str(), flag));
4343 BKE_libblock_init_empty(&ntree->id);
4344 if (is_embedded) {
4345 BLI_assert(owner_id != nullptr);
4346 ntree->id.flag |= ID_FLAG_EMBEDDED_DATA;
4347 ntree->owner_id = owner_id;
4348 bNodeTree **ntree_owner_ptr = node_tree_ptr_from_id(owner_id);
4349 BLI_assert(ntree_owner_ptr != nullptr);
4350 *ntree_owner_ptr = ntree;
4351 }
4352 else {
4353 BLI_assert(owner_id == nullptr);
4354 }
4355
4356 idname.copy_utf8_truncated(ntree->idname);
4358
4359 return ntree;
4360}
4361
4362bNodeTree *node_tree_add_tree(Main *bmain, const StringRef name, const StringRef idname)
4363{
4364 return node_tree_add_tree_do(bmain, std::nullopt, nullptr, false, name, idname);
4365}
4366
4368 Library *owner_library,
4369 const StringRefNull name,
4370 const StringRefNull idname)
4371{
4372 return node_tree_add_tree_do(bmain, owner_library, nullptr, false, name, idname);
4373}
4374
4376 ID *owner_id,
4377 const StringRefNull name,
4378 const StringRefNull idname)
4379{
4380 return node_tree_add_tree_do(nullptr, std::nullopt, owner_id, true, name, idname);
4381}
4382
4383bNodeTree *node_tree_copy_tree_ex(const bNodeTree &ntree, Main *bmain, const bool do_id_user)
4384{
4385 const int flag = do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN;
4386
4387 bNodeTree *ntree_copy = reinterpret_cast<bNodeTree *>(
4388 BKE_id_copy_ex(bmain, reinterpret_cast<const ID *>(&ntree), nullptr, flag));
4389 return ntree_copy;
4390}
4392{
4393 return node_tree_copy_tree_ex(ntree, bmain, true);
4394}
4395
4396/* *************** Node Preview *********** */
4397
4398/* XXX this should be removed eventually ...
4399 * Currently BKE functions are modeled closely on previous code,
4400 * using node_preview_init_tree to set up previews for a whole node tree in advance.
4401 * This should be left more to the individual node tree implementations. */
4402
4403bool node_preview_used(const bNode &node)
4404{
4405 /* XXX check for closed nodes? */
4406 return (node.typeinfo->flag & NODE_PREVIEW) != 0;
4407}
4408
4410 bNodeInstanceKey key,
4411 const int xsize,
4412 const int ysize,
4413 const bool create)
4414{
4415 bNodePreview *preview = create ?
4416 &previews.lookup_or_add_cb(key,
4417 [&]() {
4418 bNodePreview preview;
4419 preview.ibuf = IMB_allocImBuf(
4420 xsize, ysize, 32, IB_byte_data);
4421 return preview;
4422 }) :
4423 previews.lookup_ptr(key);
4424 if (!preview) {
4425 return nullptr;
4426 }
4427
4428 /* node previews can get added with variable size this way */
4429 if (xsize == 0 || ysize == 0) {
4430 return preview;
4431 }
4432
4433 /* sanity checks & initialize */
4434 const uint size[2] = {uint(xsize), uint(ysize)};
4435 IMB_rect_size_set(preview->ibuf, size);
4436 if (preview->ibuf->byte_buffer.data == nullptr) {
4437 IMB_alloc_byte_pixels(preview->ibuf);
4438 }
4439 /* no clear, makes nicer previews */
4440
4441 return preview;
4442}
4443
4445{
4446 this->ibuf = IMB_dupImBuf(other.ibuf);
4447}
4448
4450{
4451 this->ibuf = other.ibuf;
4452 other.ibuf = nullptr;
4453}
4454
4456{
4457 if (this->ibuf) {
4458 IMB_freeImBuf(this->ibuf);
4459 }
4460}
4461
4463 bNodeTree *ntree,
4464 bNodeInstanceKey parent_key,
4465 const int xsize,
4466 const int ysize)
4467{
4468 for (bNode *node : ntree->all_nodes()) {
4469 bNodeInstanceKey key = node_instance_key(parent_key, ntree, node);
4470
4471 if (node_preview_used(*node)) {
4472 node_preview_verify(previews, key, xsize, ysize, false);
4473 }
4474
4475 bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id);
4476 if (node->is_group() && group != nullptr) {
4477 node_preview_init_tree_recursive(previews, group, key, xsize, ysize);
4478 }
4479 }
4480}
4481
4482void node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
4483{
4485 ntree->runtime->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
4486}
4487
4489 bNodeTree *ntree,
4490 bNodeInstanceKey parent_key,
4492{
4493 for (bNode *node : ntree->all_nodes()) {
4494 bNodeInstanceKey key = node_instance_key(parent_key, ntree, node);
4495
4496 if (node_preview_used(*node)) {
4497 used.add(key);
4498 }
4499
4500 if (node->is_group()) {
4501 if (bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id)) {
4502 collect_used_previews(previews, group, key, used);
4503 }
4504 }
4505 }
4506}
4507
4509{
4510 Set<bNodeInstanceKey> used_previews;
4511 collect_used_previews(ntree->runtime->previews, ntree, NODE_INSTANCE_KEY_BASE, used_previews);
4512 ntree->runtime->previews.remove_if([&](const MapItem<bNodeInstanceKey, bNodePreview> &item) {
4513 return !used_previews.contains(item.key);
4514 });
4515}
4516
4517void node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
4518{
4519 if (remove_old || to_ntree->runtime->previews.is_empty()) {
4520 to_ntree->runtime->previews.clear();
4521 to_ntree->runtime->previews = std::move(from_ntree->runtime->previews);
4523 }
4524 else {
4525 for (const auto &item : from_ntree->runtime->previews.items()) {
4526 to_ntree->runtime->previews.add(item.key, std::move(item.value));
4527 }
4528 from_ntree->runtime->previews.clear();
4529 }
4530}
4531
4533{
4534 LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
4535 ListBase *lb = nullptr;
4536 if (link->fromnode == &node) {
4537 lb = &node.outputs;
4538 }
4539 else if (link->tonode == &node) {
4540 lb = &node.inputs;
4541 }
4542
4543 if (lb) {
4544 /* Only bother adjusting if the socket is not on the node we're deleting. */
4545 if (link->tonode != &node && link->tosock->is_multi_input()) {
4547 &ntree, link->tosock, link->multi_input_sort_id);
4548 }
4549 LISTBASE_FOREACH (const bNodeSocket *, sock, lb) {
4550 if (link->fromsock == sock || link->tosock == sock) {
4551 node_remove_link(&ntree, *link);
4552 break;
4553 }
4554 }
4555 }
4556 }
4557}
4558
4559static void node_unlink_attached(bNodeTree *ntree, const bNode *parent)
4560{
4561 for (bNode *node : ntree->all_nodes()) {
4562 if (node->parent == parent) {
4563 node_detach_node(*ntree, *node);
4564 }
4565 }
4566}
4567
4569{
4570 /* Rebuild nodes #VectorSet which must have the same order as the list. */
4571 node_tree.runtime->nodes_by_id.clear();
4572 int i;
4573 LISTBASE_FOREACH_INDEX (bNode *, node, &node_tree.nodes, i) {
4574 node_tree.runtime->nodes_by_id.add_new(node);
4575 node->runtime->index_in_tree = i;
4576 }
4577}
4578
4579void node_free_node(bNodeTree *ntree, bNode &node)
4580{
4581 /* since it is called while free database, node->id is undefined */
4582
4583 /* can be called for nodes outside a node tree (e.g. clipboard) */
4584 if (ntree) {
4585 BLI_remlink(&ntree->nodes, &node);
4586 /* Rebuild nodes #VectorSet which must have the same order as the list. */
4587 node_rebuild_id_vector(*ntree);
4588
4589 /* texture node has bad habit of keeping exec data around */
4590 if (ntree->type == NTREE_TEXTURE && ntree->runtime->execdata) {
4591 ntreeTexEndExecTree(ntree->runtime->execdata);
4592 ntree->runtime->execdata = nullptr;
4593 }
4594 }
4595
4596 if (node.typeinfo->freefunc) {
4597 node.typeinfo->freefunc(&node);
4598 }
4599
4601 /* Remember, no ID user refcount management here! */
4602 node_socket_free(sock, false);
4603 MEM_freeN(sock);
4604 }
4606 /* Remember, no ID user refcount management here! */
4607 node_socket_free(sock, false);
4608 MEM_freeN(sock);
4609 }
4610
4612
4613 if (node.prop) {
4614 /* Remember, no ID user refcount management here! */
4615 IDP_FreePropertyContent_ex(node.prop, false);
4616 MEM_freeN(node.prop);
4617 }
4618
4619 if (node.runtime->declaration) {
4620 /* Only free if this declaration is not shared with the node type, which can happen if it does
4621 * not depend on any context. */
4622 if (node.runtime->declaration != node.typeinfo->static_declaration) {
4623 delete node.runtime->declaration;
4624 }
4625 }
4626
4627 MEM_delete(node.runtime);
4628 MEM_freeN(&node);
4629
4630 if (ntree) {
4632 }
4633}
4634
4636{
4637 /* For removing nodes while editing localized node trees. */
4638 BLI_assert((ntree.id.tag & ID_TAG_LOCALIZED) != 0);
4639
4640 /* These two lines assume the caller might want to free a single node and maintain
4641 * a valid state in the node tree. */
4642 node_unlink_node(ntree, node);
4643 node_unlink_attached(&ntree, &node);
4644
4645 node_free_node(&ntree, node);
4647}
4648
4650 Main *bmain, bNodeTree &ntree, bNode &node, const bool do_id_user, const bool remove_animation)
4651{
4652 /* This function is not for localized node trees, we do not want
4653 * do to ID user reference-counting and removal of animation data then. */
4654 BLI_assert((ntree.id.tag & ID_TAG_LOCALIZED) == 0);
4655
4656 if (do_id_user) {
4657 /* Free callback for NodeCustomGroup. */
4658 if (node.typeinfo->freefunc_api) {
4659 PointerRNA ptr = RNA_pointer_create_discrete(&ntree.id, &RNA_Node, &node);
4660
4661 node.typeinfo->freefunc_api(&ptr);
4662 }
4663
4664 /* Do user counting. */
4665 if (node.id) {
4666 id_us_min(node.id);
4667 }
4668
4669 LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
4671 }
4672 LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
4674 }
4675 }
4676
4677 if (remove_animation) {
4678 char propname_esc[MAX_IDPROP_NAME * 2];
4679 char prefix[MAX_IDPROP_NAME * 2];
4680
4681 BLI_str_escape(propname_esc, node.name, sizeof(propname_esc));
4682 SNPRINTF(prefix, "nodes[\"%s\"]", propname_esc);
4683
4684 if (BKE_animdata_fix_paths_remove(&ntree.id, prefix)) {
4685 if (bmain != nullptr) {
4687 }
4688 }
4689 }
4690
4691 node_unlink_node(ntree, node);
4692 node_unlink_attached(&ntree, &node);
4693
4694 /* Free node itself. */
4695 node_free_node(&ntree, node);
4697}
4698
4700{
4701 /* Only localized node trees store a copy for each node group tree.
4702 * Each node group tree in a localized node tree can be freed,
4703 * since it is a localized copy itself (no risk of accessing freed
4704 * data in main, see #37939). */
4705 if (!(ntree->id.tag & ID_TAG_LOCALIZED)) {
4706 return;
4707 }
4708
4709 LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
4710 bNodeTree *ngroup = reinterpret_cast<bNodeTree *>(node->id);
4711 if (node->is_group() && ngroup != nullptr) {
4712 node_tree_free_tree(*ngroup);
4713 MEM_freeN(ngroup);
4714 }
4715 }
4716}
4717
4719{
4720 ntree_free_data(&ntree.id);
4721 BKE_animdata_free(&ntree.id, false);
4722}
4723
4725{
4726 node_tree_free_tree(*ntree);
4727 BKE_libblock_free_data(&ntree->id, true);
4729}
4730
4732{
4733 if (ntree->id.tag & ID_TAG_LOCALIZED) {
4734 node_tree_free_tree(*ntree);
4735 }
4736 else {
4737 node_tree_free_tree(*ntree);
4738 BKE_libblock_free_data(&ntree->id, true);
4739 }
4740}
4741
4743{
4744 const bool is_compositor = ntree.type == NTREE_COMPOSIT;
4745 const bool is_geometry = ntree.type == NTREE_GEOMETRY;
4746 /* find the active outputs, might become tree type dependent handler */
4747 LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
4748 if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
4749 /* we need a check for which output node should be tagged like this, below an exception */
4750 if (node->is_type("CompositorNodeOutputFile")) {
4751 continue;
4752 }
4753 const bool node_is_output = node->is_type("CompositorNodeViewer") ||
4754 node->is_type("GeometryNodeViewer");
4755
4756 int output = 0;
4757 /* there is more types having output class, each one is checked */
4758
4759 LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
4760 if (tnode->typeinfo->nclass != NODE_CLASS_OUTPUT) {
4761 continue;
4762 }
4763
4764 /* same type, exception for viewer */
4765 const bool tnode_is_output = tnode->is_type("CompositorNodeViewer") ||
4766 tnode->is_type("GeometryNodeViewer");
4767 const bool viewer_case = (is_compositor || is_geometry) && tnode_is_output &&
4768 node_is_output;
4769 const bool has_same_shortcut = viewer_case && node != tnode &&
4770 tnode->custom1 == node->custom1 &&
4771 tnode->custom1 != NODE_VIEWER_SHORTCUT_NONE;
4772
4773 if (tnode->type_legacy == node->type_legacy || viewer_case) {
4774 if (tnode->flag & NODE_DO_OUTPUT) {
4775 output++;
4776 if (output > 1) {
4777 tnode->flag &= ~NODE_DO_OUTPUT;
4778 }
4779 }
4780 }
4781 if (has_same_shortcut) {
4782 tnode->custom1 = NODE_VIEWER_SHORTCUT_NONE;
4783 }
4784 }
4785
4786 /* Only geometry nodes is allowed to have no active output in the node tree. */
4787 if (output == 0 && !is_geometry) {
4788 node->flag |= NODE_DO_OUTPUT;
4789 }
4790 }
4791
4792 /* group node outputs use this flag too */
4793 if (node->is_group_output()) {
4794 int output = 0;
4795 LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
4796 if (!tnode->is_group_output()) {
4797 continue;
4798 }
4799 if (tnode->flag & NODE_DO_OUTPUT) {
4800 output++;
4801 if (output > 1) {
4802 tnode->flag &= ~NODE_DO_OUTPUT;
4803 }
4804 }
4805 }
4806 if (output == 0) {
4807 node->flag |= NODE_DO_OUTPUT;
4808 }
4809 }
4810 }
4811
4812 /* here we could recursively set which nodes have to be done,
4813 * might be different for editor or for "real" use... */
4814}
4815
4817{
4818 /* If this is ever extended such that a non-animatable ID type can embed a node
4819 * tree, update blender::animrig::internal::rebuild_slot_user_cache(). That
4820 * function assumes that node trees can only be embedded by animatable IDs. */
4821
4822 switch (GS(id->name)) {
4823 case ID_MA:
4824 return &reinterpret_cast<Material *>(id)->nodetree;
4825 case ID_LA:
4826 return &reinterpret_cast<Light *>(id)->nodetree;
4827 case ID_WO:
4828 return &reinterpret_cast<World *>(id)->nodetree;
4829 case ID_TE:
4830 return &reinterpret_cast<Tex *>(id)->nodetree;
4831 case ID_SCE:
4832 return &reinterpret_cast<Scene *>(id)->nodetree;
4833 case ID_LS:
4834 return &reinterpret_cast<FreestyleLineStyle *>(id)->nodetree;
4835 default:
4836 return nullptr;
4837 }
4838}
4839
4841{
4842 bNodeTree **nodetree = node_tree_ptr_from_id(id);
4843 return (nodetree != nullptr) ? *nodetree : nullptr;
4844}
4845
4846void node_tree_node_flag_set(bNodeTree &ntree, const int flag, const bool enable)
4847{
4848 for (bNode *node : ntree.all_nodes()) {
4849 if (enable) {
4850 node->flag |= flag;
4851 }
4852 else {
4853 node->flag &= ~flag;
4854 }
4855 }
4856}
4857
4858bNodeTree *node_tree_localize(bNodeTree *ntree, std::optional<ID *> new_owner_id)
4859{
4860 if (ntree == nullptr) {
4861 return nullptr;
4862 }
4863
4864 /* Make full copy outside of Main database.
4865 * NOTE: previews are not copied here. */
4866 bNodeTree *ltree = reinterpret_cast<bNodeTree *>(
4867 BKE_id_copy_in_lib(nullptr,
4868 std::nullopt,
4869 &ntree->id,
4870 new_owner_id,
4871 nullptr,
4873
4874 ltree->id.tag |= ID_TAG_LOCALIZED;
4875
4876 LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
4877 bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id);
4878 if (node->is_group() && group != nullptr) {
4879 node->id = reinterpret_cast<ID *>(node_tree_localize(group, nullptr));
4880 }
4881 }
4882
4883 /* Ensures only a single output node is enabled. */
4884 node_tree_set_output(*ntree);
4885
4886 bNode *node_src = reinterpret_cast<bNode *>(ntree->nodes.first);
4887 bNode *node_local = reinterpret_cast<bNode *>(ltree->nodes.first);
4888 while (node_src != nullptr) {
4889 node_local->runtime->original = node_src;
4890 node_src = node_src->next;
4891 node_local = node_local->next;
4892 }
4893
4894 if (ntree->typeinfo->localize) {
4895 ntree->typeinfo->localize(ltree, ntree);
4896 }
4897
4898 return ltree;
4899}
4900
4901void node_tree_local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
4902{
4903 if (ntree && localtree) {
4904 if (ntree->typeinfo->local_merge) {
4905 ntree->typeinfo->local_merge(bmain, localtree, ntree);
4906 }
4907 }
4908}
4909
4910static bool ntree_contains_tree_exec(const bNodeTree &tree_to_search_in,
4911 const bNodeTree &tree_to_search_for,
4912 Set<const bNodeTree *> &already_passed)
4913{
4914 if (&tree_to_search_in == &tree_to_search_for) {
4915 return true;
4916 }
4917
4918 tree_to_search_in.ensure_topology_cache();
4919 for (const bNode *node_group : tree_to_search_in.group_nodes()) {
4920 const bNodeTree *sub_tree_search_in = reinterpret_cast<const bNodeTree *>(node_group->id);
4921 if (!sub_tree_search_in) {
4922 continue;
4923 }
4924 if (!already_passed.add(sub_tree_search_in)) {
4925 continue;
4926 }
4927 if (ntree_contains_tree_exec(*sub_tree_search_in, tree_to_search_for, already_passed)) {
4928 return true;
4929 }
4930 }
4931
4932 return false;
4933}
4934
4935bool node_tree_contains_tree(const bNodeTree &tree_to_search_in,
4936 const bNodeTree &tree_to_search_for)
4937{
4938 if (&tree_to_search_in == &tree_to_search_for) {
4939 return true;
4940 }
4941
4942 Set<const bNodeTree *> already_passed;
4943 return ntree_contains_tree_exec(tree_to_search_in, tree_to_search_for, already_passed);
4944}
4945
4946int node_count_socket_links(const bNodeTree &ntree, const bNodeSocket &sock)
4947{
4948 int tot = 0;
4949 LISTBASE_FOREACH (const bNodeLink *, link, &ntree.links) {
4950 if (link->fromsock == &sock || link->tosock == &sock) {
4951 tot++;
4952 }
4953 }
4954 return tot;
4955}
4956
4958{
4959 for (bNode *node : ntree.all_nodes()) {
4960 if (node->flag & NODE_ACTIVE) {
4961 return node;
4962 }
4963 }
4964 return nullptr;
4965}
4966
4967bool node_set_selected(bNode &node, const bool select)
4968{
4969 bool changed = false;
4970 if (select != ((node.flag & NODE_SELECT) != 0)) {
4971 changed = true;
4973 }
4974 if (select) {
4975 return changed;
4976 }
4977 /* Deselect sockets too. */
4978 LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
4979 changed |= (sock->flag & NODE_SELECT) != 0;
4980 sock->flag &= ~NODE_SELECT;
4981 }
4982 LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
4983 changed |= (sock->flag & NODE_SELECT) != 0;
4984 sock->flag &= ~NODE_SELECT;
4985 }
4986 return changed;
4987}
4988
4990{
4991 for (bNode *node : ntree.all_nodes()) {
4992 node->flag &= ~NODE_ACTIVE;
4993 }
4994}
4995
4997{
4998 const bool is_paint_canvas = node_supports_active_flag(node, NODE_ACTIVE_PAINT_CANVAS);
4999 const bool is_texture_class = node_supports_active_flag(node, NODE_ACTIVE_TEXTURE);
5000 int flags_to_set = NODE_ACTIVE;
5001 SET_FLAG_FROM_TEST(flags_to_set, is_paint_canvas, NODE_ACTIVE_PAINT_CANVAS);
5002 SET_FLAG_FROM_TEST(flags_to_set, is_texture_class, NODE_ACTIVE_TEXTURE);
5003
5004 /* Make sure only one node is active per node tree. */
5005 for (bNode *tnode : ntree.all_nodes()) {
5006 tnode->flag &= ~flags_to_set;
5007 }
5008 node.flag |= flags_to_set;
5009}
5010
5011void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, const bool is_available)
5012{
5013 if (is_available == sock.is_available()) {
5014 return;
5015 }
5016 if (is_available) {
5017 sock.flag &= ~SOCK_UNAVAIL;
5018 }
5019 else {
5020 sock.flag |= SOCK_UNAVAIL;
5021 }
5023}
5024
5026{
5027 if (sock.is_multi_input()) {
5028 return 4095;
5029 }
5030 if (sock.typeinfo == nullptr) {
5031 return sock.limit;
5032 }
5033 const bNodeSocketType &stype = *sock.typeinfo;
5034 if (!stype.use_link_limits_of_type) {
5035 return sock.limit;
5036 }
5037 return eNodeSocketInOut(sock.in_out) == SOCK_IN ? stype.input_link_limit :
5038 stype.output_link_limit;
5039}
5040
5043{
5044 int index;
5045 LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
5046 const SocketDeclaration &socket_decl = *declarations[index];
5047 socket->runtime->declaration = &socket_decl;
5048 }
5049}
5050
5052{
5053 LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
5054 socket->runtime->declaration = nullptr;
5055 }
5056}
5057
5059{
5060 BLI_assert(node->runtime->declaration != nullptr);
5061 if (node->runtime->declaration->skip_updating_sockets) {
5064 return;
5065 }
5066 update_socket_declarations(&node->inputs, node->runtime->declaration->inputs);
5067 update_socket_declarations(&node->outputs, node->runtime->declaration->outputs);
5068}
5069
5071{
5072 if (node.runtime->declaration != nullptr) {
5073 return false;
5074 }
5075 if (node.typeinfo->declare) {
5076 if (node.typeinfo->static_declaration) {
5077 if (!node.typeinfo->static_declaration->is_context_dependent) {
5078 node.runtime->declaration = node.typeinfo->static_declaration;
5079 return true;
5080 }
5081 }
5082 }
5083 if (node.typeinfo->declare) {
5085 return true;
5086 }
5087 return false;
5088}
5089
5091{
5094 return true;
5095 }
5096 return false;
5097}
5098
5100{
5101 return float2(node.runtime->draw_bounds.xmax, node.runtime->draw_bounds.ymax) -
5102 float2(node.runtime->draw_bounds.xmin, node.runtime->draw_bounds.ymin);
5103}
5104
5106{
5107 node.runtime->update |= NODE_UPDATE_ID;
5108}
5109
5110void node_internal_links(bNode &node, bNodeLink **r_links, int *r_len)
5111{
5112 *r_links = node.runtime->internal_links.data();
5113 *r_len = node.runtime->internal_links.size();
5114}
5115
5116/* Node Instance Hash */
5117
5120
5121/* Generate a hash key from ntree and node names
5122 * Uses the djb2 algorithm with xor by Bernstein:
5123 * http://www.cse.yorku.ca/~oz/hash.html
5124 */
5126{
5127 char c;
5128
5129 while ((c = *str++)) {
5130 hash.value = ((hash.value << 5) + hash.value) ^ c; /* (hash * 33) ^ c */
5131 }
5132
5133 /* separator '\0' character, to avoid ambiguity from concatenated strings */
5134 hash.value = (hash.value << 5) + hash.value; /* hash * 33 */
5135
5136 return hash;
5137}
5138
5140 const bNodeTree *ntree,
5141 const bNode *node)
5142{
5143 bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2);
5144
5145 if (node) {
5146 key = node_hash_int_str(key, node->name);
5147 }
5148
5149 return key;
5150}
5151
5152/* Build a set of built-in node types to check for known types. */
5154{
5156 for (const bNodeType *ntype : node_types_get()) {
5157 result.add(ntype->type_legacy);
5158 }
5159 return result;
5160}
5161
5162static bool can_read_node_type(const bNode &node)
5163{
5164 /* Can always read custom node types. */
5166 return true;
5167 }
5169 /* Check known built-in types. */
5170 static Set<int> known_types = get_known_node_types_set();
5171 return known_types.contains(node.type_legacy);
5172 }
5173 /* Nodes with larger legacy_type are only identified by their idname. */
5174 return node_type_find(node.idname) != nullptr;
5175}
5176
5178{
5179 /* If the node type is built-in but unknown, the node cannot be read. */
5180 if (!can_read_node_type(*node)) {
5181 node->type_legacy = NODE_CUSTOM;
5182 /* This type name is arbitrary, it just has to be unique enough to not match a future node
5183 * idname. Includes the old type identifier for debugging purposes. */
5184 const std::string old_idname = node->idname;
5185 SNPRINTF(node->idname, "Undefined[%s]", old_idname.c_str());
5186 node->typeinfo = &NodeTypeUndefined;
5187 }
5188}
5189
5191{
5192 /* Replace unknown node types with "Undefined".
5193 * This happens when loading files from newer Blender versions. Such nodes cannot be read
5194 * reliably so replace the idname with an undefined type. This keeps links and socket names but
5195 * discards storage and other type-specific data.
5196 *
5197 * Replacement has to happen after after-liblink-versioning, since some node types still get
5198 * replaced in those late versioning steps. */
5199 FOREACH_NODETREE_BEGIN (&main, ntree, owner_id) {
5200 for (bNode *node : ntree->all_nodes()) {
5202 }
5203 }
5205 /* Update all new node trees on file read or append, to add/remove sockets
5206 * in groups nodes if the group changed, and handle any update flags that
5207 * might have been set in file reading or versioning. */
5208 FOREACH_NODETREE_BEGIN (&main, ntree, owner_id) {
5209 if (owner_id->tag & ID_TAG_NEW) {
5211 }
5212 }
5215}
5216
5218{
5219 if (id == nullptr) {
5220 return;
5221 }
5222
5223 bool need_update = false;
5224
5225 /* Update all users of ngroup, to add/remove sockets as needed. */
5226 FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
5227 for (bNode *node : ntree->all_nodes()) {
5228 if (node->id == id) {
5230 need_update = true;
5231 }
5232 }
5233 }
5235 if (need_update) {
5237 }
5238}
5239
5240/* ************* node type access ********** */
5241
5242std::string node_label(const bNodeTree &ntree, const bNode &node)
5243{
5244 if (node.label[0] != '\0') {
5245 return node.label;
5246 }
5247
5248 if (node.typeinfo->labelfunc) {
5249 char label_buffer[MAX_NAME];
5250 node.typeinfo->labelfunc(&ntree, &node, label_buffer, MAX_NAME);
5251 return label_buffer;
5252 }
5253
5254 return IFACE_(node.typeinfo->ui_name);
5255}
5256
5257std::optional<StringRefNull> node_socket_short_label(const bNodeSocket &sock)
5258{
5259 if (sock.runtime->declaration != nullptr) {
5260 StringRefNull short_label = sock.runtime->declaration->short_label;
5261 if (!short_label.is_empty()) {
5262 return sock.runtime->declaration->short_label.data();
5263 }
5264 }
5265 return std::nullopt;
5266}
5267
5269{
5270 return (sock.label[0] != '\0') ? sock.label : sock.name;
5271}
5272
5274{
5275 /* default size values */
5277 ntype.height = 100;
5278 ntype.minheight = 30;
5279 ntype.maxheight = FLT_MAX;
5280}
5281
5282/* allow this node for any tree type */
5283static bool node_poll_default(const bNodeType * /*ntype*/,
5284 const bNodeTree * /*ntree*/,
5285 const char ** /*r_disabled_hint*/)
5286{
5287 return true;
5288}
5289
5290static bool node_poll_instance_default(const bNode *node,
5291 const bNodeTree *ntree,
5292 const char **r_disabled_hint)
5293{
5294 return node->typeinfo->poll(node->typeinfo, ntree, r_disabled_hint);
5295}
5296
5298{
5299 static std::atomic<int> next_legacy_type = []() {
5300 /* Randomize the value a bit to avoid accidentally depending on the generated legacy type to be
5301 * stable across Blender sessions. */
5304 }();
5305 const int new_type = next_legacy_type.fetch_add(1);
5306 BLI_assert(new_type <= std::numeric_limits<int16_t>::max());
5307 return new_type;
5308}
5309
5310void node_type_base(bNodeType &ntype, std::string idname, std::optional<int16_t> legacy_type)
5311{
5312 ntype.idname = std::move(idname);
5313
5314 if (!legacy_type.has_value()) {
5315 /* Still auto-generate a legacy type for this node type if none was specified. This is
5316 * necessary because some code checks if two nodes are the same type by comparing their legacy
5317 * types. The exact value does not matter, but it must be unique. */
5318 legacy_type = get_next_auto_legacy_type();
5319 }
5320
5321 if (!ELEM(*legacy_type, NODE_CUSTOM, NODE_UNDEFINED)) {
5322 StructRNA *srna = RNA_struct_find(ntype.idname.c_str());
5323 BLI_assert(srna != nullptr);
5324 ntype.rna_ext.srna = srna;
5325 RNA_struct_blender_type_set(srna, &ntype);
5326 }
5327
5328 /* make sure we have a valid type (everything registered) */
5329 BLI_assert(ntype.idname[0] != '\0');
5330
5331 ntype.type_legacy = *legacy_type;
5333
5335
5336 ntype.poll = node_poll_default;
5338}
5339
5341 const StringRefNull idname,
5342 const StringRefNull name,
5343 const StringRefNull enum_name,
5344 const short nclass)
5345{
5346 ntype.idname = idname;
5347 ntype.type_legacy = NODE_CUSTOM;
5348 ntype.ui_name = name;
5349 ntype.nclass = nclass;
5350 ntype.enum_name_legacy = enum_name.c_str();
5351
5353}
5354
5355std::optional<eCustomDataType> socket_type_to_custom_data_type(eNodeSocketDatatype type)
5356{
5357 switch (type) {
5358 case SOCK_FLOAT:
5359 return CD_PROP_FLOAT;
5360 case SOCK_VECTOR:
5361 return CD_PROP_FLOAT3;
5362 case SOCK_RGBA:
5363 return CD_PROP_COLOR;
5364 case SOCK_BOOLEAN:
5365 return CD_PROP_BOOL;
5366 case SOCK_ROTATION:
5367 return CD_PROP_QUATERNION;
5368 case SOCK_MATRIX:
5369 return CD_PROP_FLOAT4X4;
5370 case SOCK_INT:
5371 return CD_PROP_INT32;
5372 case SOCK_STRING:
5373 return CD_PROP_STRING;
5374 default:
5375 return std::nullopt;
5376 }
5377}
5378
5379std::optional<eNodeSocketDatatype> custom_data_type_to_socket_type(eCustomDataType type)
5380{
5381 switch (type) {
5382 case CD_PROP_FLOAT:
5383 return SOCK_FLOAT;
5384 case CD_PROP_INT8:
5385 return SOCK_INT;
5386 case CD_PROP_INT32:
5387 return SOCK_INT;
5388 case CD_PROP_FLOAT3:
5389 return SOCK_VECTOR;
5390 case CD_PROP_FLOAT2:
5391 return SOCK_VECTOR;
5392 case CD_PROP_BOOL:
5393 return SOCK_BOOLEAN;
5394 case CD_PROP_COLOR:
5395 return SOCK_RGBA;
5396 case CD_PROP_BYTE_COLOR:
5397 return SOCK_RGBA;
5398 case CD_PROP_QUATERNION:
5399 return SOCK_ROTATION;
5400 case CD_PROP_FLOAT4X4:
5401 return SOCK_MATRIX;
5402 default:
5403 return std::nullopt;
5404 }
5405}
5406
5408{
5409 const bNodeSocketType *typeinfo = node_socket_type_find_static(type);
5410 return typeinfo->base_cpp_type;
5411}
5412
5414{
5415 const CPPType *cpp_type;
5416 switch (type) {
5417 case SOCK_FLOAT:
5418 cpp_type = &CPPType::get<float>();
5419 break;
5420 case SOCK_INT:
5421 cpp_type = &CPPType::get<int>();
5422 break;
5423 case SOCK_RGBA:
5424 cpp_type = &CPPType::get<ColorGeometry4f>();
5425 break;
5426 case SOCK_BOOLEAN:
5427 cpp_type = &CPPType::get<bool>();
5428 break;
5429 case SOCK_VECTOR:
5430 cpp_type = &CPPType::get<float3>();
5431 break;
5432 case SOCK_ROTATION:
5433 cpp_type = &CPPType::get<math::Quaternion>();
5434 break;
5435 case SOCK_MATRIX:
5436 cpp_type = &CPPType::get<float4x4>();
5437 break;
5438 case SOCK_BUNDLE:
5439 cpp_type = &CPPType::get<nodes::BundlePtr>();
5440 break;
5441 case SOCK_CLOSURE:
5442 cpp_type = &CPPType::get<nodes::ClosurePtr>();
5443 break;
5444 default:
5446 break;
5447 }
5449 return cpp_type;
5450}
5451
5452std::optional<eNodeSocketDatatype> geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
5453{
5454 if (type.is<float>()) {
5455 return SOCK_FLOAT;
5456 }
5457 if (type.is<int>()) {
5458 return SOCK_INT;
5459 }
5460 if (type.is<float3>()) {
5461 return SOCK_VECTOR;
5462 }
5463 if (type.is<ColorGeometry4f>()) {
5464 return SOCK_RGBA;
5465 }
5466 if (type.is<bool>()) {
5467 return SOCK_BOOLEAN;
5468 }
5469 if (type.is<math::Quaternion>()) {
5470 return SOCK_ROTATION;
5471 }
5472 if (type.is<float4x4>()) {
5473 return SOCK_MATRIX;
5474 }
5475 if (type.is<std::string>()) {
5476 return SOCK_STRING;
5477 }
5478 if (type.is<nodes::BundlePtr>()) {
5479 return SOCK_BUNDLE;
5480 }
5481 if (type.is<nodes::ClosurePtr>()) {
5482 return SOCK_CLOSURE;
5483 }
5484 return std::nullopt;
5485}
5486
5487std::optional<VolumeGridType> socket_type_to_grid_type(const eNodeSocketDatatype type)
5488{
5489 switch (type) {
5490 case SOCK_BOOLEAN:
5491 return VOLUME_GRID_BOOLEAN;
5492 case SOCK_FLOAT:
5493 return VOLUME_GRID_FLOAT;
5494 case SOCK_INT:
5495 return VOLUME_GRID_INT;
5496 case SOCK_VECTOR:
5498 default:
5499 return std::nullopt;
5500 }
5501}
5502
5503std::optional<eNodeSocketDatatype> grid_type_to_socket_type(const VolumeGridType type)
5504{
5505 switch (type) {
5507 return SOCK_BOOLEAN;
5508 case VOLUME_GRID_FLOAT:
5509 return SOCK_FLOAT;
5510 case VOLUME_GRID_INT:
5511 return SOCK_INT;
5513 return SOCK_VECTOR;
5514 default:
5515 return std::nullopt;
5516 }
5517}
5518
5520 bNodeSocketTemplate *ntemp,
5521 const char defname[],
5522 const char delim)
5523{
5525 [&](const StringRef check_name) {
5526 for (bNodeSocketTemplate *ntemp_iter = list; ntemp_iter->type >= 0; ntemp_iter++) {
5527 if (ntemp_iter != ntemp) {
5528 if (ntemp_iter->identifier == check_name) {
5529 return true;
5530 }
5531 }
5532 }
5533 return false;
5534 },
5535 defname,
5536 delim,
5537 ntemp->identifier,
5538 sizeof(ntemp->identifier));
5539}
5540
5544{
5545 ntype->inputs = inputs;
5546 ntype->outputs = outputs;
5547
5548 /* automatically generate unique identifiers */
5549 if (inputs) {
5550 /* clear identifier strings (uninitialized memory) */
5551 for (bNodeSocketTemplate *ntemp = inputs; ntemp->type >= 0; ntemp++) {
5552 ntemp->identifier[0] = '\0';
5553 }
5554
5555 for (bNodeSocketTemplate *ntemp = inputs; ntemp->type >= 0; ntemp++) {
5556 STRNCPY(ntemp->identifier, ntemp->name);
5557 unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_');
5558 }
5559 }
5560 if (outputs) {
5561 /* clear identifier strings (uninitialized memory) */
5562 for (bNodeSocketTemplate *ntemp = outputs; ntemp->type >= 0; ntemp++) {
5563 ntemp->identifier[0] = '\0';
5564 }
5565
5566 for (bNodeSocketTemplate *ntemp = outputs; ntemp->type >= 0; ntemp++) {
5567 STRNCPY(ntemp->identifier, ntemp->name);
5568 unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_');
5569 }
5570 }
5571}
5572
5573void node_type_size(bNodeType &ntype, const int width, const int minwidth, const int maxwidth)
5574{
5575 ntype.width = width;
5576 ntype.minwidth = minwidth;
5577 if (maxwidth <= minwidth) {
5578 ntype.maxwidth = FLT_MAX;
5579 }
5580 else {
5581 ntype.maxwidth = maxwidth;
5582 }
5583}
5584
5586{
5587 switch (size) {
5589 node_type_size(ntype, 140, 100, NODE_DEFAULT_MAX_WIDTH);
5590 break;
5592 node_type_size(ntype, 100, 80, NODE_DEFAULT_MAX_WIDTH);
5593 break;
5595 node_type_size(ntype, 150, 120, NODE_DEFAULT_MAX_WIDTH);
5596 break;
5598 node_type_size(ntype, 240, 140, NODE_DEFAULT_MAX_WIDTH);
5599 break;
5600 }
5601}
5602
5604 const std::optional<StringRefNull> storagename,
5605 void (*freefunc)(bNode *node),
5606 void (*copyfunc)(bNodeTree *dest_ntree,
5607 bNode *dest_node,
5608 const bNode *src_node))
5609{
5610 ntype.storagename = storagename.value_or("");
5611 ntype.copyfunc = copyfunc;
5612 ntype.freefunc = freefunc;
5613}
5614
5616{
5618}
5619
5621{
5622 get_node_type_alias_map().clear();
5623
5624 const Vector<bNodeType *> node_types = get_node_type_map().extract_vector();
5625 for (bNodeType *nt : node_types) {
5626 if (nt->rna_ext.free) {
5627 nt->rna_ext.free(nt->rna_ext.data);
5628 }
5629 node_free_type(nt);
5630 }
5631
5632 const Vector<bNodeSocketType *> socket_types = get_socket_type_map().extract_vector();
5633 for (bNodeSocketType *st : socket_types) {
5634 if (st->ext_socket.free) {
5635 st->ext_socket.free(st->ext_socket.data);
5636 }
5637 if (st->ext_interface.free) {
5638 st->ext_interface.free(st->ext_interface.data);
5639 }
5641 }
5642
5643 const Vector<bNodeTreeType *> tree_types = get_node_tree_type_map().extract_vector();
5644 for (bNodeTreeType *nt : tree_types) {
5645 if (nt->rna_ext.free) {
5646 nt->rna_ext.free(nt->rna_ext.data);
5647 }
5648 ntree_free_type(nt);
5649 }
5650}
5651
5652/* -------------------------------------------------------------------- */
5653/* NodeTree Iterator Helpers (FOREACH_NODETREE_BEGIN) */
5654
5656{
5657 ntreeiter->ngroup = (bNodeTree *)bmain->nodetrees.first;
5658 ntreeiter->scene = (Scene *)bmain->scenes.first;
5659 ntreeiter->mat = (Material *)bmain->materials.first;
5660 ntreeiter->tex = (Tex *)bmain->textures.first;
5661 ntreeiter->light = (Light *)bmain->lights.first;
5662 ntreeiter->world = (World *)bmain->worlds.first;
5663 ntreeiter->linestyle = (FreestyleLineStyle *)bmain->linestyles.first;
5664}
5665bool node_tree_iterator_step(NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, ID **r_id)
5666{
5667 if (ntreeiter->ngroup) {
5668 bNodeTree &node_tree = *ntreeiter->ngroup;
5669 *r_nodetree = &node_tree;
5670 *r_id = &node_tree.id;
5671 ntreeiter->ngroup = reinterpret_cast<bNodeTree *>(node_tree.id.next);
5672 return true;
5673 }
5674 if (ntreeiter->scene) {
5675 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->scene->nodetree);
5676 *r_id = &ntreeiter->scene->id;
5677 ntreeiter->scene = reinterpret_cast<Scene *>(ntreeiter->scene->id.next);
5678 return true;
5679 }
5680 if (ntreeiter->mat) {
5681 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->mat->nodetree);
5682 *r_id = &ntreeiter->mat->id;
5683 ntreeiter->mat = reinterpret_cast<Material *>(ntreeiter->mat->id.next);
5684 return true;
5685 }
5686 if (ntreeiter->tex) {
5687 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->tex->nodetree);
5688 *r_id = &ntreeiter->tex->id;
5689 ntreeiter->tex = reinterpret_cast<Tex *>(ntreeiter->tex->id.next);
5690 return true;
5691 }
5692 if (ntreeiter->light) {
5693 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->light->nodetree);
5694 *r_id = &ntreeiter->light->id;
5695 ntreeiter->light = reinterpret_cast<Light *>(ntreeiter->light->id.next);
5696 return true;
5697 }
5698 if (ntreeiter->world) {
5699 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->world->nodetree);
5700 *r_id = &ntreeiter->world->id;
5701 ntreeiter->world = reinterpret_cast<World *>(ntreeiter->world->id.next);
5702 return true;
5703 }
5704 if (ntreeiter->linestyle) {
5705 *r_nodetree = reinterpret_cast<bNodeTree *>(ntreeiter->linestyle->nodetree);
5706 *r_id = &ntreeiter->linestyle->id;
5707 ntreeiter->linestyle = reinterpret_cast<FreestyleLineStyle *>(ntreeiter->linestyle->id.next);
5708 return true;
5709 }
5710
5711 return false;
5712}
5713
5714void node_tree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
5715{
5716 BLI_assert(layer_index != -1);
5717 BLI_assert(scene != nullptr);
5718 for (bNode *node : ntree->all_nodes()) {
5719 if (node->type_legacy == CMP_NODE_R_LAYERS && node->id == &scene->id) {
5720 if (node->custom1 == layer_index) {
5721 node->custom1 = 0;
5722 }
5723 else if (node->custom1 > layer_index) {
5724 node->custom1--;
5725 }
5726 }
5727 }
5728}
5729
5730} // namespace blender::bke
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:187
bool BKE_animdata_fix_paths_remove(struct ID *id, const char *prefix)
void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop)
Definition asset.cc:168
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping *cumap)
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
#define G_MAIN
void IDP_foreach_property(IDProperty *id_property_root, int type_filter, blender::FunctionRef< void(IDProperty *id_property)> callback)
#define IDP_BlendDataRead(reader, prop)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1243
void IDP_FreePropertyContent_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1205
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:725
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:855
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:873
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1453
void IDP_FreeProperty_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1237
void(*)(ID *id, const IDCacheKey *cache_key, void **cache_p, uint flags, void *user_data) IDTypeForeachCacheFunctionCallback
IDTypeInfo IDType_ID_NT
Definition node.cc:2359
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:44
void BKE_image_format_blend_write(BlendWriter *writer, ImageFormatData *imf)
void BKE_image_format_blend_read_data(BlendDataReader *reader, ImageFormatData *imf)
@ LIB_ID_COPY_NO_PREVIEW
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_COPY_NO_ANIMDATA
@ LIB_ID_CREATE_NO_MAIN
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, std::optional< const ID * > new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:663
void BKE_libblock_free_data_py(ID *id)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL()
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1433
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
void id_us_min(ID *id)
Definition lib_id.cc:361
void * BKE_libblock_alloc_in_lib(Main *bmain, std::optional< Library * > owner_library, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1334
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data_, func_call_)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_LOOPBACK
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER
@ IDWALK_CB_READFILE_IGNORE
@ IDWALK_CB_NOP
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:434
#define NODE_UNDEFINED
Definition BKE_node.hh:794
constexpr int GROUP_NODE_DEFAULT_WIDTH
Definition BKE_node.hh:1226
#define NODE_CUSTOM_GROUP
Definition BKE_node.hh:801
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#define NODE_LEGACY_TYPE_GENERATION_START
Definition BKE_node.hh:803
#define NODE_CUSTOM
Definition BKE_node.hh:795
constexpr int NODE_DEFAULT_MAX_WIDTH
Definition BKE_node.hh:1225
#define FOREACH_NODETREE_END
Definition BKE_node.hh:866
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:856
#define CMP_NODE_DENOISE
#define CMP_NODE_MASK
#define SH_NODE_CURVE_FLOAT
#define CMP_NODE_VECBLUR
#define CMP_NODE_TIME
#define CMP_NODE_COLOR_SPILL
#define CMP_CHAN_RGB
#define CMP_NODE_DESPECKLE
#define CMP_NODE_VIEWER
#define CMP_NODE_LUMA_MATTE
#define CMP_NODE_KEYINGSCREEN
#define CMP_NODE_MASK_ELLIPSE
#define SH_NODE_TEX_IMAGE
#define CMP_NODE_CRYPTOMATTE
#define CMP_NODE_BILATERALBLUR
#define CMP_NODE_MOVIEDISTORTION
#define CMP_NODE_TONEMAP
#define CMP_NODE_INPAINT
#define CMP_NODE_COLORBALANCE
#define CMP_NODE_BOKEHIMAGE
#define FN_NODE_INPUT_COLOR
#define CMP_NODE_KUWAHARA
#define CMP_NODE_DIFF_MATTE
#define FN_NODE_INPUT_VECTOR
#define SH_NODE_TEX_ENVIRONMENT
#define SH_NODE_VALUE
#define SH_NODE_CURVE_VEC
#define CMP_NODE_ALPHAOVER
#define CMP_NODE_HUECORRECT
#define SH_NODE_TEX_IES
#define CMP_NODE_CROP
#define CMP_NODE_CHROMA_MATTE
#define CMP_NODE_GLARE
#define CMP_NODE_PLANETRACKDEFORM
#define CMP_NODE_DILATEERODE
#define CMP_NODE_SPLIT
#define CMP_NODE_ID_MASK
#define CMP_NODE_BOKEHBLUR
#define CMP_NODE_LENSDIST
#define FN_NODE_INPUT_INT
#define CMP_NODE_ZCOMBINE
#define FN_NODE_INPUT_BOOL
#define CMP_NODE_CRYPTOMATTE_LEGACY
#define TEX_NODE_IMAGE
#define CMP_NODE_OUTPUT_FILE
#define CMP_NODE_COLORCORRECTION
#define SH_NODE_BSDF_HAIR_PRINCIPLED
#define CMP_NODE_CURVE_RGB
#define CMP_NODE_STABILIZE2D
#define CMP_NODE_PIXELATE
#define SH_NODE_TEX_POINTDENSITY
#define CMP_NODE_SWITCH
#define SH_NODE_CURVE_RGB
#define GEO_NODE_IMAGE
#define GEO_NODE_CAPTURE_ATTRIBUTE
#define CMP_NODE_MASK_BOX
#define TEX_NODE_CURVE_TIME
#define CMP_NODE_KEYING
#define CMP_NODE_ANTIALIASING
#define CMP_NODE_R_LAYERS
#define CMP_NODE_CURVE_VEC
#define CMP_NODE_INVERT
#define CMP_NODE_COLOR_MATTE
#define CMP_NODE_DIST_MATTE
#define CMP_NODE_SUNBEAMS
#define CMP_NODE_IMAGE
#define CMP_NODE_DBLUR
#define CMP_NODE_BLUR
#define SH_NODE_SCRIPT
#define CMP_CHAN_A
#define CMP_NODE_FLIP
#define TEX_NODE_CURVE_RGB
#define CMP_NODE_CHANNEL_MATTE
void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_all(bNodeTree *ntree)
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_node_type(bNodeTree *ntree, bNode *node)
void BKE_ntree_update(Main &bmain, std::optional< blender::Span< bNodeTree * > > modified_trees=std::nullopt, const NodeTreeUpdateExtraParams &params={})
void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *link)
void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *link)
void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node)
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
void BKE_previewimg_free(PreviewImage **prv)
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
VolumeGridType
@ VOLUME_GRID_VECTOR_FLOAT
@ VOLUME_GRID_BOOLEAN
@ VOLUME_GRID_INT
@ VOLUME_GRID_FLOAT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define BLO_read_data_address(reader, ptr_p)
int BLO_read_fileversion_get(BlendDataReader *reader)
Definition readfile.cc:5239
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
void * BLO_read_struct_by_name_array(BlendDataReader *reader, const char *struct_name, int64_t items_num, const void *old_address)
Definition readfile.cc:5214
bool BLO_read_lib_is_undo(BlendLibReader *reader)
Definition readfile.cc:5505
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5351
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_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_NODETREE
#define IFACE_(msgid)
#define DATA_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_relations_tag_update(Main *bmain)
@ ID_TAG_NEW
Definition DNA_ID.h:827
@ ID_TAG_LOCALIZED
Definition DNA_ID.h:895
@ INDEX_ID_NT
Definition DNA_ID.h:1205
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:687
@ ID_TE
@ ID_NT
@ ID_LA
@ ID_SCE
@ ID_LS
@ ID_WO
@ ID_MA
@ IDP_TYPE_FILTER_ID
Object groups, one object can be in many groups at once.
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_STRING
@ CD_PROP_FLOAT4X4
@ NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
@ NTREE_TEXTURE
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ CMP_NODE_MASK_FLAG_NO_FEATHER
@ CMP_NODE_MASK_FLAG_MOTION_BLUR
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ NODE_OPTIONS
@ NODE_DO_OUTPUT
@ NODE_ACTIVE
@ NODE_ACTIVE_TEXTURE
@ NODE_INIT
@ NODE_ACTIVE_PAINT_CANVAS
@ NODE_SELECT
@ NODE_PREVIEW
@ NODE_VIEWER_SHORTCUT_NONE
@ NODE_UPDATE_ID
@ SOCK_HIDE_VALUE
@ SOCK_HIDE_IN_MODIFIER
@ SOCK_COLLAPSED
@ SOCK_UNAVAIL
@ NODE_LINK_MUTED
@ NODE_LINK_VALID
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
@ NODE_IES_EXTERNAL
@ CMP_NODE_LENS_DISTORTION_HORIZONTAL
struct bNodeSocket bNodeSocket
@ NODE_SCRIPT_EXTERNAL
struct RuntimeNodeEnumItemsHandle RuntimeNodeEnumItemsHandle
@ CMP_NODE_GLARE_STREAKS
@ CMP_NODE_GLARE_SIMPLE_STAR
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
bool IMB_alloc_byte_pixels(ImBuf *ibuf, bool initialize_pixels=true)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
Definition rectop.cc:289
@ IB_byte_data
Read Guarded memory(de)allocation.
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec)
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
PropertySubType
Definition RNA_types.hh:220
@ PROP_TIME
Definition RNA_types.hh:241
@ PROP_DIRECTION
Definition RNA_types.hh:250
@ PROP_XYZ
Definition RNA_types.hh:257
@ PROP_DISTANCE
Definition RNA_types.hh:244
@ PROP_ACCELERATION
Definition RNA_types.hh:252
@ PROP_ANGLE
Definition RNA_types.hh:240
@ PROP_TIME_ABSOLUTE
Definition RNA_types.hh:242
@ PROP_EULER
Definition RNA_types.hh:254
@ PROP_COLOR_TEMPERATURE
Definition RNA_types.hh:278
@ PROP_NONE
Definition RNA_types.hh:221
@ PROP_PERCENTAGE
Definition RNA_types.hh:238
@ PROP_FREQUENCY
Definition RNA_types.hh:280
@ PROP_FACTOR
Definition RNA_types.hh:239
@ PROP_TRANSLATION
Definition RNA_types.hh:249
@ PROP_UNSIGNED
Definition RNA_types.hh:237
@ PROP_FILEPATH
Definition RNA_types.hh:224
@ PROP_VELOCITY
Definition RNA_types.hh:251
@ PROP_WAVELENGTH
Definition RNA_types.hh:275
#define C
Definition RandGen.cpp:29
#define U
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static const CPPType & get()
bool is() const
void destruct(void *ptr) const
void value_initialize(void *ptr) const
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
static RandomNumberGenerator from_random_seed()
Definition rand.cc:288
void add_destruct_call(Func func)
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr bool is_empty() const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
constexpr const char * c_str() const
const Key & lookup_key_as(const ForwardKey &key) const
void reserve(const int64_t n)
void add_new(const Key &key)
void append_non_duplicates(const T &value)
std::unique_ptr< node_tree_reference_lifetimes::ReferenceLifetimesInfo > reference_lifetimes_info
std::unique_ptr< nodes::StructureTypeInterface > structure_type_interface
Map< bNodeInstanceKey, bNodePreview > previews
std::unique_ptr< nodes::FieldInferencingInterface > field_inferencing_interface
#define offsetof(t, d)
KDTree_3d * tree
#define str(s)
#define input
#define select(A, B, C)
#define main()
#define output
#define FILTER_ID_ALL
#define MEM_SAFE_FREE(v)
#define MAX_IDPROP_NAME
#define MAX_NAME
#define GS(a)
#define FILTER_ID_NT
int count
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
#define LOG(severity)
Definition log.h:32
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
static void write_compositor_legacy_properties(bNodeTree &node_tree)
Definition node.cc:680
static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
Definition node.cc:571
static bNodeSocket * make_socket(bNodeTree *ntree, const eNodeSocketInOut in_out, const StringRef idname, const StringRef name, const StringRef identifier)
Definition node.cc:473
static void legacy_socket_interface_free(bNodeSocket *sock)
Definition node.cc:636
static void update_node_location_legacy(bNodeTree &ntree)
Definition node.cc:666
static void write_legacy_sockets(BlendWriter *writer, bNodeTree *ntree)
Definition node.cc:625
static void cleanup_legacy_sockets(bNodeTree *ntree)
Definition node.cc:651
static StringRef get_legacy_socket_subtype_idname(StringRef idname, const void *socket_data)
Definition node.cc:502
static void write_node_socket_interface(BlendWriter *writer, const bNodeSocket *sock)
Definition node.cc:459
static void write_compositor_legacy_storage(BlendWriter *writer, bNode &node)
Definition node.cc:1223
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRef prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
T & get_item_as(bNodeTreeInterfaceItem &item)
struct blender::bke::versioning_internal::bNodeSocketValueBoolean_404 bNodeSocketValueBoolean_404
struct blender::bke::versioning_internal::bNodeSocketValueFloat_404 bNodeSocketValueFloat_404
struct blender::bke::versioning_internal::bNodeSocketValueRotation_404 bNodeSocketValueRotation_404
struct blender::bke::versioning_internal::bNodeSocketValueString_404 bNodeSocketValueString_404
struct blender::bke::versioning_internal::bNodeSocketValueVector_404 bNodeSocketValueVector_404
struct blender::bke::versioning_internal::bNodeSocketValueCollection_404 bNodeSocketValueCollection_404
struct blender::bke::versioning_internal::bNodeSocketValueTexture_404 bNodeSocketValueTexture_404
struct blender::bke::versioning_internal::bNodeSocketValueRGBA_404 bNodeSocketValueRGBA_404
struct blender::bke::versioning_internal::bNodeSocketValueMenu_404 bNodeSocketValueMenu_404
struct blender::bke::versioning_internal::bNodeSocketValueInt_404 bNodeSocketValueInt_404
struct blender::bke::versioning_internal::bNodeSocketValueImage_404 bNodeSocketValueImage_404
constexpr int MIN_BLENDFILE_VERSION_FOR_MODERN_NODE_SOCKET_DEFAULT_VALUE_READING
Definition node.cc:1614
struct blender::bke::versioning_internal::bNodeSocketValueObject_404 bNodeSocketValueObject_404
static void direct_link_node_socket_legacy_data_version_do(void **dest_data, void **raw_data, blender::FunctionRef< void(T &dest, T_404 &source)> copy_fn)
Definition node.cc:1704
struct blender::bke::versioning_internal::bNodeSocketValueMaterial_404 bNodeSocketValueMaterial_404
void node_unregister_socket_type(bNodeSocketType &stype)
Definition node.cc:2835
bNode * node_find_node_by_name(bNodeTree &ntree, StringRefNull name)
Definition node.cc:3607
bNodeSocket * node_find_enabled_input_socket(bNode &node, StringRef name)
Definition node.cc:2898
void node_position_propagate(bNode &node)
Definition node.cc:4314
static void node_free_type(void *nodetype_v)
Definition node.cc:2729
void node_socket_declarations_update(bNode *node)
Definition node.cc:5058
static void node_preview_init_tree_recursive(Map< bNodeInstanceKey, bNodePreview > &previews, bNodeTree *ntree, bNodeInstanceKey parent_key, const int xsize, const int ysize)
Definition node.cc:4462
void node_tree_free_local_node(bNodeTree &ntree, bNode &node)
Definition node.cc:4635
static bool socket_id_user_decrement(bNodeSocket *sock)
Definition node.cc:3009
void node_tree_set_output(bNodeTree &ntree)
Definition node.cc:4742
static ID ** node_owner_pointer_get(ID *id, const bool debug_relationship_assert)
Definition node.cc:440
void node_modify_socket_type_static(bNodeTree *ntree, bNode *node, bNodeSocket *sock, int type, int subtype)
Definition node.cc:3123
StringRefNull node_type_find_alias(StringRefNull alias)
Definition node.cc:2720
bNodeSocketType NodeSocketTypeUndefined
Definition node.cc:123
std::string node_label(const bNodeTree &ntree, const bNode &node)
Definition node.cc:5242
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc:5452
void node_tree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index)
Definition node.cc:5714
bool node_is_parent_and_child(const bNode &parent, const bNode &child)
Definition node.cc:3662
void node_attach_node(bNodeTree &ntree, bNode &node, bNode &parent)
Definition node.cc:4255
void node_tree_blend_read_data(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
Definition node.cc:2146
static bool node_poll_default(const bNodeType *, const bNodeTree *, const char **)
Definition node.cc:5283
const bNodeTreeInterfaceSocket * node_find_interface_input_by_identifier(const bNodeTree &ntree, StringRef identifier)
Definition node.cc:3638
void node_register_alias(bNodeType &nt, StringRef alias)
Definition node.cc:2784
void node_tree_free_local_tree(bNodeTree *ntree)
Definition node.cc:4731
bool node_tree_is_registered(const bNodeTree &ntree)
Definition node.cc:2701
static void node_init(const bContext *C, bNodeTree *ntree, bNode *node)
Definition node.cc:2420
static void node_type_base_defaults(bNodeType &ntype)
Definition node.cc:5273
static void direct_link_node_socket_default_value(BlendDataReader *reader, bNodeSocket *sock)
Definition node.cc:1721
bNodeTreeType * node_tree_type_find(StringRef idname)
Definition node.cc:2635
static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
Definition node.cc:2483
void node_unlink_node(bNodeTree &ntree, bNode &node)
Definition node.cc:4532
void node_tree_free_tree(bNodeTree &ntree)
Definition node.cc:4718
Span< bNodeSocketType * > node_socket_types_get()
Definition node.cc:2789
void node_tag_update_id(bNode &node)
Definition node.cc:5105
static void socket_id_user_increment(bNodeSocket *sock)
Definition node.cc:2959
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4375
std::optional< VolumeGridType > socket_type_to_grid_type(eNodeSocketDatatype type)
Definition node.cc:5487
bNodeTree * node_tree_copy_tree(Main *bmain, const bNodeTree &ntree)
Definition node.cc:4391
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2864
void node_remove_node(Main *bmain, bNodeTree &ntree, bNode &node, bool do_id_user, bool remove_animation=true)
Definition node.cc:4649
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname)
Definition node.cc:3788
bool node_socket_is_registered(const bNodeSocket &sock)
Definition node.cc:2841
bool node_tree_iterator_step(NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, ID **r_id)
Definition node.cc:5665
static void update_socket_declarations(ListBase *sockets, Span< nodes::SocketDeclaration * > declarations)
Definition node.cc:5041
void node_internal_links(bNode &node, bNodeLink **r_links, int *r_len)
Definition node.cc:5110
static Set< int > get_known_node_types_set()
Definition node.cc:5153
static void remove_unsupported_sockets(ListBase *sockets, ListBase *links)
Definition node.cc:2027
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4957
static void defer_free_tree_type(bNodeTreeType *tree_type)
Definition node.cc:2644
void node_tree_blend_write(BlendWriter *writer, bNodeTree *ntree)
Definition node.cc:1464
static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition node.cc:413
bool node_link_is_selected(const bNodeLink &link)
Definition node.cc:4164
static const CPPType * slow_socket_type_to_geo_nodes_base_cpp_type(const eNodeSocketDatatype type)
Definition node.cc:5407
static void collect_used_previews(Map< bNodeInstanceKey, bNodePreview > &previews, bNodeTree *ntree, bNodeInstanceKey parent_key, Set< bNodeInstanceKey > &used)
Definition node.cc:4488
void node_remove_socket(bNodeTree &ntree, bNode &node, bNodeSocket &sock)
Definition node.cc:3575
void node_update_asset_metadata(bNodeTree &node_tree)
Definition node.cc:2289
static bool is_node_socket_supported(const bNodeSocket *sock)
Definition node.cc:1568
const DataTypeConversions & get_implicit_type_conversions()
static void defer_free_node_type(bNodeType *ntype)
Definition node.cc:2650
static void ntree_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int flag)
Definition node.cc:142
static auto & get_socket_type_map()
Definition node.cc:2629
static void node_blend_write_storage(BlendWriter *writer, bNodeTree *ntree, bNode *node)
Definition node.cc:1377
void node_unique_id(bNodeTree &ntree, bNode &node)
Definition node.cc:3770
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5573
bNode * node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, bool use_unique, Map< const bNodeSocket *, bNodeSocket * > &new_socket_map)
Definition node.cc:3857
bNode * node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool use_unique)
Definition node.cc:4070
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
std::optional< StringRefNull > node_socket_short_label(const bNodeSocket &sock)
Definition node.cc:5257
static void ntree_free_data(ID *id)
Definition node.cc:250
static void adjust_multi_input_indices_after_removed_link(bNodeTree *ntree, const bNodeSocket *sock, const int deleted_index)
Definition node.cc:4171
static void ntree_blend_read_after_liblink(BlendLibReader *reader, ID *id)
Definition node.cc:2266
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:5011
void node_remove_link(bNodeTree *ntree, bNodeLink &link)
Definition node.cc:4124
void node_chain_iterator_backwards(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *), void *userdata, int recursion_lvl)
Definition node.cc:3732
void node_chain_iterator(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *, const bool), void *userdata, bool reversed)
Definition node.cc:3672
static bool ntree_contains_tree_exec(const bNodeTree &tree_to_search_in, const bNodeTree &tree_to_search_for, Set< const bNodeTree * > &already_passed)
Definition node.cc:4910
Span< bNodeType * > node_types_get()
Definition node.cc:2779
static bool can_read_node_type(const bNode &node)
Definition node.cc:5162
std::optional< StringRefNull > node_static_socket_interface_type_new(int type, int subtype, std::optional< int > dimensions=std::nullopt)
Definition node.cc:3327
static void ntree_init_data(ID *id)
Definition node.cc:133
void node_tree_local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
Definition node.cc:4901
void node_tree_set_type(bNodeTree &ntree)
Definition node.cc:2586
bool node_declaration_ensure_on_outdated_node(bNodeTree &ntree, bNode &node)
Definition node.cc:5070
static void direct_link_node_socket_storage(BlendDataReader *reader, const bNode *node, bNodeSocket *sock)
Definition node.cc:1974
static void node_unlink_attached(bNodeTree *ntree, const bNode *parent)
Definition node.cc:4559
static bNodeSocket * make_socket(bNodeTree *ntree, bNode *, const int in_out, ListBase *lb, const StringRefNull idname, const StringRefNull identifier, const StringRefNull name)
Definition node.cc:2908
void node_tree_type_add(bNodeTreeType &nt)
Definition node.cc:2672
void node_tree_update_all_new(Main &main)
Definition node.cc:5190
void node_type_base(bNodeType &ntype, std::string idname, std::optional< int16_t > legacy_type=std::nullopt)
Definition node.cc:5310
bNodePreview * node_preview_verify(Map< bNodeInstanceKey, bNodePreview > &previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
Definition node.cc:4409
void node_tree_iterator_init(NodeTreeIterStore *ntreeiter, Main *bmain)
Definition node.cc:5655
static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str)
Definition node.cc:5125
static int16_t get_next_auto_legacy_type()
Definition node.cc:5297
std::optional< eNodeSocketDatatype > grid_type_to_socket_type(VolumeGridType type)
Definition node.cc:5503
void node_node_foreach_id(bNode *node, LibraryForeachIDData *data)
Definition node.cc:352
bNodeTreeType NodeTreeTypeUndefined
Definition node.cc:121
static void node_set_typeinfo(const bContext *C, bNodeTree *ntree, bNode *node, bNodeType *typeinfo)
Definition node.cc:2497
static void node_tree_asset_on_clear_asset(void *asset_ptr, AssetMetaData *asset_data)
Definition node.cc:2339
bNodeTree ** node_tree_ptr_from_id(ID *id)
Definition node.cc:4816
bNodeTree * node_tree_localize(bNodeTree *ntree, std::optional< ID * > new_owner_id)
Definition node.cc:4858
void node_parents_iterator(bNode *node, bool(*callback)(bNode *, void *), void *userdata)
Definition node.cc:3754
int node_count_socket_links(const bNodeTree &ntree, const bNodeSocket &sock)
Definition node.cc:4946
void node_internal_relink(bNodeTree &ntree, bNode &node)
Definition node.cc:4185
static void reset_socket_declarations(ListBase *sockets)
Definition node.cc:5051
bNode * node_find_node_try(bNodeTree &ntree, bNodeSocket &socket)
Definition node.cc:3625
static void direct_link_node_socket(BlendDataReader *reader, const bNode *node, bNodeSocket *sock)
Definition node.cc:2011
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE
Definition node.cc:5118
std::optional< eNodeSocketDatatype > custom_data_type_to_socket_type(eCustomDataType type)
Definition node.cc:5379
void node_system_exit()
Definition node.cc:5620
void node_free_node(bNodeTree *tree, bNode &node)
Definition node.cc:4579
void node_preview_remove_unused(bNodeTree *ntree)
Definition node.cc:4508
bool node_preview_used(const bNode &node)
Definition node.cc:4403
bNodeType NodeTypeUndefined
Definition node.cc:122
static void node_foreach_id(ID *id, LibraryForeachIDData *data)
Definition node.cc:371
void node_tree_type_free_link(const bNodeTreeType &nt)
Definition node.cc:2695
void node_type_socket_templates(bNodeType *ntype, bNodeSocketTemplate *inputs, bNodeSocketTemplate *outputs)
Definition node.cc:5541
bNodeInstanceKey node_instance_key(bNodeInstanceKey parent_key, const bNodeTree *ntree, const bNode *node)
Definition node.cc:5139
static void ntree_blend_read_data(BlendDataReader *reader, ID *id)
Definition node.cc:2260
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag)
Definition node.cc:3828
void node_register_socket_type(bNodeSocketType &stype)
Definition node.cc:2826
void node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
Definition node.cc:4517
static auto & get_node_tree_type_map()
Definition node.cc:2611
static bool node_poll_instance_default(const bNode *node, const bNodeTree *ntree, const char **r_disabled_hint)
Definition node.cc:5290
bNodeSocket * node_find_enabled_output_socket(bNode &node, StringRef name)
Definition node.cc:2903
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:5413
void node_position_relative(bNode &from_node, const bNode &to_node, const bNodeSocket *from_sock, const bNodeSocket &to_sock)
Definition node.cc:4272
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4967
bNodeSocket * node_add_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out, StringRefNull idname, StringRefNull identifier, StringRefNull name)
Definition node.cc:3136
bNode & node_find_node(bNodeTree &ntree, bNodeSocket &socket)
Definition node.cc:3613
static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData *)
Definition node.cc:2321
static void iter_backwards_ex(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *), void *userdata, const char recursion_mask)
Definition node.cc:3704
static auto & get_node_type_alias_map()
Definition node.cc:2623
bool node_tree_contains_tree(const bNodeTree &tree_to_search_in, const bNodeTree &tree_to_search_for)
Definition node.cc:4935
void node_detach_node(bNodeTree &ntree, bNode &node)
Definition node.cc:4263
void node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
Definition node.cc:4482
static void node_free_socket_type(void *socktype_v)
Definition node.cc:2812
void node_rebuild_id_vector(bNodeTree &node_tree)
Definition node.cc:4568
bNodeSocketType * node_socket_type_find(StringRef idname)
Definition node.cc:2794
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3804
bNodeTree * node_tree_copy_tree_ex(const bNodeTree &ntree, Main *bmain, bool do_id_user)
Definition node.cc:4383
bool node_supports_active_flag(const bNode &node, int sub_activity)
Does the given node supports the sub active flag.
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
static void node_replace_undefined_types(bNode *node)
Definition node.cc:5177
bNodeSocket * node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name)
Definition node.cc:2885
static void node_blend_read_data_storage(BlendDataReader *reader, bNodeTree *ntree, bNode *node)
Definition node.cc:2053
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4362
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
Definition node.cc:2803
static void free_localized_node_groups(bNodeTree *ntree)
Definition node.cc:4699
void node_link_set_mute(bNodeTree &ntree, bNodeLink &link, const bool muted)
Definition node.cc:4141
StringRefNull node_socket_type_label(const bNodeSocketType &stype)
Definition node.cc:2846
static bNodeTree * node_tree_add_tree_do(Main *bmain, std::optional< Library * > owner_library, ID *owner_id, const bool is_embedded, const StringRef name, const StringRef idname)
Definition node.cc:4325
Span< bNodeTreeType * > node_tree_types_get()
Definition node.cc:2706
bNodeSocket * node_add_static_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out, int type, int subtype, StringRefNull identifier, StringRefNull name)
Definition node.cc:3529
static void library_foreach_node_socket(bNodeSocket *sock, LibraryForeachIDData *data)
Definition node.cc:298
static void * socket_value_storage(bNodeSocket &socket)
Definition node.cc:3965
void node_remove_socket_ex(bNodeTree &ntree, bNode &node, bNodeSocket &sock, bool do_id_user)
Definition node.cc:3580
static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition node.cc:1539
void node_unregister_type(bNodeType &ntype)
Definition node.cc:2773
void node_modify_socket_type(bNodeTree &ntree, bNode &node, bNodeSocket &sock, StringRefNull idname)
Definition node.cc:3059
static void * node_static_value_storage_for(bNode &node, const bNodeSocket &socket)
Definition node.cc:3936
std::optional< StringRefNull > node_static_socket_label(int type, int subtype)
Definition node.cc:3484
std::optional< StringRefNull > node_static_socket_type(int type, int subtype, std::optional< int > dimensions=std::nullopt)
Definition node.cc:3167
void node_system_init()
Definition node.cc:5615
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
Definition node.cc:2392
void node_remove_socket_links(bNodeTree &ntree, bNodeSocket &sock)
Definition node.cc:4150
const bNodeInstanceKey NODE_INSTANCE_KEY_NONE
Definition node.cc:5119
bool node_declaration_ensure(bNodeTree &ntree, bNode &node)
Definition node.cc:5090
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4996
float2 node_dimensions_get(const bNode &node)
Definition node.cc:5099
bNodeTree * node_tree_add_in_lib(Main *bmain, Library *owner_library, StringRefNull name, StringRefNull idname)
Definition node.cc:4367
static void update_typeinfo(Main *bmain, bNodeTreeType *treetype, bNodeType *nodetype, bNodeSocketType *socktype, const bool unregister)
Definition node.cc:2549
bNodeType * node_type_find(StringRef idname)
Definition node.cc:2711
static void ntree_free_type(void *treetype_v)
Definition node.cc:2681
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
Definition node.cc:4076
static void unique_socket_template_identifier(bNodeSocketTemplate *list, bNodeSocketTemplate *ntemp, const char defname[], const char delim)
Definition node.cc:5519
static void write_node_socket_default_value(BlendWriter *writer, const bNodeSocket *sock)
Definition node.cc:1302
static void node_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
Definition node.cc:395
static void node_tree_asset_on_mark_asset(void *asset_ptr, AssetMetaData *asset_data)
Definition node.cc:2327
void node_socket_move_default_value(Main &bmain, bNodeTree &tree, bNodeSocket &src, bNodeSocket &dst)
Definition node.cc:4010
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4840
void node_tree_update_all_users(Main *main, ID *id)
Definition node.cc:5217
int node_socket_link_limit(const bNodeSocket &sock)
Definition node.cc:5025
void node_clear_active(bNodeTree &ntree)
Definition node.cc:4989
StringRefNull node_socket_sub_type_label(int subtype)
Definition node.cc:2855
bNode * node_find_root_parent(bNode &node)
Definition node.cc:3650
static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
Definition node.cc:3549
StringRefNull node_socket_label(const bNodeSocket &sock)
Definition node.cc:5268
static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo)
Definition node.cc:2527
void node_tree_free_embedded_tree(bNodeTree *ntree)
Definition node.cc:4724
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
static void write_node_socket(BlendWriter *writer, const bNodeSocket *sock)
Definition node.cc:1363
std::optional< eCustomDataType > socket_type_to_custom_data_type(eNodeSocketDatatype type)
Definition node.cc:5355
static void defer_free_socket_type(bNodeSocketType *stype)
Definition node.cc:2661
void node_type_size_preset(bNodeType &ntype, eNodeSizePreset size)
Definition node.cc:5585
void node_unique_name(bNodeTree &ntree, bNode &node)
Definition node.cc:3764
bool node_is_static_socket_type(const bNodeSocketType &stype)
Definition node.cc:3158
static auto & get_node_type_map()
Definition node.cc:2617
bool node_link_is_hidden(const bNodeLink &link)
Definition node.cc:4159
void node_type_base_custom(bNodeType &ntype, StringRefNull idname, StringRefNull name, StringRefNull enum_name, short nclass)
Definition node.cc:5340
void node_tree_node_flag_set(bNodeTree &ntree, int flag, bool enable)
Definition node.cc:4846
QuaternionBase< float > Quaternion
T ceil(const T &a)
ImplicitSharingPtr< Bundle > BundlePtr
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
void build_node_declaration(const bke::bNodeType &typeinfo, NodeDeclaration &r_declaration, const bNodeTree *ntree, const bNode *node)
ImplicitSharingPtr< Closure > ClosurePtr
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VectorSet< T, InlineBufferCapacity, DefaultProbingStrategy, CustomIDHash< T, GetIDFn >, CustomIDEqual< T, GetIDFn > > CustomIDVectorSet
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
static AssetTypeInfo AssetType_NT
Definition node.cc:2353
void register_nodes()
void node_socket_init_default_value(bNodeSocket *sock)
bNodeSocket * node_add_socket_from_template(bNodeTree *ntree, bNode *node, bke::bNodeSocketTemplate *stemp, eNodeSocketInOut in_out)
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
void node_socket_copy_default_value_data(eNodeSocketDatatype datatype, void *to, const void *from)
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
#define hash
Definition noise_c.cc:154
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
StructRNA * RNA_struct_find(const char *identifier)
void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type)
const char * RNA_struct_ui_name(const StructRNA *type)
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description)
const EnumPropertyItem rna_enum_property_subtype_items[]
Definition rna_rna.cc:124
#define FLT_MAX
Definition stdcycles.h:14
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
StructRNA * srna
Definition RNA_types.hh:909
struct bNodeTree * nodetree
unsigned int id_session_uid
Definition BKE_idtype.hh:74
size_t identifier
Definition BKE_idtype.hh:79
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct AssetMetaData * asset_data
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:410
short flag
Definition DNA_ID.h:420
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
ImBufByteBuffer byte_buffer
struct Scene * scene
struct bNodeTree * nodetree
void * first
ListBase scenes
Definition BKE_main.hh:245
ListBase textures
Definition BKE_main.hh:252
ListBase lights
Definition BKE_main.hh:255
ListBase nodetrees
Definition BKE_main.hh:270
ListBase materials
Definition BKE_main.hh:251
ListBase linestyles
Definition BKE_main.hh:282
ListBase worlds
Definition BKE_main.hh:260
struct bNodeTree * nodetree
NodeCryptomatte_Runtime runtime
ImageFormatData format
struct bNodeTree * nodetree
struct bNodeTree * nodetree
struct bNodeTree * nodetree
struct Collection * value
const RuntimeNodeEnumItemsHandle * enum_items
IDProperty * prop
bNodeSocketRuntimeHandle * runtime
struct bNodeLink * link
char description[64]
bNodeSocketTypeHandle * typeinfo
char * default_attribute_name
void * default_value
char identifier[64]
char idname[64]
bNodeTreeRuntimeHandle * runtime
char idname[64]
struct GeometryNodeAssetTraits * geometry_node_asset_traits
int nested_node_refs_num
struct PreviewImage * preview
bNestedNodeRef * nested_node_refs
struct bGPdata * gpd
int default_group_node_width
bNodeTreeTypeHandle * typeinfo
char * description
bNodeTreeInterface tree_interface
ListBase nodes
ListBase links
float location[2]
bNodeTypeHandle * typeinfo
int16_t custom1
float width
IDProperty * prop
ListBase inputs
float height
struct ID * id
float color[3]
struct bNode * parent
char name[64]
bNodePanelState * panel_states_array
int16_t type_legacy
struct bNode * next
bNodeRuntimeHandle * runtime
void * storage
char idname[64]
int16_t ui_order
char label[64]
ListBase outputs
int32_t identifier
const Key & key
Definition BLI_map.hh:69
StringRef operator()(const T *value) const
Definition node.cc:2605
FreestyleLineStyle * linestyle
Definition BKE_node.hh:850
Compact definition of a node socket.
Definition BKE_node.hh:98
Defines a socket type.
Definition BKE_node.hh:152
void(* free_self)(bNodeSocketType *stype)
Definition BKE_node.hh:196
eNodeSocketDatatype type
Definition BKE_node.hh:187
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:199
Defines a node type.
Definition BKE_node.hh:226
blender::nodes::NodeDeclaration * static_declaration
Definition BKE_node.hh:364
void(* copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
Definition BKE_node.hh:287
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:383
std::string ui_description
Definition BKE_node.hh:232
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:384
std::string storagename
Definition BKE_node.hh:244
void(* freefunc)(bNode *node)
Definition BKE_node.hh:285
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
bool(* poll_instance)(const bNode *node, const bNodeTree *nodetree, const char **r_disabled_hint)
Definition BKE_node.hh:316
bNodeSocketTemplate * inputs
Definition BKE_node.hh:242
bNodeSocketTemplate * outputs
Definition BKE_node.hh:242
const char * enum_name_legacy
Definition BKE_node.hh:235
bool(* poll)(const bNodeType *ntype, const bNodeTree *nodetree, const char **r_disabled_hint)
Definition BKE_node.hh:309
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* free_self)(bNodeType *ntype)
Definition BKE_node.hh:323
void(* initfunc_api)(const bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:290
const RuntimeNodeEnumItemsHandle * enum_items
Definition node.cc:1698
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4227
uint8_t flag
Definition wm_window.cc:139