[Bf-blender-cvs] [c71997dd672] functions: initial virtual node tree

Jacques Lucke noreply at git.blender.org
Mon Jul 22 18:13:07 CEST 2019


Commit: c71997dd672d1a02be54454f63389bd7a81b84ff
Author: Jacques Lucke
Date:   Mon Jul 22 14:19:12 2019 +0200
Branches: functions
https://developer.blender.org/rBc71997dd672d1a02be54454f63389bd7a81b84ff

initial virtual node tree

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

M	source/blender/blenkernel/BKE_node_tree.hpp
M	source/blender/blenkernel/intern/node_tree.cpp
M	source/blender/blenlib/BLI_monotonic_allocator.hpp
M	source/blender/functions/frontends/data_flow_nodes/graph_generation.cpp
M	source/blender/functions/frontends/data_flow_nodes/graph_generation.hpp

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

diff --git a/source/blender/blenkernel/BKE_node_tree.hpp b/source/blender/blenkernel/BKE_node_tree.hpp
index d996cff5a1a..69e0e8958e9 100644
--- a/source/blender/blenkernel/BKE_node_tree.hpp
+++ b/source/blender/blenkernel/BKE_node_tree.hpp
@@ -8,6 +8,7 @@
 #include "BLI_small_vector.hpp"
 #include "BLI_listbase_wrapper.hpp"
 #include "BLI_small_multimap.hpp"
+#include "BLI_monotonic_allocator.hpp"
 
 #include "RNA_access.h"
 
@@ -15,6 +16,7 @@ namespace BKE {
 
 using BLI::ArrayRef;
 using BLI::ListBaseWrapper;
+using BLI::MonotonicAllocator;
 using BLI::SmallMap;
 using BLI::SmallMultiMap;
 using BLI::SmallVector;
@@ -119,4 +121,137 @@ class IndexedNodeTree {
   SmallVector<SingleOriginLink> m_single_origin_links;
 };
 
+class VirtualNode;
+class VirtualSocket;
+class VirtualLink;
+
+class VirtualNodeTree {
+ private:
+  bool m_frozen = false;
+  MonotonicAllocator<> m_allocator;
+  SmallVector<VirtualNode *> m_nodes;
+  SmallVector<VirtualLink *> m_links;
+
+ public:
+  VirtualNode *add_bnode(bNodeTree *btree, bNode *bnode);
+  void add_link(VirtualSocket *a, VirtualSocket *b);
+
+  void freeze_and_index();
+
+  ArrayRef<VirtualNode *> nodes()
+  {
+    return m_nodes;
+  }
+
+  ArrayRef<VirtualLink *> links()
+  {
+    return m_links;
+  }
+
+  bool is_frozen()
+  {
+    return m_frozen;
+  }
+
+ private:
+  void initialize_direct_links();
+  void initialize_links();
+};
+
+class VirtualNode {
+ private:
+  friend VirtualNodeTree;
+  friend VirtualSocket;
+
+  VirtualNodeTree *m_backlink;
+  bNodeTree *m_btree;
+  bNode *m_bnode;
+  ArrayRef<VirtualSocket> m_inputs;
+  ArrayRef<VirtualSocket> m_outputs;
+
+ public:
+  ArrayRef<VirtualSocket> inputs()
+  {
+    return m_inputs;
+  }
+
+  ArrayRef<VirtualSocket> outputs()
+  {
+    return m_outputs;
+  }
+
+  VirtualSocket *input(uint index)
+  {
+    return &m_inputs[index];
+  }
+
+  VirtualSocket *output(uint index)
+  {
+    return &m_outputs[index];
+  }
+
+  bNode *bnode()
+  {
+    return m_bnode;
+  }
+};
+
+class VirtualSocket {
+ private:
+  friend VirtualNodeTree;
+
+  VirtualNode *m_vnode;
+  bNodeTree *m_btree;
+  bNodeSocket *m_bsocket;
+
+  ArrayRef<VirtualSocket *> m_direct_links;
+  ArrayRef<VirtualSocket *> m_links;
+
+ public:
+  bool is_input() const
+  {
+    return m_vnode->m_inputs.contains_ptr(this);
+  }
+
+  bool is_output() const
+  {
+    return m_vnode->m_outputs.contains_ptr(this);
+  }
+
+  bNodeSocket *bsocket()
+  {
+    return m_bsocket;
+  }
+
+  bNodeTree *btree()
+  {
+    return m_btree;
+  }
+
+  VirtualNode *vnode()
+  {
+    return m_vnode;
+  }
+
+  ArrayRef<VirtualSocket *> direct_links()
+  {
+    BLI_assert(m_vnode->m_backlink->is_frozen());
+    return m_direct_links;
+  }
+
+  ArrayRef<VirtualSocket *> links()
+  {
+    BLI_assert(m_vnode->m_backlink->is_frozen());
+    return m_links;
+  }
+};
+
+class VirtualLink {
+ private:
+  friend VirtualNodeTree;
+
+  VirtualSocket *m_from;
+  VirtualSocket *m_to;
+};
+
 }  // namespace BKE
