[Bf-blender-cvs] [fff8781973c] functions: dot export for data flow graph

Jacques Lucke noreply at git.blender.org
Sun Feb 10 20:25:56 CET 2019


Commit: fff8781973c8b72f5012bc30df3f20e22c7ef147
Author: Jacques Lucke
Date:   Mon Feb 4 15:38:27 2019 +0100
Branches: functions
https://developer.blender.org/rBfff8781973c8b72f5012bc30df3f20e22c7ef147

dot export for data flow graph

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

M	source/blender/functions/CMakeLists.txt
M	source/blender/functions/c_wrapper.cpp
M	source/blender/functions/core/core.hpp
M	source/blender/functions/core/data_flow_graph.cpp
M	source/blender/functions/core/data_flow_graph.hpp
A	source/blender/functions/core/dot_export.cpp

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

diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 4d4ae0ebc48..efc9d2a6d7e 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SRC
 	core/data_flow_graph.hpp
 	core/cpu.hpp
 	core/data_flow_graph.cpp
+	core/dot_export.cpp
 
 	FN_functions.hpp
 
diff --git a/source/blender/functions/c_wrapper.cpp b/source/blender/functions/c_wrapper.cpp
index c7823794410..56cc18b4988 100644
--- a/source/blender/functions/c_wrapper.cpp
+++ b/source/blender/functions/c_wrapper.cpp
@@ -3,6 +3,8 @@
 
 #include "./types/types.hpp"
 
+#include <iostream>
+
 #define WRAPPERS(T1, T2) \
 	inline T1 unwrap(T2 value) { return (T1)value; } \
 	inline T2 wrap(T1 value) { return (T2)value; }
@@ -111,6 +113,28 @@ public:
 	}
 };
 
+template<typename T>
+class PassThroughBody : public FN::TupleCallBody {
+public:
+	virtual void call(const FN::Tuple &fn_in, FN::Tuple &fn_out) const override
+	{
+		fn_out.set<T>(0, fn_in.get<T>(0));
+	}
+};
+
+static FN::Function *get_pass_through_float_function()
+{
+	FN::InputParameters inputs;
+	inputs.append(FN::InputParameter("In", FN::Types::float_ty));
+
+	FN::OutputParameters outputs;
+	outputs.append(FN::OutputParameter("Out", FN::Types::float_ty));
+
+	auto fn = new FN::Function(FN::Signature(inputs, outputs), "Pass Through");
+	fn->add_body(new PassThroughBody<float>());
+	return fn;
+}
+
 FnFunction FN_get_deform_function(int type)
 {
 	FN::InputParameters inputs;
@@ -120,12 +144,30 @@ FnFunction FN_get_deform_function(int type)
 	FN::OutputParameters outputs;
 	outputs.append(FN::OutputParameter("Position", FN::Types::floatvec3d_ty));
 
-	auto fn = new FN::Function(FN::Signature(inputs, outputs));
+	auto fn = new FN::Function(FN::Signature(inputs, outputs), "Deform");
 	if (type == 0) {
 		fn->add_body(new Deform1());
 	}
 	else {
 		fn->add_body(new Deform2());
 	}
+
+	FN::DataFlowGraph graph;
+	const FN::Node *n1 = graph.insert(*fn);
+	const FN::Node *n2 = graph.insert(*fn);
+	const FN::Node *n3 = graph.insert(*fn);
+	const FN::Node *n4 = graph.insert(*fn);
+	const FN::Node *p = graph.insert(*get_pass_through_float_function());
+	graph.link(n1->output(0), n2->input(0));
+	graph.link(n2->output(0), n3->input(0));
+	graph.link(n2->output(0), n4->input(0));
+	graph.link(p->output(0), n1->input(1));
+	graph.link(p->output(0), n2->input(1));
+	graph.link(p->output(0), n3->input(1));
+	graph.link(p->output(0), n4->input(1));
+
+	std::string dot = graph.to_dot();
+	//std::cout << dot << std::endl;
+
 	return wrap(fn);
 }
