diff options
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r-- | source/blender/editors/space_node/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.cc | 568 | ||||
-rw-r--r-- | source/blender/editors/space_node/link_drag_search.cc | 3 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_add.cc | 316 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_draw.cc | 185 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.cc | 103 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_gizmo.cc | 45 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_group.cc | 42 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_intern.hh | 44 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_ops.cc | 2 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_relationships.cc | 454 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_select.cc | 90 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_templates.cc | 67 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_view.cc | 20 | ||||
-rw-r--r-- | source/blender/editors/space_node/space_node.cc | 14 |
15 files changed, 968 insertions, 990 deletions
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index badcccca87b..8a1d47eaa8d 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -17,7 +17,6 @@ set(INC ../../nodes ../../render ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna @@ -50,8 +49,8 @@ set(LIB bf_editor_screen ) -if(WITH_COMPOSITOR) - add_definitions(-DWITH_COMPOSITOR) +if(WITH_COMPOSITOR_CPU) + add_definitions(-DWITH_COMPOSITOR_CPU) endif() if(WITH_OPENIMAGEDENOISE) diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 25ab06850f5..a4db5edf0f6 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -6,6 +6,7 @@ * \brief lower level node drawing for nodes (boarders, headers etc), also node layout. */ +#include "BLI_color.hh" #include "BLI_system.h" #include "BLI_threads.h" @@ -477,7 +478,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_RGB: ntype->draw_buttons = node_buts_rgb; break; - case SH_NODE_MIX_RGB: + case SH_NODE_MIX_RGB_LEGACY: ntype->draw_buttons = node_buts_mix_rgb; break; case SH_NODE_VALTORGB: @@ -1584,102 +1585,75 @@ void draw_nodespace_back_pix(const bContext &C, GPU_matrix_pop(); } -bool node_link_bezier_handles(const View2D *v2d, - const SpaceNode *snode, - const bNodeLink &link, - float vec[4][2]) +static float2 socket_link_connection_location(const bNodeSocket &socket, const bNodeLink &link) { - float cursor[2] = {0.0f, 0.0f}; - - /* this function can be called with snode null (via cut_links_intersect) */ - /* XXX map snode->runtime->cursor back to view space */ - if (snode) { - cursor[0] = snode->runtime->cursor[0] * UI_DPI_FAC; - cursor[1] = snode->runtime->cursor[1] * UI_DPI_FAC; - } - - /* in v0 and v3 we put begin/end points */ - if (link.fromsock) { - vec[0][0] = link.fromsock->locx; - vec[0][1] = link.fromsock->locy; - if (link.fromsock->flag & SOCK_MULTI_INPUT) { - const float2 position = node_link_calculate_multi_input_position( - {link.fromsock->locx, link.fromsock->locy}, - link.fromsock->total_inputs - 1, - link.fromsock->total_inputs); - copy_v2_v2(vec[0], position); - } + const float2 socket_location(socket.locx, socket.locy); + if (socket.flag & SOCK_MULTI_INPUT && socket.in_out == SOCK_IN) { + return node_link_calculate_multi_input_position( + socket_location, link.multi_input_socket_index, socket.total_inputs); } - else { - if (snode == nullptr) { - return false; - } - copy_v2_v2(vec[0], cursor); - } - if (link.tosock) { - vec[3][0] = link.tosock->locx; - vec[3][1] = link.tosock->locy; - if (!(link.tonode->flag & NODE_HIDDEN) && link.tosock->flag & SOCK_MULTI_INPUT) { - const float2 position = node_link_calculate_multi_input_position( - {link.tosock->locx, link.tosock->locy}, - link.multi_input_socket_index, - link.tosock->total_inputs); - copy_v2_v2(vec[3], position); - } - } - else { - if (snode == nullptr) { - return false; - } - copy_v2_v2(vec[3], cursor); - } - - /* may be called outside of drawing (so pass spacetype) */ - int curving = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE); + return socket_location; +} +static void calculate_inner_link_bezier_points(std::array<float2, 4> &points) +{ + const int curving = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE); if (curving == 0) { /* Straight line: align all points. */ - mid_v2_v2v2(vec[1], vec[0], vec[3]); - mid_v2_v2v2(vec[2], vec[1], vec[3]); - return true; + points[1] = math::interpolate(points[0], points[3], 1.0f / 3.0f); + points[2] = math::interpolate(points[0], points[3], 2.0f / 3.0f); } + else { + const float dist = curving * 0.1f * math::distance(points[0].x, points[3].x); - const float dist = curving * 0.10f * fabsf(vec[0][0] - vec[3][0]); + points[1].x = points[0].x + dist; + points[1].y = points[0].y; - vec[1][0] = vec[0][0] + dist; - vec[1][1] = vec[0][1]; + points[2].x = points[3].x - dist; + points[2].y = points[3].y; + } +} - vec[2][0] = vec[3][0] - dist; - vec[2][1] = vec[3][1]; +static std::array<float2, 4> node_link_bezier_points(const bNodeLink &link) +{ + std::array<float2, 4> points; + points[0] = socket_link_connection_location(*link.fromsock, link); + points[3] = socket_link_connection_location(*link.tosock, link); + calculate_inner_link_bezier_points(points); + return points; +} - if (v2d && min_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax) { - return false; /* clipped */ +static bool node_link_draw_is_visible(const View2D &v2d, const std::array<float2, 4> &points) +{ + if (min_ffff(points[0].x, points[1].x, points[2].x, points[3].x) > v2d.cur.xmax) { + return false; } - if (v2d && max_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin) { - return false; /* clipped */ + if (max_ffff(points[0].x, points[1].x, points[2].x, points[3].x) < v2d.cur.xmin) { + return false; } - return true; } -bool node_link_bezier_points(const View2D *v2d, - const SpaceNode *snode, - const bNodeLink &link, - float coord_array[][2], - const int resol) +void node_link_bezier_points_evaluated(const bNodeLink &link, + std::array<float2, NODE_LINK_RESOL + 1> &coords) { - float vec[4][2]; - - if (node_link_bezier_handles(v2d, snode, link, vec)) { - /* always do all three, to prevent data hanging around */ - BKE_curve_forward_diff_bezier( - vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0] + 0, resol, sizeof(float[2])); - BKE_curve_forward_diff_bezier( - vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0] + 1, resol, sizeof(float[2])); + const std::array<float2, 4> points = node_link_bezier_points(link); - return true; - } - return false; + /* The extra +1 in size is required by these functions and would be removed ideally. */ + BKE_curve_forward_diff_bezier(points[0].x, + points[1].x, + points[2].x, + points[3].x, + &coords[0].x, + NODE_LINK_RESOL, + sizeof(float2)); + BKE_curve_forward_diff_bezier(points[0].y, + points[1].y, + points[2].y, + points[3].y, + &coords[0].y, + NODE_LINK_RESOL, + sizeof(float2)); } #define NODELINK_GROUP_SIZE 256 @@ -1938,189 +1912,252 @@ void nodelink_batch_end(SpaceNode &snode) g_batch_link.enabled = false; } +struct NodeLinkDrawConfig { + int th_col1; + int th_col2; + int th_col3; + + ColorTheme4f start_color; + ColorTheme4f end_color; + ColorTheme4f outline_color; + + bool drawarrow; + bool drawmuted; + bool highlighted; + + float dim_factor; + float thickness; + float dash_factor; + float dash_alpha; +}; + static void nodelink_batch_add_link(const SpaceNode &snode, - const float2 &p0, - const float2 &p1, - const float2 &p2, - const float2 &p3, - int th_col1, - int th_col2, - int th_col3, - const float start_color[4], - const float end_color[4], - bool drawarrow, - bool drawmuted, - float dim_factor, - float thickness, - float dash_factor, - float dash_alpha) + const std::array<float2, 4> &points, + const NodeLinkDrawConfig &draw_config) { /* Only allow these colors. If more is needed, you need to modify the shader accordingly. */ - BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); - BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); - BLI_assert(ELEM(th_col3, TH_WIRE, TH_REDALERT, -1)); + BLI_assert( + ELEM(draw_config.th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); + BLI_assert( + ELEM(draw_config.th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT)); + BLI_assert(ELEM(draw_config.th_col3, TH_WIRE, TH_REDALERT, -1)); g_batch_link.count++; - copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p0_step), p0); - copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p1_step), p1); - copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p2_step), p2); - copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p3_step), p3); + copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p0_step), points[0]); + copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p1_step), points[1]); + copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p2_step), points[2]); + copy_v2_v2((float *)GPU_vertbuf_raw_step(&g_batch_link.p3_step), points[3]); char *colid = (char *)GPU_vertbuf_raw_step(&g_batch_link.colid_step); - colid[0] = nodelink_get_color_id(th_col1); - colid[1] = nodelink_get_color_id(th_col2); - colid[2] = nodelink_get_color_id(th_col3); - colid[3] = drawarrow; - copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.start_color_step), start_color); - copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.end_color_step), end_color); + colid[0] = nodelink_get_color_id(draw_config.th_col1); + colid[1] = nodelink_get_color_id(draw_config.th_col2); + colid[2] = nodelink_get_color_id(draw_config.th_col3); + colid[3] = draw_config.drawarrow; + copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.start_color_step), + draw_config.start_color); + copy_v4_v4((float *)GPU_vertbuf_raw_step(&g_batch_link.end_color_step), draw_config.end_color); char *muted = (char *)GPU_vertbuf_raw_step(&g_batch_link.muted_step); - muted[0] = drawmuted; - *(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = dim_factor; - *(float *)GPU_vertbuf_raw_step(&g_batch_link.thickness_step) = thickness; - *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_factor_step) = dash_factor; - *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_alpha_step) = dash_alpha; + muted[0] = draw_config.drawmuted; + *(float *)GPU_vertbuf_raw_step(&g_batch_link.dim_factor_step) = draw_config.dim_factor; + *(float *)GPU_vertbuf_raw_step(&g_batch_link.thickness_step) = draw_config.thickness; + *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_factor_step) = draw_config.dash_factor; + *(float *)GPU_vertbuf_raw_step(&g_batch_link.dash_alpha_step) = draw_config.dash_alpha; if (g_batch_link.count == NODELINK_GROUP_SIZE) { nodelink_batch_draw(snode); } } -void node_draw_link_bezier(const bContext &C, - const View2D &v2d, - const SpaceNode &snode, - const bNodeLink &link, - const int th_col1, - const int th_col2, - const int th_col3, - const bool selected) +static void node_draw_link_end_marker(const float2 center, + const float radius, + const ColorTheme4f &color) +{ + rctf rect; + BLI_rctf_init(&rect, center.x - radius, center.x + radius, center.y - radius, center.y + radius); + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_4fv(&rect, true, radius, color); + /* Roundbox disables alpha. Reenable it for node links that are drawn after this one. */ + GPU_blend(GPU_BLEND_ALPHA); +} + +static void node_draw_link_end_markers(const bNodeLink &link, + const NodeLinkDrawConfig &draw_config, + const std::array<float2, 4> &points, + const bool outline) +{ + const float radius = (outline ? 0.65f : 0.45f) * NODE_SOCKSIZE; + if (link.fromsock) { + node_draw_link_end_marker( + points[0], radius, outline ? draw_config.outline_color : draw_config.start_color); + } + if (link.tosock) { + node_draw_link_end_marker( + points[3], radius, outline ? draw_config.outline_color : draw_config.end_color); + } +} + +static bool node_link_is_field_link(const SpaceNode &snode, const bNodeLink &link) +{ + if (snode.edittree->type != NTREE_GEOMETRY) { + return false; + } + if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) { + return true; + } + return false; +} + +static NodeLinkDrawConfig nodelink_get_draw_config(const bContext &C, + const View2D &v2d, + const SpaceNode &snode, + const bNodeLink &link, + const int th_col1, + const int th_col2, + const int th_col3, + const bool selected) { - const float dim_factor = selected ? 1.0f : node_link_dim_factor(v2d, link); - float thickness = 1.5f; - float dash_factor = 1.0f; + NodeLinkDrawConfig draw_config; + + draw_config.th_col1 = th_col1; + draw_config.th_col2 = th_col2; + draw_config.th_col3 = th_col3; + + draw_config.dim_factor = selected ? 1.0f : node_link_dim_factor(v2d, link); bTheme *btheme = UI_GetTheme(); - const float dash_alpha = btheme->space_node.dash_alpha; - - if (snode.edittree->type == NTREE_GEOMETRY) { - if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) { - /* Make field links a bit thinner. */ - thickness = 1.0f; - /* Draw field as dashes. */ - dash_factor = 0.75f; + draw_config.dash_alpha = btheme->space_node.dash_alpha; + + const bool field_link = node_link_is_field_link(snode, link); + + draw_config.dash_factor = field_link ? 0.75f : 1.0f; + + const float scale = UI_view2d_scale_get_x(&v2d); + /* Clamp the thickness to make the links more readable when zooming out. */ + draw_config.thickness = max_ff(scale, 1.0f) * (field_link ? 0.7f : 1.0f); + draw_config.highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT; + draw_config.drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) && + (link.fromnode && (link.fromnode->type == NODE_REROUTE))); + draw_config.drawmuted = (link.flag & NODE_LINK_MUTED); + + UI_GetThemeColor4fv(th_col3, draw_config.outline_color); + + if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && + snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) { + PointerRNA from_node_ptr, to_node_ptr; + RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr); + RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr); + + if (link.fromsock) { + node_socket_color_get( + C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.start_color); + } + else { + node_socket_color_get( + C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.start_color); } - } - float vec[4][2]; - const bool highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT; - if (node_link_bezier_handles(&v2d, &snode, link, vec)) { - int drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) && - (link.fromnode && (link.fromnode->type == NODE_REROUTE))); - int drawmuted = (link.flag & NODE_LINK_MUTED); - if (g_batch_link.batch == nullptr) { - nodelink_batch_init(); + if (link.tosock) { + node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, draw_config.end_color); } - /* Draw single link. */ - float colors[3][4] = {{0.0f}}; - if (th_col3 != -1) { - UI_GetThemeColor4fv(th_col3, colors[0]); + else { + node_socket_color_get( + C, *snode.edittree, from_node_ptr, *link.fromsock, draw_config.end_color); } + } + else { + UI_GetThemeColor4fv(th_col1, draw_config.start_color); + UI_GetThemeColor4fv(th_col2, draw_config.end_color); + } + + /* Highlight links connected to selected nodes. */ + if (selected) { + ColorTheme4f color_selected; + UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected); + const float alpha = color_selected.a; - if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && - snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) { - PointerRNA from_node_ptr, to_node_ptr; - RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr); - RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr); + /* Interpolate color if highlight color is not fully transparent. */ + if (alpha != 0.0) { if (link.fromsock) { - node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[1]); + interp_v3_v3v3(draw_config.start_color, draw_config.start_color, color_selected, alpha); } - else { - node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[1]); - } - if (link.tosock) { - node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[2]); - } - else { - node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[2]); + interp_v3_v3v3(draw_config.end_color, draw_config.end_color, color_selected, alpha); } } - else { - UI_GetThemeColor4fv(th_col1, colors[1]); - UI_GetThemeColor4fv(th_col2, colors[2]); - } + } - /* Highlight links connected to selected nodes. */ - if (selected) { - float color_selected[4]; - UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected); - const float alpha = color_selected[3]; + if (draw_config.highlighted) { + ColorTheme4f link_preselection_highlight_color; + UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color); + /* Multi sockets can only be inputs. So we only have to highlight the end of the link. */ + copy_v4_v4(draw_config.end_color, link_preselection_highlight_color); + } - /* Interpolate color if highlight color is not fully transparent. */ - if (alpha != 0.0) { - if (link.fromsock) { - interp_v3_v3v3(colors[1], colors[1], color_selected, alpha); - } - if (link.tosock) { - interp_v3_v3v3(colors[2], colors[2], color_selected, alpha); - } - } - } + return draw_config; +} - if (g_batch_link.enabled && !highlighted) { - /* Add link to batch. */ - nodelink_batch_add_link(snode, - vec[0], - vec[1], - vec[2], - vec[3], - th_col1, - th_col2, - th_col3, - colors[1], - colors[2], - drawarrow, - drawmuted, - dim_factor, - thickness, - dash_factor, - dash_alpha); - } - else { - if (highlighted) { - float link_preselection_highlight_color[4]; - UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color); - copy_v4_v4(colors[2], link_preselection_highlight_color); - } +static void node_draw_link_bezier_ex(const SpaceNode &snode, + const NodeLinkDrawConfig &draw_config, + const std::array<float2, 4> &points) +{ + if (g_batch_link.batch == nullptr) { + nodelink_batch_init(); + } - NodeLinkData node_link_data; - for (int i = 0; i < 4; i++) { - copy_v2_v2(node_link_data.bezierPts[i], vec[i]); - } - for (int i = 0; i < 3; i++) { - copy_v4_v4(node_link_data.colors[i], colors[i]); - } - node_link_data.doArrow = drawarrow; - node_link_data.doMuted = drawmuted; - node_link_data.dim_factor = dim_factor; - node_link_data.thickness = thickness; - node_link_data.dash_factor = dash_factor; - node_link_data.dash_alpha = dash_alpha; - node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; - node_link_data.arrowSize = ARROW_SIZE; - - GPUBatch *batch = g_batch_link.batch_single; - GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( - sizeof(NodeLinkData), &node_link_data, __func__); - - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK); - GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo); - GPU_batch_draw(batch); - - GPU_uniformbuf_unbind(ubo); - GPU_uniformbuf_free(ubo); + if (g_batch_link.enabled && !draw_config.highlighted) { + /* Add link to batch. */ + nodelink_batch_add_link(snode, points, draw_config); + } + else { + NodeLinkData node_link_data; + for (const int i : IndexRange(points.size())) { + copy_v2_v2(node_link_data.bezierPts[i], points[i]); } + + copy_v4_v4(node_link_data.colors[0], draw_config.outline_color); + copy_v4_v4(node_link_data.colors[1], draw_config.start_color); + copy_v4_v4(node_link_data.colors[2], draw_config.end_color); + + node_link_data.doArrow = draw_config.drawarrow; + node_link_data.doMuted = draw_config.drawmuted; + node_link_data.dim_factor = draw_config.dim_factor; + node_link_data.thickness = draw_config.thickness; + node_link_data.dash_factor = draw_config.dash_factor; + node_link_data.dash_alpha = draw_config.dash_alpha; + node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; + node_link_data.arrowSize = ARROW_SIZE; + + GPUBatch *batch = g_batch_link.batch_single; + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(NodeLinkData), &node_link_data, __func__); + + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK); + GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo); + GPU_batch_draw(batch); + + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); } } +void node_draw_link_bezier(const bContext &C, + const View2D &v2d, + const SpaceNode &snode, + const bNodeLink &link, + const int th_col1, + const int th_col2, + const int th_col3, + const bool selected) +{ + const std::array<float2, 4> points = node_link_bezier_points(link); + if (!node_link_draw_is_visible(v2d, points)) { + return; + } + const NodeLinkDrawConfig draw_config = nodelink_get_draw_config( + C, v2d, snode, link, th_col1, th_col2, th_col3, selected); + + node_draw_link_bezier_ex(snode, draw_config, points); +} + void node_draw_link(const bContext &C, const View2D &v2d, const SpaceNode &snode, @@ -2133,34 +2170,29 @@ void node_draw_link(const bContext &C, return; } - /* new connection */ - if (!link.fromsock || !link.tosock) { - th_col1 = th_col2 = TH_ACTIVE; + /* going to give issues once... */ + if (link.tosock->flag & SOCK_UNAVAIL) { + return; + } + if (link.fromsock->flag & SOCK_UNAVAIL) { + return; } - else { - /* going to give issues once... */ - if (link.tosock->flag & SOCK_UNAVAIL) { - return; - } - if (link.fromsock->flag & SOCK_UNAVAIL) { - return; - } - if (link.flag & NODE_LINK_VALID) { - /* special indicated link, on drop-node */ - if (link.flag & NODE_LINKFLAG_HILITE) { - th_col1 = th_col2 = TH_ACTIVE; - } - else if (link.flag & NODE_LINK_MUTED) { - th_col1 = th_col2 = TH_REDALERT; - } + if (link.flag & NODE_LINK_VALID) { + /* special indicated link, on drop-node */ + if (link.flag & NODE_LINKFLAG_HILITE) { + th_col1 = th_col2 = TH_ACTIVE; } - else { - /* Invalid link. */ - th_col1 = th_col2 = th_col3 = TH_REDALERT; - // th_col3 = -1; /* no shadow */ + else if (link.flag & NODE_LINK_MUTED) { + th_col1 = th_col2 = TH_REDALERT; } } + else { + /* Invalid link. */ + th_col1 = th_col2 = th_col3 = TH_REDALERT; + // th_col3 = -1; /* no shadow */ + } + /* Links from field to non-field sockets are not allowed. */ if (snode.edittree->type == NTREE_GEOMETRY && !(link.flag & NODE_LINK_DRAGGED)) { if ((link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) && @@ -2172,6 +2204,38 @@ void node_draw_link(const bContext &C, node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3, selected); } +static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &snode, + const bNodeLink &link) +{ + const float2 cursor = snode.runtime->cursor * UI_DPI_FAC; + std::array<float2, 4> points; + points[0] = link.fromsock ? socket_link_connection_location(*link.fromsock, link) : cursor; + points[3] = link.tosock ? socket_link_connection_location(*link.tosock, link) : cursor; + calculate_inner_link_bezier_points(points); + return points; +} + +void node_draw_link_dragged(const bContext &C, + const View2D &v2d, + const SpaceNode &snode, + const bNodeLink &link) +{ + if (link.fromsock == nullptr && link.tosock == nullptr) { + return; + } + + const std::array<float2, 4> points = node_link_bezier_points_dragged(snode, link); + + const NodeLinkDrawConfig draw_config = nodelink_get_draw_config( + C, v2d, snode, link, TH_ACTIVE, TH_ACTIVE, TH_WIRE, true); + /* End marker outline. */ + node_draw_link_end_markers(link, draw_config, points, true); + /* Link. */ + node_draw_link_bezier_ex(snode, draw_config, points); + /* End marker fill. */ + node_draw_link_end_markers(link, draw_config, points, false); +} + } // namespace blender::ed::space_node void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos) diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index c524de2c55d..553d4013324 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -232,6 +232,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_boolean_set(&ptr, "view2d_edge_pan", true); + RNA_boolean_set(&ptr, "remove_on_cancel", true); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); WM_operator_properties_free(&ptr); } @@ -292,7 +293,7 @@ static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *ar 0, nullptr); - const int offset[2] = {0, -UI_UNIT_Y}; + const int2 offset = {0, -UI_UNIT_Y}; UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset); return block; } diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index e96efb888f3..7e46877d0ba 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -5,6 +5,8 @@ * \ingroup spnode */ +#include <numeric> + #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" @@ -20,6 +22,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -49,231 +52,165 @@ namespace blender::ed::space_node { /** \name Utilities * \{ */ -bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy) +static void position_node_based_on_mouse(bNode &node, const float2 &location) +{ + node.locx = location.x - NODE_DY * 1.5f / UI_DPI_FAC; + node.locy = location.y + NODE_DY * 0.5f / UI_DPI_FAC; +} + +bNode *add_node(const bContext &C, const StringRef idname, const float2 &location) { SpaceNode &snode = *CTX_wm_space_node(&C); Main &bmain = *CTX_data_main(&C); - bNode *node = nullptr; node_deselect_all(snode); - if (idname) { - node = nodeAddNode(&C, snode.edittree, idname); - } - else { - node = nodeAddStaticNode(&C, snode.edittree, type); - } + const std::string idname_str = idname; + + bNode *node = nodeAddNode(&C, snode.edittree, idname_str.c_str()); BLI_assert(node && node->typeinfo); - /* Position mouse in node header. */ - node->locx = locx - NODE_DY * 1.5f / UI_DPI_FAC; - node->locy = locy + NODE_DY * 0.5f / UI_DPI_FAC; + position_node_based_on_mouse(*node, location); nodeSetSelected(node, true); - ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); return node; } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Add Reroute Operator - * \{ */ - -static bool add_reroute_intersect_check(const bNodeLink &link, - float mcoords[][2], - int tot, - float result[2]) +bNode *add_static_node(const bContext &C, int type, const float2 &location) { - float coord_array[NODE_LINK_RESOL + 1][2]; - - if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) { - for (int i = 0; i < tot - 1; i++) { - for (int b = 0; b < NODE_LINK_RESOL; b++) { - if (isect_seg_seg_v2_point( - mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1], result) > 0) { - return true; - } - } - } - } - return false; -} + SpaceNode &snode = *CTX_wm_space_node(&C); + Main &bmain = *CTX_data_main(&C); -struct bNodeSocketLink { - struct bNodeSocketLink *next, *prev; + node_deselect_all(snode); - struct bNodeSocket *sock; - struct bNodeLink *link; - float point[2]; -}; + bNode *node = nodeAddStaticNode(&C, snode.edittree, type); + BLI_assert(node && node->typeinfo); -static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb, - bNodeSocket *sock, - bNodeLink *link, - const float point[2]) -{ - bNodeSocketLink *socklink, *prev; + position_node_based_on_mouse(*node, location); - socklink = MEM_cnew<bNodeSocketLink>("socket link"); - socklink->sock = sock; - socklink->link = link; - copy_v2_v2(socklink->point, point); + nodeSetSelected(node, true); + ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); - for (prev = (bNodeSocketLink *)lb->last; prev; prev = prev->prev) { - if (prev->sock == sock) { - break; - } - } - BLI_insertlinkafter(lb, prev, socklink); - return socklink; + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); + return node; } -static bNodeSocketLink *add_reroute_do_socket_section(bContext *C, - bNodeSocketLink *socklink, - int in_out) -{ - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - bNode *reroute_node = nullptr; - bNodeSocket *cursock = socklink->sock; - float insert_point[2]; - int num_links; - - zero_v2(insert_point); - num_links = 0; - - while (socklink && socklink->sock == cursock) { - if (!(socklink->link->flag & NODE_LINK_TEST)) { - socklink->link->flag |= NODE_LINK_TEST; - - /* create the reroute node for this cursock */ - if (!reroute_node) { - reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE); - - /* add a single link to/from the reroute node to replace multiple links */ - if (in_out == SOCK_OUT) { - nodeAddLink(ntree, - socklink->link->fromnode, - socklink->link->fromsock, - reroute_node, - (bNodeSocket *)reroute_node->inputs.first); - } - else { - nodeAddLink(ntree, - reroute_node, - (bNodeSocket *)reroute_node->outputs.first, - socklink->link->tonode, - socklink->link->tosock); - } - } - - /* insert the reroute node into the link */ - if (in_out == SOCK_OUT) { - socklink->link->fromnode = reroute_node; - socklink->link->fromsock = (bNodeSocket *)reroute_node->outputs.first; - } - else { - socklink->link->tonode = reroute_node; - socklink->link->tosock = (bNodeSocket *)reroute_node->inputs.first; - } - - add_v2_v2(insert_point, socklink->point); - num_links++; - } - socklink = socklink->next; - } - - if (num_links > 0) { - /* average cut point from shared links */ - mul_v2_fl(insert_point, 1.0f / num_links); +/** \} */ - reroute_node->locx = insert_point[0] / UI_DPI_FAC; - reroute_node->locy = insert_point[1] / UI_DPI_FAC; +/* -------------------------------------------------------------------- */ +/** \name Add Reroute Operator + * \{ */ - LISTBASE_FOREACH_BACKWARD (bNode *, frame_node, &ntree->nodes) { - if (frame_node->type == NODE_FRAME && BLI_rctf_isect_pt_v(&frame_node->totr, insert_point)) { - nodeAttachNode(reroute_node, frame_node); - break; +std::optional<float2> link_path_intersection(const bNodeLink &link, const Span<float2> path) +{ + std::array<float2, NODE_LINK_RESOL + 1> coords; + node_link_bezier_points_evaluated(link, coords); + + for (const int i : path.index_range().drop_back(1)) { + for (const int j : IndexRange(NODE_LINK_RESOL)) { + float2 result; + if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) { + return result; } } } - return socklink; + return std::nullopt; } +struct RerouteCutsForSocket { + /* The output socket's owner node. */ + bNode *from_node; + /* Intersected links connected to the socket and their path intersection locations. */ + Map<bNodeLink *, float2> links; +}; + static int add_reroute_exec(bContext *C, wmOperator *op) { + const ARegion ®ion = *CTX_wm_region(C); SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); bNodeTree &ntree = *snode.edittree; - float mcoords[256][2]; - int i = 0; - /* Get the cut path */ + Vector<float2> path; RNA_BEGIN (op->ptr, itemptr, "path") { - float loc[2]; - - RNA_float_get_array(&itemptr, "loc", loc); - UI_view2d_region_to_view( - ®ion.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]); - i++; - if (i >= 256) { + float2 loc_region; + RNA_float_get_array(&itemptr, "loc", loc_region); + float2 loc_view; + UI_view2d_region_to_view(®ion.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y); + path.append(loc_view); + if (path.size() >= 256) { break; } } RNA_END; - if (i > 1) { - ListBase output_links, input_links; - bNodeSocketLink *socklink; - float insert_point[2]; - - /* always first */ - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - - node_deselect_all(snode); + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } - /* Find cut links and sort them by sockets */ - BLI_listbase_clear(&output_links); - BLI_listbase_clear(&input_links); + ntree.ensure_topology_cache(); + const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame"); - LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } - if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) { - add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point); - add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + node_deselect_all(snode); - /* Clear flag */ - link->flag &= ~NODE_LINK_TEST; - } - } + /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per + * output socket is useful because it allows reusing reroutes for connected intersections. + * Further deduplication using the second map means we only have one cut per link.*/ + Map<bNodeSocket *, RerouteCutsForSocket> cuts_per_socket; - /* Create reroute nodes for intersected links. - * Only one reroute if links share the same input/output socket. - */ - socklink = (bNodeSocketLink *)output_links.first; - while (socklink) { - socklink = add_reroute_do_socket_section(C, socklink, SOCK_OUT); + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; } - socklink = (bNodeSocketLink *)input_links.first; - while (socklink) { - socklink = add_reroute_do_socket_section(C, socklink, SOCK_IN); + const std::optional<float2> intersection = link_path_intersection(*link, path); + if (!intersection) { + continue; } + RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock); + from_cuts.from_node = link->fromnode; + from_cuts.links.add(link, *intersection); + } + + for (const auto item : cuts_per_socket.items()) { + const Map<bNodeLink *, float2> &cuts = item.value.links; + + bNode *reroute = nodeAddStaticNode(C, &ntree, NODE_REROUTE); - BLI_freelistN(&output_links); - BLI_freelistN(&input_links); + nodeAddLink(&ntree, + item.value.from_node, + item.key, + reroute, + static_cast<bNodeSocket *>(reroute->inputs.first)); - /* always last */ - ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); - return OPERATOR_FINISHED; + /* Reconnect links from the original output socket to the new reroute. */ + for (bNodeLink *link : cuts.keys()) { + link->fromnode = reroute; + link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first); + BKE_ntree_update_tag_link_changed(&ntree); + } + + /* Place the new reroute at the average location of all connected cuts. */ + const float2 loc = std::accumulate(cuts.values().begin(), cuts.values().end(), float2(0)) / + cuts.size() / UI_DPI_FAC; + reroute->locx = loc.x; + reroute->locy = loc.y; + + /* Attach the reroute node to frame nodes behind it. */ + for (const int i : frame_nodes.index_range()) { + bNode *frame_node = frame_nodes.last(i); + if (BLI_rctf_isect_pt_v(&frame_node->totr, loc)) { + nodeAttachNode(reroute, frame_node); + break; + } + } } - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + return OPERATOR_FINISHED; } void NODE_OT_add_reroute(wmOperatorType *ot) @@ -345,9 +282,9 @@ static int node_add_group_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeTree *node_group; - if (!(node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree))) { + bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree); + if (!node_group) { return OPERATOR_CANCELLED; } @@ -359,12 +296,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - bNode *group_node = node_add_node(*C, - node_idname, - (node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP : - NODE_GROUP, - snode->runtime->cursor[0], - snode->runtime->cursor[1]); + bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor); if (!group_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node group"); return OPERATOR_CANCELLED; @@ -452,8 +384,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - bNode *object_node = node_add_node( - *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]); + bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor); if (!object_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node object"); return OPERATOR_CANCELLED; @@ -529,7 +460,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNodeTree *ntree = snode.edittree; + bNodeTree &ntree = *snode.edittree; Collection *collection = reinterpret_cast<Collection *>( WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR)); @@ -540,8 +471,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - bNode *collection_node = node_add_node( - *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor); if (!collection_node) { BKE_report(op->reports, RPT_WARNING, "Could not add node collection"); return OPERATOR_CANCELLED; @@ -557,8 +487,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) socket_data->value = collection; id_us_plus(&collection->id); - nodeSetActive(ntree, collection_node); - ED_node_tree_propagate_change(C, bmain, ntree); + nodeSetActive(&ntree, collection_node); + ED_node_tree_propagate_change(C, bmain, &ntree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -624,11 +554,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNode *node; - Image *ima; int type = 0; - ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); + Image *ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); if (!ima) { return OPERATOR_CANCELLED; } @@ -652,7 +580,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *node = add_static_node(*C, type, snode.runtime->cursor); if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add an image node"); @@ -746,7 +674,6 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - bNode *node; ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK); if (!mask) { @@ -755,8 +682,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - node = node_add_node( - *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]); + bNode *node = add_static_node(*C, CMP_NODE_MASK, snode.runtime->cursor); if (!node) { BKE_report(op->reports, RPT_WARNING, "Could not add a mask node"); diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 2cee7c4984a..225bae89c66 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -340,13 +340,13 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, bool add_output_space = false; int buty; - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) { - if (nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) { + if (nodeSocketIsHidden(socket)) { continue; } PointerRNA sockptr; - RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr); + RNA_pointer_create(&ntree.id, &RNA_NodeSocket, socket, &sockptr); uiLayout *layout = UI_block_layout(&block, UI_LAYOUT_VERTICAL, @@ -369,10 +369,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, /* Align output buttons to the right. */ uiLayout *row = uiLayoutRow(layout, true); uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); - const char *socket_label = nodeSocketLabel(nsock); - nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label)); + const char *socket_label = nodeSocketLabel(socket); + socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label)); - node_socket_add_tooltip(&ntree, &node, nsock, row); + node_socket_add_tooltip(ntree, node, *socket, *row); UI_block_align_end(&block); UI_block_layout_resolve(&block, nullptr, &buty); @@ -381,11 +381,11 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, buty = min_ii(buty, dy - NODE_DY); /* Round the socket location to stop it from jiggling. */ - nsock->locx = round(loc.x + NODE_WIDTH(node)); - nsock->locy = round(dy - NODE_DYS); + socket->locx = round(loc.x + NODE_WIDTH(node)); + socket->locy = round(dy - NODE_DYS); dy = buty; - if (nsock->next) { + if (socket->next) { dy -= NODE_SOCKDY; } @@ -463,20 +463,20 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, } /* Input sockets. */ - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) { - if (nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { + if (nodeSocketIsHidden(socket)) { continue; } PointerRNA sockptr; - RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr); + RNA_pointer_create(&ntree.id, &RNA_NodeSocket, socket, &sockptr); /* Add the half the height of a multi-input socket to cursor Y * to account for the increased height of the taller sockets. */ float multi_input_socket_offset = 0.0f; - if (nsock->flag & SOCK_MULTI_INPUT) { - if (nsock->total_inputs > 2) { - multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP; + if (socket->flag & SOCK_MULTI_INPUT) { + if (socket->total_inputs > 2) { + multi_input_socket_offset = (socket->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP; } } dy -= multi_input_socket_offset * 0.5f; @@ -501,10 +501,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiLayout *row = uiLayoutRow(layout, true); - const char *socket_label = nodeSocketLabel(nsock); - nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label)); + const char *socket_label = nodeSocketLabel(socket); + socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label)); - node_socket_add_tooltip(&ntree, &node, nsock, row); + node_socket_add_tooltip(ntree, node, *socket, *row); UI_block_align_end(&block); UI_block_layout_resolve(&block, nullptr, &buty); @@ -512,12 +512,12 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, /* Ensure minimum socket height in case layout is empty. */ buty = min_ii(buty, dy - NODE_DY); - nsock->locx = loc.x; + socket->locx = loc.x; /* Round the socket vertical position to stop it from jiggling. */ - nsock->locy = round(dy - NODE_DYS); + socket->locy = round(dy - NODE_DYS); dy = buty - multi_input_socket_offset * 0.5; - if (nsock->next) { + if (socket->next) { dy -= NODE_SOCKDY; } } @@ -555,13 +555,13 @@ static void node_update_hidden(bNode &node, uiBlock &block) loc.y = round(loc.y); /* Calculate minimal radius. */ - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) { - if (!nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { + if (!nodeSocketIsHidden(socket)) { totin++; } } - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) { - if (!nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) { + if (!nodeSocketIsHidden(socket)) { totout++; } } @@ -581,11 +581,11 @@ static void node_update_hidden(bNode &node, uiBlock &block) float rad = (float)M_PI / (1.0f + (float)totout); float drad = rad; - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) { - if (!nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.outputs) { + if (!nodeSocketIsHidden(socket)) { /* Round the socket location to stop it from jiggling. */ - nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad); - nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad); + socket->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad); + socket->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad); rad += drad; } } @@ -593,11 +593,11 @@ static void node_update_hidden(bNode &node, uiBlock &block) /* Input sockets. */ rad = drad = -(float)M_PI / (1.0f + (float)totin); - LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) { - if (!nodeSocketIsHidden(nsock)) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { + if (!nodeSocketIsHidden(socket)) { /* Round the socket location to stop it from jiggling. */ - nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad); - nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad); + socket->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad); + socket->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad); rad += drad; } } @@ -720,8 +720,7 @@ static void node_socket_draw_multi_input(const float color[4], const float color_outline[4], const float width, const float height, - const int locx, - const int locy) + const float2 location) { /* The other sockets are drawn with the keyframe shader. There, the outline has a base thickness * that can be varied but always scales with the size the socket is drawn at. Using `U.dpi_fac` @@ -731,10 +730,10 @@ static void node_socket_draw_multi_input(const float color[4], /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */ const rctf rect = { - locx - width + outline_width * 0.5f, - locx + width - outline_width * 0.5f, - locy - height + outline_width * 0.5f, - locy + height - outline_width * 0.5f, + location.x - width + outline_width * 0.5f, + location.x + width - outline_width * 0.5f, + location.y - height + outline_width * 0.5f, + location.y + height - outline_width * 0.5f, }; UI_draw_roundbox_corner_set(UI_CNR_ALL); @@ -758,6 +757,7 @@ static void node_socket_outline_color_get(const bool selected, } else { UI_GetThemeColor4fv(TH_WIRE, r_outline_color); + r_outline_color[3] = 1.0f; } } @@ -775,9 +775,9 @@ void node_socket_color_get(const bContext &C, } struct SocketTooltipData { - bNodeTree *ntree; - bNode *node; - bNodeSocket *socket; + const bNodeTree *ntree; + const bNode *node; + const bNodeSocket *socket; }; static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss) @@ -998,11 +998,11 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo } } -static std::optional<std::string> create_socket_inspection_string(bContext *C, - bNode &node, - bNodeSocket &socket) +static std::optional<std::string> create_socket_inspection_string(const bContext &C, + const bNode &node, + const bNodeSocket &socket) { - SpaceNode *snode = CTX_wm_space_node(C); + const SpaceNode *snode = CTX_wm_space_node(&C); if (snode == nullptr) { return {}; }; @@ -1037,41 +1037,41 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, return ss.str(); } -static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket) +static bool node_socket_has_tooltip(const bNodeTree &ntree, const bNodeSocket &socket) { - if (ntree->type == NTREE_GEOMETRY) { + if (ntree.type == NTREE_GEOMETRY) { return true; } - if (socket->runtime->declaration != nullptr) { - const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration; + if (socket.runtime->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration; return !socket_decl.description().is_empty(); } return false; } -static char *node_socket_get_tooltip(bContext *C, - bNodeTree *ntree, - bNode *node, - bNodeSocket *socket) +static char *node_socket_get_tooltip(const bContext &C, + const bNodeTree &ntree, + const bNode &node, + const bNodeSocket &socket) { std::stringstream output; - if (socket->runtime->declaration != nullptr) { - const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration; + if (socket.runtime->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration; blender::StringRef description = socket_decl.description(); if (!description.is_empty()) { output << TIP_(description.data()); } } - if (ntree->type == NTREE_GEOMETRY) { + if (ntree.type == NTREE_GEOMETRY) { if (!output.str().empty()) { output << ".\n\n"; } std::optional<std::string> socket_inspection_str = create_socket_inspection_string( - C, *node, *socket); + C, node, socket); if (socket_inspection_str.has_value()) { output << *socket_inspection_str; } @@ -1081,28 +1081,31 @@ static char *node_socket_get_tooltip(bContext *C, } if (output.str().empty()) { - output << nodeSocketLabel(socket); + output << nodeSocketLabel(&socket); } return BLI_strdup(output.str().c_str()); } -void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout) +void node_socket_add_tooltip(const bNodeTree &ntree, + const bNode &node, + const bNodeSocket &sock, + uiLayout &layout) { if (!node_socket_has_tooltip(ntree, sock)) { return; } - SocketTooltipData *data = MEM_cnew<SocketTooltipData>(__func__); - data->ntree = ntree; - data->node = node; - data->socket = sock; + SocketTooltipData *data = MEM_new<SocketTooltipData>(__func__); + data->ntree = &ntree; + data->node = &node; + data->socket = &sock; uiLayoutSetTooltipFunc( - layout, + &layout, [](bContext *C, void *argN, const char *UNUSED(tip)) { - SocketTooltipData *data = static_cast<SocketTooltipData *>(argN); - return node_socket_get_tooltip(C, data->ntree, data->node, data->socket); + const SocketTooltipData *data = static_cast<SocketTooltipData *>(argN); + return node_socket_get_tooltip(*C, *data->ntree, *data->node, *data->socket); }, data, MEM_dupallocN, @@ -1122,9 +1125,10 @@ static void node_socket_draw_nested(const bContext &C, const float size, const bool selected) { + const float2 location(sock.locx, sock.locy); + float color[4]; float outline_color[4]; - node_socket_color_get(C, ntree, node_ptr, sock, color); node_socket_outline_color_get(selected, sock.type, outline_color); @@ -1132,15 +1136,15 @@ static void node_socket_draw_nested(const bContext &C, color, outline_color, size, - sock.locx, - sock.locy, + location.x, + location.y, pos_id, col_id, shape_id, size_id, outline_col_id); - if (!node_socket_has_tooltip(&ntree, &sock)) { + if (!node_socket_has_tooltip(ntree, sock)) { return; } @@ -1152,8 +1156,8 @@ static void node_socket_draw_nested(const bContext &C, UI_BTYPE_BUT, 0, ICON_NONE, - sock.locx - size / 2, - sock.locy - size / 2, + location.x - size / 2.0f, + location.y - size / 2.0f, size, size, nullptr, @@ -1163,16 +1167,16 @@ static void node_socket_draw_nested(const bContext &C, 0, nullptr); - SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__); + SocketTooltipData *data = MEM_new<SocketTooltipData>(__func__); data->ntree = &ntree; - data->node = (bNode *)node_ptr.data; + data->node = static_cast<const bNode *>(node_ptr.data); data->socket = &sock; UI_but_func_tooltip_set( but, [](bContext *C, void *argN, const char *UNUSED(tip)) { SocketTooltipData *data = (SocketTooltipData *)argN; - return node_socket_get_tooltip(C, data->ntree, data->node, data->socket); + return node_socket_get_tooltip(*C, *data->ntree, *data->node, *data->socket); }, data, MEM_freeN); @@ -1307,7 +1311,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) } /* Common handle function for operator buttons that need to select the node first. */ -static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_argv) +static void node_toggle_button_cb(bContext *C, void *node_argv, void *op_argv) { bNode *node = (bNode *)node_argv; const char *opname = (const char *)op_argv; @@ -1526,7 +1530,8 @@ static void node_draw_sockets(const View2D &v2d, node_socket_color_get(C, ntree, node_ptr, *socket, color); node_socket_outline_color_get(socket->flag & SELECT, socket->type, outline_color); - node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy); + const float2 location(socket->locx, socket->locy); + node_socket_draw_multi_input(color, outline_color, width, height, location); } } @@ -2263,6 +2268,7 @@ static void node_draw_basis(const bContext &C, if (node.flag & NODE_MUTED) { UI_GetThemeColor4fv(TH_WIRE, color_underline); + color_underline[3] = 1.0f; } else { UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.2f, color_underline); @@ -2643,13 +2649,13 @@ static void reroute_node_prepare_for_draw(bNode &node) const float2 loc = node_to_view(node, float2(0)); /* reroute node has exactly one input and one output, both in the same place */ - bNodeSocket *nsock = (bNodeSocket *)node.outputs.first; - nsock->locx = loc.x; - nsock->locy = loc.y; + bNodeSocket *socket = (bNodeSocket *)node.outputs.first; + socket->locx = loc.x; + socket->locy = loc.y; - nsock = (bNodeSocket *)node.inputs.first; - nsock->locx = loc.x; - nsock->locy = loc.y; + socket = (bNodeSocket *)node.inputs.first; + socket->locx = loc.x; + socket->locy = loc.y; const float size = 8.0f; node.width = size * 2; @@ -2766,7 +2772,7 @@ static void frame_node_draw_label(const bNodeTree &ntree, BLF_wordwrap(fontid, line_width); LISTBASE_FOREACH (const TextLine *, line, &text->lines) { - struct ResultBLF info; + ResultBLF info; if (line->line[0]) { BLF_position(fontid, x, y, 0); BLF_draw_ex(fontid, line->line, line->len, &info); @@ -3021,8 +3027,9 @@ static void draw_nodetree(const bContext &C, bNodeInstanceKey parent_key) { SpaceNode *snode = CTX_wm_space_node(&C); + ntree.ensure_topology_cache(); - Vector<bNode *> nodes = ntree.nodes; + Span<bNode *> nodes = ntree.all_nodes(); Array<uiBlock *> blocks = node_uiblocks_init(C, nodes); @@ -3102,8 +3109,8 @@ void node_draw_space(const bContext &C, ARegion ®ion) } /* Current View2D center, will be set temporarily for parent node trees. */ - float center[2]; - UI_view2d_center_get(&v2d, ¢er[0], ¢er[1]); + float2 center; + UI_view2d_center_get(&v2d, ¢er.x, ¢er.y); /* Store new view center in path and current edit tree. */ copy_v2_v2(path->view_center, center); @@ -3142,7 +3149,7 @@ void node_draw_space(const bContext &C, ARegion ®ion) GPU_line_smooth(true); if (snode.runtime->linkdrag) { for (const bNodeLink *link : snode.runtime->linkdrag->links) { - node_draw_link(C, v2d, snode, *link, true); + node_draw_link_dragged(C, v2d, snode, *link); } } GPU_line_smooth(false); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 36836ed3691..5f92e514385 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -29,6 +29,8 @@ #include "BKE_scene.h" #include "BKE_workspace.h" +#include "BLT_translation.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" @@ -107,8 +109,7 @@ float2 node_link_calculate_multi_input_position(const float2 &socket_position, { const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) * 0.5f; - return {socket_position.x - NODE_SOCKSIZE * 0.5f, - socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP}; + return {socket_position.x, socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP}; } static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) @@ -319,7 +320,7 @@ static void compo_completejob(void *cjv) /** \name Composite Job C API * \{ */ -void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner) +void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner) { using namespace blender::ed::space_node; @@ -463,22 +464,22 @@ void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) } } -bool ED_node_is_compositor(struct SpaceNode *snode) +bool ED_node_is_compositor(SpaceNode *snode) { return STREQ(snode->tree_idname, ntreeType_Composite->idname); } -bool ED_node_is_shader(struct SpaceNode *snode) +bool ED_node_is_shader(SpaceNode *snode) { return STREQ(snode->tree_idname, ntreeType_Shader->idname); } -bool ED_node_is_texture(struct SpaceNode *snode) +bool ED_node_is_texture(SpaceNode *snode) { return STREQ(snode->tree_idname, ntreeType_Texture->idname); } -bool ED_node_is_geometry(struct SpaceNode *snode) +bool ED_node_is_geometry(SpaceNode *snode) { return STREQ(snode->tree_idname, ntreeType_Geometry->idname); } @@ -549,7 +550,7 @@ void ED_node_shader_default(const bContext *C, ID *id) } } -void ED_node_composit_default(const bContext *C, struct Scene *sce) +void ED_node_composit_default(const bContext *C, Scene *sce) { /* but lets check it anyway */ if (sce->nodetree) { @@ -920,7 +921,7 @@ static void edit_node_properties_get( /** \name Node Generic * \{ */ -static bool socket_is_occluded(const bNodeSocket &sock, +static bool socket_is_occluded(const float2 &location, const bNode &node_the_socket_belongs_to, const SpaceNode &snode) { @@ -932,7 +933,7 @@ static bool socket_is_occluded(const bNodeSocket &sock, rctf socket_hitbox; const float socket_hitbox_radius = NODE_SOCKSIZE - 0.1f * U.widget_unit; - BLI_rctf_init_pt_radius(&socket_hitbox, float2(sock.locx, sock.locy), socket_hitbox_radius); + BLI_rctf_init_pt_radius(&socket_hitbox, location, socket_hitbox_radius); if (BLI_rctf_inside_rctf(&node->totr, &socket_hitbox)) { return true; } @@ -955,14 +956,14 @@ struct NodeSizeWidget { }; static void node_resize_init( - bContext *C, wmOperator *op, const float cursor[2], const bNode *node, NodeResizeDirection dir) + bContext *C, wmOperator *op, const float2 &cursor, const bNode *node, NodeResizeDirection dir) { NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__); op->customdata = nsw; - nsw->mxstart = cursor[0]; - nsw->mystart = cursor[1]; + nsw->mxstart = cursor.x; + nsw->mystart = cursor.y; /* store old */ nsw->oldlocx = node->locx; @@ -1009,12 +1010,12 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: { - int mval[2]; + int2 mval; WM_event_drag_start_mval(event, region, mval); float mx, my; - UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &mx, &my); - float dx = (mx - nsw->mxstart) / UI_DPI_FAC; - float dy = (my - nsw->mystart) / UI_DPI_FAC; + UI_view2d_region_to_view(®ion->v2d, mval.x, mval.y, &mx, &my); + const float dx = (mx - nsw->mxstart) / UI_DPI_FAC; + const float dy = (my - nsw->mystart) / UI_DPI_FAC; if (node) { float *pwidth = &node->width; @@ -1116,11 +1117,11 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event) } /* convert mouse coordinates to v2d space */ - float cursor[2]; - int mval[2]; + float2 cursor; + int2 mval; WM_event_drag_start_mval(event, region, mval); - UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); - const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]); + UI_view2d_region_to_view(®ion->v2d, mval.x, mval.y, &cursor.x, &cursor.y); + const NodeResizeDirection dir = node_get_resize_direction(node, cursor.x, cursor.y); if (dir == NODE_RESIZE_NONE) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -1198,21 +1199,22 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) } /* checks snode->mouse position, and returns found node/socket */ -static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket &socket) +static bool cursor_isect_multi_input_socket(const float2 &cursor, const bNodeSocket &socket) { const float node_socket_height = node_socket_calculate_height(socket); - rctf multi_socket_rect; + const float2 location(socket.locx, socket.locy); /* `.xmax = socket->locx + NODE_SOCKSIZE * 5.5f` * would be the same behavior as for regular sockets. * But keep it smaller because for multi-input socket you * sometimes want to drag the link to the other side, if you may * accidentally pick the wrong link otherwise. */ + rctf multi_socket_rect; BLI_rctf_init(&multi_socket_rect, - socket.locx - NODE_SOCKSIZE * 4.0f, - socket.locx + NODE_SOCKSIZE * 2.0f, - socket.locy - node_socket_height, - socket.locy + node_socket_height); - if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) { + location.x - NODE_SOCKSIZE * 4.0f, + location.x + NODE_SOCKSIZE * 2.0f, + location.y - node_socket_height, + location.y + node_socket_height); + if (BLI_rctf_isect_pt(&multi_socket_rect, cursor.x, cursor.y)) { return true; } return false; @@ -1250,17 +1252,18 @@ bool node_find_indicated_socket(SpaceNode &snode, if (in_out & SOCK_IN) { LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (!nodeSocketIsHidden(sock)) { + const float2 location(sock->locx, sock->locy); if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) { if (cursor_isect_multi_input_socket(cursor, *sock)) { - if (!socket_is_occluded(*sock, *node, snode)) { + if (!socket_is_occluded(location, *node, snode)) { *nodep = node; *sockp = sock; return true; } } } - else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - if (!socket_is_occluded(*sock, *node, snode)) { + else if (BLI_rctf_isect_pt(&rect, location.x, location.y)) { + if (!socket_is_occluded(location, *node, snode)) { *nodep = node; *sockp = sock; return true; @@ -1272,8 +1275,9 @@ bool node_find_indicated_socket(SpaceNode &snode, if (in_out & SOCK_OUT) { LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (!nodeSocketIsHidden(sock)) { - if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { - if (!socket_is_occluded(*sock, *node, snode)) { + const float2 location(sock->locx, sock->locy); + if (BLI_rctf_isect_pt(&rect, location.x, location.y)) { + if (!socket_is_occluded(location, *node, snode)) { *nodep = node; *sockp = sock; return true; @@ -1299,11 +1303,12 @@ float node_link_dim_factor(const View2D &v2d, const bNodeLink &link) return 1.0f; } + const float2 from(link.fromsock->locx, link.fromsock->locy); + const float2 to(link.tosock->locx, link.tosock->locy); + const float min_endpoint_distance = std::min( - std::max(BLI_rctf_length_x(&v2d.cur, link.fromsock->locx), - BLI_rctf_length_y(&v2d.cur, link.fromsock->locy)), - std::max(BLI_rctf_length_x(&v2d.cur, link.tosock->locx), - BLI_rctf_length_y(&v2d.cur, link.tosock->locy))); + std::max(BLI_rctf_length_x(&v2d.cur, from.x), BLI_rctf_length_y(&v2d.cur, from.y)), + std::max(BLI_rctf_length_x(&v2d.cur, to.x), BLI_rctf_length_y(&v2d.cur, to.y))); if (min_endpoint_distance == 0.0f) { return 1.0f; @@ -1362,7 +1367,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) bNode *lastnode = (bNode *)ntree->nodes.last; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - bNode *new_node = blender::bke::node_copy_with_mapping( + bNode *new_node = bke::node_copy_with_mapping( ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, new_node); changed = true; @@ -2229,12 +2234,12 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ - bNode *new_node = blender::bke::node_copy_with_mapping(nullptr, - *node, - LIB_ID_CREATE_NO_USER_REFCOUNT | - LIB_ID_CREATE_NO_MAIN, - false, - socket_map); + bNode *new_node = bke::node_copy_with_mapping(nullptr, + *node, + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_MAIN, + false, + socket_map); node_map.add_new(node, new_node); } } @@ -2354,11 +2359,11 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) node_deselect_all(*snode); /* calculate "barycenter" for placing on mouse cursor */ - float center[2] = {0.0f, 0.0f}; + float2 center = {0.0f, 0.0f}; int num_nodes = 0; LISTBASE_FOREACH_INDEX (bNode *, node, clipboard_nodes_lb, num_nodes) { - center[0] += BLI_rctf_cent_x(&node->totr); - center[1] += BLI_rctf_cent_y(&node->totr); + center.x += BLI_rctf_cent_x(&node->totr); + center.y += BLI_rctf_cent_y(&node->totr); } mul_v2_fl(center, 1.0 / num_nodes); @@ -2367,7 +2372,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) /* copy nodes from clipboard */ LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = blender::bke::node_copy_with_mapping( + bNode *new_node = bke::node_copy_with_mapping( ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, new_node); } @@ -2442,7 +2447,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) const eNodeSocketInOut in_out = (eNodeSocketInOut)RNA_enum_get(op->ptr, "in_out"); ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; - const char *default_name = (in_out == SOCK_IN) ? "Input" : "Output"; + const char *default_name = (in_out == SOCK_IN) ? DATA_("Input") : DATA_("Output"); bNodeSocket *active_sock = ntree_get_active_interface_socket(sockets); bNodeSocket *sock; diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc index 4f27f9baabc..f9126556b71 100644 --- a/source/blender/editors/space_node/node_gizmo.cc +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -49,14 +49,14 @@ static void node_gizmo_calc_matrix_space(const SpaceNode *snode, static void node_gizmo_calc_matrix_space_with_image_dims(const SpaceNode *snode, const ARegion *region, - const float image_dims[2], + const float2 &image_dims, float matrix_space[4][4]) { unit_m4(matrix_space); - mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]); - mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]); - matrix_space[3][0] = ((region->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom); - matrix_space[3][1] = ((region->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom); + mul_v3_fl(matrix_space[0], snode->zoom * image_dims.x); + mul_v3_fl(matrix_space[1], snode->zoom * image_dims.y); + matrix_space[3][0] = ((region->winx / 2) + snode->xof) - ((image_dims.x / 2.0f) * snode->zoom); + matrix_space[3][1] = ((region->winy / 2) + snode->yof) - ((image_dims.y / 2.0f) * snode->zoom); } /** \} */ @@ -135,7 +135,7 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { - const float dims[2] = { + const float2 dims = { (ibuf->x > 0) ? ibuf->x : 64.0f, (ibuf->y > 0) ? ibuf->y : 64.0f, }; @@ -190,7 +190,7 @@ struct NodeCropWidgetGroup { wmGizmo *border; struct { - float dims[2]; + float2 dims; } state; struct { @@ -206,10 +206,7 @@ static void gizmo_node_crop_update(struct NodeCropWidgetGroup *crop_group) crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop); } -static void two_xy_to_rect(const NodeTwoXYs *nxy, - rctf *rect, - const float dims[2], - bool is_relative) +static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float2 &dims, bool is_relative) { if (is_relative) { rect->xmin = nxy->fac_x1; @@ -218,16 +215,16 @@ static void two_xy_to_rect(const NodeTwoXYs *nxy, rect->ymax = nxy->fac_y2; } else { - rect->xmin = nxy->x1 / dims[0]; - rect->xmax = nxy->x2 / dims[0]; - rect->ymin = nxy->y1 / dims[1]; - rect->ymax = nxy->y2 / dims[1]; + rect->xmin = nxy->x1 / dims.x; + rect->xmax = nxy->x2 / dims.x; + rect->ymin = nxy->y1 / dims.y; + rect->ymax = nxy->y2 / dims.y; } } static void two_xy_from_rect(NodeTwoXYs *nxy, const rctf *rect, - const float dims[2], + const float2 &dims, bool is_relative) { if (is_relative) { @@ -237,10 +234,10 @@ static void two_xy_from_rect(NodeTwoXYs *nxy, nxy->fac_y2 = rect->ymax; } else { - nxy->x1 = rect->xmin * dims[0]; - nxy->x2 = rect->xmax * dims[0]; - nxy->y1 = rect->ymin * dims[1]; - nxy->y2 = rect->ymax * dims[1]; + nxy->x1 = rect->xmin * dims.x; + nxy->x2 = rect->xmax * dims.x; + nxy->y1 = rect->ymin * dims.y; + nxy->y2 = rect->ymax * dims.y; } } @@ -321,9 +318,7 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN( - sizeof(struct NodeCropWidgetGroup), __func__); - + NodeCropWidgetGroup *crop_group = MEM_new<NodeCropWidgetGroup>(__func__); crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(crop_group->border->ptr, @@ -407,7 +402,7 @@ struct NodeSunBeamsWidgetGroup { wmGizmo *gizmo; struct { - float dims[2]; + float2 dims; } state; }; @@ -512,7 +507,7 @@ struct NodeCornerPinWidgetGroup { wmGizmo *gizmos[4]; struct { - float dims[2]; + float2 dims; } state; }; diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index a926f7e8917..21def1bd9d7 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -25,6 +25,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_report.h" @@ -45,7 +46,12 @@ #include "UI_resources.h" #include "NOD_common.h" +#include "NOD_composite.h" +#include "NOD_geometry.h" +#include "NOD_shader.h" #include "NOD_socket.h" +#include "NOD_texture.h" + #include "node_intern.hh" /* own include */ namespace blender::ed::space_node { @@ -100,16 +106,16 @@ const char *node_group_idname(bContext *C) SpaceNode *snode = CTX_wm_space_node(C); if (ED_node_is_shader(snode)) { - return "ShaderNodeGroup"; + return ntreeType_Shader->group_idname; } if (ED_node_is_compositor(snode)) { - return "CompositorNodeGroup"; + return ntreeType_Composite->group_idname; } if (ED_node_is_texture(snode)) { - return "TextureNodeGroup"; + return ntreeType_Texture->group_idname; } if (ED_node_is_geometry(snode)) { - return "GeometryNodeGroup"; + return ntreeType_Geometry->group_idname; } return ""; @@ -457,8 +463,7 @@ static bool node_group_separate_selected( bNode *newnode; if (make_copy) { /* make a copy */ - newnode = blender::bke::node_copy_with_mapping( - &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + newnode = bke::node_copy_with_mapping(&ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, newnode); } else { @@ -648,7 +653,7 @@ static bool node_group_make_use_node(bNode &node, bNode *gnode) static bool node_group_make_test_selected(bNodeTree &ntree, bNode *gnode, const char *ntree_idname, - struct ReportList &reports) + ReportList &reports) { int ok = true; @@ -712,13 +717,13 @@ static int node_get_selected_minmax( INIT_MINMAX2(min, max); LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (node_group_make_use_node(*node, gnode)) { - float loc[2]; - nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]); - minmax_v2v2_v2(min, max, loc); + float2 loc; + nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y); + math::min_max(loc, min, max); if (use_size) { - loc[0] += node->width; - loc[1] -= node->height; - minmax_v2v2_v2(min, max, loc); + loc.x += node->width; + loc.y -= node->height; + math::min_max(loc, min, max); } totselect++; } @@ -832,8 +837,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* relink external sockets */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { - int fromselect = node_group_make_use_node(*link->fromnode, gnode); - int toselect = node_group_make_use_node(*link->tonode, gnode); + const bool fromselect = node_group_make_use_node(*link->fromnode, gnode); + const bool toselect = node_group_make_use_node(*link->tonode, gnode); if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) { /* remove all links to/from the gnode. @@ -913,8 +918,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* move internal links */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { - int fromselect = node_group_make_use_node(*link->fromnode, gnode); - int toselect = node_group_make_use_node(*link->tonode, gnode); + const bool fromselect = node_group_make_use_node(*link->fromnode, gnode); + const bool toselect = node_group_make_use_node(*link->tonode, gnode); if (fromselect && toselect) { BLI_remlink(&ntree.links, link); @@ -1037,9 +1042,6 @@ static int node_group_make_exec(bContext *C, wmOperator *op) nodeSetActive(&ntree, gnode); if (ngroup) { ED_node_tree_push(&snode, ngroup, gnode); - LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { - sort_multi_input_socket_links(snode, *node, nullptr, nullptr); - } } } diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 924537d0e8a..6754673cffc 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -144,7 +144,10 @@ void node_socket_color_get(const bContext &C, void node_draw_space(const bContext &C, ARegion ®ion); -void node_socket_add_tooltip(bNodeTree *ntree, bNode *node, bNodeSocket *sock, uiLayout *layout); +void node_socket_add_tooltip(const bNodeTree &ntree, + const bNode &node, + const bNodeSocket &sock, + uiLayout &layout); /** * Sort nodes by selection: unselected nodes first, then selected, @@ -166,7 +169,7 @@ void node_keymap(wmKeyConfig *keyconf); /* node_select.cc */ rctf node_frame_rect_inside(const bNode &node); -bool node_or_socket_isect_event(bContext *C, const wmEvent *event); +bool node_or_socket_isect_event(const bContext &C, const wmEvent &event); void node_deselect_all(SpaceNode &snode); void node_socket_select(bNode *node, bNodeSocket &sock); @@ -214,6 +217,10 @@ void node_draw_link(const bContext &C, const SpaceNode &snode, const bNodeLink &link, bool selected); +void node_draw_link_dragged(const bContext &C, + const View2D &v2d, + const SpaceNode &snode, + const bNodeLink &link); /** * Don't do shadows if th_col3 is -1. */ @@ -225,19 +232,12 @@ void node_draw_link_bezier(const bContext &C, int th_col2, int th_col3, bool selected); -/** If v2d not nullptr, it clips and returns 0 if not visible. */ -bool node_link_bezier_points(const View2D *v2d, - const SpaceNode *snode, - const bNodeLink &link, - float coord_array[][2], - int resol); -/** - * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr. - */ -bool node_link_bezier_handles(const View2D *v2d, - const SpaceNode *snode, - const bNodeLink &ink, - float vec[4][2]); + +void node_link_bezier_points_evaluated(const bNodeLink &link, + std::array<float2, NODE_LINK_RESOL + 1> &coords); + +std::optional<float2> link_path_intersection(const bNodeLink &link, Span<float2> path); + void draw_nodespace_back_pix(const bContext &C, ARegion ®ion, SpaceNode &snode, @@ -245,12 +245,9 @@ void draw_nodespace_back_pix(const bContext &C, /* node_add.cc */ -/** - * XXX Does some additional initialization on top of #nodeAddNode - * Can be used with both custom and static nodes, - * if `idname == nullptr` the static int type will be used instead. - */ -bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy); +bNode *add_node(const bContext &C, StringRef idname, const float2 &location); +bNode *add_static_node(const bContext &C, int type, const float2 &location); + void NODE_OT_add_reroute(wmOperatorType *ot); void NODE_OT_add_group(wmOperatorType *ot); void NODE_OT_add_object(wmOperatorType *ot); @@ -270,11 +267,6 @@ void NODE_OT_group_edit(wmOperatorType *ot); /* node_relationships.cc */ -void sort_multi_input_socket_links(SpaceNode &snode, - bNode &node, - bNodeLink *drag_link, - const float2 *cursor); - void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); void NODE_OT_links_cut(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index ce000aba1da..c936f07a594 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -111,7 +111,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_cryptomatte_layer_remove); } -void node_keymap(struct wmKeyConfig *keyconf) +void node_keymap( wmKeyConfig *keyconf) { /* Entire Editor only ----------------- */ WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index ce4ae421498..067c01dcc58 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -11,6 +11,7 @@ #include "DNA_node_types.h" #include "BLI_easing.h" +#include "BLI_stack.hh" #include "BKE_anim_data.h" #include "BKE_context.h" @@ -18,6 +19,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_screen.h" @@ -46,19 +48,11 @@ #include "BLT_translation.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" #include "node_intern.hh" /* own include */ -using namespace blender::nodes::node_tree_ref_types; - -struct bNodeListItem { - struct bNodeListItem *next, *prev; - struct bNode *node; -}; - struct NodeInsertOfsData { bNodeTree *ntree; bNode *insert; /* inserted node */ @@ -79,6 +73,8 @@ static void clear_picking_highlight(ListBase *links) namespace blender::ed::space_node { +void update_multi_input_indices_for_removed_links(bNode &node); + /* -------------------------------------------------------------------- */ /** \name Add Node * \{ */ @@ -109,11 +105,9 @@ static void pick_link( nldrag.links.append(link); nodeRemLink(snode.edittree, &link_to_pick); - + snode.edittree->ensure_topology_cache(); BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr); - - sort_multi_input_socket_links( - snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr); + update_multi_input_indices_for_removed_links(*nldrag.last_node_hovered_while_dragging_a_link); /* Send changed event to original link->tonode. */ if (node) { @@ -127,10 +121,8 @@ static void pick_input_link_by_link_intersect(const bContext &C, const float2 &cursor) { SpaceNode *snode = CTX_wm_space_node(&C); - const ARegion *region = CTX_wm_region(&C); - const View2D *v2d = ®ion->v2d; - float drag_start[2]; + float2 drag_start; RNA_float_get_array(op.ptr, "drag_start", drag_start); bNode *node; bNodeSocket *socket; @@ -139,26 +131,16 @@ static void pick_input_link_by_link_intersect(const bContext &C, /* Distance to test overlapping of cursor on link. */ const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC; - const int resolution = NODE_LINK_RESOL; - bNodeLink *link_to_pick = nullptr; clear_picking_highlight(&snode->edittree->links); LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { if (link->tosock == socket) { /* Test if the cursor is near a link. */ - float vec[4][2]; - node_link_bezier_handles(v2d, snode, *link, vec); - - float data[NODE_LINK_RESOL * 2 + 2]; - BKE_curve_forward_diff_bezier( - vec[0][0], vec[1][0], vec[2][0], vec[3][0], data, resolution, sizeof(float[2])); - BKE_curve_forward_diff_bezier( - vec[0][1], vec[1][1], vec[2][1], vec[3][1], data + 1, resolution, sizeof(float[2])); - - for (int i = 0; i < resolution * 2; i += 2) { - float *l1 = &data[i]; - float *l2 = &data[i + 2]; - float distance = dist_squared_to_line_segment_v2(cursor, l1, l2); + std::array<float2, NODE_LINK_RESOL + 1> coords; + node_link_bezier_points_evaluated(*link, coords); + + for (const int i : IndexRange(coords.size() - 1)) { + const float distance = dist_squared_to_line_segment_v2(cursor, coords[i], coords[i + 1]); if (distance < cursor_link_touch_distance) { link_to_pick = link; nldrag.last_picked_multi_input_socket_link = link_to_pick; @@ -310,35 +292,24 @@ struct LinkAndPosition { float2 multi_socket_position; }; -void sort_multi_input_socket_links(SpaceNode &snode, - bNode &node, - bNodeLink *drag_link, - const float2 *cursor) +static void sort_multi_input_socket_links_with_drag(bNode &node, + bNodeLink &drag_link, + const float2 &cursor) { - LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { - if (!(socket->flag & SOCK_MULTI_INPUT)) { + for (bNodeSocket *socket : node.input_sockets()) { + if (!socket->is_multi_input()) { continue; } - Vector<LinkAndPosition, 8> links; + const float2 &socket_location = {socket->locx, socket->locy}; - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (link->tosock == socket) { - links.append( - {link, - node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy}, - link->multi_input_socket_index, - link->tosock->total_inputs)}); - } - } + Vector<LinkAndPosition, 8> links; + for (bNodeLink *link : socket->directly_linked_links()) { + const float2 location = node_link_calculate_multi_input_position( + socket_location, link->multi_input_socket_index, link->tosock->total_inputs); + links.append({link, location}); + }; - if (drag_link) { - LinkAndPosition link_and_position{}; - link_and_position.link = drag_link; - if (cursor) { - link_and_position.multi_socket_position = *cursor; - } - links.append(link_and_position); - } + links.append({&drag_link, cursor}); std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) { return a.multi_socket_position.y < b.multi_socket_position.y; @@ -350,6 +321,23 @@ void sort_multi_input_socket_links(SpaceNode &snode, } } +void update_multi_input_indices_for_removed_links(bNode &node) +{ + for (bNodeSocket *socket : node.input_sockets()) { + if (!socket->is_multi_input()) { + continue; + } + Vector<bNodeLink *, 8> links = socket->directly_linked_links(); + std::sort(links.begin(), links.end(), [](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index < b->multi_input_socket_index; + }); + + for (const int i : links.index_range()) { + links[i]->multi_input_socket_index = i; + } + } +} + static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const bool replace) { bNodeTree *ntree = snode.edittree; @@ -434,18 +422,18 @@ namespace viewer_linking { * \{ */ /* Depending on the node tree type, different socket types are supported by viewer nodes. */ -static bool socket_can_be_viewed(const OutputSocketRef &socket) +static bool socket_can_be_viewed(const bNodeSocket &socket) { - if (nodeSocketIsHidden(socket.bsocket())) { + if (nodeSocketIsHidden(&socket)) { return false; } - if (socket.idname() == "NodeSocketVirtual") { + if (STREQ(socket.idname, "NodeSocketVirtual")) { return false; } - if (socket.tree().btree()->type != NTREE_GEOMETRY) { + if (socket.owner_tree().type != NTREE_GEOMETRY) { return true; } - return ELEM(socket.typeinfo()->type, + return ELEM(socket.typeinfo->type, SOCK_GEOMETRY, SOCK_FLOAT, SOCK_VECTOR, @@ -502,15 +490,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return nullptr; } -static bool is_viewer_node(const NodeRef &node) +static bool is_viewer_node(const bNode &node) { - return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); + return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); } -static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree) +static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree) { - Vector<const NodeRef *> viewer_nodes; - for (const NodeRef *node : tree.nodes()) { + Vector<const bNode *> viewer_nodes; + for (const bNode *node : tree.all_nodes()) { if (is_viewer_node(*node)) { viewer_nodes.append(node); } @@ -518,20 +506,20 @@ static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree) return viewer_nodes; } -static bool is_viewer_socket_in_viewer(const InputSocketRef &socket) +static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) { - const NodeRef &node = socket.node(); + const bNode &node = socket.owner_node(); BLI_assert(is_viewer_node(node)); - if (node.typeinfo()->type == GEO_NODE_VIEWER) { + if (node.typeinfo->type == GEO_NODE_VIEWER) { return true; } return socket.index() == 0; } -static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node) +static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node) { - for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) { - if (&target_socket->node() != &viewer_node) { + for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) { + if (&target_socket->owner_node() != &viewer_node) { continue; } if (!target_socket->is_available()) { @@ -561,39 +549,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode & } } -static const NodeRef *get_existing_viewer(const NodeTreeRef &tree) +static const bNode *get_existing_viewer(const bNodeTree &tree) { - Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree); + Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree); /* Check if there is already an active viewer node that should be used. */ - for (const NodeRef *viewer_node : viewer_nodes) { - if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *viewer_node : viewer_nodes) { + if (viewer_node->flag & NODE_DO_OUTPUT) { return viewer_node; } } /* If no active but non-active viewers exist, make one active. */ if (!viewer_nodes.is_empty()) { - viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT; + const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT; return viewer_nodes[0]; } return nullptr; } -static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node, - const NodeRef &node_to_view) +static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node, + const bNode &node_to_view) { /* Check if any of the output sockets is selected, which is the case when the user just clicked * on the socket. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { - if (output_socket->bsocket()->flag & SELECT) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { + if (output_socket->flag & SELECT) { return output_socket; } } - const OutputSocketRef *last_socket_linked_to_viewer = nullptr; + const bNodeSocket *last_socket_linked_to_viewer = nullptr; if (active_viewer_node != nullptr) { - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (!socket_can_be_viewed(*output_socket)) { continue; } @@ -604,7 +592,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } if (last_socket_linked_to_viewer == nullptr) { /* If no output is connected to a viewer, use the first output that can be viewed. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (socket_can_be_viewed(*output_socket)) { return output_socket; } @@ -612,10 +600,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } else { /* Pick the next socket to be linked to the viewer. */ - const int tot_outputs = node_to_view.outputs().size(); + const int tot_outputs = node_to_view.output_sockets().size(); for (const int offset : IndexRange(1, tot_outputs - 1)) { const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs; - const OutputSocketRef &output_socket = node_to_view.output(index); + const bNodeSocket &output_socket = node_to_view.output_socket(index); if (!socket_can_be_viewed(output_socket)) { continue; } @@ -639,13 +627,9 @@ static int link_socket_to_viewer(const bContext &C, if (viewer_bnode == nullptr) { /* Create a new viewer node if none exists. */ const int viewer_type = get_default_viewer_type(&C); - /* The socket location is in view space, so dividing by #UI_DPI_FAC - * brings it into the coordinate space of the node editor. */ - viewer_bnode = node_add_node(C, - nullptr, - viewer_type, - bsocket_to_view.locx / UI_DPI_FAC + 100, - bsocket_to_view.locy / UI_DPI_FAC); + const float2 location{bsocket_to_view.locx / UI_DPI_FAC + 100, + bsocket_to_view.locy / UI_DPI_FAC}; + viewer_bnode = add_static_node(C, viewer_type, location); if (viewer_bnode == nullptr) { return OPERATOR_CANCELLED; } @@ -687,20 +671,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) { SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree *btree = snode.edittree; + btree->ensure_topology_cache(); - const NodeTreeRef tree{btree}; - const NodeRef &node_to_view = *tree.find_node(bnode_to_view); - const NodeRef *active_viewer_node = get_existing_viewer(tree); - - const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node, - node_to_view); - if (socket_to_view == nullptr) { + bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree)); + bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>( + find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view)); + if (bsocket_to_view == nullptr) { return OPERATOR_FINISHED; } - - bNodeSocket &bsocket_to_view = *socket_to_view->bsocket(); - bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr; - return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); + return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view); } /** \} */ @@ -954,6 +933,7 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur if (nldrag->in_out == SOCK_OUT) { bNode *tnode; bNodeSocket *tsock = nullptr; + snode.edittree->ensure_topology_cache(); if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { for (bNodeLink *link : nldrag->links) { /* skip if socket is on the same node as the fromsock */ @@ -980,19 +960,19 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur continue; } if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) { - sort_multi_input_socket_links(snode, *tnode, link, &cursor); + sort_multi_input_socket_links_with_drag(*tnode, *link, cursor); } } } else { for (bNodeLink *link : nldrag->links) { - if (nldrag->last_node_hovered_while_dragging_a_link) { - sort_multi_input_socket_links( - snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor); - } link->tonode = nullptr; link->tosock = nullptr; } + if (nldrag->last_node_hovered_while_dragging_a_link) { + update_multi_input_indices_for_removed_links( + *nldrag->last_node_hovered_while_dragging_a_link); + } } } else { @@ -1189,7 +1169,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) bool detach = RNA_boolean_get(op->ptr, "detach"); - int mval[2]; + int2 mval; WM_event_drag_start_mval(event, ®ion, mval); float2 cursor; @@ -1329,28 +1309,6 @@ void NODE_OT_link_make(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Node Link Intersect - * \{ */ - -static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot) -{ - float coord_array[NODE_LINK_RESOL + 1][2]; - - if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) { - for (int i = 0; i < tot - 1; i++) { - for (int b = 0; b < NODE_LINK_RESOL; b++) { - if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) { - return true; - } - } - } - } - return false; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Cut Link Operator * \{ */ @@ -1358,56 +1316,63 @@ static int cut_links_exec(bContext *C, wmOperator *op) { Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); + const ARegion ®ion = *CTX_wm_region(C); - int i = 0; - float mcoords[256][2]; + Vector<float2> path; RNA_BEGIN (op->ptr, itemptr, "path") { - float loc[2]; - - RNA_float_get_array(&itemptr, "loc", loc); - UI_view2d_region_to_view( - ®ion.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]); - i++; - if (i >= 256) { + float2 loc_region; + RNA_float_get_array(&itemptr, "loc", loc_region); + float2 loc_view; + UI_view2d_region_to_view(®ion.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y); + path.append(loc_view); + if (path.size() >= 256) { break; } } RNA_END; - if (i > 1) { - bool found = false; + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + bool found = false; - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - if (node_links_intersect(*link, mcoords, i)) { + bNodeTree &node_tree = *snode.edittree; - if (found == false) { - /* TODO(sergey): Why did we kill jobs twice? */ - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - found = true; - } + Set<bNode *> affected_nodes; - bNode *to_node = link->tonode; - nodeRemLink(snode.edittree, link); - sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr); - } + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_tree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); - if (found) { - return OPERATOR_FINISHED; + if (link_path_intersection(*link, path)) { + + if (!found) { + /* TODO(sergey): Why did we kill jobs twice? */ + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + found = true; + } + + bNode *to_node = link->tonode; + nodeRemLink(snode.edittree, link); + affected_nodes.add(to_node); } + } - return OPERATOR_CANCELLED; + node_tree.ensure_topology_cache(); + for (bNode *node : affected_nodes) { + update_multi_input_indices_for_removed_links(*node); } - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + if (found) { + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } void NODE_OT_links_cut(wmOperatorType *ot) @@ -1441,69 +1406,99 @@ void NODE_OT_links_cut(wmOperatorType *ot) /** \name Mute Links Operator * \{ */ +static bool all_links_muted(const bNodeSocket &socket) +{ + for (const bNodeLink *link : socket.directly_linked_links()) { + if (!(link->flag & NODE_LINK_MUTED)) { + return false; + } + } + return true; +} + static int mute_links_exec(bContext *C, wmOperator *op) { Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); + const ARegion ®ion = *CTX_wm_region(C); + bNodeTree &ntree = *snode.edittree; - int i = 0; - float mcoords[256][2]; + Vector<float2> path; RNA_BEGIN (op->ptr, itemptr, "path") { - float loc[2]; - - RNA_float_get_array(&itemptr, "loc", loc); - UI_view2d_region_to_view( - ®ion.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]); - i++; - if (i >= 256) { + float2 loc_region; + RNA_float_get_array(&itemptr, "loc", loc_region); + float2 loc_view; + UI_view2d_region_to_view(®ion.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y); + path.append(loc_view); + if (path.size() >= 256) { break; } } RNA_END; - if (i > 1) { - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } - /* Count intersected links and clear test flag. */ - int tot = 0; - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } - link->flag &= ~NODE_LINK_TEST; - if (node_links_intersect(*link, mcoords, i)) { - tot++; - } + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + + ntree.ensure_topology_cache(); + + Set<bNodeLink *> affected_links; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; } - if (tot == 0) { - return OPERATOR_CANCELLED; + if (!link_path_intersection(*link, path)) { + continue; } + affected_links.add(link); + } - /* Mute links. */ - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) { - continue; - } + if (affected_links.is_empty()) { + return OPERATOR_CANCELLED; + } + + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + + for (bNodeLink *link : affected_links) { + nodeLinkSetMute(&ntree, link, !(link->flag & NODE_LINK_MUTED)); + const bool muted = link->flag & NODE_LINK_MUTED; - if (node_links_intersect(*link, mcoords, i)) { - nodeMuteLinkToggle(snode.edittree, link); + /* Propagate mute status downsteam past reroute nodes. */ + if (link->tonode->is_reroute()) { + Stack<bNodeLink *> links; + links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links()); + while (!links.is_empty()) { + bNodeLink *link = links.pop(); + nodeLinkSetMute(&ntree, link, muted); + if (!link->tonode->is_reroute()) { + continue; + } + links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links()); } } - - /* Clear remaining test flags. */ - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; + /* Propagate mute status upstream past reroutes, but only if all outputs are muted. */ + if (link->fromnode->is_reroute()) { + if (!muted || all_links_muted(*link->fromsock)) { + Stack<bNodeLink *> links; + links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links()); + while (!links.is_empty()) { + bNodeLink *link = links.pop(); + nodeLinkSetMute(&ntree, link, muted); + if (!link->fromnode->is_reroute()) { + continue; + } + if (!muted || all_links_muted(*link->fromsock)) { + links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links()); + } + } } - link->flag &= ~NODE_LINK_TEST; } - - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); - return OPERATOR_FINISHED; } - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + return OPERATOR_FINISHED; } void NODE_OT_links_mute(wmOperatorType *ot) @@ -1659,7 +1654,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; - /* XXX save selection: node_add_node call below sets the new frame as single + /* XXX save selection: add_static_node call below sets the new frame as single * active+selected node */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (node->flag & NODE_SELECT) { @@ -1670,7 +1665,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) } } - bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f); + bNode *frame = add_static_node(*C, NODE_FRAME, float2(0)); /* reset tags */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { @@ -1719,11 +1714,11 @@ void NODE_OT_join(wmOperatorType *ot) static bNode *node_find_frame_to_attach(ARegion ®ion, const bNodeTree &ntree, - const int mouse_xy[2]) + const int2 mouse_xy) { /* convert mouse coordinates to v2d space */ - float cursor[2]; - UI_view2d_region_to_view(®ion.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); + float2 cursor; + UI_view2d_region_to_view(®ion.v2d, mouse_xy.x, mouse_xy.y, &cursor.x, &cursor.y); LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) { /* skip selected, those are the nodes we want to attach */ @@ -1947,6 +1942,7 @@ static bool ed_node_link_conditions(ScrArea *area, void ED_node_link_intersect_test(ScrArea *area, int test) { + using namespace blender; using namespace blender::ed::space_node; bNode *select; @@ -1970,36 +1966,34 @@ void ED_node_link_intersect_test(ScrArea *area, int test) bNodeLink *selink = nullptr; float dist_best = FLT_MAX; LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - float coord_array[NODE_LINK_RESOL + 1][2]; if (node_link_is_hidden_or_dimmed(region->v2d, *link)) { continue; } - if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) { - float dist = FLT_MAX; + std::array<float2, NODE_LINK_RESOL + 1> coords; + node_link_bezier_points_evaluated(*link, coords); + float dist = FLT_MAX; - /* loop over link coords to find shortest dist to - * upper left node edge of a intersected line segment */ - for (int i = 0; i < NODE_LINK_RESOL; i++) { - /* Check if the node rectangle intersects the line from this point to next one. */ - if (BLI_rctf_isect_segment(&select->totr, coord_array[i], coord_array[i + 1])) { - /* store the shortest distance to the upper left edge - * of all intersections found so far */ - const float node_xy[] = {select->totr.xmin, select->totr.ymax}; + /* loop over link coords to find shortest dist to + * upper left node edge of a intersected line segment */ + for (int i = 0; i < NODE_LINK_RESOL; i++) { + /* Check if the node rectangle intersects the line from this point to next one. */ + if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) { + /* store the shortest distance to the upper left edge + * of all intersections found so far */ + const float node_xy[] = {select->totr.xmin, select->totr.ymax}; - /* to be precise coord_array should be clipped by select->totr, - * but not done since there's no real noticeable difference */ - dist = min_ff( - dist_squared_to_line_segment_v2(node_xy, coord_array[i], coord_array[i + 1]), dist); - } + /* to be precise coords should be clipped by select->totr, + * but not done since there's no real noticeable difference */ + dist = min_ff(dist_squared_to_line_segment_v2(node_xy, coords[i], coords[i + 1]), dist); } + } - /* we want the link with the shortest distance to node center */ - if (dist < dist_best) { - dist_best = dist; - selink = link; - } + /* we want the link with the shortest distance to node center */ + if (dist < dist_best) { + dist_best = dist; + selink = link; } } @@ -2053,7 +2047,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const nodes::NodeDeclaration *node_decl = node.runtime->declaration; + const nodes::NodeDeclaration *node_decl = node.declaration(); if (node_decl != nullptr) { Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : node_decl->outputs(); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 9d73156edab..8cc3c80fdfd 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -48,7 +48,7 @@ namespace blender::ed::space_node { -static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event); +static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event); /** * Function to detect if there is a visible view3d that uses workbench in texture mode. @@ -100,17 +100,17 @@ rctf node_frame_rect_inside(const bNode &node) return frame_inside; } -bool node_or_socket_isect_event(bContext *C, const wmEvent *event) +bool node_or_socket_isect_event(const bContext &C, const wmEvent &event) { return is_event_over_node_or_socket(C, event); } -static bool node_frame_select_isect_mouse(bNode *node, const float2 &mouse) +static bool node_frame_select_isect_mouse(const bNode &node, const float2 &mouse) { /* Frame nodes are selectable by their borders (including their whole rect - as for other nodes - * would prevent e.g. box selection of nodes inside that frame). */ - const rctf frame_inside = node_frame_rect_inside(*node); - if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y) && + const rctf frame_inside = node_frame_rect_inside(node); + if (BLI_rctf_isect_pt(&node.totr, mouse.x, mouse.y) && !BLI_rctf_isect_pt(&frame_inside, mouse.x, mouse.y)) { return true; } @@ -118,19 +118,18 @@ static bool node_frame_select_isect_mouse(bNode *node, const float2 &mouse) return false; } -static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my) +static bNode *node_under_mouse_select(bNodeTree &ntree, const float2 mouse) { LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { switch (node->type) { case NODE_FRAME: { - const float2 mouse{(float)mx, (float)my}; - if (node_frame_select_isect_mouse(node, mouse)) { + if (node_frame_select_isect_mouse(*node, mouse)) { return node; } break; } default: { - if (BLI_rctf_isect_pt(&node->totr, mx, my)) { + if (BLI_rctf_isect_pt(&node->totr, int(mouse.x), int(mouse.y))) { return node; } break; @@ -140,35 +139,32 @@ static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my) return nullptr; } -static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse) +static bool node_under_mouse_tweak(const bNodeTree &ntree, const float2 &mouse) { - using namespace blender::math; - - LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { + LISTBASE_FOREACH_BACKWARD (const bNode *, node, &ntree.nodes) { switch (node->type) { case NODE_REROUTE: { - bNodeSocket *socket = (bNodeSocket *)node->inputs.first; - const float2 location{socket->locx, socket->locy}; - if (distance(mouse, location) < 24.0f) { - return node; + const float2 location = node_to_view(*node, {node->locx, node->locy}); + if (math::distance(mouse, location) < 24.0f) { + return true; } break; } case NODE_FRAME: { - if (node_frame_select_isect_mouse(node, mouse)) { - return node; + if (node_frame_select_isect_mouse(*node, mouse)) { + return true; } break; } default: { if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y)) { - return node; + return true; } break; } } } - return nullptr; + return false; } static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mouse) @@ -187,17 +183,17 @@ static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mous return false; } -static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event) +static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event) { - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *region = CTX_wm_region(C); - float2 mouse; + SpaceNode &snode = *CTX_wm_space_node(&C); + ARegion ®ion = *CTX_wm_region(&C); - int mval[2]; - WM_event_drag_start_mval(event, region, mval); + int2 mval; + WM_event_drag_start_mval(&event, ®ion, mval); - UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &mouse.x, &mouse.y); - return is_position_over_node_or_socket(*snode, mouse); + float2 mouse; + UI_view2d_region_to_view(®ion.v2d, mval.x, mval.y, &mouse.x, &mouse.y); + return is_position_over_node_or_socket(snode, mouse); } void node_socket_select(bNode *node, bNodeSocket &sock) @@ -514,8 +510,8 @@ void node_select_single(bContext &C, bNode &node) static bool node_mouse_select(bContext *C, wmOperator *op, - const int mval[2], - struct SelectPick_Params *params) + const int2 mval, + SelectPick_Params *params) { Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); @@ -526,7 +522,6 @@ static bool node_mouse_select(bContext *C, bNode *node, *tnode; bNodeSocket *sock = nullptr; bNodeSocket *tsock; - float cursor[2]; /* always do socket_select when extending selection. */ const bool socket_select = (params->sel_op == SEL_OP_XOR) || @@ -536,7 +531,8 @@ static bool node_mouse_select(bContext *C, bool node_was_selected = false; /* get mouse coordinates in view2d space */ - UI_view2d_region_to_view(®ion.v2d, mval[0], mval[1], &cursor[0], &cursor[1]); + float2 cursor; + UI_view2d_region_to_view(®ion.v2d, mval.x, mval.y, &cursor.x, &cursor.y); /* first do socket selection, these generally overlap with nodes. */ if (socket_select) { @@ -593,7 +589,7 @@ static bool node_mouse_select(bContext *C, if (!sock) { /* find the closest visible node */ - node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]); + node = node_under_mouse_select(*snode.edittree, cursor); found = (node != nullptr); node_was_selected = node && (node->flag & SELECT); @@ -667,10 +663,10 @@ static bool node_mouse_select(bContext *C, static int node_select_exec(bContext *C, wmOperator *op) { /* get settings from RNA properties for operator */ - int mval[2]; + int2 mval; RNA_int_get_array(op->ptr, "location", mval); - struct SelectPick_Params params = {}; + SelectPick_Params params = {}; ED_select_pick_params_from_operator(op->ptr, ¶ms); /* perform the select */ @@ -787,7 +783,7 @@ static int node_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *ev { const bool tweak = RNA_boolean_get(op->ptr, "tweak"); - if (tweak && is_event_over_node_or_socket(C, event)) { + if (tweak && is_event_over_node_or_socket(*C, *event)) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -836,7 +832,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op) bNode *node; int x, y, radius; - float offset[2]; + float2 offset; float zoom = (float)(BLI_rcti_size_x(®ion->winrct)) / (float)(BLI_rctf_size_x(®ion->v2d.cur)); @@ -854,7 +850,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op) y = RNA_int_get(op->ptr, "y"); radius = RNA_int_get(op->ptr, "radius"); - UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); + UI_view2d_region_to_view(®ion->v2d, x, y, &offset.x, &offset.y); for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { switch (node->type) { @@ -916,7 +912,7 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent * { const bool tweak = RNA_boolean_get(op->ptr, "tweak"); - if (tweak && is_event_over_node_or_socket(C, event)) { + if (tweak && is_event_over_node_or_socket(*C, *event)) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -968,14 +964,14 @@ static bool do_lasso_select_node(bContext *C, break; } default: { - int screen_co[2]; - const float cent[2] = {BLI_rctf_cent_x(&node->totr), BLI_rctf_cent_y(&node->totr)}; + int2 screen_co; + const float2 center = {BLI_rctf_cent_x(&node->totr), BLI_rctf_cent_y(&node->totr)}; /* marker in screen coords */ if (UI_view2d_view_to_region_clip( - ®ion->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) && - BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) { + ®ion->v2d, center.x, center.y, &screen_co.x, &screen_co.y) && + BLI_rcti_isect_pt(&rect, screen_co.x, screen_co.y) && + BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co.x, screen_co.y, INT_MAX)) { nodeSetSelected(node, select); changed = true; } @@ -1298,7 +1294,7 @@ static void node_find_create_label(const bNode *node, char *str, int maxlen) } /* Generic search invoke. */ -static void node_find_update_fn(const struct bContext *C, +static void node_find_update_fn(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items, @@ -1330,7 +1326,7 @@ static void node_find_update_fn(const struct bContext *C, BLI_string_search_free(search); } -static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2) +static void node_find_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { SpaceNode *snode = CTX_wm_space_node(C); bNode *active = (bNode *)arg2; diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 58a313c328e..5fc194e02a4 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -758,43 +758,42 @@ namespace blender::ed::space_node { /**************************** Node Tree Layout *******************************/ static void ui_node_draw_input( - uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth); + uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, bNodeSocket &input, int depth); static void ui_node_draw_node( - uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth) + uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, int depth) { - bNodeSocket *input; PointerRNA nodeptr; - RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); + RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr); - if (node->typeinfo->draw_buttons) { - if (node->type != NODE_GROUP) { - uiLayoutSetPropSep(layout, true); - node->typeinfo->draw_buttons(layout, C, &nodeptr); + if (node.typeinfo->draw_buttons) { + if (node.type != NODE_GROUP) { + uiLayoutSetPropSep(&layout, true); + node.typeinfo->draw_buttons(&layout, &C, &nodeptr); } } - for (input = (bNodeSocket *)node->inputs.first; input; input = input->next) { - ui_node_draw_input(layout, C, ntree, node, input, depth + 1); + LISTBASE_FOREACH (bNodeSocket *, input, &node.inputs) { + ui_node_draw_input(layout, C, ntree, node, *input, depth + 1); } } static void ui_node_draw_input( - uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth) + uiLayout &layout, bContext &C, bNodeTree &ntree, bNode &node, bNodeSocket &input, int depth) { PointerRNA inputptr, nodeptr; - uiBlock *block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(&layout); uiLayout *row = nullptr; bool dependency_loop; - if (input->flag & SOCK_UNAVAIL) { + if (input.flag & SOCK_UNAVAIL) { return; } /* to avoid eternal loops on cyclic dependencies */ - node->flag |= NODE_TEST; - bNode *lnode = (input->link) ? input->link->fromnode : nullptr; + node.flag |= NODE_TEST; + bNode *lnode = (input.link) ? input.link->fromnode : nullptr; dependency_loop = (lnode && (lnode->flag & NODE_TEST)); if (dependency_loop) { @@ -802,10 +801,10 @@ static void ui_node_draw_input( } /* socket RNA pointer */ - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr); - RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); + RNA_pointer_create(&ntree.id, &RNA_NodeSocket, &input, &inputptr); + RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr); - row = uiLayoutRow(layout, true); + row = uiLayoutRow(&layout, true); /* Decorations are added manually here. */ uiLayoutSetPropDecorate(row, false); @@ -821,8 +820,8 @@ static void ui_node_draw_input( if (lnode && (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) { - int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : - ICON_DISCLOSURE_TRI_DOWN; + int icon = (input.flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : + ICON_DISCLOSURE_TRI_DOWN; uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon); } @@ -831,7 +830,7 @@ static void ui_node_draw_input( sub = uiLayoutRow(sub, true); uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); - uiItemL(sub, IFACE_(input->name), ICON_NONE); + uiItemL(sub, IFACE_(input.name), ICON_NONE); } if (dependency_loop) { @@ -840,28 +839,28 @@ static void ui_node_draw_input( } else if (lnode) { /* input linked to a node */ - uiTemplateNodeLink(row, C, ntree, node, input); + uiTemplateNodeLink(row, &C, &ntree, &node, &input); add_dummy_decorator = true; - if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) { + if (depth == 0 || !(input.flag & SOCK_COLLAPSED)) { if (depth == 0) { - uiItemS(layout); + uiItemS(&layout); } - ui_node_draw_node(layout, C, ntree, lnode, depth); + ui_node_draw_node(layout, C, ntree, *lnode, depth); } } else { uiLayout *sub = uiLayoutRow(row, true); - uiTemplateNodeLink(sub, C, ntree, node, input); + uiTemplateNodeLink(sub, &C, &ntree, &node, &input); - if (input->flag & SOCK_HIDE_VALUE) { + if (input.flag & SOCK_HIDE_VALUE) { add_dummy_decorator = true; } /* input not linked, show value */ else { - switch (input->type) { + switch (input.type) { case SOCK_VECTOR: uiItemS(sub); sub = uiLayoutColumn(sub, true); @@ -876,11 +875,11 @@ static void ui_node_draw_input( break; case SOCK_STRING: { const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id; - SpaceNode *snode = CTX_wm_space_node(C); + SpaceNode *snode = CTX_wm_space_node(&C); if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) { /* Only add the attribute search in the node editor, in other places there is not * enough context. */ - node_geometry_add_attribute_search_button(*C, *node, inputptr, *sub); + node_geometry_add_attribute_search_button(C, node, inputptr, *sub); } else { uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); @@ -899,10 +898,10 @@ static void ui_node_draw_input( uiItemDecoratorR(split_wrapper.decorate_column, nullptr, nullptr, 0); } - node_socket_add_tooltip(ntree, node, input, row); + node_socket_add_tooltip(ntree, node, input, *row); /* clear */ - node->flag &= ~NODE_TEST; + node.flag &= ~NODE_TEST; } } // namespace blender::ed::space_node @@ -924,9 +923,9 @@ void uiTemplateNodeView( } if (input) { - ui_node_draw_input(layout, C, ntree, node, input, 0); + ui_node_draw_input(*layout, *C, *ntree, *node, *input, 0); } else { - ui_node_draw_node(layout, C, ntree, node, 0); + ui_node_draw_node(*layout, *C, *ntree, *node, 0); } } diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index 6f30632244b..00756083580 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -177,7 +177,7 @@ void NODE_OT_view_selected(wmOperatorType *ot) * \{ */ struct NodeViewMove { - int mvalo[2]; + int2 mvalo; int xmin, ymin, xmax, ymax; /** Original Offset for cancel. */ float xof_orig, yof_orig; @@ -192,10 +192,10 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e switch (event->type) { case MOUSEMOVE: - snode->xof -= (nvm->mvalo[0] - event->mval[0]); - snode->yof -= (nvm->mvalo[1] - event->mval[1]); - nvm->mvalo[0] = event->mval[0]; - nvm->mvalo[1] = event->mval[1]; + snode->xof -= (nvm->mvalo.x - event->mval[0]); + snode->yof -= (nvm->mvalo.y - event->mval[1]); + nvm->mvalo.x = event->mval[0]; + nvm->mvalo.y = event->mval[1]; /* prevent dragging image outside of the window and losing it! */ CLAMP(snode->xof, nvm->xmin, nvm->xmax); @@ -252,10 +252,10 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_CANCELLED; } - nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct"); + nvm = MEM_cnew<NodeViewMove>(__func__); op->customdata = nvm; - nvm->mvalo[0] = event->mval[0]; - nvm->mvalo[1] = event->mval[1]; + nvm->mvalo.x = event->mval[0]; + nvm->mvalo.y = event->mval[1]; nvm->xmin = -(region->winx / 2) - (ibuf->x * (0.5f * snode->zoom)) + pad; nvm->xmax = (region->winx / 2) + (ibuf->x * (0.5f * snode->zoom)) - pad; @@ -447,7 +447,7 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info) } // namespace blender::ed::space_node bool ED_space_node_get_position( - Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2]) + Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float fpos[2]) { if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) { return false; @@ -645,7 +645,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* Don't handle events intended for nodes (which rely on click/drag distinction). * which this operator would use since sampling is normally activated on press, see: T98191. */ - if (node_or_socket_isect_event(C, event)) { + if (node_or_socket_isect_event(*C, *event)) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 15afd024766..17fc02e98a8 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -302,7 +302,7 @@ static void node_free(SpaceLink *sl) } /* spacetype; init callback */ -static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) +static void node_init(wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -362,7 +362,7 @@ static void node_area_tag_tree_recalc(SpaceNode *snode, ScrArea *area) static void node_area_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; - wmNotifier *wmn = params->notifier; + const wmNotifier *wmn = params->notifier; /* NOTE: #ED_area_tag_refresh will re-execute compositor. */ SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -511,7 +511,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) } } -static void node_area_refresh(const struct bContext *C, ScrArea *area) +static void node_area_refresh(const bContext *C, ScrArea *area) { /* default now: refresh node is starting preview */ SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -526,7 +526,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) if (snode->runtime->recalc_auto_compositing) { snode->runtime->recalc_auto_compositing = false; snode->runtime->recalc_regular_compositing = false; - node_render_changed_exec((struct bContext *)C, nullptr); + node_render_changed_exec((bContext *)C, nullptr); } else if (snode->runtime->recalc_regular_compositing) { snode->runtime->recalc_regular_compositing = false; @@ -753,7 +753,7 @@ static void node_header_region_draw(const bContext *C, ARegion *region) static void node_region_listener(const wmRegionListenerParams *params) { ARegion *region = params->region; - wmNotifier *wmn = params->notifier; + const wmNotifier *wmn = params->notifier; wmGizmoMap *gzmap = region->gizmo_map; /* context changes */ @@ -973,9 +973,7 @@ static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data) } } -static void node_id_remap(ScrArea *UNUSED(area), - SpaceLink *slink, - const struct IDRemapper *mappings) +static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, const IDRemapper *mappings) { /* Although we should be able to perform all the mappings in a single go this lead to issues when * running the python test cases. Somehow the nodetree/edittree weren't updated to the new |