diff --git a/source/blender/blenkernel/intern/node_tree.cpp b/source/blender/blenkernel/intern/node_tree.cpp
index d9c369a9e05..ee36b754649 100644
--- a/source/blender/blenkernel/intern/node_tree.cpp
+++ b/source/blender/blenkernel/intern/node_tree.cpp
@@ -101,4 +101,137 @@ ArrayRef<SingleOriginLink> IndexedNodeTree::single_origin_links() const
   return m_single_origin_links;
 }
 
+/* Virtual Node Tree
+ *****************************************/
+
+VirtualNode *VirtualNodeTree::add_bnode(bNodeTree *btree, bNode *bnode)
+{
+  BLI_assert(!m_frozen);
+
+  VirtualNode *vnode = m_allocator.allocate<VirtualNode>();
+  vnode->m_backlink = this;
+  vnode->m_bnode = bnode;
+  vnode->m_btree = btree;
+
+  SmallVector<bNodeSocket *, 10> original_inputs(bnode->inputs, true);
+  SmallVector<bNodeSocket *, 10> original_outputs(bnode->inputs, true);
+
+  vnode->m_inputs = m_allocator.allocate_array<VirtualSocket>(original_inputs.size());
+  vnode->m_outputs = m_allocator.allocate_array<VirtualSocket>(original_outputs.size());
+
+  for (uint i = 0; i < original_inputs.size(); i++) {
+    VirtualSocket &vsocket = vnode->m_inputs[i];
+    new (&vsocket) VirtualSocket();
+    vsocket.m_vnode = vnode;
+    vsocket.m_btree = btree;
+    vsocket.m_bsocket = original_inputs[i];
+  }
+  for (uint i = 0; i < original_outputs.size(); i++) {
+    VirtualSocket &vsocket = vnode->m_outputs[i];
+    new (&vsocket) VirtualSocket();
+    vsocket.m_vnode = vnode;
+    vsocket.m_btree = btree;
+    vsocket.m_bsocket = original_outputs[i];
+  }
+
+  m_nodes.append(vnode);
+  return vnode;
+}
+
+void VirtualNodeTree::add_link(VirtualSocket *a, VirtualSocket *b)
+{
+  BLI_assert(!m_frozen);
+
+  VirtualLink *vlink = m_allocator.allocate<VirtualLink>();
+  if (a->is_input()) {
+    BLI_assert(b->is_output());
+    vlink->m_from = a;
+    vlink->m_to = b;
+  }
+  else {
+    BLI_assert(b->is_input());
+    vlink->m_from = b;
+    vlink->m_to = a;
+  }
+
+  m_links.append(vlink);
+}
+
+void VirtualNodeTree::freeze_and_index()
+{
+  m_frozen = true;
+  this->initialize_direct_links();
+  this->initialize_links();
+}
+
+BLI_NOINLINE void VirtualNodeTree::initialize_direct_links()
+{
+  /* TODO(jacques): reserve */
+  SmallMultiMap<VirtualSocket *, VirtualSocket *> connections;
+  for (VirtualLink *link : m_links) {
+    connections.add(link->m_from, link->m_to);
+    connections.add(link->m_to, link->m_from);
+  }
+
+  /* TODO(jacques): items iterator */
+  for (VirtualSocket *vsocket : connections.keys()) {
+    auto others = connections.lookup(vsocket);
+    vsocket->m_direct_links = m_allocator.allocate_array<VirtualSocket *>(others.size());
+    vsocket->m_direct_links.copy_from(others);
+  }
+}
+
+static bool is_reroute(VirtualNode *vnode)
+{
+  return STREQ(vnode->bnode()->idname, "NodeReroute");
+}
+
+static void find_connected_sockets_left(VirtualSocket *vsocket,
+                                        SmallVector<VirtualSocket *> &r_found)
+{
+  BLI_assert(vsocket->is_input());
+  for (VirtualSocket *other : vsocket->direct_links()) {
+    if (is_reroute(other->vnode())) {
+      find_connected_sockets_left(other->vnode()->input(0), r_found);
+    }
+    else {
+      r_found.append(other);
+    }
+  }
+}
+
+static void find_connected_sockets_right(VirtualSocket *vsocket,
+                                         SmallVector<VirtualSocket *> &r_found)
+{
+  BLI_assert(vsocket->is_output());
+  for (VirtualSocket *other : vsocket->direct_links()) {
+    if (is_reroute(other->vnode())) {
+      find_connected_sockets_right(other->vnode()->output(0), r_found);
+    }
+    else {
+      r_found.append(other);
+    }
+  }
+}
+
+BLI_NOINLINE void VirtualNodeTree::initialize_links()
+{
+  for (VirtualLink *vlink : m_links) {
+    if (vlink->m_from->m_links.size() == 0) {
+      VirtualSocket *vsocket = vlink->m_from;
+      SmallVector<VirtualSocket *> found;
+      find_connected_sockets_right(vsocket, found);
+      vsocket->m_links = m_allocator.allocate_array<VirtualSocket *>(found.size());
+      vsocket->m_links.copy_from(found);
+    }
+    if (vlink->m_to->m_links.size() == 0) {
+      VirtualSocket *vsocket = vlink->m_to;
+      SmallVector<VirtualSocket *> found;
+      find_connected_sockets_left(vsocket, found);
+      vsocket->m_links = m_allocator.allocate_array<VirtualSocket *>(found.size());
+      vsocket->m_links.copy_from(found);
+    }
+  }
+}
+
 }  // namespace BKE
