Blender  V3.3
COM_NodeGraph.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2013 Blender Foundation. */
3 
4 #include <cstring>
5 
6 #include "DNA_node_types.h"
7 
8 #include "BKE_node.h"
9 
10 #include "COM_Converter.h"
11 #include "COM_Debug.h"
12 #include "COM_SocketProxyNode.h"
13 
14 #include "COM_NodeGraph.h" /* own include */
15 
16 namespace blender::compositor {
17 
18 /*******************
19  **** NodeGraph ****
20  *******************/
21 
23 {
24  while (nodes_.size()) {
25  delete nodes_.pop_last();
26  }
27 }
28 
30 {
32 }
33 
34 bNodeSocket *NodeGraph::find_b_node_input(bNode *b_node, const char *identifier)
35 {
36  for (bNodeSocket *b_sock = (bNodeSocket *)b_node->inputs.first; b_sock; b_sock = b_sock->next) {
37  if (STREQ(b_sock->identifier, identifier)) {
38  return b_sock;
39  }
40  }
41  return nullptr;
42 }
43 
44 bNodeSocket *NodeGraph::find_b_node_output(bNode *b_node, const char *identifier)
45 {
46  for (bNodeSocket *b_sock = (bNodeSocket *)b_node->outputs.first; b_sock; b_sock = b_sock->next) {
47  if (STREQ(b_sock->identifier, identifier)) {
48  return b_sock;
49  }
50  }
51  return nullptr;
52 }
53 
55  bNodeTree *b_ntree,
56  bNodeInstanceKey key,
57  bool is_active_group)
58 {
59  node->set_bnodetree(b_ntree);
60  node->set_instance_key(key);
61  node->set_is_in_active_group(is_active_group);
62 
63  nodes_.append(node);
64 
66 }
67 
68 void NodeGraph::add_link(NodeOutput *from_socket, NodeInput *to_socket)
69 {
70  links_.append(Link(from_socket, to_socket));
71 
72  /* register with the input */
73  to_socket->set_link(from_socket);
74 }
75 
77  int nodes_start,
78  bNodeTree *tree,
79  bNodeInstanceKey parent_key)
80 {
81  const bNodeTree *basetree = context.get_bnodetree();
82 
83  /* Update viewers in the active edit-tree as well the base tree (for backdrop). */
84  bool is_active_group = (parent_key.value == basetree->active_viewer_key.value);
85 
86  /* add all nodes of the tree to the node list */
87  for (bNode *node = (bNode *)tree->nodes.first; node; node = node->next) {
88  bNodeInstanceKey key = BKE_node_instance_key(parent_key, tree, node);
89  add_bNode(context, tree, node, key, is_active_group);
90  }
91 
92  NodeRange node_range(nodes_.begin() + nodes_start, nodes_.end());
93  /* Add all node-links of the tree to the link list. */
94  for (bNodeLink *nodelink = (bNodeLink *)tree->links.first; nodelink; nodelink = nodelink->next) {
95  add_bNodeLink(node_range, nodelink);
96  }
97 }
98 
100  bNodeTree *b_ntree,
101  bNode *b_node,
102  bNodeInstanceKey key,
103  bool is_active_group)
104 {
105  /* replace muted nodes by proxies for internal links */
106  if (b_node->flag & NODE_MUTED) {
107  add_proxies_mute(b_ntree, b_node, key, is_active_group);
108  return;
109  }
110 
111  /* replace slow nodes with proxies for fast execution */
112  if (context.is_fast_calculation() && !COM_bnode_is_fast_node(*b_node)) {
113  add_proxies_skip(b_ntree, b_node, key, is_active_group);
114  return;
115  }
116 
117  /* special node types */
118  if (ELEM(b_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
119  add_proxies_group(context, b_node, key);
120  }
121  else if (b_node->type == NODE_REROUTE) {
122  add_proxies_reroute(b_ntree, b_node, key, is_active_group);
123  }
124  else {
125  /* regular nodes, handled in Converter */
126  Node *node = COM_convert_bnode(b_node);
127  if (node) {
128  add_node(node, b_ntree, key, is_active_group);
129  }
130  }
131 }
132 
134 {
135  for (Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
136  Node *node = *it;
137  for (NodeOutput *output : node->get_output_sockets()) {
138  if (output->get_bnode_socket() == b_socket) {
139  return output;
140  }
141  }
142  }
143  return nullptr;
144 }
145 
146 void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink)
147 {
149  if (!(b_nodelink->flag & NODE_LINK_VALID)) {
150  return;
151  }
152  if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL) ||
153  (b_nodelink->flag & NODE_LINK_MUTED)) {
154  return;
155  }
156 
157  /* NOTE: a DNA input socket can have multiple NodeInput in the compositor tree! (proxies)
158  * The output then gets linked to each one of them.
159  */
160 
161  NodeOutput *output = find_output(node_range, b_nodelink->fromsock);
162  if (!output) {
163  return;
164  }
165 
166  for (Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) {
167  Node *node = *it;
168  for (NodeInput *input : node->get_input_sockets()) {
169  if (input->get_bnode_socket() == b_nodelink->tosock && !input->is_linked()) {
171  }
172  }
173  }
174 }
175 
176 /* **** Special proxy node type conversions **** */
177 
179  bNode *b_node,
180  bNodeInstanceKey key,
181  bool is_active_group)
182 {
183  for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link;
184  b_link = b_link->next) {
185  SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false);
186  add_node(proxy, b_ntree, key, is_active_group);
187  }
188 }
189 
191  bNode *b_node,
192  bNodeInstanceKey key,
193  bool is_active_group)
194 {
195  for (bNodeSocket *output = (bNodeSocket *)b_node->outputs.first; output; output = output->next) {
197 
198  /* look for first input with matching datatype for each output */
199  for (input = (bNodeSocket *)b_node->inputs.first; input; input = input->next) {
200  if (input->type == output->type) {
201  break;
202  }
203  }
204 
205  if (input) {
206  SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output, true);
207  add_node(proxy, b_ntree, key, is_active_group);
208  }
209  }
210 }
211 
213 {
214  bNodeTree *b_group_tree = (bNodeTree *)b_node->id;
215  BLI_assert(b_group_tree); /* should have been checked in advance */
216 
217  /* not important for proxies */
219  bool is_active_group = false;
220 
221  for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->outputs.first; b_sock_io;
222  b_sock_io = b_sock_io->next) {
223  bNodeSocket *b_sock_group = find_b_node_input(b_node, b_sock_io->identifier);
224  if (b_sock_group) {
225  SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io, true);
226  add_node(proxy, b_group_tree, key, is_active_group);
227  }
228  }
229 }
230 
232  bNode *b_node,
233  bNode *b_node_io)
234 {
235  bNodeTree *b_group_tree = (bNodeTree *)b_node->id;
236  BLI_assert(b_group_tree); /* should have been checked in advance */
237 
238  /* not important for proxies */
240  bool is_active_group = false;
241 
242  for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->inputs.first; b_sock_io;
243  b_sock_io = b_sock_io->next) {
244  bNodeSocket *b_sock_group = find_b_node_output(b_node, b_sock_io->identifier);
245  if (b_sock_group) {
246  if (context.is_groupnode_buffer_enabled() &&
247  context.get_execution_model() == eExecutionModel::Tiled) {
248  SocketBufferNode *buffer = new SocketBufferNode(b_node_io, b_sock_io, b_sock_group);
249  add_node(buffer, b_group_tree, key, is_active_group);
250  }
251  else {
252  SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group, true);
253  add_node(proxy, b_group_tree, key, is_active_group);
254  }
255  }
256  }
257 }
258 
260  bNode *b_node,
261  bNodeInstanceKey key)
262 {
263  bNodeTree *b_group_tree = (bNodeTree *)b_node->id;
264 
265  /* missing node group datablock can happen with library linking */
266  if (!b_group_tree) {
267  /* This error case its handled in convert_to_operations()
268  * so we don't get un-converted sockets. */
269  return;
270  }
271 
272  /* use node list size before adding proxies, so they can be connected in add_bNodeTree */
273  int nodes_start = nodes_.size();
274 
275  /* create proxy nodes for group input/output nodes */
276  for (bNode *b_node_io = (bNode *)b_group_tree->nodes.first; b_node_io;
277  b_node_io = b_node_io->next) {
278  if (b_node_io->type == NODE_GROUP_INPUT) {
279  add_proxies_group_inputs(b_node, b_node_io);
280  }
281 
282  if (b_node_io->type == NODE_GROUP_OUTPUT && (b_node_io->flag & NODE_DO_OUTPUT)) {
283  add_proxies_group_outputs(context, b_node, b_node_io);
284  }
285  }
286 
287  add_bNodeTree(context, nodes_start, b_group_tree, key);
288 }
289 
291  bNode *b_node,
292  bNodeInstanceKey key,
293  bool is_active_group)
294 {
295  SocketProxyNode *proxy = new SocketProxyNode(
296  b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false);
297  add_node(proxy, b_ntree, key, is_active_group);
298 }
299 
300 } // namespace blender::compositor
#define NODE_REROUTE
Definition: BKE_node.h:986
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE
Definition: node.cc:3896
#define NODE_CUSTOM_GROUP
Definition: BKE_node.h:989
#define NODE_GROUP_INPUT
Definition: BKE_node.h:987
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, const struct bNodeTree *ntree, const struct bNode *node)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ELEM(...)
#define STREQ(a, b)
struct Link Link
#define NODE_LINK_VALID
#define NODE_DO_OUTPUT
#define NODE_MUTED
@ SOCK_UNAVAIL
#define NODE_LINK_MUTED
NODE_GROUP_OUTPUT
NODE_GROUP
Overall context of the compositor.
static void node_added(const Node *node)
Definition: COM_Debug.h:74
static bNodeSocket * find_b_node_input(bNode *b_node, const char *identifier)
void add_bNodeTree(const CompositorContext &context, int nodes_start, bNodeTree *tree, bNodeInstanceKey parent_key)
void add_bNode(const CompositorContext &context, bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
std::pair< Vector< Node * >::iterator, Vector< Node * >::iterator > NodeRange
Definition: COM_NodeGraph.h:53
void from_bNodeTree(const CompositorContext &context, bNodeTree *tree)
void add_proxies_group_inputs(bNode *b_node, bNode *b_node_io)
void add_proxies_reroute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
void add_proxies_skip(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
NodeOutput * find_output(const NodeRange &node_range, bNodeSocket *b_socket)
void add_proxies_mute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
void add_proxies_group_outputs(const CompositorContext &context, bNode *b_node, bNode *b_node_io)
void add_link(NodeOutput *from_socket, NodeInput *to_socket)
static bNodeSocket * find_b_node_output(bNode *b_node, const char *identifier)
void add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink)
void add_proxies_group(const CompositorContext &context, bNode *b_node, bNodeInstanceKey key)
void add_node(Node *node, bNodeTree *b_ntree, bNodeInstanceKey key, bool is_active_group)
NodeInput are sockets that can receive data/input.
Definition: COM_Node.h:190
void set_link(NodeOutput *link)
Definition: COM_Node.cc:130
NodeOutput are sockets that can send data/input.
Definition: COM_Node.h:238
OperationNode * node
void * tree
ccl_global float * buffer
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
Node * COM_convert_bnode(bNode *b_node)
Wraps a bNode in its Node instance.
bool COM_bnode_is_fast_node(const bNode &b_node)
True if the node is considered 'fast'.
void * first
Definition: DNA_listBase.h:31
unsigned int value
ListBase nodes
bNodeInstanceKey active_viewer_key
ListBase inputs
struct ID * id
ListBase internal_links
short type
ListBase outputs