Fix: Various mishandling of node identifiers and vector

In a few places, nodes were added without updating the Identifiers and
vector. In other places nodes we removed without removing from and
rebuilding the vector. This is solved in a few ways. First I exposed
a function to rebuild the vector from scratch, and added unique ID
finding to a few places.

The changes to node group building and separating are more involved,
mostly because it was hard to see the correct behavior without some
refactoring. Now `VectorSet` is used to store nodes involved in the
operation. Some things are handled more simply with the topology
cache and by passing a span of nodes.
This commit is contained in:
2022-12-02 13:20:40 -06:00
parent 948f13a8e7
commit ab4926bcff
9 changed files with 199 additions and 202 deletions

View File

@@ -670,6 +670,13 @@ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueID(struct bNodeTree *ntree, struct bNode *node);
/**
* Rebuild the `node_by_id` runtime vector set. Call after removing a node if not handled
* separately. This is important instead of just using `nodes_by_id.remove()` since it maintains
* the node order.
*/
void nodeRebuildIDVector(struct bNodeTree *node_tree);
/**
* Delete node, associated animation data and ID user count.
*/

View File

@@ -2933,12 +2933,12 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
}
}
static void rebuild_nodes_vector(bNodeTree &node_tree)
void nodeRebuildIDVector(bNodeTree *node_tree)
{
/* Rebuild nodes #VectorSet which must have the same order as the list. */
node_tree.runtime->nodes_by_id.clear();
LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node_tree.runtime->nodes_by_id.add_new(node);
node_tree->runtime->nodes_by_id.clear();
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
node_tree->runtime->nodes_by_id.add_new(node);
}
}
@@ -2955,7 +2955,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
if (ntree) {
BLI_remlink(&ntree->nodes, node);
/* Rebuild nodes #VectorSet which must have the same order as the list. */
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
/* texture node has bad habit of keeping exec data around */
if (ntree->type == NTREE_TEXTURE && ntree->runtime->execdata) {
@@ -3013,7 +3013,7 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
node_unlink_attached(ntree, node);
node_free_node(ntree, node);
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
}
void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
@@ -3073,7 +3073,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
/* Free node itself. */
node_free_node(ntree, node);
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
}
static void node_socket_interface_free(bNodeTree * /*ntree*/,

View File

@@ -2001,6 +2001,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
*/
link = MEM_callocN(sizeof(bNodeLink), "link");
BLI_addtail(&ntree->links, link);
nodeUniqueID(ntree, node);
link->fromnode = NULL;
link->fromsock = gsock;
link->tonode = node;
@@ -2024,6 +2025,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
*/
link = MEM_callocN(sizeof(bNodeLink), "link");
BLI_addtail(&ntree->links, link);
nodeUniqueID(ntree, node);
link->fromnode = node;
link->fromsock = sock;
link->tonode = NULL;

View File

@@ -2795,7 +2795,7 @@ static bool node_shader_script_update_text_recursive(RenderEngine *engine,
RenderEngineType *type,
bNodeTree *ntree,
Text *text,
Set<bNodeTree *> &done_trees)
VectorSet<bNodeTree *> &done_trees)
{
bool found = false;
@@ -2855,7 +2855,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
if (text) {
Set<bNodeTree *> done_trees;
VectorSet<bNodeTree *> done_trees;
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {

View File

@@ -269,6 +269,7 @@ static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
node->flag |= NODE_SELECT;
}
wgroup->runtime->nodes_by_id.clear();
bNodeLink *glinks_first = (bNodeLink *)ntree->links.last;
@@ -446,30 +447,24 @@ static bool node_group_separate_selected(
ListBase anim_basepaths = {nullptr, nullptr};
Map<const bNode *, bNode *> node_map;
Map<const bNodeSocket *, bNodeSocket *> socket_map;
/* add selected nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
continue;
}
/* ignore interface nodes */
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
nodeSetSelected(node, false);
continue;
}
/* Add selected nodes into the ntree, ignoring interface nodes. */
VectorSet<bNode *> nodes_to_move = get_selected_nodes(ngroup);
nodes_to_move.remove_if(
[](const bNode *node) { return node->is_group_input() || node->is_group_output(); });
for (bNode *node : nodes_to_move) {
bNode *newnode;
if (make_copy) {
/* make a copy */
newnode = bke::node_copy_with_mapping(&ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, newnode);
newnode = bke::node_copy_with_mapping(&ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
}
else {
/* use the existing node */
newnode = node;
BLI_remlink(&ngroup.nodes, newnode);
BLI_addtail(&ntree.nodes, newnode);
nodeUniqueID(&ntree, newnode);
nodeUniqueName(&ntree, newnode);
}
/* Keep track of this node's RNA "base" path (the part of the path identifying the node)
@@ -491,17 +486,14 @@ static bool node_group_separate_selected(
nodeDetachNode(&ngroup, newnode);
}
/* migrate node */
BLI_remlink(&ngroup.nodes, newnode);
BLI_addtail(&ntree.nodes, newnode);
nodeUniqueID(&ntree, newnode);
nodeUniqueName(&ntree, newnode);
if (!newnode->parent) {
newnode->locx += offset.x;
newnode->locy += offset.y;
}
}
if (!make_copy) {
nodeRebuildIDVector(&ngroup);
}
/* add internal links to the ntree */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
@@ -512,9 +504,9 @@ static bool node_group_separate_selected(
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
node_map.lookup(link->fromnode),
ntree.node_by_id(link->fromnode->identifier),
socket_map.lookup(link->fromsock),
node_map.lookup(link->tonode),
ntree.node_by_id(link->tonode->identifier),
socket_map.lookup(link->tosock));
}
}
@@ -642,97 +634,97 @@ void NODE_OT_group_separate(wmOperatorType *ot)
/** \name Make Group Operator
* \{ */
static bool node_group_make_use_node(const bNode &node, bNode *gnode)
static VectorSet<bNode *> get_nodes_to_group(bNodeTree &node_tree, bNode *group_node)
{
return (&node != gnode && !ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
(node.flag & NODE_SELECT));
VectorSet<bNode *> nodes_to_group = get_selected_nodes(node_tree);
nodes_to_group.remove_if(
[](bNode *node) { return node->is_group_input() || node->is_group_output(); });
nodes_to_group.remove(group_node);
return nodes_to_group;
}
static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const VectorSet<bNode *> &nodes_to_group,
const char *ntree_idname,
ReportList &reports)
{
int ok = true;
if (nodes_to_group.is_empty()) {
return false;
}
/* make a local pseudo node tree to pass to the node poll functions */
bNodeTree *ngroup = ntreeAddTree(nullptr, "Pseudo Node Group", ntree_idname);
BLI_SCOPED_DEFER([&]() {
ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
});
/* check poll functions for selected nodes */
for (bNode *node : ntree.all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
ok = false;
break;
for (bNode *node : nodes_to_group) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
return false;
}
node->runtime->done = 0;
}
/* free local pseudo node tree again */
ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
if (!ok) {
return false;
}
/* check if all connections are OK, no unselected node has both
* inputs and outputs to a selection */
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (node_group_make_use_node(*link->fromnode, gnode)) {
link->tonode->runtime->done |= 1;
}
if (node_group_make_use_node(*link->tonode, gnode)) {
link->fromnode->runtime->done |= 2;
}
}
ntree.ensure_topology_cache();
for (bNode *node : ntree.all_nodes()) {
if (!(node->flag & NODE_SELECT) && node != gnode && node->runtime->done == 3) {
if (nodes_to_group.contains(node)) {
continue;
}
auto sockets_connected_to_group = [&](const Span<bNodeSocket *> sockets) {
for (const bNodeSocket *socket : sockets) {
for (const bNodeSocket *other_socket : socket->directly_linked_sockets()) {
if (nodes_to_group.contains(const_cast<bNode *>(&other_socket->owner_node()))) {
return true;
}
}
}
return false;
};
if (sockets_connected_to_group(node->input_sockets()) &&
sockets_connected_to_group(node->output_sockets())) {
return false;
}
}
return true;
}
static int node_get_selected_minmax(
bNodeTree &ntree, bNode *gnode, float2 &min, float2 &max, bool use_size)
static void get_min_max_of_nodes(const Span<bNode *> nodes,
const bool use_size,
float2 &min,
float2 &max)
{
int totselect = 0;
if (nodes.is_empty()) {
min = float2(0);
max = float2(0);
return;
}
INIT_MINMAX2(min, max);
for (const bNode *node : ntree.all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
float2 loc;
nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y);
for (const bNode *node : nodes) {
float2 loc;
nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y);
math::min_max(loc, min, max);
if (use_size) {
loc.x += node->width;
loc.y -= node->height;
math::min_max(loc, min, max);
if (use_size) {
loc.x += node->width;
loc.y -= node->height;
math::min_max(loc, min, max);
}
totselect++;
}
}
/* sane min/max if no selected nodes */
if (totselect == 0) {
min[0] = min[1] = max[0] = max[1] = 0.0f;
}
return totselect;
}
/**
@@ -803,11 +795,14 @@ static void node_group_make_redirect_incoming_link(
}
}
static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode)
static void node_group_make_insert_selected(const bContext &C,
bNodeTree &ntree,
bNode *gnode,
const VectorSet<bNode *> &nodes_to_move)
{
Main *bmain = CTX_data_main(&C);
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bool expose_visible = false;
BLI_assert(!nodes_to_move.contains(gnode));
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
static const float offsetx = 200;
@@ -818,18 +813,16 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
nodeSetSelected(node, false);
}
/* auto-add interface for "solo" nodes */
const bool expose_visible = nodes_to_move.size() == 1;
float2 center, min, max;
const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
get_min_max_of_nodes(nodes_to_move, false, min, max);
add_v2_v2v2(center, min, max);
mul_v2_fl(center, 0.5f);
float2 real_min, real_max;
node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
expose_visible = true;
}
get_min_max_of_nodes(nodes_to_move, true, real_min, real_max);
ListBase anim_basepaths = {nullptr, nullptr};
@@ -839,44 +832,42 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
if (node->parent == nullptr) {
continue;
}
if (node_group_make_use_node(*node->parent, gnode) &&
!node_group_make_use_node(*node, gnode)) {
if (nodes_to_move.contains(node->parent) && nodes_to_move.contains(node)) {
nodeDetachNode(&ntree, node);
}
}
/* move nodes over */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
if (node_group_make_use_node(*node, gnode)) {
/* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
for (bNode *node : nodes_to_move) {
/* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
}
if (path) {
BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
}
/* ensure valid parent pointers, detach if parent stays outside the group */
if (node->parent && !(node->parent->flag & NODE_SELECT)) {
nodeDetachNode(&ntree, node);
}
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
nodeUniqueID(ngroup, node);
nodeUniqueName(ngroup, node);
BKE_ntree_update_tag_node_removed(&ntree);
BKE_ntree_update_tag_node_new(ngroup, node);
}
/* ensure valid parent pointers, detach if parent stays outside the group */
if (node->parent && !(node->parent->flag & NODE_SELECT)) {
nodeDetachNode(&ntree, node);
}
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
nodeUniqueID(ngroup, node);
nodeUniqueName(ngroup, node);
BKE_ntree_update_tag_node_removed(&ntree);
BKE_ntree_update_tag_node_new(ngroup, node);
}
nodeRebuildIDVector(&ntree);
/* move animation data over */
if (ntree.adt) {
@@ -904,8 +895,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
Map<bNodeSocket *, bNodeSocket *> reusable_sockets;
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
const bool toselect = node_group_make_use_node(*link->tonode, gnode);
const bool fromselect = nodes_to_move.contains(link->fromnode);
const bool toselect = nodes_to_move.contains(link->tonode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
@@ -969,8 +960,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* move internal links */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
const bool toselect = node_group_make_use_node(*link->tonode, gnode);
const bool fromselect = nodes_to_move.contains(link->fromnode);
const bool toselect = nodes_to_move.contains(link->tonode);
if (fromselect && toselect) {
BLI_remlink(&ntree.links, link);
@@ -979,8 +970,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
}
/* move nodes in the group to the center */
for (bNode *node : ngroup->all_nodes()) {
if (node_group_make_use_node(*node, gnode) && !node->parent) {
for (bNode *node : nodes_to_move) {
if (!node->parent) {
node->locx -= center[0];
node->locy -= center[1];
}
@@ -988,73 +979,67 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* Expose all unlinked sockets too but only the visible ones. */
if (expose_visible) {
for (bNode *node : ngroup->all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->tosock == sock) {
skip = true;
break;
}
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
for (bNode *node : nodes_to_move) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->tosock == sock) {
skip = true;
break;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_input_update(ngroup, input_node);
/* create new internal link */
bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
nodeAddLink(ngroup, input_node, input_sock, node, sock);
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
skip = true;
}
if (skip) {
continue;
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->fromsock == sock) {
skip = true;
}
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_input_update(ngroup, input_node);
/* create new internal link */
bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
nodeAddLink(ngroup, input_node, input_sock, node, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->fromsock == sock) {
skip = true;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_output_update(ngroup, output_node);
/* create new internal link */
bNodeSocket *output_sock = node_group_output_find_socket(output_node,
iosock->identifier);
nodeAddLink(ngroup, node, sock, output_node, output_sock);
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
skip = true;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_output_update(ngroup, output_node);
/* create new internal link */
bNodeSocket *output_sock = node_group_output_find_socket(output_node, iosock->identifier);
nodeAddLink(ngroup, node, sock, output_node, output_sock);
}
}
}
}
static bNode *node_group_make_from_selected(const bContext &C,
bNodeTree &ntree,
const char *ntype,
const char *ntreetype)
static bNode *node_group_make_from_nodes(const bContext &C,
bNodeTree &ntree,
const VectorSet<bNode *> &nodes_to_group,
const char *ntype,
const char *ntreetype)
{
Main *bmain = CTX_data_main(&C);
float2 min, max;
const int totselect = node_get_selected_minmax(ntree, nullptr, min, max, false);
/* don't make empty group */
if (totselect == 0) {
return nullptr;
}
get_min_max_of_nodes(nodes_to_group, false, min, max);
/* New node-tree. */
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
@@ -1066,7 +1051,7 @@ static bNode *node_group_make_from_selected(const bContext &C,
gnode->locx = 0.5f * (min[0] + max[0]);
gnode->locy = 0.5f * (min[1] + max[1]);
node_group_make_insert_selected(C, ntree, gnode);
node_group_make_insert_selected(C, ntree, gnode, nodes_to_group);
return gnode;
}
@@ -1081,11 +1066,12 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, *op->reports)) {
VectorSet<bNode *> nodes_to_group = get_nodes_to_group(ntree, nullptr);
if (!node_group_make_test_selected(ntree, nodes_to_group, ntree_idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
bNode *gnode = node_group_make_from_selected(*C, ntree, node_idname, ntree_idname);
bNode *gnode = node_group_make_from_nodes(*C, ntree, nodes_to_group, node_idname, ntree_idname);
if (gnode) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
@@ -1137,17 +1123,17 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *gnode = node_group_get_active(C, node_idname);
if (!gnode || !gnode->id) {
return OPERATOR_CANCELLED;
}
bNodeTree *ngroup = (bNodeTree *)gnode->id;
if (!node_group_make_test_selected(*ntree, gnode, ngroup->idname, *op->reports)) {
VectorSet<bNode *> nodes_to_group = get_nodes_to_group(*ntree, gnode);
if (!node_group_make_test_selected(*ntree, nodes_to_group, ngroup->idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
node_group_make_insert_selected(*C, *ntree, gnode);
node_group_make_insert_selected(*C, *ntree, gnode, nodes_to_group);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);

View File

@@ -9,8 +9,8 @@
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "BKE_node.h"
@@ -183,7 +183,7 @@ void node_keymap(wmKeyConfig *keyconf);
rctf node_frame_rect_inside(const bNode &node);
bool node_or_socket_isect_event(const bContext &C, const wmEvent &event);
Set<bNode *> get_selected_nodes(bNodeTree &node_tree);
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree);
void node_deselect_all(SpaceNode &snode);
void node_socket_select(bNode *node, bNodeSocket &sock);
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);

View File

@@ -1637,7 +1637,7 @@ void NODE_OT_parent_set(wmOperatorType *ot)
static void node_join_attach_recursive(bNodeTree &ntree,
bNode *node,
bNode *frame,
const Set<bNode *> &selected_nodes)
const VectorSet<bNode *> &selected_nodes)
{
node->runtime->done |= NODE_JOIN_DONE;
@@ -1673,7 +1673,7 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/)
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
const Set<bNode *> selected_nodes = get_selected_nodes(ntree);
const VectorSet<bNode *> selected_nodes = get_selected_nodes(ntree);
bNode *frame_node = nodeAddStaticNode(C, &ntree, NODE_FRAME);
nodeSetActive(&ntree, frame_node);

View File

@@ -312,9 +312,9 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node
}
}
Set<bNode *> get_selected_nodes(bNodeTree &node_tree)
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree)
{
Set<bNode *> selected_nodes;
VectorSet<bNode *> selected_nodes;
for (bNode *node : node_tree.all_nodes()) {
if (node->flag & NODE_SELECT) {
selected_nodes.add(node);
@@ -1142,7 +1142,7 @@ static int node_select_linked_to_exec(bContext *C, wmOperator * /*op*/)
node_tree.ensure_topology_cache();
Set<bNode *> initial_selection = get_selected_nodes(node_tree);
VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
for (bNode *node : initial_selection) {
for (bNodeSocket *output_socket : node->output_sockets()) {
@@ -1192,7 +1192,7 @@ static int node_select_linked_from_exec(bContext *C, wmOperator * /*op*/)
node_tree.ensure_topology_cache();
Set<bNode *> initial_selection = get_selected_nodes(node_tree);
VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
for (bNode *node : initial_selection) {
for (bNodeSocket *input_socket : node->input_sockets()) {

View File

@@ -446,10 +446,12 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&ngroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
nodeUniqueID(ntree, node);
/* ensure unique node name in the node tree */
/* This is very slow and it has no use for GPU nodetree. (see T70609) */
// nodeUniqueName(ntree, node);
}
ngroup->runtime->nodes_by_id.clear();
/* Save first and last link to iterate over flattened group links. */
bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last);