/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "node_geometry_util.hh" #include "UI_interface.h" #include "UI_resources.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BKE_material.h" #include "NOD_socket_search_link.hh" #include "FN_multi_function_signature.hh" namespace blender::nodes::node_geo_switch_cc { NODE_STORAGE_FUNCS(NodeSwitch) static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Switch")).default_value(false).supports_field(); b.add_input(N_("Switch"), "Switch_001").default_value(false); b.add_input(N_("False")).supports_field(); b.add_input(N_("True")).supports_field(); b.add_input(N_("False"), "False_001").min(-100000).max(100000).supports_field(); b.add_input(N_("True"), "True_001").min(-100000).max(100000).supports_field(); b.add_input(N_("False"), "False_002") .default_value(false) .hide_value() .supports_field(); b.add_input(N_("True"), "True_002") .default_value(true) .hide_value() .supports_field(); b.add_input(N_("False"), "False_003").supports_field(); b.add_input(N_("True"), "True_003").supports_field(); b.add_input(N_("False"), "False_004") .default_value({0.8f, 0.8f, 0.8f, 1.0f}) .supports_field(); b.add_input(N_("True"), "True_004") .default_value({0.8f, 0.8f, 0.8f, 1.0f}) .supports_field(); b.add_input(N_("False"), "False_005").supports_field(); b.add_input(N_("True"), "True_005").supports_field(); b.add_input(N_("False"), "False_006"); b.add_input(N_("True"), "True_006"); b.add_input(N_("False"), "False_007"); b.add_input(N_("True"), "True_007"); b.add_input(N_("False"), "False_008"); b.add_input(N_("True"), "True_008"); b.add_input(N_("False"), "False_009"); b.add_input(N_("True"), "True_009"); b.add_input(N_("False"), "False_010"); b.add_input(N_("True"), "True_010"); b.add_input(N_("False"), "False_011"); b.add_input(N_("True"), "True_011"); b.add_output(N_("Output")).dependent_field(); b.add_output(N_("Output"), "Output_001").dependent_field(); b.add_output(N_("Output"), "Output_002").dependent_field(); b.add_output(N_("Output"), "Output_003").dependent_field(); b.add_output(N_("Output"), "Output_004").dependent_field(); b.add_output(N_("Output"), "Output_005").dependent_field(); b.add_output(N_("Output"), "Output_006"); b.add_output(N_("Output"), "Output_007"); b.add_output(N_("Output"), "Output_008"); b.add_output(N_("Output"), "Output_009"); b.add_output(N_("Output"), "Output_010"); b.add_output(N_("Output"), "Output_011"); } static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) { uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE); } static void node_init(bNodeTree * /*tree*/, bNode *node) { NodeSwitch *data = MEM_cnew(__func__); data->input_type = SOCK_GEOMETRY; node->storage = data; } static void node_update(bNodeTree *ntree, bNode *node) { const NodeSwitch &storage = node_storage(*node); int index = 0; bNodeSocket *field_switch = static_cast(node->inputs.first); bNodeSocket *non_field_switch = static_cast(field_switch->next); const bool fields_type = ELEM( storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING); nodeSetSocketAvailability(ntree, field_switch, fields_type); nodeSetSocketAvailability(ntree, non_field_switch, !fields_type); LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) { if (index <= 1) { continue; } nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type); } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type); } } static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) { if (params.in_out() == SOCK_OUT) { params.add_item(IFACE_("Output"), [](LinkSearchOpParams ¶ms) { bNode &node = params.add_node("GeometryNodeSwitch"); node_storage(node).input_type = params.socket.type; params.update_and_connect_available_socket(node, "Output"); }); } else { if (params.other_socket().type == SOCK_BOOLEAN) { params.add_item(IFACE_("Switch"), [](LinkSearchOpParams ¶ms) { bNode &node = params.add_node("GeometryNodeSwitch"); params.connect_available_socket(node, "Start"); }); } params.add_item(IFACE_("False"), [](LinkSearchOpParams ¶ms) { bNode &node = params.add_node("GeometryNodeSwitch"); node_storage(node).input_type = params.socket.type; params.update_and_connect_available_socket(node, "False"); }); params.add_item(IFACE_("True"), [](LinkSearchOpParams ¶ms) { bNode &node = params.add_node("GeometryNodeSwitch"); node_storage(node).input_type = params.socket.type; params.update_and_connect_available_socket(node, "True"); }); } } template void switch_fields(GeoNodeExecParams ¶ms, const StringRef suffix) { if (params.lazy_require_input("Switch")) { return; } const std::string name_false = "False" + suffix; const std::string name_true = "True" + suffix; const std::string name_output = "Output" + suffix; Field switches_field = params.get_input>("Switch"); if (switches_field.node().depends_on_input()) { /* The switch has to be incorporated into the field. Both inputs have to be evaluated. */ const bool require_false = params.lazy_require_input(name_false); const bool require_true = params.lazy_require_input(name_true); if (require_false | require_true) { return; } Field falses_field = params.extract_input>(name_false); Field trues_field = params.extract_input>(name_true); static fn::CustomMF_SI_SI_SI_SO switch_fn{ "Switch", [](bool condition, const T &false_value, const T &true_value) { return condition ? true_value : false_value; }}; auto switch_op = std::make_shared(FieldOperation( std::move(switch_fn), {std::move(switches_field), std::move(falses_field), std::move(trues_field)})); params.set_output(name_output, Field(switch_op, 0)); } else { /* The switch input is constant, so just evaluate and forward one of the inputs. */ const bool switch_value = fn::evaluate_constant_field(switches_field); if (switch_value) { params.set_input_unused(name_false); if (params.lazy_require_input(name_true)) { return; } params.set_output(name_output, params.extract_input>(name_true)); } else { params.set_input_unused(name_true); if (params.lazy_require_input(name_false)) { return; } params.set_output(name_output, params.extract_input>(name_false)); } } } template void switch_no_fields(GeoNodeExecParams ¶ms, const StringRef suffix) { if (params.lazy_require_input("Switch_001")) { return; } bool switch_value = params.get_input("Switch_001"); const std::string name_false = "False" + suffix; const std::string name_true = "True" + suffix; const std::string name_output = "Output" + suffix; if (switch_value) { params.set_input_unused(name_false); if (params.lazy_require_input(name_true)) { return; } params.set_output(name_output, params.extract_input(name_true)); } else { params.set_input_unused(name_true); if (params.lazy_require_input(name_false)) { return; } params.set_output(name_output, params.extract_input(name_false)); } } static void node_geo_exec(GeoNodeExecParams params) { const NodeSwitch &storage = node_storage(params.node()); const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type); switch (data_type) { case SOCK_FLOAT: { switch_fields(params, ""); break; } case SOCK_INT: { switch_fields(params, "_001"); break; } case SOCK_BOOLEAN: { switch_fields(params, "_002"); break; } case SOCK_VECTOR: { switch_fields(params, "_003"); break; } case SOCK_RGBA: { switch_fields(params, "_004"); break; } case SOCK_STRING: { switch_fields(params, "_005"); break; } case SOCK_GEOMETRY: { switch_no_fields(params, "_006"); break; } case SOCK_OBJECT: { switch_no_fields(params, "_007"); break; } case SOCK_COLLECTION: { switch_no_fields(params, "_008"); break; } case SOCK_TEXTURE: { switch_no_fields(params, "_009"); break; } case SOCK_MATERIAL: { switch_no_fields(params, "_010"); break; } case SOCK_IMAGE: { switch_no_fields(params, "_011"); break; } default: BLI_assert_unreachable(); break; } } } // namespace blender::nodes::node_geo_switch_cc void register_node_type_geo_switch() { namespace file_ns = blender::nodes::node_geo_switch_cc; static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare; ntype.initfunc = file_ns::node_init; ntype.updatefunc = file_ns::node_update; node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; ntype.gather_link_search_ops = file_ns::node_gather_link_searches; ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); }