[Bf-blender-cvs] [4990e4dd01f] master: Nodes: Generate multi-function network from node tree

Jacques Lucke noreply at git.blender.org
Tue Jul 7 18:24:19 CEST 2020


Commit: 4990e4dd01f2b085f5d1842dfa31d79e4df92fbd
Author: Jacques Lucke
Date:   Tue Jul 7 18:23:33 2020 +0200
Branches: master
https://developer.blender.org/rB4990e4dd01f2b085f5d1842dfa31d79e4df92fbd

Nodes: Generate multi-function network from node tree

This adds new callbacks to `bNodeSocketType` and `bNodeType`.
Those are used to generate a multi-function network from a node
tree. Later, this network is evaluated on e.g. particle data.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D8169

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

M	source/blender/blenkernel/BKE_node.h
A	source/blender/blenkernel/BKE_node_tree_multi_function.hh
M	source/blender/blenkernel/CMakeLists.txt
A	source/blender/blenkernel/intern/node_tree_multi_function.cc
A	source/blender/blenlib/BLI_resource_collector.hh
M	source/blender/blenlib/CMakeLists.txt
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/function/node_function_util.cc
R091	source/blender/nodes/function/node_function_util.h	source/blender/nodes/function/node_function_util.hh
M	source/blender/nodes/function/nodes/node_fn_boolean_math.cc
M	source/blender/nodes/function/nodes/node_fn_combine_strings.cc
M	source/blender/nodes/function/nodes/node_fn_float_compare.cc
M	source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
M	source/blender/nodes/function/nodes/node_fn_switch.cc
M	source/blender/nodes/intern/node_socket.cc
M	source/blender/nodes/shader/node_shader_util.h
R054	source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c	source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc

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

diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index bdcbe2129c8..acd4c75befd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -101,6 +101,30 @@ typedef struct bNodeSocketTemplate {
   char identifier[64];      /* generated from name */
 } bNodeSocketTemplate;
 
+/* Use `void *` for callbacks that require C++. This is rather ugly, but works well for now. This
+ * would not be necessary if we would use bNodeSocketType and bNodeType only in C++ code.
+ * However, achieving this requires quite a few changes currently. */
+#ifdef __cplusplus
+namespace blender {
+namespace bke {
+class SocketMFNetworkBuilder;
+class NodeMFNetworkBuilder;
+}  // namespace bke
+namespace fn {
+class MFDataType;
+}
+}  // namespace blender
+
+using NodeExpandInMFNetworkFunction = void (*)(blender::bke::NodeMFNetworkBuilder &builder);
+using SocketGetMFDataTypeFunction = blender::fn::MFDataType (*)();
+using SocketExpandInMFNetworkFunction = void (*)(blender::bke::SocketMFNetworkBuilder &builder);
+
+#else
+typedef void *NodeExpandInMFNetworkFunction;
+typedef void *SocketGetMFDataTypeFunction;
+typedef void *SocketExpandInMFNetworkFunction;
+#endif
+
 /**
  * \brief Defines a socket type.
  *
@@ -153,6 +177,11 @@ typedef struct bNodeSocketType {
 
   /* Callback to free the socket type. */
   void (*free_self)(struct bNodeSocketType *stype);
+
+  /* Returns the multi-function data type of this socket type. */
+  SocketGetMFDataTypeFunction get_mf_data_type;
+  /* Expands the socket into a multi-function node that outputs the socket value. */
+  SocketExpandInMFNetworkFunction expand_in_mf_network;
 } bNodeSocketType;
 
 typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context,
@@ -267,6 +296,9 @@ typedef struct bNodeType {
   /* gpu */
   NodeGPUExecFunction gpufunc;
 
+  /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
+  NodeExpandInMFNetworkFunction expand_in_mf_network;
+
   /* RNA integration */
   ExtensionRNA rna_ext;
 } bNodeType;
