/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup blenloader */ /* allow readfile to use deprecated functionality */ #define DNA_DEPRECATED_ALLOW #include #include "DNA_node_types.h" #include "DNA_screen_types.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_ref.hh" #include "BKE_animsys.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_main_namemap.h" #include "BKE_node.h" #include "MEM_guardedalloc.h" #include "versioning_common.h" using blender::StringRef; ARegion *do_versions_add_region_if_not_found(ListBase *regionbase, int region_type, const char *name, int link_after_region_type) { ARegion *link_after_region = nullptr; LISTBASE_FOREACH (ARegion *, region, regionbase) { if (region->regiontype == region_type) { return nullptr; } if (region->regiontype == link_after_region_type) { link_after_region = region; } } ARegion *new_region = static_cast(MEM_callocN(sizeof(ARegion), name)); new_region->regiontype = region_type; BLI_insertlinkafter(regionbase, link_after_region, new_region); return new_region; } ID *do_versions_rename_id(Main *bmain, const short id_type, const char *name_src, const char *name_dst) { /* We can ignore libraries */ ListBase *lb = which_libbase(bmain, id_type); ID *id = nullptr; LISTBASE_FOREACH (ID *, idtest, lb) { if (!ID_IS_LINKED(idtest)) { if (STREQ(idtest->name + 2, name_src)) { id = idtest; } if (STREQ(idtest->name + 2, name_dst)) { return nullptr; } } } if (id != nullptr) { BKE_main_namemap_remove_name(bmain, id, id->name + 2); BLI_strncpy(id->name + 2, name_dst, sizeof(id->name) - 2); /* We know it's unique, this just sorts. */ BLI_libblock_ensure_unique_name(bmain, id->name); } return id; } static void change_node_socket_name(ListBase *sockets, const char *old_name, const char *new_name) { LISTBASE_FOREACH (bNodeSocket *, socket, sockets) { if (STREQ(socket->name, old_name)) { BLI_strncpy(socket->name, new_name, sizeof(socket->name)); } if (STREQ(socket->identifier, old_name)) { BLI_strncpy(socket->identifier, new_name, sizeof(socket->name)); } } } void version_node_socket_id_delim(bNodeSocket *socket) { StringRef name = socket->name; StringRef id = socket->identifier; if (!id.startswith(name)) { /* We only need to affect the case where the identifier starts with the name. */ return; } StringRef id_number = id.drop_known_prefix(name); if (id_number.is_empty()) { /* The name was already unique, and didn't need numbers at the end for the id. */ return; } if (id_number.startswith(".")) { socket->identifier[name.size()] = '_'; } } void version_node_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { change_node_socket_name(&node->inputs, old_name, new_name); change_node_socket_name(&node->outputs, old_name, new_name); } } } void version_node_input_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { change_node_socket_name(&node->inputs, old_name, new_name); } } } void version_node_output_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { change_node_socket_name(&node->outputs, old_name, new_name); } } } bNodeSocket *version_node_add_socket_if_not_exist(bNodeTree *ntree, bNode *node, eNodeSocketInOut in_out, int type, int subtype, const char *identifier, const char *name) { bNodeSocket *sock = nodeFindSocket(node, in_out, identifier); if (sock != nullptr) { return sock; } return nodeAddStaticSocket(ntree, node, in_out, type, subtype, identifier, name); } void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { if (!STREQ(node->idname, new_name)) { strcpy(node->idname, new_name); } } } } void version_node_socket_index_animdata(Main *bmain, const int node_tree_type, const int node_type, const int socket_index_orig, const int socket_index_offset, const int total_number_of_sockets) { /* The for loop for the input ids is at the top level otherwise we lose the animation * keyframe data. Not sure what causes that, so I (Sybren) moved the code here from * versioning_290.c as-is (structure-wise). */ for (int input_index = total_number_of_sockets - 1; input_index >= socket_index_orig; input_index--) { FOREACH_NODETREE_BEGIN (bmain, ntree, owner_id) { if (ntree->type != node_tree_type) { continue; } LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type != node_type) { continue; } const size_t node_name_length = strlen(node->name); const size_t node_name_escaped_max_length = (node_name_length * 2); char *node_name_escaped = (char *)MEM_mallocN(node_name_escaped_max_length + 1, "escaped name"); BLI_str_escape(node_name_escaped, node->name, node_name_escaped_max_length); char *rna_path_prefix = BLI_sprintfN("nodes[\"%s\"].inputs", node_name_escaped); const int new_index = input_index + socket_index_offset; BKE_animdata_fix_paths_rename_all_ex( bmain, owner_id, rna_path_prefix, nullptr, nullptr, input_index, new_index, false); MEM_freeN(rna_path_prefix); MEM_freeN(node_name_escaped); } } FOREACH_NODETREE_END; } } void version_socket_update_is_used(bNodeTree *ntree) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { socket->flag &= ~SOCK_IN_USE; } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { socket->flag &= ~SOCK_IN_USE; } } LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { link->fromsock->flag |= SOCK_IN_USE; link->tosock->flag |= SOCK_IN_USE; } } ARegion *do_versions_add_region(int regiontype, const char *name) { ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), name); region->regiontype = regiontype; return region; }