diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index ba6e1c37810..c1b2ceab113 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1094,13 +1094,6 @@ static void std_node_socket_draw( // int subtype = sock->typeinfo->subtype; const nodes::SocketDeclaration *socket_decl = sock->runtime->declaration; - if (socket_decl) { - if (socket_decl->custom_draw_fn) { - nodes::CustomSocketDrawParams params{*C, *layout, *tree, *node, *sock, *node_ptr, *ptr}; - (*socket_decl->custom_draw_fn)(params); - return; - } - } if (sock->is_inactive()) { layout->active_set(false); diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index ae55fe18a7b..aefa45ffa1e 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -96,6 +96,7 @@ #include "NOD_node_declaration.hh" #include "NOD_node_extra_info.hh" #include "NOD_sync_sockets.hh" +#include "NOD_trace_values.hh" #include "GEO_fillet_curves.hh" @@ -149,6 +150,13 @@ struct TreeDrawContext { */ Map reroute_auto_labels; + /** + * Index Switch nodes can draw labels retrieved from a connected menu switch node. The + * corresponding node pairs are preprocessed to avoid the overhead of having to detect them while + * drawing individual sockets. + */ + Map menu_switch_source_by_index_switch; + /** * Precomputed extra info rows for each node. This avoids having to compute them multiple times * during drawing. The array is indexed by `bNode::index()`. @@ -489,7 +497,38 @@ const char *node_socket_get_label(const bNodeSocket *socket, const char *panel_l return translated_socket_label; } -static bool node_update_basis_socket(const bContext &C, +static void draw_socket_layout(TreeDrawContext &tree_draw_ctx, + const bContext &C, + uiLayout &layout, + bNodeSocket &socket, + bNodeTree &ntree, + bNode &node, + PointerRNA &node_ptr, + PointerRNA &socket_ptr, + const char *panel_label) +{ + const nodes::SocketDeclaration *socket_decl = socket.runtime->declaration; + const StringRefNull label = node_socket_get_label(&socket, panel_label); + nodes::CustomSocketDrawParams params{C, + layout, + ntree, + node, + socket, + node_ptr, + socket_ptr, + label, + &tree_draw_ctx.menu_switch_source_by_index_switch}; + if (socket_decl) { + if (socket_decl->custom_draw_fn) { + (*socket_decl->custom_draw_fn)(params); + return; + } + } + params.draw_standard(layout); +} + +static bool node_update_basis_socket(TreeDrawContext &tree_draw_ctx, + const bContext &C, bNodeTree &ntree, bNode &node, const char *panel_label, @@ -545,8 +584,8 @@ static bool node_update_basis_socket(const bContext &C, row->alignment_set(ui::LayoutAlign::Expand); - input_socket->typeinfo->draw( - (bContext *)&C, row, &sockptr, &nodeptr, node_socket_get_label(input_socket, panel_label)); + draw_socket_layout( + tree_draw_ctx, C, *row, *input_socket, ntree, node, nodeptr, sockptr, panel_label); } else { /* Context pointers for current node and socket. */ @@ -556,11 +595,8 @@ static bool node_update_basis_socket(const bContext &C, /* Align output buttons to the right. */ row->alignment_set(ui::LayoutAlign::Right); - output_socket->typeinfo->draw((bContext *)&C, - row, - &sockptr, - &nodeptr, - node_socket_get_label(output_socket, panel_label)); + draw_socket_layout( + tree_draw_ctx, C, *row, *output_socket, ntree, node, nodeptr, sockptr, panel_label); } if (input_socket) { @@ -1098,8 +1134,13 @@ static void tag_final_panel(bNode &node, const Span items) } /* Advanced drawing with panels and arbitrary input/output ordering. */ -static void node_update_basis_from_declaration( - const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block, const int locx, int &locy) +static void node_update_basis_from_declaration(TreeDrawContext &tree_draw_ctx, + const bContext &C, + bNodeTree &ntree, + bNode &node, + uiBlock &block, + const int locx, + int &locy) { BLI_assert(is_node_panels_supported(node)); BLI_assert(node.runtime->panels.size() == node.num_panel_states); @@ -1146,8 +1187,16 @@ static void node_update_basis_from_declaration( bNodeSocket *output_socket = item.output; const nodes::PanelDeclaration *panel_decl = item.panel_decl; const char *parent_label = panel_decl ? panel_decl->name.c_str() : ""; - node_update_basis_socket( - C, ntree, node, parent_label, input_socket, output_socket, block, locx, locy); + node_update_basis_socket(tree_draw_ctx, + C, + ntree, + node, + parent_label, + input_socket, + output_socket, + block, + locx, + locy); } else if constexpr (std::is_same_v) { const nodes::LayoutDeclaration &decl = *item.decl; @@ -1223,8 +1272,13 @@ static void node_update_basis_from_declaration( } /* Conventional drawing in outputs/buttons/inputs order. */ -static void node_update_basis_from_socket_lists( - const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block, const int locx, int &locy) +static void node_update_basis_from_socket_lists(TreeDrawContext &tree_draw_ctx, + const bContext &C, + bNodeTree &ntree, + bNode &node, + uiBlock &block, + const int locx, + int &locy) { /* Space at the top. */ locy -= NODE_DYS / 2; @@ -1236,7 +1290,9 @@ static void node_update_basis_from_socket_lists( /* Clear flag, conventional drawing does not support panels. */ socket->flag &= ~SOCK_PANEL_COLLAPSED; - if (node_update_basis_socket(C, ntree, node, nullptr, nullptr, socket, block, locx, locy)) { + if (node_update_basis_socket( + tree_draw_ctx, C, ntree, node, nullptr, nullptr, socket, block, locx, locy)) + { if (socket->next) { locy -= NODE_ITEM_SPACING_Y; } @@ -1258,7 +1314,9 @@ static void node_update_basis_from_socket_lists( /* Clear flag, conventional drawing does not support panels. */ socket->flag &= ~SOCK_PANEL_COLLAPSED; - if (node_update_basis_socket(C, ntree, node, nullptr, socket, nullptr, block, locx, locy)) { + if (node_update_basis_socket( + tree_draw_ctx, C, ntree, node, nullptr, socket, nullptr, block, locx, locy)) + { if (socket->next) { locy -= NODE_ITEM_SPACING_Y; } @@ -1276,7 +1334,7 @@ static void node_update_basis_from_socket_lists( * Based on settings and sockets in node, set drawing rect info. */ static void node_update_basis(const bContext &C, - const TreeDrawContext & /*tree_draw_ctx*/, + TreeDrawContext &tree_draw_ctx, bNodeTree &ntree, bNode &node, uiBlock &block) @@ -1290,10 +1348,10 @@ static void node_update_basis(const bContext &C, dy -= NODE_DY; if (is_node_panels_supported(node)) { - node_update_basis_from_declaration(C, ntree, node, block, loc.x, dy); + node_update_basis_from_declaration(tree_draw_ctx, C, ntree, node, block, loc.x, dy); } else { - node_update_basis_from_socket_lists(C, ntree, node, block, loc.x, dy); + node_update_basis_from_socket_lists(tree_draw_ctx, C, ntree, node, block, loc.x, dy); } node.runtime->draw_bounds.xmin = loc.x; @@ -3933,8 +3991,8 @@ static void frame_node_draw_overlay(const bContext &C, UI_block_draw(&C, &block); } -static Set find_sockets_on_active_gizmo_paths(const bContext &C, - const SpaceNode &snode) +static Set find_sockets_on_active_gizmo_paths( + const bContext &C, const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache) { const std::optional object_and_modifier = ed::space_node::get_modifier_for_node_editor(snode); @@ -3943,7 +4001,6 @@ static Set find_sockets_on_active_gizmo_paths(const bContex } snode.edittree->ensure_topology_cache(); - bke::ComputeContextCache compute_context_cache; const ComputeContext *current_compute_context = ed::space_node::compute_context_for_edittree( snode, compute_context_cache); if (!current_compute_context) { @@ -4714,6 +4771,29 @@ static void snode_setup_v2d(SpaceNode &snode, ARegion ®ion, const float2 &cen snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / float(region.winx); } +static Map find_menu_switch_sources_for_index_switch_nodes( + const SpaceNode &snode, + const bNodeTree &ntree, + bke::ComputeContextCache &compute_context_cache) +{ + Map result; + for (const bNode *index_switch_node : ntree.nodes_by_type("GeometryNodeIndexSwitch")) { + const bNodeSocket &index_socket = index_switch_node->input_socket(0); + const ComputeContext *compute_context = ed::space_node::compute_context_for_edittree_socket( + snode, compute_context_cache, index_socket); + if (!compute_context) { + continue; + } + const std::optional menu_switch = nodes::find_origin_index_menu_switch( + {compute_context, &index_socket}, compute_context_cache); + if (!menu_switch) { + continue; + } + result.add(index_switch_node, menu_switch->node); + } + return result; +} + static void draw_nodetree(const bContext &C, ARegion ®ion, bNodeTree &ntree, @@ -4726,6 +4806,8 @@ static void draw_nodetree(const bContext &C, Array blocks = node_uiblocks_init(C, nodes); + bke::ComputeContextCache compute_context_cache; + TreeDrawContext tree_draw_ctx; tree_draw_ctx.bmain = CTX_data_main(&C); tree_draw_ctx.window = CTX_wm_window(&C); @@ -4733,6 +4815,8 @@ static void draw_nodetree(const bContext &C, tree_draw_ctx.region = CTX_wm_region(&C); tree_draw_ctx.depsgraph = CTX_data_depsgraph_pointer(&C); tree_draw_ctx.extra_info_rows_per_node.reinitialize(nodes.size()); + tree_draw_ctx.menu_switch_source_by_index_switch = + find_menu_switch_sources_for_index_switch_nodes(*snode, ntree, compute_context_cache); BLI_SCOPED_DEFER([&]() { ntree.runtime->sockets_on_active_gizmo_paths.clear(); }); if (ntree.type == NTREE_GEOMETRY) { @@ -4747,7 +4831,8 @@ static void draw_nodetree(const bContext &C, /* This set of socket is used when drawing links to determine which links should use the * special gizmo drawing. */ - ntree.runtime->sockets_on_active_gizmo_paths = find_sockets_on_active_gizmo_paths(C, *snode); + ntree.runtime->sockets_on_active_gizmo_paths = find_sockets_on_active_gizmo_paths( + C, *snode, compute_context_cache); } else if (ntree.type == NTREE_COMPOSIT) { const Scene *scene = CTX_data_scene(&C); diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index a047d24bbf1..24e98eda6c2 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -9,6 +9,7 @@ #include #include "BLI_array.hh" +#include "BLI_map.hh" #include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" @@ -189,6 +190,10 @@ struct CustomSocketDrawParams { bNodeSocket &socket; PointerRNA node_ptr; PointerRNA socket_ptr; + StringRefNull label; + const Map *menu_switch_source_by_index_switch = nullptr; + + void draw_standard(uiLayout &layout, std::optional label_override = std::nullopt); }; using CustomSocketDrawFn = std::function; diff --git a/source/blender/nodes/NOD_trace_values.hh b/source/blender/nodes/NOD_trace_values.hh index de308423bf5..6dc5745c723 100644 --- a/source/blender/nodes/NOD_trace_values.hh +++ b/source/blender/nodes/NOD_trace_values.hh @@ -45,4 +45,7 @@ LinkedClosureSignatures gather_linked_origin_closure_signatures( const bNodeSocket &closure_socket, bke::ComputeContextCache &compute_context_cache); +std::optional find_origin_index_menu_switch( + const SocketInContext &socket, bke::ComputeContextCache &compute_context_cache); + } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_index_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_index_switch.cc index 600c6c91399..54427660058 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_index_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_index_switch.cc @@ -2,9 +2,11 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#include "UI_interface_c.hh" +#include + #include "node_geometry_util.hh" +#include "UI_interface_c.hh" #include "UI_interface_layout.hh" #include "UI_resources.hh" @@ -26,6 +28,48 @@ namespace blender::nodes::node_geo_index_switch_cc { NODE_STORAGE_FUNCS(NodeIndexSwitch) +static void draw_item_socket(CustomSocketDrawParams ¶ms, const int index) +{ + if (!params.menu_switch_source_by_index_switch) { + params.draw_standard(params.layout); + return; + } + const bNode *menu_switch_node = params.menu_switch_source_by_index_switch->lookup_default( + ¶ms.node, nullptr); + if (!menu_switch_node) { + params.draw_standard(params.layout); + return; + } + const auto &menu_switch_storage = *static_cast( + menu_switch_node->storage); + BLI_assert(menu_switch_storage.data_type == SOCK_INT); + const NodeEnumItem *found_item = nullptr; + for (const int i : IndexRange(menu_switch_storage.enum_definition.items_num)) { + const NodeEnumItem &item = menu_switch_storage.enum_definition.items_array[i]; + const bNodeSocket &menu_switch_input_socket = menu_switch_node->input_socket(1 + i); + if (menu_switch_input_socket.is_directly_linked()) { + params.draw_standard(params.layout); + return; + } + const auto &menu_switch_input_socket_value = *static_cast( + menu_switch_input_socket.default_value); + if (menu_switch_input_socket_value.value == index) { + if (found_item) { + /* Found multiple items, so there is not a unique label for this index. */ + params.draw_standard(params.layout); + return; + } + found_item = &item; + } + } + if (!found_item) { + params.draw_standard(params.layout); + return; + } + const std::string label = fmt::format("{}: {}", index, found_item->name); + params.draw_standard(params.layout, label); +} + static void node_declare(NodeDeclarationBuilder &b) { const bNode *node = b.node_or_null(); @@ -49,6 +93,8 @@ static void node_declare(NodeDeclarationBuilder &b) for (const int i : items.index_range()) { const std::string identifier = IndexSwitchItemsAccessor::socket_identifier_for_item(items[i]); auto &input = b.add_input(data_type, std::to_string(i), std::move(identifier)); + input.custom_draw( + [index = i](CustomSocketDrawParams ¶ms) { draw_item_socket(params, index); }); if (supports_fields) { input.supports_field(); } diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index e31ed25b89a..8114f0d416d 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -1120,4 +1120,14 @@ bool socket_type_supports_default_input_type(const bke::bNodeSocketType &socket_ return false; } +void CustomSocketDrawParams::draw_standard(uiLayout &layout, + const std::optional label_override) +{ + this->socket.typeinfo->draw(const_cast(&this->C), + &layout, + &this->socket_ptr, + &this->node_ptr, + (label_override.has_value()) ? *label_override : this->label); +} + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/trace_values.cc b/source/blender/nodes/intern/trace_values.cc index 4351c9f5d35..7ec67b53789 100644 --- a/source/blender/nodes/intern/trace_values.cc +++ b/source/blender/nodes/intern/trace_values.cc @@ -666,4 +666,30 @@ LinkedClosureSignatures gather_linked_origin_closure_signatures( return result; } +std::optional find_origin_index_menu_switch( + const SocketInContext &src_socket, bke::ComputeContextCache &compute_context_cache) +{ + std::optional result; + find_origin_sockets_through_contexts( + src_socket, + compute_context_cache, + [&](const SocketInContext &socket) { + if (socket->is_input()) { + return false; + } + const NodeInContext node = socket.owner_node(); + if (!node->is_type("GeometryNodeMenuSwitch")) { + return false; + } + const auto &storage = *static_cast(node->storage); + if (storage.data_type != SOCK_INT) { + return false; + } + result = socket.owner_node(); + return true; + }, + false); + return result; +} + } // namespace blender::nodes