diff --git a/source/blender/blenkernel/BKE_node_tree_multi_function.hh b/source/blender/blenkernel/BKE_node_tree_multi_function.hh
new file mode 100644
index 00000000000..34809a5f506
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_multi_function.hh
@@ -0,0 +1,355 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BKE_NODE_TREE_FUNCTION_HH__
+#define __BKE_NODE_TREE_FUNCTION_HH__
+
+/** \file
+ * \ingroup bke
+ *
+ * This file allows you to generate a multi-function network from a user-generated node tree.
+ */
+
+#include "FN_multi_function_builder.hh"
+#include "FN_multi_function_network.hh"
+
+#include "BKE_derived_node_tree.hh"
+
+#include "BLI_resource_collector.hh"
+
+namespace blender {
+namespace bke {
+
+/* Maybe this should be moved to BKE_node.h. */
+inline bool is_multi_function_data_socket(const bNodeSocket *bsocket)
+{
+  if (bsocket->typeinfo->get_mf_data_type != nullptr) {
+    BLI_assert(bsocket->typeinfo->expand_in_mf_network != nullptr);
+    return true;
+  }
+  return false;
+}
+
+/**
+ * A MFNetworkTreeMap maps various components of a bke::DerivedNodeTree to components of a
+ * fn::MFNetwork. This is necessary for further processing of a multi-function network that has
+ * been generated from a node tree.
+ */
+class MFNetworkTreeMap {
+ private:
+  /**
+   * Store by id instead of using a hash table to avoid unnecessary hash table lookups.
+   *
+   * Input sockets in a node tree can have multiple corresponding sockets in the generated
+   * MFNetwork. This is because nodes are allowed to expand into multiple multi-function nodes.
+   */
+  Array<Vector<fn::MFSocket *, 1>> m_sockets_by_dsocket_id;
+  Array<fn::MFOutputSocket *> m_socket_by_group_input_id;
+
+ public:
+  MFNetworkTreeMap(const DerivedNodeTree &tree)
+      : m_sockets_by_dsocket_id(tree.sockets().size()),
+        m_socket_by_group_input_id(tree.group_inputs().size(), nullptr)
+  {
+  }
+
+  void add(const DSocket &dsocket, fn::MFSocket &socket)
+  {
+    BLI_assert(dsocket.is_input() == socket.is_input());
+    m_sockets_by_dsocket_id[dsocket.id()].append(&socket);
+  }
+
+  void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
+  {
+    m_sockets_by_dsocket_id[dsocket.id()].append(&socket);
+  }
+
+  void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
+  {
+    m_sockets_by_dsocket_id[dsocket.id()].append(&socket);
+  }
+
+  void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets)
+  {
+    assert_same_size(dsockets, sockets);
+    for (uint i : dsockets.index_range()) {
+      this->add(*dsockets[i], *sockets[i]);
+    }
+  }
+
+  void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets)
+  {
+    assert_same_size(dsockets, sockets);
+    for (uint i : dsockets.index_range()) {
+      this->add(*dsockets[i], *sockets[i]);
+    }
+  }
+
+  void add(const DGroupInput &group_input, fn::MFOutputSocket &socket)
+  {
+    BLI_assert(m_socket_by_group_input_id[group_input.id()] == nullptr);
+    m_socket_by_group_input_id[group_input.id()] = &socket;
+  }
+
+  void add_try_match(const DNode &dnode, fn::MFNode &node)
+  {
+    this->add_try_match(dnode.inputs(), node.inputs());
+    this->add_try_match(dnode.outputs(), node.outputs());
+  }
+
+  void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets)
+  {
+    uint used_sockets = 0;
+    for (const DSocket *dsocket : dsockets) {
+      if (!dsocket->is_available()) {
+        continue;
+      }
+      if (!is_multi_function_data_socket(dsocket->bsocket())) {
+        continue;
+      }
+      fn::MFSocket *socket = sockets[used_sockets];
+      this->add(*dsocket, *socket);
+      used_sockets++;
+    }
+  }
+
+  fn::MFOutputSocket &lookup(const DGroupInput &group_input)
+  {
+    fn::MFOutputSocket *socket = m_socket_by_group_input_id[group_input.id()];
+    BLI_assert(socket != nullptr);
+    return *socket;
+  }
+
+  fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
+  {
+    auto &sockets = m_sockets_by_dsocket_id[dsocket.id()];
+    BLI_assert(sockets.size() == 1);
+    return sockets[0]->as_output();
+  }
+
+  Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
+  {
+    return m_sockets_by_dsocket_id[dsocket.id()].as_span().cast<fn::MFInputSocket *>();
+  }
+
+  fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
+  {
+    Span<fn::MFInputSocket *> sockets = this->lookup(dsocket);
+    BLI_assert(sockets.size() == 1);
+    fn::MFInputSocket &socket = *sockets[0];
+    BLI_assert(socket.node().is_dummy());
+    return socket;
+  }
+
+  fn::MFOutputSocket &lookup_dummy(const DOutputSocket &dsocket)
+  {
+    fn::MFOutputSocket &socket = this->lookup(dsocket);
+    BLI_assert(socket.node().is_dummy());
+    return socket;
+  }
+
+  bool is_mapped(const DSocket &dsocket) const
+  {
+    return m_sockets_by_dsocket_id[dsocket.id()].size() >= 1;
+  }
+};
+
+/**
+ * This data is necessary throughout the generation of a MFNetwork from a node tree.
+ */
+struct CommonMFNetworkBuilderData {
+  ResourceCollector &resources;
+  fn::MFNetwork &network;
+  MFNetworkTreeMap &network_map;
+  const DerivedNodeTree &tree;
+};
+
+class MFNetworkBuilderBase {
+ protected:
+  CommonMFNetworkBuilderData &m_common;
+
+ public:
+  MFNetworkBuilderBase(CommonMFNetworkBuilderData &common) : m_common(common)
+  {
+  }
+
+  /**
+   * Returns the network that is currently being built.
+   */
+  fn::MFNetwork &network()
+  {
+    return m_common.network;
+  }
+
+  /**
+   * Returns the map between the node tree and the multi-function network that is being built.
+   */
+  MFNetworkTreeMap &network_map()
+  {
+    return m_common.network_map;
+  }
+
+  /**
+   * Returns a resource collector that will only be destructed after the multi-function network is
+   * destructed.
+   */
+  ResourceCollector &resources()
+  {
+    return m_common.resources;
+  }
+
+  /**
+   * Constructs a new function that will live at least as long as the MFNetwork.
+   */
+  template<typename T, typename... Args> T &construct_fn(Args &&... args)
+  {
+    BLI_STATIC_ASSERT((std::is_base_of_v<fn::MultiFunction, T>), "");
+    void *buffer = m_common.resources.linear_allocator().allocate(sizeof(T), alignof(T));
+    T *fn = new (buffer) T(std::forward<Args>(args)...);
+    m_common.resources.add(destruct_ptr<T>(fn), fn->name().data());
+    return *fn;
+  }
+};
+
+/**
+ * This class is used by socket implementations to define how an unlinked input socket is handled
+ * in a multi-function network.
+ */
+class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
+ private:
+  const DSocket *m_dsocket = nullptr;
+  const DGroupInput *m_group_input = nullptr;
+  bNodeSocket *m_bsocket;
+  fn::MFOutputSocket *m_built_socket = nullptr;
+
+ public:
+  SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
+      : MFNetworkBuilderBase(common), m_dsocket(&dsocket), m_bsocket(dsocket.bsocket())
+  {
+  }
+
+  SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input)
+      : MFNetworkBuilderBase(common), m_group_input(&group_input), m_bsocket(group_input.bsocket())
+  {
+  }
+
+  /**
+   * Returns the socket that is currently being built.
+   */
+  bNodeSocket &bsocket()
+  {
+    return *m_bsocket;
+  }
+
+  /**
+   * Utility method that returns bsocket->default_value for the current socket.
+   */
+  template<typename

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list