\ No newline at end of file
diff --git a/source/blender/functions/core/core.hpp b/source/blender/functions/core/core.hpp
index 4c85f58be31..ccf1a96d1c3 100644
--- a/source/blender/functions/core/core.hpp
+++ b/source/blender/functions/core/core.hpp
@@ -150,8 +150,8 @@ namespace FN {
 
 	class Function {
 	public:
-		Function(const Signature &signature)
-			: m_signature(signature) {}
+		Function(const Signature &signature, const std::string &name = "Function")
+			: m_signature(signature), m_name(name) {}
 
 		virtual ~Function() {}
 
@@ -173,9 +173,15 @@ namespace FN {
 			this->m_bodies.add(body);
 		}
 
+		const std::string &name() const
+		{
+			return this->m_name;
+		}
+
 	private:
 		const Signature m_signature;
 		Composition m_bodies;
+		const std::string m_name;
 	};
 
 } /* namespace FN */
\ No newline at end of file
diff --git a/source/blender/functions/core/data_flow_graph.cpp b/source/blender/functions/core/data_flow_graph.cpp
index 684310b56dd..61c52b525e8 100644
--- a/source/blender/functions/core/data_flow_graph.cpp
+++ b/source/blender/functions/core/data_flow_graph.cpp
@@ -10,4 +10,14 @@ namespace FN {
 			return this->node()->signature().inputs()[this->m_index].type();
 		}
 	}
+
+	std::string Socket::name() const
+	{
+		if (this->m_is_output) {
+			return this->node()->signature().outputs()[this->m_index].name();
+		}
+		else {
+			return this->node()->signature().inputs()[this->m_index].name();
+		}
+	}
 };
