[Bf-blender-cvs] [c7eada103c6] master: Nodes: support implicit conversions and incorrectly linked sockets

Jacques Lucke noreply at git.blender.org
Sat Jul 11 18:02:24 CEST 2020


Commit: c7eada103c67021052f4c6a2340ca8f744cf17db
Author: Jacques Lucke
Date:   Sat Jul 11 18:02:06 2020 +0200
Branches: master
https://developer.blender.org/rBc7eada103c67021052f4c6a2340ca8f744cf17db

Nodes: support implicit conversions and incorrectly linked sockets

===================================================================

M	source/blender/blenkernel/intern/node_tree_multi_function.cc
M	source/blender/functions/FN_multi_function_builder.hh
M	tests/gtests/functions/FN_multi_function_test.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/node_tree_multi_function.cc b/source/blender/blenkernel/intern/node_tree_multi_function.cc
index 02437d98732..1aaefd4a301 100644
--- a/source/blender/blenkernel/intern/node_tree_multi_function.cc
+++ b/source/blender/blenkernel/intern/node_tree_multi_function.cc
@@ -16,6 +16,8 @@
 
 #include "BKE_node_tree_multi_function.hh"
 
+#include "BLI_float3.hh"
+
 namespace blender {
 namespace bke {
 
@@ -136,37 +138,93 @@ static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
   }
 
   if (from_dsockets.size() == 1) {
-    return &common.network_map.lookup(*from_dsockets[0]);
+    if (is_multi_function_data_socket(from_dsockets[0]->bsocket())) {
+      return &common.network_map.lookup(*from_dsockets[0]);
+    }
+    else {
+      return nullptr;
+    }
   }
   else {
-    return &common.network_map.lookup(*from_group_inputs[0]);
+    if (is_multi_function_data_socket(from_group_inputs[0]->bsocket())) {
+      return &common.network_map.lookup(*from_group_inputs[0]);
+    }
+    else {
+      return nullptr;
+    }
   }
 }
 
+static const fn::MultiFunction *try_get_conversion_function(fn::MFDataType from, fn::MFDataType to)
+{
+  if (from == fn::MFDataType::ForSingle<float>()) {
+    if (to == fn::MFDataType::ForSingle<float3>()) {
+      static fn::CustomMF_Convert<float, float3> function;
+      return &function;
+    }
+  }
+  if (from == fn::MFDataType::ForSingle<float3>()) {
+    if (to == fn::MFDataType::ForSingle<float>()) {
+      static fn::CustomMF_SI_SO<float3, float> function{"Vector Length",
+                                                        [](float3 a) { return a.length(); }};
+      return &function;
+    }
+  }
+  return nullptr;
+}
+
+static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
+                                                         fn::MFDataType type)
+{
+  const fn::MultiFunction *default_fn;
+  if (type.is_single()) {
+    default_fn = &common.resources.construct<fn::CustomMF_GenericConstant>(
+        AT, type.single_type(), type.single_type().default_value());
+  }
+  else {
+    default_fn = &common.resources.construct<fn::CustomMF_GenericConstantArray>(
+        AT, fn::GSpan(type.vector_base_type()));
+  }
+
+  fn::MFNode &node = common.network.add_function(*default_fn);
+  return node.output(0);
+}
+
 static void insert_links(CommonMFNetworkBuilderData &common)
 {
   for (const DInputSocket *to_dsocket : common.tree.input_sockets()) {
     if (!to_dsocket->is_available()) {
       continue;
     }
-
-    if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
+    if (!to_dsocket->is_linked()) {
       continue;
     }
-
-    fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
-    if (from_socket == nullptr) {
+    if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
       continue;
     }
 
     Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket);
     BLI_assert(to_sockets.size() >= 1);
+    fn::MFDataType to_type = to_sockets[0]->data_type();
+
+    fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket);
+    if (from_socket == nullptr) {
+      from_socket = &insert_default_value_for_type(common, to_type);
+    }
 
     fn::MFDataType from_type = from_socket->data_type();
-    fn::MFDataType to_type = to_sockets[0]->data_type();
 
     if (from_type != to_type) {
-      /* Todo: Try inserting implicit conversion. */
+      const fn::MultiFunction *conversion_fn = try_get_conversion_function(from_type, to_type);
+      if (conversion_fn != nullptr) {
+        fn::MFNode &node = common.network.add_function(*conversion_fn);
+        common.network.add_link(*from_socket, node.input(0));
+        from_socket = &node.output(0);
+      }
+      else {
+        from_socket = &insert_default_value_for_type(common, to_type);
+        continue;
+      }
     }
 
     for (fn::MFInputSocket *to_socket : to_sockets) {
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 5905d1cc315..6e7efb21850 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -202,6 +202,30 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
   }
 };
 
+/**
+ * Generates a multi-function that converts between two types.
+ */
+template<typename From, typename To> class CustomMF_Convert : public MultiFunction {
+ public:
+  CustomMF_Convert()
+  {
+    std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
+    MFSignatureBuilder signature = this->get_builder(std::move(name));
+    signature.single_input<From>("Input");
+    signature.single_output<To>("Output");
+  }
+
+  void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+  {
+    VSpan<From> inputs = params.readonly_single_input<From>(0);
+    MutableSpan<To> outputs = params.uninitialized_single_output<To>(1);
+
+    for (uint i : mask) {
+      new ((void *)&outputs[i]) To(inputs[i]);
+    }
+  }
+};
+
 /**
  * A multi-function that outputs the same value every time. The value is not owned by an instance
  * of this function. The caller is responsible for destructing and freeing the value.
diff --git a/tests/gtests/functions/FN_multi_function_test.cc b/tests/gtests/functions/FN_multi_function_test.cc
index 51115e4cd6b..2544f1c63b0 100644
--- a/tests/gtests/functions/FN_multi_function_test.cc
+++ b/tests/gtests/functions/FN_multi_function_test.cc
@@ -364,4 +364,23 @@ TEST(multi_function, CustomMF_GenericConstantArray)
   }
 }
 
+TEST(multi_function, CustomMF_Convert)
+{
+  CustomMF_Convert<float, int> fn;
+
+  Array<float> inputs = {5.4f, 7.1f, 9.0f};
+  Array<int> outputs{inputs.size(), 0};
+
+  MFParamsBuilder params(fn, inputs.size());
+  params.add_readonly_single_input(inputs.as_span());
+  params.add_uninitialized_single_output(outputs.as_mutable_span());
+
+  MFContextBuilder context;
+  fn.call({0, 2}, params, context);
+
+  EXPECT_EQ(outputs[0], 5);
+  EXPECT_EQ(outputs[1], 0);
+  EXPECT_EQ(outputs[2], 9);
+}
+
 }  // namespace blender::fn



More information about the Bf-blender-cvs mailing list