diff --git a/source/blender/blenlib/BLI_monotonic_allocator.hpp b/source/blender/blenlib/BLI_monotonic_allocator.hpp
index 3fe30299107..bd2b95f180d 100644
--- a/source/blender/blenlib/BLI_monotonic_allocator.hpp
+++ b/source/blender/blenlib/BLI_monotonic_allocator.hpp
@@ -61,6 +61,16 @@ template<uint N = 0> class MonotonicAllocator {
       return ptr;
     }
   }
+
+  template<typename T> T *allocate()
+  {
+    return (T *)this->allocate(sizeof(T));
+  }
+
+  template<typename T> ArrayRef<T> allocate_array(uint length)
+  {
+    return ArrayRef<T>((T *)this->allocate(sizeof(T) * length), length);
+  }
 };
 
 }  // namespace BLI
diff --git a/source/blender/functions/frontends/data_flow_nodes/graph_generation.cpp b/source/blender/functions/frontends/data_flow_nodes/graph_generation.cpp
index 132fed03859..167e066b720 100644
--- a/source/blender/functions/frontends/data_flow_nodes/graph_generation.cpp
+++ b/source/blender/functions/frontends/data_flow_nodes/graph_generation.cpp
@@ -145,6 +145,32 @@ class BasicUnlinkedInputsHandler : public UnlinkedInputsHandler {
 
 Optional<BTreeDataGraph> generate_graph(IndexedNodeTree &indexed_btree)
 {
+  bNodeTree *btree = indexed_btree.btree();
+
+  VirtualNodeTree vtree;
+  SmallMap<bNode *, VirtualNode *> node_mapping;
+  for (bNode *bnode : BKE::bNodeList(btree->nodes)) {
+    VirtualNode *vnode = vtree.add_bnode(btree, bnode);
+    node_mapping.add_new(bnode, vnode);
+  }
+  for (bNodeLink *blink : BKE::bLinkList(btree->links)) {
+    VirtualNode *from_node = node_mapping.lookup(blink->fromnode);
+    VirtualNode *to_node = node_mapping.lookup(blink->tonode);
+    VirtualSocket *from_socket = nullptr;
+    VirtualSocket *to_socket = nullptr;
+    for (VirtualSocket &output : from_node->outputs()) {
+      if (output.bsocket() == blink->fromsock) {
+        from_socket = &output;
+      }
+    }
+    for (VirtualSocket &input : to_node->inputs()) {
+      if (input.bsocket() == blink->tosock) {
+        to_socket = &input;
+      }
+    }
+    vtree.add_link(from_socket, to_socket);
+  }
+
   DataFlowGraphBuilder graph_builder;
   SmallMap<bNodeSocket *, DFGB_Socket> socket_map;
 
diff --git a/source/blender/functions/frontends/data_flow_nodes/graph_generation.hpp b/source/blender/functions/frontends/data_flow_nodes/graph_generation.hpp
index e384836b7d7..2a87ea5ae1d 100644
--- a/source/blender/functions/frontends/data_flow_nodes/graph_generation.hpp
+++ b/source/blender/functions/frontends/data_flow_nodes/graph_generation.hpp
@@ -11,6 +11,10 @@ namespace DataFlowNodes {
 
 using BKE::IndexedNodeTree;
 using BKE::SocketWithNode;
+using BKE::VirtualLink;
+using BKE::VirtualNode;
+using BKE::VirtualNodeTree;
+using BKE::VirtualSocket;
 
 class UnlinkedInputsHandler {
  public:



More information about the Bf-blender-cvs mailing list