Blender  V2.93
derived_node_tree.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "NOD_derived_node_tree.hh"
18 
19 #include "BLI_dot_export.hh"
20 
21 namespace blender::nodes {
22 
23 /* Construct a new derived node tree for a given root node tree. The generated derived node tree
24  * does not own the used node tree refs (so that those can be used by others as well). The caller
25  * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
26  * derived node tree. */
28 {
29  /* Construct all possible contexts immediately. This is significantly cheaper than inlining all
30  * node groups. If it still becomes a performance issue in the future, contexts could be
31  * constructed lazily when they are needed. */
32  root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs);
33 }
34 
35 DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context,
36  const NodeRef *parent_node,
37  bNodeTree &btree,
38  NodeTreeRefMap &node_tree_refs)
39 {
40  DTreeContext &context = *allocator_.construct<DTreeContext>().release();
41  context.parent_context_ = parent_context;
42  context.parent_node_ = parent_node;
43  context.derived_tree_ = this;
44  context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
45  used_node_tree_refs_.add(context.tree_);
46 
47  for (const NodeRef *node : context.tree_->nodes()) {
48  if (node->is_group_node()) {
49  bNode *bnode = node->bnode();
50  bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id);
51  if (child_btree != nullptr) {
52  DTreeContext &child = this->construct_context_recursively(
53  &context, node, *child_btree, node_tree_refs);
54  context.children_.add_new(node, &child);
55  }
56  }
57  }
58 
59  return context;
60 }
61 
63 {
64  /* Has to be destructed manually, because the context info is allocated in a linear allocator. */
65  this->destruct_context_recursively(root_context_);
66 }
67 
68 void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
69 {
70  for (DTreeContext *child : context->children_.values()) {
71  this->destruct_context_recursively(child);
72  }
73  context->~DTreeContext();
74 }
75 
76 /* Returns true if there are any cycles in the node tree. */
78 {
79  for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
80  if (tree_ref->has_link_cycles()) {
81  return true;
82  }
83  }
84  return false;
85 }
86 
88 {
89  for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
90  if (tree_ref->has_undefined_nodes_or_sockets()) {
91  return true;
92  }
93  }
94  return false;
95 }
96 
97 /* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
99 {
100  this->foreach_node_in_context_recursive(*root_context_, callback);
101 }
102 
103 void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context,
104  FunctionRef<void(DNode)> callback) const
105 {
106  for (const NodeRef *node_ref : context.tree_->nodes()) {
107  callback(DNode(&context, node_ref));
108  }
109  for (const DTreeContext *child_context : context.children_.values()) {
110  this->foreach_node_in_context_recursive(*child_context, callback);
111  }
112 }
113 
115 {
116  BLI_assert(*this);
118  BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1);
119 
120  const DTreeContext *parent_context = context_->parent_context();
121  const NodeRef *parent_node = context_->parent_node();
122  BLI_assert(parent_context != nullptr);
123  BLI_assert(parent_node != nullptr);
124 
125  const int socket_index = socket_ref_->index();
126  return {parent_context, &parent_node->output(socket_index)};
127 }
128 
130 {
131  BLI_assert(*this);
133 
134  const DTreeContext *child_context = context_->child_context(socket_ref_->node());
135  BLI_assert(child_context != nullptr);
136 
137  const NodeTreeRef &child_tree = child_context->tree();
138  Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput");
139  const int socket_index = socket_ref_->index();
140  Vector<DOutputSocket> sockets;
141  for (const NodeRef *group_input_node : group_input_nodes) {
142  sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index)));
143  }
144  return sockets;
145 }
146 
148 {
149  BLI_assert(*this);
151  BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1);
152 
153  const DTreeContext *parent_context = context_->parent_context();
154  const NodeRef *parent_node = context_->parent_node();
155  BLI_assert(parent_context != nullptr);
156  BLI_assert(parent_node != nullptr);
157 
158  const int socket_index = socket_ref_->index();
159  return {parent_context, &parent_node->input(socket_index)};
160 }
161 
163 {
164  BLI_assert(*this);
166 
167  const DTreeContext *child_context = context_->child_context(socket_ref_->node());
168  BLI_assert(child_context != nullptr);
169 
170  const NodeTreeRef &child_tree = child_context->tree();
171  Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput");
172  const int socket_index = socket_ref_->index();
173  for (const NodeRef *group_output_node : group_output_nodes) {
174  if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) {
175  return {child_context, &group_output_node->input(socket_index)};
176  }
177  }
178  return {};
179 }
180 
181 /* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
182  * and node groups are handled by this function. Origin sockets are ones where a node gets its
183  * inputs from. */
185 {
186  BLI_assert(*this);
187  for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) {
188  const NodeRef &linked_node = linked_socket->node();
189  DOutputSocket linked_dsocket{context_, linked_socket};
190 
191  if (linked_node.is_group_input_node()) {
192  if (context_->is_root()) {
193  /* This is a group input in the root node group. */
194  origin_fn(linked_dsocket);
195  }
196  else {
197  DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
198  if (socket_in_parent_group->is_logically_linked()) {
199  /* Follow the links coming into the corresponding socket on the parent group node. */
200  socket_in_parent_group.foreach_origin_socket(origin_fn);
201  }
202  else {
203  /* The corresponding input on the parent group node is not connected. Therefore, we use
204  * the value of that input socket directly. */
205  origin_fn(socket_in_parent_group);
206  }
207  }
208  }
209  else if (linked_node.is_group_node()) {
210  DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket();
211  if (socket_in_group) {
212  if (socket_in_group->is_logically_linked()) {
213  /* Follow the links coming into the group output node of the child node group. */
214  socket_in_group.foreach_origin_socket(origin_fn);
215  }
216  else {
217  /* The output of the child node group is not connected, so we have to get the value from
218  * that socket. */
219  origin_fn(socket_in_group);
220  }
221  }
222  }
223  else {
224  /* The normal case: just use the value of a linked output socket. */
225  origin_fn(linked_dsocket);
226  }
227  }
228 }
229 
230 /* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
231  * and node groups are handled by this function. Target sockets are on the nodes that use the value
232  * from this socket. The `skipped_fn` function is called for sockets that have been skipped during
233  * the search for target sockets (e.g. reroutes). */
235  FunctionRef<void(DSocket)> skipped_fn) const
236 {
237  for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) {
238  skipped_fn.call_safe({context_, skipped_socket});
239  }
240  for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) {
241  const NodeRef &linked_node = linked_socket->node();
242  DInputSocket linked_dsocket{context_, linked_socket};
243 
244  if (linked_node.is_group_output_node()) {
245  if (context_->is_root()) {
246  /* This is a group output in the root node group. */
247  target_fn(linked_dsocket);
248  }
249  else {
250  /* Follow the links going out of the group node in the parent node group. */
251  DOutputSocket socket_in_parent_group =
252  linked_dsocket.get_corresponding_group_node_output();
253  skipped_fn.call_safe(linked_dsocket);
254  skipped_fn.call_safe(socket_in_parent_group);
255  socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn);
256  }
257  }
258  else if (linked_node.is_group_node()) {
259  /* Follow the links within the nested node group. */
260  Vector<DOutputSocket> sockets_in_group =
261  linked_dsocket.get_corresponding_group_input_sockets();
262  skipped_fn.call_safe(linked_dsocket);
263  for (DOutputSocket socket_in_group : sockets_in_group) {
264  skipped_fn.call_safe(socket_in_group);
265  socket_in_group.foreach_target_socket(target_fn, skipped_fn);
266  }
267  }
268  else {
269  /* The normal case: just use the linked input socket as target. */
270  target_fn(linked_dsocket);
271  }
272  }
273 }
274 
275 /* Each nested node group gets its own cluster. Just as node groups, clusters can be nested. */
277  dot::DirectedGraph &digraph,
278  const DTreeContext *context,
280 {
281  return dot_clusters.lookup_or_add_cb(context, [&]() -> dot::Cluster * {
282  const DTreeContext *parent_context = context->parent_context();
283  if (parent_context == nullptr) {
284  return nullptr;
285  }
286  dot::Cluster *parent_cluster = get_dot_cluster_for_context(
287  digraph, parent_context, dot_clusters);
288  std::string cluster_name = context->tree().name() + " / " + context->parent_node()->name();
289  dot::Cluster &cluster = digraph.new_cluster(cluster_name);
290  cluster.set_parent_cluster(parent_cluster);
291  return &cluster;
292  });
293 }
294 
295 /* Generates a graph in dot format. The generated graph has all node groups inlined. */
296 std::string DerivedNodeTree::to_dot() const
297 {
298  dot::DirectedGraph digraph;
299  digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
300 
302  Map<DInputSocket, dot::NodePort> dot_input_sockets;
303  Map<DOutputSocket, dot::NodePort> dot_output_sockets;
304 
305  this->foreach_node([&](DNode node) {
306  /* Ignore nodes that should not show up in the final output. */
307  if (node->is_muted() || node->is_group_node() || node->is_reroute_node() || node->is_frame()) {
308  return;
309  }
310  if (!node.context()->is_root()) {
311  if (node->is_group_input_node() || node->is_group_output_node()) {
312  return;
313  }
314  }
315 
316  dot::Cluster *cluster = get_dot_cluster_for_context(digraph, node.context(), dot_clusters);
317 
318  dot::Node &dot_node = digraph.new_node("");
319  dot_node.set_parent_cluster(cluster);
320  dot_node.set_background_color("white");
321 
322  Vector<std::string> input_names;
323  Vector<std::string> output_names;
324  for (const InputSocketRef *socket : node->inputs()) {
325  if (socket->is_available()) {
326  input_names.append(socket->name());
327  }
328  }
329  for (const OutputSocketRef *socket : node->outputs()) {
330  if (socket->is_available()) {
331  output_names.append(socket->name());
332  }
333  }
334 
335  dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef(
336  dot_node, node->name(), input_names, output_names);
337 
338  int input_index = 0;
339  for (const InputSocketRef *socket : node->inputs()) {
340  if (socket->is_available()) {
341  dot_input_sockets.add_new(DInputSocket{node.context(), socket},
342  dot_node_with_sockets.input(input_index));
343  input_index++;
344  }
345  }
346  int output_index = 0;
347  for (const OutputSocketRef *socket : node->outputs()) {
348  if (socket->is_available()) {
349  dot_output_sockets.add_new(DOutputSocket{node.context(), socket},
350  dot_node_with_sockets.output(output_index));
351  output_index++;
352  }
353  }
354  });
355 
356  /* Floating inputs are used for example to visualize unlinked group node inputs. */
357  Map<DSocket, dot::Node *> dot_floating_inputs;
358 
359  for (const auto item : dot_input_sockets.items()) {
360  DInputSocket to_socket = item.key;
361  dot::NodePort dot_to_port = item.value;
362  to_socket.foreach_origin_socket([&](DSocket from_socket) {
363  if (from_socket->is_output()) {
364  dot::NodePort *dot_from_port = dot_output_sockets.lookup_ptr(DOutputSocket(from_socket));
365  if (dot_from_port != nullptr) {
366  digraph.new_edge(*dot_from_port, dot_to_port);
367  return;
368  }
369  }
370  dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() {
371  dot::Node &dot_node = digraph.new_node(from_socket->name());
372  dot_node.set_background_color("white");
373  dot_node.set_shape(dot::Attr_shape::Ellipse);
374  dot_node.set_parent_cluster(
375  get_dot_cluster_for_context(digraph, from_socket.context(), dot_clusters));
376  return &dot_node;
377  });
378  digraph.new_edge(dot_node, dot_to_port);
379  });
380  }
381 
382  digraph.set_random_cluster_bgcolors();
383 
384  return digraph.to_dot_string();
385 }
386 
387 } // namespace blender::nodes
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define NODE_DO_OUTPUT
destruct_ptr< T > construct(Args &&... args)
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition: BLI_map.hh:575
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:234
constexpr int64_t size() const
Definition: BLI_span.hh:254
void append(const T &value)
Definition: BLI_vector.hh:438
void set_parent_cluster(Cluster *new_parent)
Definition: dot_export.cc:58
Cluster & new_cluster(StringRef label="")
Definition: dot_export.cc:35
Node & new_node(StringRef label)
Definition: dot_export.cc:26
void set_rankdir(Attr_rankdir rankdir)
NodePort output(int index) const
NodePort input(int index) const
void set_shape(Attr_shape shape)
void set_background_color(StringRef name)
void set_parent_cluster(Cluster *cluster)
Definition: dot_export.cc:78
void foreach_origin_socket(FunctionRef< void(DSocket)> origin_fn) const
DOutputSocket get_corresponding_group_node_output() const
Vector< DOutputSocket, 4 > get_corresponding_group_input_sockets() const
void foreach_target_socket(FunctionRef< void(DInputSocket)> target_fn, FunctionRef< void(DSocket)> skipped_fn) const
DInputSocket get_corresponding_group_node_input() const
DInputSocket get_active_corresponding_group_output_socket() const
const DTreeContext * context() const
const DTreeContext * context_
const DTreeContext * parent_context() const
const DTreeContext * child_context(const NodeRef &node) const
const NodeRef * parent_node() const
const NodeTreeRef & tree() const
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
void foreach_node(FunctionRef< void(DNode)> callback) const
Span< const OutputSocketRef * > logically_linked_sockets() const
const OutputSocketRef & output(int index) const
Span< const InputSocketRef * > inputs() const
const InputSocketRef & input(int index) const
Span< const OutputSocketRef * > outputs() const
Span< const NodeRef * > nodes_by_type(StringRefNull idname) const
Span< const InputSocketRef * > logically_linked_sockets() const
const NodeRef & node() const
const OutputSocketRef & as_output() const
Span< const SocketRef * > logically_linked_skipped_sockets() const
const InputSocketRef & as_input() const
StringRefNull name() const
OperationNode * node
DEGForeachIDComponentCallback callback
const NodeTreeRef & get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree)
static dot::Cluster * get_dot_cluster_for_context(dot::DirectedGraph &digraph, const DTreeContext *context, Map< const DTreeContext *, dot::Cluster * > &dot_clusters)
struct SELECTID_Context context
Definition: select_engine.c:47
struct ID * id