Nodes: Replace implementation of select next/prev type operator

The previous code was quadratic; it looped over every link for every
node. For one large node tree I tested the operator took 20ms. On the
same node tree it now takes less than 1ms.

The change replaces the current building of the "dependency list"
on every call with a use of the topology cache from 25e307d725.
This commit is contained in:
Hans Goudey 2022-11-20 13:55:36 -06:00
parent 012895e8a1
commit 984edb2c4e
1 changed files with 35 additions and 48 deletions

View File

@ -1235,65 +1235,52 @@ void NODE_OT_select_linked_from(wmOperatorType *ot)
/** \name Select Same Type Step Operator
* \{ */
static bool nodes_are_same_type_for_select(const bNode &a, const bNode &b)
{
return a.type == b.type;
}
static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
bNode **node_array;
bNode *active = nodeGetActive(snode->edittree);
int totnodes;
const bool revert = RNA_boolean_get(op->ptr, "prev");
const bool prev = RNA_boolean_get(op->ptr, "prev");
bNode &active_node = *nodeGetActive(snode->edittree);
ntreeGetDependencyList(snode->edittree, &node_array, &totnodes);
bNodeTree &node_tree = *snode->edittree;
node_tree.ensure_topology_cache();
if (node_tree.all_nodes().size() == 1) {
return OPERATOR_CANCELLED;
}
if (totnodes > 1) {
int a;
const Span<const bNode *> toposort = node_tree.toposort_left_to_right();
const int index = toposort.first_index(&active_node);
for (a = 0; a < totnodes; a++) {
if (node_array[a] == active) {
break;
}
int new_index = index;
while (true) {
new_index += (prev ? -1 : 1);
if (!toposort.index_range().contains(new_index)) {
return OPERATOR_CANCELLED;
}
bNode *node = nullptr;
while (node == nullptr) {
if (revert) {
a--;
}
else {
a++;
}
if (a < 0 || a >= totnodes) {
break;
}
node = node_array[a];
if (node->type == active->type) {
break;
}
node = nullptr;
}
if (node) {
active = node;
}
node_select_single(*C, *active);
/* is note outside view? */
if (active->runtime->totr.xmax < region->v2d.cur.xmin ||
active->runtime->totr.xmin > region->v2d.cur.xmax ||
active->runtime->totr.ymax < region->v2d.cur.ymin ||
active->runtime->totr.ymin > region->v2d.cur.ymax) {
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
if (nodes_are_same_type_for_select(*toposort[new_index], active_node)) {
break;
}
}
if (node_array) {
MEM_freeN(node_array);
bNode *new_active_node = node_tree.all_nodes()[toposort[new_index]->runtime->index_in_tree];
if (new_active_node == &active_node) {
return OPERATOR_CANCELLED;
}
node_select_single(*C, *new_active_node);
/* is note outside view? */
if (new_active_node->runtime->totr.xmax < region->v2d.cur.xmin ||
new_active_node->runtime->totr.xmin > region->v2d.cur.xmax ||
new_active_node->runtime->totr.ymax < region->v2d.cur.ymin ||
new_active_node->runtime->totr.ymin > region->v2d.cur.ymax) {
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
}
return OPERATOR_FINISHED;