From 34cf33eb12099d3a1940de070d7dc7e88e3bebc7 Mon Sep 17 00:00:00 2001 From: guitargeek Date: Sat, 2 Oct 2021 17:33:25 -0500 Subject: Geometry Nodes: Switch Node Fields Update This update of the Switch node allows for field compatible types to be switched through the node. This includes the following: Float, Int, Bool, String, Vector, and Color The remaining types are processed with the orginal code: Geometry, Object, Collection, Texture, and Material Because the old types require a diffent "switch" socket than the field types, versioning for old files is included to move links of those types to a new switch socket. Once fields of other types are supported, this node can be updated to support them as well. Differential Revision: https://developer.blender.org/D12642 --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_300.c | 26 +++ .../nodes/geometry/nodes/node_geo_switch.cc | 198 +++++++++++++++------ 3 files changed, 171 insertions(+), 55 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index b04bbdfb187..31ce1b124e9 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 31 +#define BLENDER_FILE_SUBVERSION 32 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 11b6ad9b8ea..5b436d59213 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -617,6 +617,32 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) do_versions_idproperty_ui_data(bmain); } + if (!MAIN_VERSION_ATLEAST(bmain, 300, 32)) { + /* Update Switch Node Non-Fields switch input to Switch_001. */ + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type != NTREE_GEOMETRY) { + continue; + } + + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + if (link->tonode->type == GEO_NODE_SWITCH) { + if (STREQ(link->tosock->identifier, "Switch")) { + bNode *to_node = link->tonode; + + uint8_t mode = ((NodeSwitch *)to_node->storage)->input_type; + if (ELEM(mode, + SOCK_GEOMETRY, + SOCK_OBJECT, + SOCK_COLLECTION, + SOCK_TEXTURE, + SOCK_MATERIAL)) { + link->tosock = link->tosock->next; + } + } + } + } + } + } /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index ca857c4d2e3..05df927fb39 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -19,24 +19,37 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_material.h" + +#include "FN_multi_function_signature.hh" + namespace blender::nodes { static void geo_node_switch_declare(NodeDeclarationBuilder &b) { - b.add_input("Switch"); - - b.add_input("False"); - b.add_input("True"); - b.add_input("False", "False_001").min(-100000).max(100000); - b.add_input("True", "True_001").min(-100000).max(100000); - b.add_input("False", "False_002"); - b.add_input("True", "True_002"); - b.add_input("False", "False_003"); - b.add_input("True", "True_003"); - b.add_input("False", "False_004").default_value({0.8f, 0.8f, 0.8f, 1.0f}); - b.add_input("True", "True_004").default_value({0.8f, 0.8f, 0.8f, 1.0f}); - b.add_input("False", "False_005"); - b.add_input("True", "True_005"); + b.add_input("Switch").default_value(false).supports_field(); + b.add_input("Switch", "Switch_001").default_value(false); + + b.add_input("False").supports_field(); + b.add_input("True").supports_field(); + b.add_input("False", "False_001").min(-100000).max(100000).supports_field(); + b.add_input("True", "True_001").min(-100000).max(100000).supports_field(); + b.add_input("False", "False_002").default_value(false).hide_value().supports_field(); + b.add_input("True", "True_002").default_value(true).hide_value().supports_field(); + b.add_input("False", "False_003").supports_field(); + b.add_input("True", "True_003").supports_field(); + b.add_input("False", "False_004") + .default_value({0.8f, 0.8f, 0.8f, 1.0f}) + .supports_field(); + b.add_input("True", "True_004") + .default_value({0.8f, 0.8f, 0.8f, 1.0f}) + .supports_field(); + b.add_input("False", "False_005").supports_field(); + b.add_input("True", "True_005").supports_field(); + b.add_input("False", "False_006"); b.add_input("True", "True_006"); b.add_input("False", "False_007"); @@ -48,12 +61,12 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b) b.add_input("False", "False_010"); b.add_input("True", "True_010"); - b.add_output("Output"); - b.add_output("Output", "Output_001"); - b.add_output("Output", "Output_002"); - b.add_output("Output", "Output_003"); - b.add_output("Output", "Output_004"); - b.add_output("Output", "Output_005"); + b.add_output("Output").dependent_field(); + b.add_output("Output", "Output_001").dependent_field(); + b.add_output("Output", "Output_002").dependent_field(); + b.add_output("Output", "Output_003").dependent_field(); + b.add_output("Output", "Output_004").dependent_field(); + b.add_output("Output", "Output_005").dependent_field(); b.add_output("Output", "Output_006"); b.add_output("Output", "Output_007"); b.add_output("Output", "Output_008"); @@ -77,91 +90,168 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) { NodeSwitch *node_storage = (NodeSwitch *)node->storage; int index = 0; - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - nodeSetSocketAvailability( - socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type); - index++; + bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first; + bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next; + + const bool fields_type = ELEM((eNodeSocketDatatype)node_storage->input_type, + SOCK_FLOAT, + SOCK_INT, + SOCK_BOOLEAN, + SOCK_VECTOR, + SOCK_RGBA, + SOCK_STRING); + + nodeSetSocketAvailability(field_switch, fields_type); + nodeSetSocketAvailability(non_field_switch, !fields_type); + + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) { + if (index <= 1) { + continue; + } + nodeSetSocketAvailability(socket, + socket->type == (eNodeSocketDatatype)node_storage->input_type); } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { nodeSetSocketAvailability(socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } } -template -static void output_input(GeoNodeExecParams ¶ms, - const bool input, - const StringRef input_suffix, - const StringRef output_identifier) +template class SwitchFieldsFunction : public fn::MultiFunction { + public: + SwitchFieldsFunction() + { + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + static fn::MFSignature create_signature() + { + fn::MFSignatureBuilder signature{"Switch"}; + signature.single_input("Switch"); + signature.single_input("False"); + signature.single_input("True"); + signature.single_output("Output"); + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArray &switches = params.readonly_single_input(0, "Switch"); + const VArray &falses = params.readonly_single_input(1, "False"); + const VArray &trues = params.readonly_single_input(2, "True"); + MutableSpan values = params.uninitialized_single_output_if_required(3, "Output"); + for (int64_t i : mask) { + new (&values[i]) T(switches[i] ? trues[i] : falses[i]); + } + } +}; + +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; + + /* TODO: Allow for Laziness when the switch field is constant. */ + 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 switches_field = params.extract_input>("Switch"); + Field falses_field = params.extract_input>(name_false); + Field trues_field = params.extract_input>(name_true); + + auto switch_fn = std::make_unique>(); + 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)); +} + +template void switch_no_fields(GeoNodeExecParams ¶ms, const StringRef suffix) { - const std::string name_a = "False" + input_suffix; - const std::string name_b = "True" + input_suffix; - if (input) { - params.set_input_unused(name_a); - if (params.lazy_require_input(name_b)) { + 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(output_identifier, params.extract_input(name_b)); + params.set_output(name_output, params.extract_input(name_true)); } else { - params.set_input_unused(name_b); - if (params.lazy_require_input(name_a)) { + params.set_input_unused(name_true); + if (params.lazy_require_input(name_false)) { return; } - params.set_output(output_identifier, params.extract_input(name_a)); + params.set_output(name_output, params.extract_input(name_false)); } } static void geo_node_switch_exec(GeoNodeExecParams params) { - if (params.lazy_require_input("Switch")) { - return; - } const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage; - const bool input = params.get_input("Switch"); - switch ((eNodeSocketDatatype)storage.input_type) { + const eNodeSocketDatatype data_type = static_cast(storage.input_type); + + switch (data_type) { + case SOCK_FLOAT: { - output_input(params, input, "", "Output"); + switch_fields(params, ""); break; } case SOCK_INT: { - output_input(params, input, "_001", "Output_001"); + switch_fields(params, "_001"); break; } case SOCK_BOOLEAN: { - output_input(params, input, "_002", "Output_002"); + switch_fields(params, "_002"); break; } case SOCK_VECTOR: { - output_input(params, input, "_003", "Output_003"); + switch_fields(params, "_003"); break; } case SOCK_RGBA: { - output_input(params, input, "_004", "Output_004"); + switch_fields(params, "_004"); break; } case SOCK_STRING: { - output_input(params, input, "_005", "Output_005"); + switch_fields(params, "_005"); break; } case SOCK_GEOMETRY: { - output_input(params, input, "_006", "Output_006"); + switch_no_fields(params, "_006"); break; } case SOCK_OBJECT: { - output_input(params, input, "_007", "Output_007"); + switch_no_fields(params, "_007"); break; } case SOCK_COLLECTION: { - output_input(params, input, "_008", "Output_008"); + switch_no_fields(params, "_008"); break; } case SOCK_TEXTURE: { - output_input(params, input, "_009", "Output_009"); + switch_no_fields(params, "_009"); break; } case SOCK_MATERIAL: { - output_input(params, input, "_010", "Output_010"); + switch_no_fields(params, "_010"); break; } default: -- cgit v1.2.3