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:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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*/,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user