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