diff options
Diffstat (limited to 'source/blender/blenkernel/intern/node.cc')
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 241 |
1 files changed, 145 insertions, 96 deletions
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index b82cf30416a..31fc8afea84 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -47,6 +47,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" +#include "BKE_asset.h" #include "BKE_bpath.h" #include "BKE_colortools.h" #include "BKE_context.h" @@ -54,6 +55,7 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_idprop.h" +#include "BKE_idprop.hh" #include "BKE_idtype.h" #include "BKE_image_format.h" #include "BKE_lib_id.h" @@ -82,8 +84,6 @@ #include "BLO_read_write.h" -#include "MOD_nodes.h" - #define NODE_DEFAULT_MAX_WIDTH 700 using blender::Array; @@ -116,7 +116,7 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo); static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag); static void free_localized_node_groups(bNodeTree *ntree); static void node_free_node(bNodeTree *ntree, bNode *node); -static void node_socket_interface_free(bNodeTree *UNUSED(ntree), +static void node_socket_interface_free(bNodeTree * /*ntree*/, bNodeSocket *sock, const bool do_id_user); @@ -127,12 +127,12 @@ static void ntree_init_data(ID *id) ntree_set_typeinfo(ntree, nullptr); } -static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) +static void ntree_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag) { bNodeTree *ntree_dst = (bNodeTree *)id_dst; const bNodeTree *ntree_src = (const bNodeTree *)id_src; - /* We never handle usercount here for own data. */ + /* We never handle user-count here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; ntree_dst->runtime = MEM_new<bNodeTreeRuntime>(__func__); @@ -372,7 +372,7 @@ static void node_foreach_cache(ID *id, if (nodetree->type == NTREE_COMPOSIT) { LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { if (node->type == CMP_NODE_MOVIEDISTORTION) { - key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(node->name); + key.offset_in_ID = size_t(BLI_ghashutil_strhash_p(node->name)); function_callback(id, &key, (void **)&node->storage, 0, user_data); } } @@ -405,13 +405,13 @@ static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data) static ID **node_owner_pointer_get(ID *id) { if ((id->flag & LIB_EMBEDDED_DATA) == 0) { - return NULL; + return nullptr; } /* TODO: Sort this NO_MAIN or not for embedded node trees. See T86119. */ // BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0); bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id); - BLI_assert(ntree->owner_id != NULL); + BLI_assert(ntree->owner_id != nullptr); BLI_assert(ntreeFromID(ntree->owner_id) == ntree); return &ntree->owner_id; @@ -516,10 +516,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) write_node_socket(writer, sock); } - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_write_struct(writer, bNodeLink, link); - } - if (node->storage) { if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { @@ -660,7 +656,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) if (BLO_read_fileversion_get(reader) > 300) { BLI_assert((ntree->id.flag & LIB_EMBEDDED_DATA) != 0 || owner_id == nullptr); } - BLI_assert(owner_id == NULL || owner_id->lib == ntree->id.lib); + BLI_assert(owner_id == nullptr || owner_id->lib == ntree->id.lib); if (owner_id != nullptr && (ntree->id.flag & LIB_EMBEDDED_DATA) == 0) { /* This is unfortunate, but currently a lot of existing files (including startup ones) have * missing `LIB_EMBEDDED_DATA` flag. @@ -703,13 +699,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); - BLO_read_list(reader, &node->internal_links); - LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { - BLO_read_data_address(reader, &link->fromnode); - BLO_read_data_address(reader, &link->fromsock); - BLO_read_data_address(reader, &link->tonode); - BLO_read_data_address(reader, &link->tosock); - } + BLI_listbase_clear(&node->internal_links); if (node->type == CMP_NODE_MOVIEDISTORTION) { /* Do nothing, this is runtime cache and hence handled by generic code using @@ -1026,6 +1016,33 @@ static void ntree_blend_read_expand(BlendExpander *expander, ID *id) ntreeBlendReadExpand(expander, ntree); } +namespace blender::bke { + +static void node_tree_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data) +{ + bNodeTree &node_tree = *static_cast<bNodeTree *>(asset_ptr); + + BKE_asset_metadata_idprop_ensure(asset_data, idprop::create("type", node_tree.type).release()); + auto inputs = idprop::create_group("inputs"); + auto outputs = idprop::create_group("outputs"); + LISTBASE_FOREACH (const bNodeSocket *, socket, &node_tree.inputs) { + auto property = idprop::create(socket->name, socket->typeinfo->idname); + IDP_AddToGroup(inputs.get(), property.release()); + } + LISTBASE_FOREACH (const bNodeSocket *, socket, &node_tree.outputs) { + auto property = idprop::create(socket->name, socket->typeinfo->idname); + IDP_AddToGroup(outputs.get(), property.release()); + } + BKE_asset_metadata_idprop_ensure(asset_data, inputs.release()); + BKE_asset_metadata_idprop_ensure(asset_data, outputs.release()); +} + +} // namespace blender::bke + +static AssetTypeInfo AssetType_NT = { + /* pre_save_fn */ blender::bke::node_tree_asset_pre_save, +}; + IDTypeInfo IDType_ID_NT = { /* id_code */ ID_NT, /* id_filter */ FILTER_ID_NT, @@ -1035,7 +1052,7 @@ IDTypeInfo IDType_ID_NT = { /* name_plural */ "node_groups", /* translation_context */ BLT_I18NCONTEXT_ID_NODETREE, /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, - /* asset_type_info */ nullptr, + /* asset_type_info */ &AssetType_NT, /* init_data */ ntree_init_data, /* copy_data */ ntree_copy_data, @@ -1388,8 +1405,8 @@ void nodeUnregisterType(bNodeType *nt) bool nodeTypeUndefined(const bNode *node) { return (node->typeinfo == &NodeTypeUndefined) || - ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id && - ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING)); + (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id && ID_IS_LINKED(node->id) && + (node->id->tag & LIB_TAG_MISSING)); } GHashIterator *nodeTypeGetIterator() @@ -1504,7 +1521,7 @@ static bool unique_identifier_check(void *arg, const char *identifier) } static bNodeSocket *make_socket(bNodeTree *ntree, - bNode *UNUSED(node), + bNode * /*node*/, int in_out, ListBase *lb, const char *idname, @@ -1647,7 +1664,7 @@ static bool socket_id_user_decrement(bNodeSocket *sock) } void nodeModifySocketType(bNodeTree *ntree, - bNode *UNUSED(node), + bNode * /*node*/, bNodeSocket *sock, const char *idname) { @@ -1866,7 +1883,7 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype) return nullptr; } -const char *nodeStaticSocketLabel(int type, int UNUSED(subtype)) +const char *nodeStaticSocketLabel(int type, int /*subtype*/) { switch (type) { case SOCK_FLOAT: @@ -2005,21 +2022,29 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex) { *r_node = nullptr; + if (!ntree->runtime->topology_cache_is_dirty) { + bNode *node = &sock->owner_node(); + *r_node = node; + if (r_sockindex) { + ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; + *r_sockindex = BLI_findindex(sockets, sock); + } + return true; + } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { ListBase *sockets = (sock->in_out == SOCK_IN) ? &node->inputs : &node->outputs; - int index = 0; - LISTBASE_FOREACH (bNodeSocket *, tsock, sockets) { + int i; + LISTBASE_FOREACH_INDEX (bNodeSocket *, tsock, sockets, i) { if (sock == tsock) { if (r_node != nullptr) { *r_node = node; } if (r_sockindex != nullptr) { - *r_sockindex = index; + *r_sockindex = i; } return true; } - index++; } } return false; @@ -2130,6 +2155,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd } } +bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node) +{ + ntree->ensure_topology_cache(); + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*ntree)); + BLI_assert(!ntree->has_available_link_cycle()); + + const bNode *iter_node = node; + if (!iter_node->is_reroute()) { + return false; + } + + while (true) { + const blender::Span<const bNodeLink *> links = + iter_node->input_socket(0).directly_linked_links(); + BLI_assert(links.size() <= 1); + if (links.is_empty()) { + return true; + } + const bNodeLink &link = *links[0]; + if (!link.is_available()) { + return false; + } + if (link.is_muted()) { + return false; + } + iter_node = link.fromnode; + if (!iter_node->is_reroute()) { + return false; + } + } +} + /* ************** Add stuff ********** */ void nodeUniqueName(bNodeTree *ntree, bNode *node) @@ -2149,7 +2206,7 @@ bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idnam BKE_ntree_update_tag_node_new(ntree, node); - if (node->type == GEO_NODE_INPUT_SCENE_TIME) { + if (ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) { DEG_relations_tag_update(CTX_data_main(C)); } @@ -2601,15 +2658,15 @@ static bNodeTree *ntreeAddTree_do( bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag); BKE_libblock_init_empty(&ntree->id); if (is_embedded) { - BLI_assert(owner_id != NULL); + BLI_assert(owner_id != nullptr); ntree->id.flag |= LIB_EMBEDDED_DATA; ntree->owner_id = owner_id; bNodeTree **ntree_owner_ptr = BKE_ntree_ptr_from_id(owner_id); - BLI_assert(ntree_owner_ptr != NULL); + BLI_assert(ntree_owner_ptr != nullptr); *ntree_owner_ptr = ntree; } else { - BLI_assert(owner_id == NULL); + BLI_assert(owner_id == nullptr); } BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname)); @@ -2623,7 +2680,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) return ntreeAddTree_do(bmain, nullptr, false, name, idname); } -bNodeTree *ntreeAddTreeEmbedded(Main *UNUSED(bmain), +bNodeTree *ntreeAddTreeEmbedded(Main * /*bmain*/, ID *owner_id, const char *name, const char *idname) @@ -2687,8 +2744,8 @@ bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, } if (preview->rect == nullptr) { - preview->rect = (unsigned char *)MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), - "node preview rect"); + preview->rect = (uchar *)MEM_callocN(4 * xsize + xsize * ysize * sizeof(char[4]), + "node preview rect"); preview->xsize = xsize; preview->ysize = ysize; } @@ -2701,7 +2758,7 @@ bNodePreview *BKE_node_preview_copy(bNodePreview *preview) { bNodePreview *new_preview = (bNodePreview *)MEM_dupallocN(preview); if (preview->rect) { - new_preview->rect = (unsigned char *)MEM_dupallocN(preview->rect); + new_preview->rect = (uchar *)MEM_dupallocN(preview->rect); } return new_preview; } @@ -2992,7 +3049,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) /* Also update relations for the scene time node, which causes a dependency * on time that users expect to be removed when the node is removed. */ - if (node_has_id || node->type == GEO_NODE_INPUT_SCENE_TIME) { + if (node_has_id || ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) { if (bmain != nullptr) { DEG_relations_tag_update(bmain); } @@ -3005,7 +3062,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) node_free_node(ntree, node); } -static void node_socket_interface_free(bNodeTree *UNUSED(ntree), +static void node_socket_interface_free(bNodeTree * /*ntree*/, bNodeSocket *sock, const bool do_id_user) { @@ -3085,7 +3142,7 @@ void ntreeSetOutput(bNodeTree *ntree) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) { /* we need a check for which output node should be tagged like this, below an exception */ - if (node->type == CMP_NODE_OUTPUT_FILE) { + if (ELEM(node->type, CMP_NODE_OUTPUT_FILE, GEO_NODE_VIEWER)) { continue; } @@ -3096,8 +3153,8 @@ void ntreeSetOutput(bNodeTree *ntree) if (ntree->type == NTREE_COMPOSIT) { /* same type, exception for viewer */ if (tnode->type == node->type || - (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) && - ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER))) { + (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && + ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { @@ -3324,10 +3381,18 @@ struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock) { - bNodeSocket *iosock = ntreeAddSocketInterface(ntree, - static_cast<eNodeSocketInOut>(from_sock->in_out), - from_sock->idname, - DATA_(from_sock->name)); + return ntreeAddSocketInterfaceFromSocketWithName( + ntree, from_node, from_sock, from_sock->idname, from_sock->name); +} + +struct bNodeSocket *ntreeAddSocketInterfaceFromSocketWithName(bNodeTree *ntree, + bNode *from_node, + bNodeSocket *from_sock, + const char *idname, + const char *name) +{ + bNodeSocket *iosock = ntreeAddSocketInterface( + ntree, static_cast<eNodeSocketInOut>(from_sock->in_out), idname, DATA_(name)); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); @@ -3371,12 +3436,12 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock) static void ntree_interface_identifier_base(bNodeTree *ntree, char *base) { /* generate a valid RNA identifier */ - sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2); + BLI_sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2); RNA_identifier_sanitize(base, false); } /* check if the identifier is already in use */ -static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier) +static bool ntree_interface_unique_identifier_check(void * /*data*/, const char *identifier) { return (RNA_struct_find(identifier) != nullptr); } @@ -3397,8 +3462,8 @@ static void ntree_interface_identifier(bNodeTree *ntree, BLI_uniquename_cb( ntree_interface_unique_identifier_check, nullptr, base, '_', identifier, maxlen); - sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); - sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); + BLI_sprintf(name, "Node Tree %s Interface", ntree->id.name + 2); + BLI_sprintf(description, "Interface properties of node group %s", ntree->id.name + 2); } static void ntree_interface_type_create(bNodeTree *ntree) @@ -3650,7 +3715,7 @@ void nodeSocketDeclarationsUpdate(bNode *node) update_socket_declarations(&node->outputs, node->runtime->declaration->outputs()); } -bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) +bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree * /*ntree*/, bNode *node) { if (node->runtime->declaration != nullptr) { return false; @@ -3870,15 +3935,15 @@ bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, return key; } -static unsigned int node_instance_hash_key(const void *key) +static uint node_instance_hash_key(const void *key) { return ((const bNodeInstanceKey *)key)->value; } static bool node_instance_hash_key_cmp(const void *a, const void *b) { - unsigned int value_a = ((const bNodeInstanceKey *)a)->value; - unsigned int value_b = ((const bNodeInstanceKey *)b)->value; + uint value_a = ((const bNodeInstanceKey *)a)->value; + uint value_b = ((const bNodeInstanceKey *)b)->value; return (value_a != value_b); } @@ -3949,7 +4014,7 @@ void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash) } } -void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value) +void BKE_node_instance_hash_tag(bNodeInstanceHash * /*hash*/, void *value) { bNodeInstanceHashEntry *entry = (bNodeInstanceHashEntry *)value; entry->tag = 1; @@ -4155,9 +4220,9 @@ static void node_type_base_defaults(bNodeType *ntype) } /* allow this node for any tree type */ -static bool node_poll_default(bNodeType *UNUSED(ntype), - bNodeTree *UNUSED(ntree), - const char **UNUSED(disabled_hint)) +static bool node_poll_default(bNodeType * /*ntype*/, + bNodeTree * /*ntree*/, + const char ** /*disabled_hint*/) { return true; } @@ -4281,12 +4346,6 @@ void node_type_socket_templates(struct bNodeType *ntype, } } -void node_type_init(struct bNodeType *ntype, - void (*initfunc)(struct bNodeTree *ntree, struct bNode *node)) -{ - ntype->initfunc = initfunc; -} - void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth) { ntype->width = width; @@ -4334,38 +4393,11 @@ void node_type_storage(bNodeType *ntype, ntype->freefunc = freefunc; } -void node_type_update(struct bNodeType *ntype, - void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node)) -{ - ntype->updatefunc = updatefunc; -} - -void node_type_group_update(struct bNodeType *ntype, - void (*group_update_func)(struct bNodeTree *ntree, struct bNode *node)) -{ - ntype->group_update_func = group_update_func; -} - -void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction init_exec_fn, - NodeFreeExecFunction free_exec_fn, - NodeExecFunction exec_fn) -{ - ntype->init_exec_fn = init_exec_fn; - ntype->free_exec_fn = free_exec_fn; - ntype->exec_fn = exec_fn; -} - -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) -{ - ntype->gpu_fn = gpu_fn; -} - /* callbacks for undefined types */ -static bool node_undefined_poll(bNodeType *UNUSED(ntype), - bNodeTree *UNUSED(nodetree), - const char **UNUSED(r_disabled_hint)) +static bool node_undefined_poll(bNodeType * /*ntype*/, + bNodeTree * /*nodetree*/, + const char ** /*r_disabled_hint*/) { /* this type can not be added deliberately, it's just a placeholder */ return false; @@ -4699,9 +4731,12 @@ static void registerGeometryNodes() register_node_type_geo_curve_subdivide(); register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); + register_node_type_geo_curve_topology_curve_of_point(); + register_node_type_geo_curve_topology_points_of_curve(); register_node_type_geo_curve_trim(); register_node_type_geo_deform_curves_on_surface(); register_node_type_geo_delete_geometry(); + register_node_type_geo_distribute_points_in_volume(); register_node_type_geo_distribute_points_on_faces(); register_node_type_geo_dual_mesh(); register_node_type_geo_duplicate_elements(); @@ -4748,6 +4783,7 @@ static void registerGeometryNodes() register_node_type_geo_material_replace(); register_node_type_geo_material_selection(); register_node_type_geo_merge_by_distance(); + register_node_type_geo_mesh_face_set_boundaries(); register_node_type_geo_mesh_primitive_circle(); register_node_type_geo_mesh_primitive_cone(); register_node_type_geo_mesh_primitive_cube(); @@ -4760,7 +4796,15 @@ static void registerGeometryNodes() register_node_type_geo_mesh_to_curve(); register_node_type_geo_mesh_to_points(); register_node_type_geo_mesh_to_volume(); + register_node_type_geo_mesh_topology_offset_corner_in_face(); + register_node_type_geo_mesh_topology_corners_of_face(); + register_node_type_geo_mesh_topology_corners_of_vertex(); + register_node_type_geo_mesh_topology_edges_of_corner(); + register_node_type_geo_mesh_topology_edges_of_vertex(); + register_node_type_geo_mesh_topology_face_of_corner(); + register_node_type_geo_mesh_topology_vertex_of_corner(); register_node_type_geo_object_info(); + register_node_type_geo_offset_point_in_curve(); register_node_type_geo_points_to_vertices(); register_node_type_geo_points_to_volume(); register_node_type_geo_points(); @@ -4769,11 +4813,17 @@ static void registerGeometryNodes() register_node_type_geo_realize_instances(); register_node_type_geo_remove_attribute(); register_node_type_geo_rotate_instances(); + register_node_type_geo_sample_index(); + register_node_type_geo_sample_nearest_surface(); + register_node_type_geo_sample_nearest(); + register_node_type_geo_sample_uv_surface(); register_node_type_geo_scale_elements(); register_node_type_geo_scale_instances(); register_node_type_geo_separate_components(); register_node_type_geo_separate_geometry(); + register_node_type_geo_self_object(); register_node_type_geo_set_curve_handles(); + register_node_type_geo_set_curve_normal(); register_node_type_geo_set_curve_radius(); register_node_type_geo_set_curve_tilt(); register_node_type_geo_set_id(); @@ -4789,7 +4839,6 @@ static void registerGeometryNodes() register_node_type_geo_string_to_curves(); register_node_type_geo_subdivision_surface(); register_node_type_geo_switch(); - register_node_type_geo_transfer_attribute(); register_node_type_geo_transform(); register_node_type_geo_translate_instances(); register_node_type_geo_triangulate(); |