\ No newline at end of file
diff --git a/source/blender/functions/core/data_flow_graph.hpp b/source/blender/functions/core/data_flow_graph.hpp
index 727be5a4220..1ea5285c57c 100644
--- a/source/blender/functions/core/data_flow_graph.hpp
+++ b/source/blender/functions/core/data_flow_graph.hpp
@@ -13,15 +13,8 @@ namespace FN {
 
 	class Socket {
 	public:
-		static Socket Input(const Node *node, uint index)
-		{
-			return Socket(node, false, index);
-		}
-
-		static Socket Output(const Node *node, uint index)
-		{
-			return Socket(node, true, index);
-		}
+		static inline Socket Input(const Node *node, uint index);
+		static inline Socket Output(const Node *node, uint index);
 
 		const Node *node() const
 		{
@@ -44,6 +37,7 @@ namespace FN {
 		}
 
 		const Type *type() const;
+		std::string name() const;
 
 		friend bool operator==(const Socket &a, const Socket &b)
 		{
@@ -91,19 +85,59 @@ namespace FN {
 		const Function &m_function;
 	};
 
+	class Link {
+	public:
+		static Link New(Socket a, Socket b)
+		{
+			BLI_assert(a.is_input() != b.is_input());
+			if (a.is_input()) {
+				return Link(b, a);
+			}
+			else {
+				return Link(a, b);
+			}
+		}
+
+		Socket from() const
+		{
+			return this->m_from;
+		}
+
+		Socket to() const
+		{
+			return this->m_to;
+		}
+
+		friend bool operator==(const Link &a, const Link &b)
+		{
+			return a.m_from == b.m_from && a.m_to == b.m_to;
+		}
+
+	private:
+		Link(Socket from, Socket to)
+			: m_from(from), m_to(to) {}
+
+		const Socket m_from;
+		const Socket m_to;
+	};
+
 	class GraphLinks {
 	public:
-		void insert(Socket a, Socket b)
+		void insert(Link link)
 		{
-			if (!this->m_links.contains(a)) {
-				this->m_links.add(a, SmallSet<Socket>());
+			Socket from = link.from();
+			Socket to = link.to();
+
+			if (!this->m_links.contains(from)) {
+				this->m_links.add(from, SmallSet<Socket>());
 			}
-			if (!this->m_links.contains(b)) {
-				this->m_links.add(b, SmallSet<Socket>());
+			if (!this->m_links.contains(to)) {
+				this->m_links.add(to, SmallSet<Socket>());
 			}
 
-			this->m_links.lookup_ref(a).add(b);
-			this->m_links.lookup_ref(b).add(a);
+			this->m_links.lookup_ref(from).add(to);
+			this->m_links.lookup_ref(to).add(from);
+			this->m_all_links.append(Link::New(from, to));
 		}
 
 		SmallSet<Socket> get_linked(Socket socket) const
@@ -111,8 +145,14 @@ namespace FN {
 			return this->m_links.lookup(socket);
 		}
 
+		SmallVector<Link> all_links() const
+		{
+			return this->m_all_links;
+		}
+
 	private:
 		SmallMap<Socket, SmallSet<Socket>> m_links;
+		SmallVector<Link> m_all_links;
 	};
 
 	class DataFlowGraph {
@@ -142,8 +182,7 @@ namespace FN {
 			BLI_assert(m_nodes.contains(a.node()));
 			BLI_assert(m_nodes.contains(b.node()));
 
-			m_links.insert(a, b);
-			m_links.insert(b, a);
+			m_links.insert(Link::New(a, b));
 		}
 
 		inline bool can_modify() const
@@ -161,10 +200,33 @@ namespace FN {
 			this->m_frozen = true;
 		}
 
+		SmallVector<Link> all_links() const
+		{
+			return this->m_links.all_links();
+		}
+
+		std::string to_dot() const;
+
 	private:
 		bool m_frozen = false;
 		SmallSet<const Node *> m_nodes;
 		GraphLinks m_links;
 	};
 
+
+	/* Some inline functions.
+	 * Those can only come after the declaration of other types. */
+
+	inline Socket Socket::Input(const Node *node, uint index)
+	{
+		BLI_assert(index < node->signature().inputs().size());
+		return Socket(node, false, index);
+	}
+
+	inline Socket Socket::Output(const Node *node, uint index)
+	{
+		BLI_assert(index < node->signature().outputs().size());
+		return Socket(node, true, index);
+	}
+
 } /* namespace FN */
\ No newline at end of file
diff --git a/source/blender/functions/core/dot_export.cpp b/source/blender/functions/core/dot_export.cpp
new file mode 100644
index 00000000000..b1071420a03
--- /dev/null
+++ b/source/blender/functions/core/dot_export.cpp
@@ -0,0 +1,105 @@
+#include "data_flow_graph.hpp"
+
+#include <sstream>
+
+namespace FN {
+	static std::string get_id(const Node *node)
+	{
+		std::stringstream ss;
+		ss << "\"";
+		ss << (void *)node;
+		ss << "\"";
+		return ss.str();
+	}
+
+	static std::string get_id(Socket socket)
+	{
+		std::stringstream ss;
+		ss << "\"";
+		ss << std::to_string(socket.is_input());
+		ss << std::to_string(socket.index());
+		ss << "\"";
+		return ss.str();
+	}
+
+	static std::string port_id(Socket socket)
+	{
+		std::string n = get_id(socket.node());
+		std::string s = get_id(socket);
+		return get_id(socket.node()) + ":" + get_id(socket);
+	}
+
+	static void insert_node_table(std::stringstream &ss, const Node *node)
+	{
+		ss << "<table border=\"0\" cellspacing=\"3\">";
+
+		/* Header */
+		ss << "<tr><td colspan=\"3\" align=\"center\"><b>";
+		ss << node->function().name();
+		ss << "</b></td></tr>";
+
+		/* Sockets */
+		const Signature &sig = node->signature();
+		uint inputs_amount = sig.inputs().size();
+		uint outputs_amount = sig.outputs().size();
+		uint socket_max_amount = std::max(inputs_amount, outputs_amount);
+		for (uint i = 0; i < socket_max_amount; i++) {
+			ss << "<tr>";
+			if (i < inputs_amount) {
+				Socket socket = node->input(i);
+				ss << "<td align=\"left\" port=" << get_id(socket) << ">";
+				ss << socket.name();
+				ss << "</td>";
+			}
+			else {
+				ss << "<td></td>";
+			}
+			ss << "<td></td>";
+			if (i < outputs_amount) {
+				ss << "<td align=\"right\" port=" << get_id(node->output(i)) << ">";
+				ss << node->output(i).name();
+				ss << "</td>";
+			}
+			else {
+				ss << "<td></td>";
+			}
+			ss << "</tr>";
+		}
+
+		ss << "</table>";
+	}
+
+	static void insert_node(std::stringstream &ss, const Node *node)
+	{
+		ss << get_id(node) << " ";
+		ss << "[style=\"filled\", fillcolor=\"#FFFFFF\", shape=\"square\"";
+		ss << ", label=<";
+		insert_node_table(ss, node);
+		ss << ">]";
+	}
+
+	static void insert_link(std::stringstream &ss, Link link)
+	{
+		ss << port_id(link.from()) << " -> " << port_id(link.to());
+	}
+
+	std::string DataFlowGraph::to_dot() const
+	{
+		std::stringstream ss;
+		ss << "digraph MyGraph {" << std::endl;
+		ss << "rankdir=LR" << std::endl;
+
+		for (const Node *node : this->m_nodes) {
+			insert_node(ss, node);
+			ss 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list