Blender  V2.93
multi_function_network.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 "BLI_dot_export.hh"
18 #include "BLI_stack.hh"
19 
21 
22 namespace blender::fn {
23 
25 {
26  for (MFFunctionNode *node : function_nodes_) {
27  node->destruct_sockets();
28  node->~MFFunctionNode();
29  }
30  for (MFDummyNode *node : dummy_nodes_) {
31  node->destruct_sockets();
32  node->~MFDummyNode();
33  }
34 }
35 
36 void MFNode::destruct_sockets()
37 {
38  for (MFInputSocket *socket : inputs_) {
39  socket->~MFInputSocket();
40  }
41  for (MFOutputSocket *socket : outputs_) {
42  socket->~MFOutputSocket();
43  }
44 }
45 
52 {
53  Vector<int, 16> input_param_indices, output_param_indices;
54 
55  for (int param_index : function.param_indices()) {
56  switch (function.param_type(param_index).interface_type()) {
57  case MFParamType::Input: {
58  input_param_indices.append(param_index);
59  break;
60  }
61  case MFParamType::Output: {
62  output_param_indices.append(param_index);
63  break;
64  }
65  case MFParamType::Mutable: {
66  input_param_indices.append(param_index);
67  output_param_indices.append(param_index);
68  break;
69  }
70  }
71  }
72 
73  MFFunctionNode &node = *allocator_.construct<MFFunctionNode>().release();
74  function_nodes_.add_new(&node);
75 
76  node.network_ = this;
77  node.is_dummy_ = false;
78  node.id_ = node_or_null_by_id_.append_and_get_index(&node);
79  node.function_ = &function;
80  node.input_param_indices_ = allocator_.construct_array_copy<int>(input_param_indices);
81  node.output_param_indices_ = allocator_.construct_array_copy<int>(output_param_indices);
82 
84  input_param_indices.size());
86  output_param_indices.size());
87 
88  for (int i : input_param_indices.index_range()) {
89  int param_index = input_param_indices[i];
90  MFParamType param = function.param_type(param_index);
92 
93  MFInputSocket &socket = *node.inputs_[i];
94  socket.data_type_ = param.data_type();
95  socket.node_ = &node;
96  socket.index_ = i;
97  socket.is_output_ = false;
98  socket.name_ = function.param_name(param_index);
99  socket.origin_ = nullptr;
100  socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
101  }
102 
103  for (int i : output_param_indices.index_range()) {
104  int param_index = output_param_indices[i];
105  MFParamType param = function.param_type(param_index);
107 
108  MFOutputSocket &socket = *node.outputs_[i];
109  socket.data_type_ = param.data_type();
110  socket.node_ = &node;
111  socket.index_ = i;
112  socket.is_output_ = true;
113  socket.name_ = function.param_name(param_index);
114  socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
115  }
116 
117  return node;
118 }
119 
124  Span<MFDataType> input_types,
125  Span<MFDataType> output_types,
126  Span<StringRef> input_names,
127  Span<StringRef> output_names)
128 {
129  assert_same_size(input_types, input_names);
130  assert_same_size(output_types, output_names);
131 
132  MFDummyNode &node = *allocator_.construct<MFDummyNode>().release();
133  dummy_nodes_.add_new(&node);
134 
135  node.network_ = this;
136  node.is_dummy_ = true;
137  node.name_ = allocator_.copy_string(name);
138  node.id_ = node_or_null_by_id_.append_and_get_index(&node);
139 
141  input_types.size());
143  output_types.size());
144 
145  node.input_names_ = allocator_.allocate_array<StringRefNull>(input_types.size());
146  node.output_names_ = allocator_.allocate_array<StringRefNull>(output_types.size());
147 
148  for (int i : input_types.index_range()) {
149  MFInputSocket &socket = *node.inputs_[i];
150  socket.data_type_ = input_types[i];
151  socket.node_ = &node;
152  socket.index_ = i;
153  socket.is_output_ = false;
154  socket.name_ = allocator_.copy_string(input_names[i]);
155  socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
156  node.input_names_[i] = socket.name_;
157  }
158 
159  for (int i : output_types.index_range()) {
160  MFOutputSocket &socket = *node.outputs_[i];
161  socket.data_type_ = output_types[i];
162  socket.node_ = &node;
163  socket.index_ = i;
164  socket.is_output_ = true;
165  socket.name_ = allocator_.copy_string(output_names[i]);
166  socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
167  node.output_names_[i] = socket.name_;
168  }
169 
170  return node;
171 }
172 
179 {
180  BLI_assert(to.origin_ == nullptr);
181  BLI_assert(from.node_->network_ == to.node_->network_);
182  BLI_assert(from.data_type_ == to.data_type_);
183  from.targets_.append(&to);
184  to.origin_ = &from;
185 }
186 
188 {
189  return this->add_dummy(name, {}, {data_type}, {}, {"Value"}).output(0);
190 }
191 
193 {
194  return this->add_dummy(name, {data_type}, {}, {"Value"}, {}).input(0);
195 }
196 
197 void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output)
198 {
199  BLI_assert(&old_output != &new_output);
200  BLI_assert(old_output.data_type_ == new_output.data_type_);
201  for (MFInputSocket *input : old_output.targets()) {
202  input->origin_ = &new_output;
203  }
204  new_output.targets_.extend(old_output.targets_);
205  old_output.targets_.clear();
206 }
207 
209 {
210  for (MFInputSocket *socket : node.inputs_) {
211  if (socket->origin_ != nullptr) {
212  socket->origin_->targets_.remove_first_occurrence_and_reorder(socket);
213  }
214  socket_or_null_by_id_[socket->id_] = nullptr;
215  }
216  for (MFOutputSocket *socket : node.outputs_) {
217  for (MFInputSocket *other : socket->targets_) {
218  other->origin_ = nullptr;
219  }
220  socket_or_null_by_id_[socket->id_] = nullptr;
221  }
222  node.destruct_sockets();
223  if (node.is_dummy()) {
224  MFDummyNode &dummy_node = node.as_dummy();
225  dummy_node.~MFDummyNode();
226  dummy_nodes_.remove_contained(&dummy_node);
227  }
228  else {
229  MFFunctionNode &function_node = node.as_function();
230  function_node.~MFFunctionNode();
231  function_nodes_.remove_contained(&function_node);
232  }
233  node_or_null_by_id_[node.id_] = nullptr;
234 }
235 
237 {
238  for (MFNode *node : nodes) {
239  this->remove(*node);
240  }
241 }
242 
244  VectorSet<const MFOutputSocket *> &r_dummy_sockets,
245  VectorSet<const MFInputSocket *> &r_unlinked_inputs) const
246 {
247  Set<const MFNode *> visited_nodes;
248  Stack<const MFInputSocket *> sockets_to_check;
249  sockets_to_check.push_multiple(sockets);
250 
251  while (!sockets_to_check.is_empty()) {
252  const MFInputSocket &socket = *sockets_to_check.pop();
253  const MFOutputSocket *origin_socket = socket.origin();
254  if (origin_socket == nullptr) {
255  r_unlinked_inputs.add(&socket);
256  continue;
257  }
258 
259  const MFNode &origin_node = origin_socket->node();
260 
261  if (origin_node.is_dummy()) {
262  r_dummy_sockets.add(origin_socket);
263  continue;
264  }
265 
266  if (visited_nodes.add(&origin_node)) {
267  sockets_to_check.push_multiple(origin_node.inputs());
268  }
269  }
270 }
271 
273 {
274  VectorSet<const MFOutputSocket *> dummy_sockets;
275  VectorSet<const MFInputSocket *> unlinked_inputs;
276  this->find_dependencies(sockets, dummy_sockets, unlinked_inputs);
277  return dummy_sockets.size() + unlinked_inputs.size() > 0;
278 }
279 
280 std::string MFNetwork::to_dot(Span<const MFNode *> marked_nodes) const
281 {
282  dot::DirectedGraph digraph;
283  digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
284 
286 
287  Vector<const MFNode *> all_nodes;
288  all_nodes.extend(function_nodes_.as_span().cast<const MFNode *>());
289  all_nodes.extend(dummy_nodes_.as_span().cast<const MFNode *>());
290 
291  for (const MFNode *node : all_nodes) {
292  dot::Node &dot_node = digraph.new_node("");
293 
294  Vector<std::string> input_names, output_names;
295  for (const MFInputSocket *socket : node->inputs_) {
296  input_names.append(socket->name() + "(" + socket->data_type().to_string() + ")");
297  }
298  for (const MFOutputSocket *socket : node->outputs_) {
299  output_names.append(socket->name() + " (" + socket->data_type().to_string() + ")");
300  }
301 
302  dot::NodeWithSocketsRef dot_node_ref{dot_node, node->name(), input_names, output_names};
303  dot_nodes.add_new(node, dot_node_ref);
304  }
305 
306  for (const MFDummyNode *node : dummy_nodes_) {
307  dot_nodes.lookup(node).node().set_background_color("#77EE77");
308  }
309  for (const MFNode *node : marked_nodes) {
310  dot_nodes.lookup(node).node().set_background_color("#7777EE");
311  }
312 
313  for (const MFNode *to_node : all_nodes) {
314  dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node);
315 
316  for (const MFInputSocket *to_socket : to_node->inputs_) {
317  const MFOutputSocket *from_socket = to_socket->origin_;
318  if (from_socket != nullptr) {
319  const MFNode *from_node = from_socket->node_;
320  dot::NodeWithSocketsRef from_dot_node = dot_nodes.lookup(from_node);
321  digraph.new_edge(from_dot_node.output(from_socket->index_),
322  to_dot_node.input(to_socket->index_));
323  }
324  }
325  }
326 
327  return digraph.to_dot_string();
328 }
329 
330 } // namespace blender::fn
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define output
MutableSpan< T > construct_array_copy(Span< T > src)
StringRefNull copy_string(StringRef str)
Span< T * > construct_elements_and_pointer_array(int64_t n, Args &&... args)
MutableSpan< T > allocate_array(int64_t size)
destruct_ptr< T > construct(Args &&... args)
const Value & lookup(const Key &key) const
Definition: BLI_map.hh:499
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:234
bool add(const Key &key)
Definition: BLI_set.hh:267
constexpr int64_t size() const
Definition: BLI_span.hh:254
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
bool is_empty() const
Definition: BLI_stack.hh:321
void push_multiple(Span< T > values)
Definition: BLI_stack.hh:294
bool add(const Key &key)
int64_t size() const
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
IndexRange index_range() const
Definition: BLI_vector.hh:887
void extend(Span< T > array)
Definition: BLI_vector.hh:515
DirectedEdge & new_edge(NodePort from, NodePort to)
Definition: dot_export.cc:51
std::string to_dot_string() const
Definition: dot_export.cc:135
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
bool have_dummy_or_unlinked_dependencies(Span< const MFInputSocket * > sockets) const
void relink(MFOutputSocket &old_output, MFOutputSocket &new_output)
void find_dependencies(Span< const MFInputSocket * > sockets, VectorSet< const MFOutputSocket * > &r_dummy_sockets, VectorSet< const MFInputSocket * > &r_unlinked_inputs) const
MFDummyNode & add_dummy(StringRef name, Span< MFDataType > input_types, Span< MFDataType > output_types, Span< StringRef > input_names, Span< StringRef > output_names)
std::string to_dot(Span< const MFNode * > marked_nodes={}) const
void add_link(MFOutputSocket &from, MFInputSocket &to)
MFFunctionNode & add_function(const MultiFunction &function)
MFOutputSocket & add_input(StringRef name, MFDataType data_type)
MFInputSocket & add_output(StringRef name, MFDataType data_type)
Span< MFInputSocket * > inputs()
Span< MFOutputSocket * > outputs_
Span< MFInputSocket * > inputs_
const MFDataType & data_type() const
OperationNode * node
StackEntry * from
constexpr void assert_same_size(const T1 &v1, const T2 &v2)
Definition: BLI_span.hh:715