| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_dot_export.hh"
 | 
					
						
							| 
									
										
										
										
											2020-07-10 14:22:35 +02:00
										 |  |  | #include "BLI_stack.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | #include "FN_multi_function_network.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | namespace blender::fn { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | MFNetwork::~MFNetwork() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFFunctionNode *node : function_nodes_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     node->destruct_sockets(); | 
					
						
							|  |  |  |     node->~MFFunctionNode(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFDummyNode *node : dummy_nodes_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     node->destruct_sockets(); | 
					
						
							|  |  |  |     node->~MFDummyNode(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MFNode::destruct_sockets() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFInputSocket *socket : inputs_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     socket->~MFInputSocket(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFOutputSocket *socket : outputs_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     socket->~MFOutputSocket(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Add a new function node to the network. The caller keeps the ownership of the function. The | 
					
						
							|  |  |  |  * function should not be freed before the network. A reference to the new node is returned. The | 
					
						
							|  |  |  |  * node is owned by the network. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | MFFunctionNode &MFNetwork::add_function(const MultiFunction &function) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   Vector<int, 16> input_param_indices, output_param_indices; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int param_index : function.param_indices()) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     switch (function.param_type(param_index).interface_type()) { | 
					
						
							|  |  |  |       case MFParamType::Input: { | 
					
						
							|  |  |  |         input_param_indices.append(param_index); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case MFParamType::Output: { | 
					
						
							|  |  |  |         output_param_indices.append(param_index); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       case MFParamType::Mutable: { | 
					
						
							|  |  |  |         input_param_indices.append(param_index); | 
					
						
							|  |  |  |         output_param_indices.append(param_index); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   MFFunctionNode &node = *allocator_.construct<MFFunctionNode>(); | 
					
						
							|  |  |  |   function_nodes_.add_new(&node); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.network_ = this; | 
					
						
							|  |  |  |   node.is_dummy_ = false; | 
					
						
							|  |  |  |   node.id_ = node_or_null_by_id_.append_and_get_index(&node); | 
					
						
							|  |  |  |   node.function_ = &function; | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   node.input_param_indices_ = allocator_.construct_array_copy<int>(input_param_indices); | 
					
						
							|  |  |  |   node.output_param_indices_ = allocator_.construct_array_copy<int>(output_param_indices); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.inputs_ = allocator_.construct_elements_and_pointer_array<MFInputSocket>( | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       input_param_indices.size()); | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.outputs_ = allocator_.construct_elements_and_pointer_array<MFOutputSocket>( | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       output_param_indices.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int i : input_param_indices.index_range()) { | 
					
						
							|  |  |  |     int param_index = input_param_indices[i]; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     MFParamType param = function.param_type(param_index); | 
					
						
							|  |  |  |     BLI_assert(param.is_input_or_mutable()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     MFInputSocket &socket = *node.inputs_[i]; | 
					
						
							|  |  |  |     socket.data_type_ = param.data_type(); | 
					
						
							|  |  |  |     socket.node_ = &node; | 
					
						
							|  |  |  |     socket.index_ = i; | 
					
						
							|  |  |  |     socket.is_output_ = false; | 
					
						
							|  |  |  |     socket.name_ = function.param_name(param_index); | 
					
						
							|  |  |  |     socket.origin_ = nullptr; | 
					
						
							|  |  |  |     socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int i : output_param_indices.index_range()) { | 
					
						
							|  |  |  |     int param_index = output_param_indices[i]; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     MFParamType param = function.param_type(param_index); | 
					
						
							|  |  |  |     BLI_assert(param.is_output_or_mutable()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     MFOutputSocket &socket = *node.outputs_[i]; | 
					
						
							|  |  |  |     socket.data_type_ = param.data_type(); | 
					
						
							|  |  |  |     socket.node_ = &node; | 
					
						
							|  |  |  |     socket.index_ = i; | 
					
						
							|  |  |  |     socket.is_output_ = true; | 
					
						
							|  |  |  |     socket.name_ = function.param_name(param_index); | 
					
						
							|  |  |  |     socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Add a dummy node with the given input and output sockets. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | MFDummyNode &MFNetwork::add_dummy(StringRef name, | 
					
						
							|  |  |  |                                   Span<MFDataType> input_types, | 
					
						
							|  |  |  |                                   Span<MFDataType> output_types, | 
					
						
							|  |  |  |                                   Span<StringRef> input_names, | 
					
						
							|  |  |  |                                   Span<StringRef> output_names) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   assert_same_size(input_types, input_names); | 
					
						
							|  |  |  |   assert_same_size(output_types, output_names); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   MFDummyNode &node = *allocator_.construct<MFDummyNode>(); | 
					
						
							|  |  |  |   dummy_nodes_.add_new(&node); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.network_ = this; | 
					
						
							|  |  |  |   node.is_dummy_ = true; | 
					
						
							|  |  |  |   node.name_ = allocator_.copy_string(name); | 
					
						
							|  |  |  |   node.id_ = node_or_null_by_id_.append_and_get_index(&node); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.inputs_ = allocator_.construct_elements_and_pointer_array<MFInputSocket>( | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       input_types.size()); | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.outputs_ = allocator_.construct_elements_and_pointer_array<MFOutputSocket>( | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       output_types.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node.input_names_ = allocator_.allocate_array<StringRefNull>(input_types.size()); | 
					
						
							|  |  |  |   node.output_names_ = allocator_.allocate_array<StringRefNull>(output_types.size()); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int i : input_types.index_range()) { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     MFInputSocket &socket = *node.inputs_[i]; | 
					
						
							|  |  |  |     socket.data_type_ = input_types[i]; | 
					
						
							|  |  |  |     socket.node_ = &node; | 
					
						
							|  |  |  |     socket.index_ = i; | 
					
						
							|  |  |  |     socket.is_output_ = false; | 
					
						
							|  |  |  |     socket.name_ = allocator_.copy_string(input_names[i]); | 
					
						
							|  |  |  |     socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); | 
					
						
							|  |  |  |     node.input_names_[i] = socket.name_; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int i : output_types.index_range()) { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     MFOutputSocket &socket = *node.outputs_[i]; | 
					
						
							|  |  |  |     socket.data_type_ = output_types[i]; | 
					
						
							|  |  |  |     socket.node_ = &node; | 
					
						
							|  |  |  |     socket.index_ = i; | 
					
						
							|  |  |  |     socket.is_output_ = true; | 
					
						
							|  |  |  |     socket.name_ = allocator_.copy_string(output_names[i]); | 
					
						
							|  |  |  |     socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket); | 
					
						
							|  |  |  |     node.output_names_[i] = socket.name_; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Connect two sockets. This invokes undefined behavior if the sockets belong to different | 
					
						
							|  |  |  |  * networks, the sockets have a different data type, or the `to` socket is connected to something | 
					
						
							|  |  |  |  * else already. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void MFNetwork::add_link(MFOutputSocket &from, MFInputSocket &to) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   BLI_assert(to.origin_ == nullptr); | 
					
						
							|  |  |  |   BLI_assert(from.node_->network_ == to.node_->network_); | 
					
						
							|  |  |  |   BLI_assert(from.data_type_ == to.data_type_); | 
					
						
							|  |  |  |   from.targets_.append(&to); | 
					
						
							|  |  |  |   to.origin_ = &from; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MFOutputSocket &MFNetwork::add_input(StringRef name, MFDataType data_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-08 17:04:50 +02:00
										 |  |  |   return this->add_dummy(name, {}, {data_type}, {}, {"Value"}).output(0); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MFInputSocket &MFNetwork::add_output(StringRef name, MFDataType data_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-08 17:04:50 +02:00
										 |  |  |   return this->add_dummy(name, {data_type}, {}, {"Value"}, {}).input(0); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  | void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   BLI_assert(&old_output != &new_output); | 
					
						
							| 
									
										
										
										
											2020-07-11 17:59:43 +02:00
										 |  |  |   BLI_assert(old_output.data_type_ == new_output.data_type_); | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   for (MFInputSocket *input : old_output.targets()) { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     input->origin_ = &new_output; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   new_output.targets_.extend(old_output.targets_); | 
					
						
							|  |  |  |   old_output.targets_.clear(); | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MFNetwork::remove(MFNode &node) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFInputSocket *socket : node.inputs_) { | 
					
						
							|  |  |  |     if (socket->origin_ != nullptr) { | 
					
						
							|  |  |  |       socket->origin_->targets_.remove_first_occurrence_and_reorder(socket); | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     socket_or_null_by_id_[socket->id_] = nullptr; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   for (MFOutputSocket *socket : node.outputs_) { | 
					
						
							|  |  |  |     for (MFInputSocket *other : socket->targets_) { | 
					
						
							|  |  |  |       other->origin_ = nullptr; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     socket_or_null_by_id_[socket->id_] = nullptr; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   node.destruct_sockets(); | 
					
						
							|  |  |  |   if (node.is_dummy()) { | 
					
						
							|  |  |  |     MFDummyNode &dummy_node = node.as_dummy(); | 
					
						
							|  |  |  |     dummy_node.~MFDummyNode(); | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     dummy_nodes_.remove_contained(&dummy_node); | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     MFFunctionNode &function_node = node.as_function(); | 
					
						
							|  |  |  |     function_node.~MFFunctionNode(); | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     function_nodes_.remove_contained(&function_node); | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |   node_or_null_by_id_[node.id_] = nullptr; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:03:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 18:45:34 +02:00
										 |  |  | void MFNetwork::remove(Span<MFNode *> nodes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   for (MFNode *node : nodes) { | 
					
						
							|  |  |  |     this->remove(*node); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 14:22:35 +02:00
										 |  |  | void MFNetwork::find_dependencies(Span<const MFInputSocket *> sockets, | 
					
						
							|  |  |  |                                   VectorSet<const MFOutputSocket *> &r_dummy_sockets, | 
					
						
							|  |  |  |                                   VectorSet<const MFInputSocket *> &r_unlinked_inputs) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Set<const MFNode *> visited_nodes; | 
					
						
							|  |  |  |   Stack<const MFInputSocket *> sockets_to_check; | 
					
						
							|  |  |  |   sockets_to_check.push_multiple(sockets); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (!sockets_to_check.is_empty()) { | 
					
						
							|  |  |  |     const MFInputSocket &socket = *sockets_to_check.pop(); | 
					
						
							|  |  |  |     const MFOutputSocket *origin_socket = socket.origin(); | 
					
						
							|  |  |  |     if (origin_socket == nullptr) { | 
					
						
							|  |  |  |       r_unlinked_inputs.add(&socket); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const MFNode &origin_node = origin_socket->node(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (origin_node.is_dummy()) { | 
					
						
							|  |  |  |       r_dummy_sockets.add(origin_socket); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (visited_nodes.add(&origin_node)) { | 
					
						
							|  |  |  |       sockets_to_check.push_multiple(origin_node.inputs()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 10:51:38 +02:00
										 |  |  | bool MFNetwork::have_dummy_or_unlinked_dependencies(Span<const MFInputSocket *> sockets) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   VectorSet<const MFOutputSocket *> dummy_sockets; | 
					
						
							|  |  |  |   VectorSet<const MFInputSocket *> unlinked_inputs; | 
					
						
							|  |  |  |   this->find_dependencies(sockets, dummy_sockets, unlinked_inputs); | 
					
						
							|  |  |  |   return dummy_sockets.size() + unlinked_inputs.size() > 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 18:45:34 +02:00
										 |  |  | std::string MFNetwork::to_dot(Span<const MFNode *> marked_nodes) const | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |   dot::DirectedGraph digraph; | 
					
						
							|  |  |  |   digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |   Map<const MFNode *, dot::NodeWithSocketsRef> dot_nodes; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Vector<const MFNode *> all_nodes; | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |   all_nodes.extend(function_nodes_.as_span().cast<const MFNode *>()); | 
					
						
							|  |  |  |   all_nodes.extend(dummy_nodes_.as_span().cast<const MFNode *>()); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (const MFNode *node : all_nodes) { | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |     dot::Node &dot_node = digraph.new_node(""); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Vector<std::string> input_names, output_names; | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     for (const MFInputSocket *socket : node->inputs_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       input_names.append(socket->name() + "(" + socket->data_type().to_string() + ")"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     for (const MFOutputSocket *socket : node->outputs_) { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       output_names.append(socket->name() + " (" + socket->data_type().to_string() + ")"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |     dot::NodeWithSocketsRef dot_node_ref{dot_node, node->name(), input_names, output_names}; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |     dot_nodes.add_new(node, dot_node_ref); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 18:45:34 +02:00
										 |  |  |   for (const MFDummyNode *node : dummy_nodes_) { | 
					
						
							|  |  |  |     dot_nodes.lookup(node).node().set_background_color("#77EE77"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (const MFNode *node : marked_nodes) { | 
					
						
							|  |  |  |     dot_nodes.lookup(node).node().set_background_color("#7777EE"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |   for (const MFNode *to_node : all_nodes) { | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |     dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |     for (const MFInputSocket *to_socket : to_node->inputs_) { | 
					
						
							|  |  |  |       const MFOutputSocket *from_socket = to_socket->origin_; | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       if (from_socket != nullptr) { | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |         const MFNode *from_node = from_socket->node_; | 
					
						
							| 
									
										
										
										
											2020-06-29 11:53:17 +02:00
										 |  |  |         dot::NodeWithSocketsRef from_dot_node = dot_nodes.lookup(from_node); | 
					
						
							| 
									
										
										
										
											2020-07-03 14:20:42 +02:00
										 |  |  |         digraph.new_edge(from_dot_node.output(from_socket->index_), | 
					
						
							|  |  |  |                          to_dot_node.input(to_socket->index_)); | 
					
						
							| 
									
										
										
										
											2020-06-23 10:16:14 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return digraph.to_dot_string(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 14:25:20 +02:00
										 |  |  | }  // namespace blender::fn
 |