Files
test2/source/blender/blenloader/intern/versioning_common.cc
Hans Goudey fc06a471f1 Geometry Nodes: Only use realized geometry in mesh boolean node
Since 44e4f077a9 and related commits, geometry nodes doesn't
try to hide the difference between real geometry data and instances from
the user. Other nodes were updated to only support real geometry, but
the "Mesh Boolean" node was never updated and still implicitly gathered
all the instances. This commit removes the special instance behavior in the
boolean node and adds realize instances nodes to keep existing behavior
in most cases. Typically this doesn't make a difference in the result,
though it could in the union mode for instance inputs. Shifting more of
the work to realizing instances should generally be better for
performance, since it's much faster.
2023-05-18 15:08:53 -04:00

326 lines
10 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup blenloader
*/
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
#include <cstring>
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#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.hh"
#include "BKE_node_runtime.hh"
#include "MEM_guardedalloc.h"
#include "versioning_common.h"
using blender::Map;
using blender::StringRef;
ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
int region_type,
const char *allocname,
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<ARegion *>(MEM_callocN(sizeof(ARegion), allocname));
new_region->regiontype = region_type;
BLI_insertlinkafter(regionbase, link_after_region, new_region);
return new_region;
}
ARegion *do_versions_ensure_region(ListBase *regionbase,
int region_type,
const char *allocname,
int link_after_region_type)
{
ARegion *link_after_region = nullptr;
LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == region_type) {
return region;
}
if (region->regiontype == link_after_region_type) {
link_after_region = region;
}
}
ARegion *new_region = MEM_cnew<ARegion>(allocname);
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)) {
STRNCPY(socket->name, new_name);
}
if (STREQ(socket->identifier, old_name)) {
STRNCPY(socket->identifier, new_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)
{
for (bNode *node : ntree->all_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)
{
for (bNode *node : ntree->all_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)
{
for (bNode *node : ntree->all_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)
{
for (bNode *node : ntree->all_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.cc 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;
}
for (bNode *node : ntree->all_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)
{
for (bNode *node : ntree->all_nodes()) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
socket->flag &= ~SOCK_IS_LINKED;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
socket->flag &= ~SOCK_IS_LINKED;
}
}
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
link->fromsock->flag |= SOCK_IS_LINKED;
link->tosock->flag |= SOCK_IS_LINKED;
}
}
ARegion *do_versions_add_region(int regiontype, const char *name)
{
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), name);
region->regiontype = regiontype;
return region;
}
void node_tree_relink_with_socket_id_map(bNodeTree &ntree,
bNode &old_node,
bNode &new_node,
const Map<std::string, std::string> &map)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
if (link->tonode == &old_node) {
bNodeSocket *old_socket = link->tosock;
if (const std::string *new_identifier = map.lookup_ptr_as(old_socket->identifier)) {
bNodeSocket *new_socket = nodeFindSocket(&new_node, SOCK_IN, new_identifier->c_str());
link->tonode = &new_node;
link->tosock = new_socket;
old_socket->link = nullptr;
}
}
if (link->fromnode == &old_node) {
bNodeSocket *old_socket = link->fromsock;
if (const std::string *new_identifier = map.lookup_ptr_as(old_socket->identifier)) {
bNodeSocket *new_socket = nodeFindSocket(&new_node, SOCK_OUT, new_identifier->c_str());
link->fromnode = &new_node;
link->fromsock = new_socket;
old_socket->link = nullptr;
}
}
}
}
static blender::Vector<bNodeLink *> find_connected_links(bNodeTree *ntree, bNodeSocket *in_socket)
{
blender::Vector<bNodeLink *> links;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->tosock == in_socket) {
links.append(link);
}
}
return links;
}
void add_realize_instances_before_socket(bNodeTree *ntree,
bNode *node,
bNodeSocket *geometry_socket)
{
BLI_assert(geometry_socket->type == SOCK_GEOMETRY);
blender::Vector<bNodeLink *> links = find_connected_links(ntree, geometry_socket);
for (bNodeLink *link : links) {
/* If the realize instances node is already before this socket, no need to continue. */
if (link->fromnode->type == GEO_NODE_REALIZE_INSTANCES) {
return;
}
bNode *realize_node = nodeAddStaticNode(nullptr, ntree, GEO_NODE_REALIZE_INSTANCES);
realize_node->parent = node->parent;
realize_node->locx = node->locx - 100;
realize_node->locy = node->locy;
nodeAddLink(ntree,
link->fromnode,
link->fromsock,
realize_node,
static_cast<bNodeSocket *>(realize_node->inputs.first));
link->fromnode = realize_node;
link->fromsock = static_cast<bNodeSocket *>(realize_node->outputs.first);
}
}