From 68bccbaeeefe1ec007b7fe4caa2302afe06158e8 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Mon, 15 Sep 2025 09:09:43 +0200 Subject: [PATCH] Nodes: Recursively apply usage inference This patch extends the usage_by_menu method to also consider the usage of the menu socket in the make available and usage inference callbacks. This essentially means that if a socket depends on menu B which, in turn, depends on menu A, it will be sufficiently to check the value of menu B, while A will be checked recursively. The single variant of the usage_by_menu function is now implemented in terms of its overloaded vector variant for code deduplication since the new code increase the size quite a bit. Pull Request: https://projects.blender.org/blender/blender/pulls/146141 --- .../blender/nodes/intern/node_declaration.cc | 62 +++++++++++++------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index f8bc5a9ca19..e31ed25b89a 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -825,7 +825,7 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::usage_by_single_menu const bNodeSocket &socket = find_single_menu_input(params.node); if (const std::optional any_output_used = params.any_output_is_used()) { if (!*any_output_used) { - /* If no output is used, none if the inputs is used either. */ + /* If no output is used, none of the inputs is used either. */ return false; } } @@ -842,16 +842,8 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::usage_by_single_menu BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::usage_by_menu( const StringRef menu_input_identifier, const int menu_value) { - this->make_available([menu_input_identifier, menu_value](bNode &node) { - bNodeSocket &socket = *blender::bke::node_find_socket(node, SOCK_IN, menu_input_identifier); - bNodeSocketValueMenu *value = socket.default_value_typed(); - value->value = menu_value; - }); - this->usage_inference( - [menu_input_identifier, menu_value]( - const socket_usage_inference::InputSocketUsageParams ¶ms) -> std::optional { - return params.menu_input_may_be(menu_input_identifier, menu_value); - }); + Array menu_values = {menu_value}; + this->usage_by_menu(menu_input_identifier, menu_values); return *this; } @@ -859,20 +851,54 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::usage_by_menu( const StringRef menu_input_identifier, const Array menu_values) { this->make_available([menu_input_identifier, menu_values](bNode &node) { - bNodeSocket &socket = *blender::bke::node_find_socket(node, SOCK_IN, menu_input_identifier); - bNodeSocketValueMenu *value = socket.default_value_typed(); + bNodeSocket &menu_socket = *blender::bke::node_find_socket( + node, SOCK_IN, menu_input_identifier); + const SocketDeclaration &socket_declaration = *menu_socket.runtime->declaration; + socket_declaration.make_available(node); + bNodeSocketValueMenu *value = menu_socket.default_value_typed(); value->value = menu_values[0]; }); this->usage_inference( [menu_input_identifier, menu_values]( const socket_usage_inference::InputSocketUsageParams ¶ms) -> std::optional { - for (const int menu_value : menu_values) { - const bool might_be = params.menu_input_may_be(menu_input_identifier, menu_value); - if (might_be) { - return true; + if (const std::optional any_output_used = params.any_output_is_used()) { + if (!*any_output_used) { + /* If no output is used, none of the inputs is used either. */ + return false; } } - return false; + else { + /* It's not known if any output is used yet. This function will be called again once new + * information about output usages is available. */ + return std::nullopt; + } + + /* Check if the menu might be any of the given values. */ + bool menu_might_be_any_value = false; + for (const int menu_value : menu_values) { + menu_might_be_any_value = params.menu_input_may_be(menu_input_identifier, menu_value); + if (menu_might_be_any_value) { + break; + } + } + + const bNodeSocket &menu_socket = *blender::bke::node_find_socket( + params.node, SOCK_IN, menu_input_identifier); + const SocketDeclaration &menu_socket_declaration = *menu_socket.runtime->declaration; + if (!menu_socket_declaration.usage_inference_fn) { + return menu_might_be_any_value; + } + + /* If the menu socket has a usage inference function, check if it might be used. */ + const std::optional menu_might_be_used = + (*menu_socket_declaration.usage_inference_fn)(params); + if (!menu_might_be_used.has_value()) { + return menu_might_be_any_value; + } + + /* The input is only used if the menu might be any of the values and the menu itself is + * used. */ + return *menu_might_be_used && menu_might_be_any_value; }); return *this; }