Fix #104219: Node links are sometimes created from the wrong socket #104420
|
@ -6,6 +6,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "BLI_cache_mutex.hh"
|
#include "BLI_cache_mutex.hh"
|
||||||
|
#include "BLI_math_vector_types.hh"
|
||||||
#include "BLI_multi_value_map.hh"
|
#include "BLI_multi_value_map.hh"
|
||||||
#include "BLI_resource_scope.hh"
|
#include "BLI_resource_scope.hh"
|
||||||
#include "BLI_utility_mixins.hh"
|
#include "BLI_utility_mixins.hh"
|
||||||
|
@ -150,6 +151,13 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
|
||||||
Vector<bNode *> root_frames;
|
Vector<bNode *> root_frames;
|
||||||
Vector<bNodeSocket *> interface_inputs;
|
Vector<bNodeSocket *> interface_inputs;
|
||||||
Vector<bNodeSocket *> interface_outputs;
|
Vector<bNodeSocket *> interface_outputs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of all sockets in the tree, calculated while drawing the nodes.
|
||||||
|
* Indexed with #bNodeSocket::index_in_tree(). In the node tree's "world space"
|
||||||
|
|||||||
|
* (the same as #bNode::runtime::totr).
|
||||||
|
*/
|
||||||
|
Vector<float2> all_socket_locations;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2039,9 +2039,11 @@ static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C,
|
||||||
draw_config.th_col2 = th_col2;
|
draw_config.th_col2 = th_col2;
|
||||||
draw_config.th_col3 = th_col3;
|
draw_config.th_col3 = th_col3;
|
||||||
|
|
||||||
|
const bNodeTree &node_tree = *snode.edittree;
|
||||||
|
|
||||||
draw_config.dim_factor = selected ? 1.0f :
|
draw_config.dim_factor = selected ? 1.0f :
|
||||||
node_link_dim_factor(
|
node_link_dim_factor(
|
||||||
snode.runtime->all_socket_locations, v2d, link);
|
node_tree.runtime->all_socket_locations, v2d, link);
|
||||||
|
|
||||||
bTheme *btheme = UI_GetTheme();
|
bTheme *btheme = UI_GetTheme();
|
||||||
draw_config.dash_alpha = btheme->space_node.dash_alpha;
|
draw_config.dash_alpha = btheme->space_node.dash_alpha;
|
||||||
|
@ -2063,24 +2065,21 @@ static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C,
|
||||||
if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
|
if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
|
||||||
snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
|
snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
|
||||||
PointerRNA from_node_ptr, to_node_ptr;
|
PointerRNA from_node_ptr, to_node_ptr;
|
||||||
RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
|
RNA_pointer_create((ID *)&node_tree, &RNA_Node, link.fromnode, &from_node_ptr);
|
||||||
RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
|
RNA_pointer_create((ID *)&node_tree, &RNA_Node, link.tonode, &to_node_ptr);
|
||||||
|
|
||||||
if (link.fromsock) {
|
if (link.fromsock) {
|
||||||
node_socket_color_get(
|
node_socket_color_get(C, node_tree, from_node_ptr, *link.fromsock, draw_config.start_color);
|
||||||
C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.start_color);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node_socket_color_get(
|
node_socket_color_get(C, node_tree, to_node_ptr, *link.tosock, draw_config.start_color);
|
||||||
C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.start_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link.tosock) {
|
if (link.tosock) {
|
||||||
node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.end_color);
|
node_socket_color_get(C, node_tree, to_node_ptr, *link.tosock, draw_config.end_color);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node_socket_color_get(
|
node_socket_color_get(C, node_tree, from_node_ptr, *link.fromsock, draw_config.end_color);
|
||||||
C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.end_color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2167,8 +2166,9 @@ void node_draw_link_bezier(const bContext &C,
|
||||||
const int th_col3,
|
const int th_col3,
|
||||||
const bool selected)
|
const bool selected)
|
||||||
{
|
{
|
||||||
const std::array<float2, 4> points = node_link_bezier_points(snode.runtime->all_socket_locations,
|
const bNodeTree &node_tree = *snode.edittree;
|
||||||
link);
|
const std::array<float2, 4> points = node_link_bezier_points(
|
||||||
|
node_tree.runtime->all_socket_locations, link);
|
||||||
if (!node_link_draw_is_visible(v2d, points)) {
|
if (!node_link_draw_is_visible(v2d, points)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2227,15 +2227,18 @@ void node_draw_link(const bContext &C,
|
||||||
static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &snode,
|
static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &snode,
|
||||||
const bNodeLink &link)
|
const bNodeLink &link)
|
||||||
{
|
{
|
||||||
|
const bNodeTree &node_tree = *snode.edittree;
|
||||||
const float2 cursor = snode.runtime->cursor * UI_DPI_FAC;
|
const float2 cursor = snode.runtime->cursor * UI_DPI_FAC;
|
||||||
std::array<float2, 4> points;
|
std::array<float2, 4> points;
|
||||||
points[0] = link.fromsock ?
|
points[0] = link.fromsock ?
|
||||||
socket_link_connection_location(
|
socket_link_connection_location(node_tree.runtime->all_socket_locations,
|
||||||
snode.runtime->all_socket_locations, *link.fromnode, *link.fromsock, link) :
|
*link.fromnode,
|
||||||
|
*link.fromsock,
|
||||||
|
link) :
|
||||||
cursor;
|
cursor;
|
||||||
points[3] = link.tosock ?
|
points[3] = link.tosock ?
|
||||||
socket_link_connection_location(
|
socket_link_connection_location(
|
||||||
snode.runtime->all_socket_locations, *link.tonode, *link.tosock, link) :
|
node_tree.runtime->all_socket_locations, *link.tonode, *link.tosock, link) :
|
||||||
cursor;
|
cursor;
|
||||||
calculate_inner_link_bezier_points(points);
|
calculate_inner_link_bezier_points(points);
|
||||||
return points;
|
return points;
|
||||||
|
|
|
@ -138,7 +138,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
|
||||||
const ARegion ®ion = *CTX_wm_region(C);
|
const ARegion ®ion = *CTX_wm_region(C);
|
||||||
SpaceNode &snode = *CTX_wm_space_node(C);
|
SpaceNode &snode = *CTX_wm_space_node(C);
|
||||||
bNodeTree &ntree = *snode.edittree;
|
bNodeTree &ntree = *snode.edittree;
|
||||||
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
|
const Span<float2> socket_locations = ntree.runtime->all_socket_locations;
|
||||||
|
|
||||||
Vector<float2> path;
|
Vector<float2> path;
|
||||||
RNA_BEGIN (op->ptr, itemptr, "path") {
|
RNA_BEGIN (op->ptr, itemptr, "path") {
|
||||||
|
|
|
@ -268,6 +268,9 @@ void node_sort(bNodeTree &ntree)
|
||||||
ntree.runtime->nodes_by_id.add_new(sort_nodes[i]);
|
ntree.runtime->nodes_by_id.add_new(sort_nodes[i]);
|
||||||
sort_nodes[i]->runtime->index_in_tree = i;
|
sort_nodes[i]->runtime->index_in_tree = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Nodes have been reordered; the socket locations are invalid until the node tree is redrawn. */
|
||||||
|
ntree.runtime->all_socket_locations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Array<uiBlock *> node_uiblocks_init(const bContext &C, const Span<bNode *> nodes)
|
static Array<uiBlock *> node_uiblocks_init(const bContext &C, const Span<bNode *> nodes)
|
||||||
|
@ -3178,16 +3181,16 @@ static void draw_nodetree(const bContext &C,
|
||||||
else if (ntree.type == NTREE_COMPOSIT) {
|
else if (ntree.type == NTREE_COMPOSIT) {
|
||||||
tree_draw_ctx.used_by_realtime_compositor = realtime_compositor_is_in_use(C);
|
tree_draw_ctx.used_by_realtime_compositor = realtime_compositor_is_in_use(C);
|
||||||
}
|
}
|
||||||
snode->runtime->all_socket_locations.reinitialize(ntree.all_sockets().size());
|
ntree.runtime->all_socket_locations.reinitialize(ntree.all_sockets().size());
|
||||||
|
|
||||||
node_update_nodetree(
|
node_update_nodetree(
|
||||||
C, tree_draw_ctx, ntree, nodes, blocks, snode->runtime->all_socket_locations);
|
C, tree_draw_ctx, ntree, nodes, blocks, ntree.runtime->all_socket_locations);
|
||||||
node_draw_nodetree(C,
|
node_draw_nodetree(C,
|
||||||
tree_draw_ctx,
|
tree_draw_ctx,
|
||||||
region,
|
region,
|
||||||
*snode,
|
*snode,
|
||||||
ntree,
|
ntree,
|
||||||
snode->runtime->all_socket_locations,
|
ntree.runtime->all_socket_locations,
|
||||||
nodes,
|
nodes,
|
||||||
blocks,
|
blocks,
|
||||||
parent_key);
|
parent_key);
|
||||||
|
|
|
@ -1129,13 +1129,14 @@ bNodeSocket *node_find_indicated_socket(SpaceNode &snode,
|
||||||
rctf rect;
|
rctf rect;
|
||||||
const float size_sock_padded = NODE_SOCKSIZE + 4;
|
const float size_sock_padded = NODE_SOCKSIZE + 4;
|
||||||
|
|
||||||
snode.edittree->ensure_topology_cache();
|
bNodeTree &node_tree = *snode.edittree;
|
||||||
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
|
node_tree.ensure_topology_cache();
|
||||||
if (socket_locations.size() != snode.edittree->all_sockets().size()) {
|
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
|
||||||
|
if (socket_locations.size() != node_tree.all_sockets().size()) {
|
||||||
/* Sockets haven't been drawn yet, e.g. when the file is currently opening. */
|
/* Sockets haven't been drawn yet, e.g. when the file is currently opening. */
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const Span<bNode *> nodes = snode.edittree->all_nodes();
|
const Span<bNode *> nodes = node_tree.all_nodes();
|
||||||
if (nodes.is_empty()) {
|
if (nodes.is_empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,6 @@ struct bNodeLinkDrag {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpaceNode_Runtime {
|
struct SpaceNode_Runtime {
|
||||||
/**
|
|
||||||
* The location of all sockets in the tree, calculated while drawing the nodes.
|
|
||||||
* To be indexed with #bNodeSocket::index_in_tree().
|
|
||||||
*/
|
|
||||||
Vector<float2> all_socket_locations;
|
|
||||||
|
|
||||||
float aspect;
|
float aspect;
|
||||||
|
|
||||||
/** Mouse position for drawing socket-less links and adding nodes. */
|
/** Mouse position for drawing socket-less links and adding nodes. */
|
||||||
|
|
|
@ -121,7 +121,11 @@ static void pick_input_link_by_link_intersect(const bContext &C,
|
||||||
const float2 &cursor)
|
const float2 &cursor)
|
||||||
{
|
{
|
||||||
SpaceNode *snode = CTX_wm_space_node(&C);
|
SpaceNode *snode = CTX_wm_space_node(&C);
|
||||||
const Span<float2> socket_locations = snode->runtime->all_socket_locations;
|
bNodeTree &node_tree = *snode->edittree;
|
||||||
|
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
|
||||||
|
if (socket_locations.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float2 drag_start;
|
float2 drag_start;
|
||||||
RNA_float_get_array(op.ptr, "drag_start", drag_start);
|
RNA_float_get_array(op.ptr, "drag_start", drag_start);
|
||||||
|
@ -132,7 +136,7 @@ static void pick_input_link_by_link_intersect(const bContext &C,
|
||||||
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
|
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
|
||||||
|
|
||||||
bNodeLink *link_to_pick = nullptr;
|
bNodeLink *link_to_pick = nullptr;
|
||||||
clear_picking_highlight(&snode->edittree->links);
|
clear_picking_highlight(&node_tree.links);
|
||||||
for (bNodeLink *link : socket->directly_linked_links()) {
|
for (bNodeLink *link : socket->directly_linked_links()) {
|
||||||
/* Test if the cursor is near a link. */
|
/* Test if the cursor is near a link. */
|
||||||
std::array<float2, NODE_LINK_RESOL + 1> coords;
|
std::array<float2, NODE_LINK_RESOL + 1> coords;
|
||||||
|
@ -643,7 +647,7 @@ static int view_socket(const bContext &C,
|
||||||
}
|
}
|
||||||
if (viewer_node == nullptr) {
|
if (viewer_node == nullptr) {
|
||||||
const float2 socket_location =
|
const float2 socket_location =
|
||||||
snode.runtime->all_socket_locations[bsocket_to_view.index_in_tree()];
|
btree.runtime->all_socket_locations[bsocket_to_view.index_in_tree()];
|
||||||
const int viewer_type = get_default_viewer_type(&C);
|
const int viewer_type = get_default_viewer_type(&C);
|
||||||
const float2 location{socket_location.x / UI_DPI_FAC + 100, socket_location.y / UI_DPI_FAC};
|
const float2 location{socket_location.x / UI_DPI_FAC + 100, socket_location.y / UI_DPI_FAC};
|
||||||
viewer_node = add_static_node(C, viewer_type, location);
|
viewer_node = add_static_node(C, viewer_type, location);
|
||||||
|
@ -1072,7 +1076,12 @@ static void node_link_cancel(bContext *C, wmOperator *op)
|
||||||
static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
|
static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
|
||||||
{
|
{
|
||||||
SpaceNode &snode = *CTX_wm_space_node(&C);
|
SpaceNode &snode = *CTX_wm_space_node(&C);
|
||||||
|
bNodeTree &node_tree = *snode.edittree;
|
||||||
bNodeLinkDrag &nldrag = *static_cast<bNodeLinkDrag *>(op.customdata);
|
bNodeLinkDrag &nldrag = *static_cast<bNodeLinkDrag *>(op.customdata);
|
||||||
|
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
|
||||||
|
if (socket_locations.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (nldrag.in_out == SOCK_OUT) {
|
if (nldrag.in_out == SOCK_OUT) {
|
||||||
if (bNodeSocket *tsock = node_find_indicated_socket(snode, cursor, SOCK_IN)) {
|
if (bNodeSocket *tsock = node_find_indicated_socket(snode, cursor, SOCK_IN)) {
|
||||||
|
@ -1103,8 +1112,7 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (tsock && tsock->is_multi_input()) {
|
if (tsock && tsock->is_multi_input()) {
|
||||||
sort_multi_input_socket_links_with_drag(
|
sort_multi_input_socket_links_with_drag(socket_locations, *tsock, link, cursor);
|
||||||
snode.runtime->all_socket_locations, *tsock, link, cursor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1477,7 +1485,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
|
||||||
|
|
||||||
bNodeTree &node_tree = *snode.edittree;
|
bNodeTree &node_tree = *snode.edittree;
|
||||||
node_tree.ensure_topology_cache();
|
node_tree.ensure_topology_cache();
|
||||||
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
|
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
|
||||||
|
|
||||||
Set<bNodeLink *> links_to_remove;
|
Set<bNodeLink *> links_to_remove;
|
||||||
LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
|
LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
|
||||||
|
@ -1563,7 +1571,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
|
||||||
SpaceNode &snode = *CTX_wm_space_node(C);
|
SpaceNode &snode = *CTX_wm_space_node(C);
|
||||||
const ARegion ®ion = *CTX_wm_region(C);
|
const ARegion ®ion = *CTX_wm_region(C);
|
||||||
bNodeTree &ntree = *snode.edittree;
|
bNodeTree &ntree = *snode.edittree;
|
||||||
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
|
const Span<float2> socket_locations = ntree.runtime->all_socket_locations;
|
||||||
|
|
||||||
Vector<float2> path;
|
Vector<float2> path;
|
||||||
RNA_BEGIN (op->ptr, itemptr, "path") {
|
RNA_BEGIN (op->ptr, itemptr, "path") {
|
||||||
|
@ -2046,7 +2054,10 @@ void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion)
|
||||||
{
|
{
|
||||||
bNodeTree &node_tree = *snode.edittree;
|
bNodeTree &node_tree = *snode.edittree;
|
||||||
node_tree.ensure_topology_cache();
|
node_tree.ensure_topology_cache();
|
||||||
const Span<float2> socket_locations = snode.runtime->all_socket_locations;
|
const Span<float2> socket_locations = node_tree.runtime->all_socket_locations;
|
||||||
|
if (socket_locations.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
node_insert_on_link_flags_clear(node_tree);
|
node_insert_on_link_flags_clear(node_tree);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
This should mention which coordinate space is used.