Blender V4.3
dot_export.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <iomanip>
6
7#include "BLI_dot_export.hh"
8
9#include <sstream>
10
11namespace blender::dot {
12
13/* Graph Building
14 ************************************************/
15
17{
18 Node *node = new Node(*this);
19 nodes_.append(std::unique_ptr<Node>(node));
20 top_level_nodes_.add_new(node);
21 node->attributes.set("label", label);
22 return *node;
23}
24
26{
27 Cluster *cluster = new Cluster(*this);
28 clusters_.append(std::unique_ptr<Cluster>(cluster));
29 top_level_clusters_.add_new(cluster);
30 cluster->attributes.set("label", label);
31 return *cluster;
32}
33
35{
36 UndirectedEdge *edge = new UndirectedEdge(a, b);
37 edges_.append(std::unique_ptr<UndirectedEdge>(edge));
38 return *edge;
39}
40
42{
43 DirectedEdge *edge = new DirectedEdge(from, to);
44 edges_.append(std::unique_ptr<DirectedEdge>(edge));
45 return *edge;
46}
47
49{
50 if (parent_ == new_parent) {
51 return;
52 }
53 if (parent_ == nullptr) {
54 graph_.top_level_clusters_.remove(this);
55 new_parent->children_.add_new(this);
56 }
57 else if (new_parent == nullptr) {
58 parent_->children_.remove(this);
59 graph_.top_level_clusters_.add_new(this);
60 }
61 else {
62 parent_->children_.remove(this);
63 new_parent->children_.add_new(this);
64 }
65 parent_ = new_parent;
66}
67
69{
70 if (cluster_ == cluster) {
71 return;
72 }
73 if (cluster_ == nullptr) {
74 graph_.top_level_nodes_.remove(this);
75 cluster->nodes_.add_new(this);
76 }
77 else if (cluster == nullptr) {
78 cluster_->nodes_.remove(this);
79 graph_.top_level_nodes_.add_new(this);
80 }
81 else {
82 cluster_->nodes_.remove(this);
83 cluster->nodes_.add_new(this);
84 }
85 cluster_ = cluster;
86}
87
88/* Utility methods
89 **********************************************/
90
92{
93 for (Cluster *cluster : top_level_clusters_) {
94 cluster->set_random_cluster_bgcolors();
95 }
96}
97
99{
100 float hue = rand() / float(RAND_MAX);
101 float staturation = 0.3f;
102 float value = 0.8f;
103 this->attributes.set("bgcolor", color_attr_from_hsv(hue, staturation, value));
104
105 for (Cluster *cluster : children_) {
106 cluster->set_random_cluster_bgcolors();
107 }
108}
109
110bool Cluster::contains(Node &node) const
111{
112 Cluster *current = node.parent_cluster();
113 while (current != nullptr) {
114 if (current == this) {
115 return true;
116 }
117 current = current->parent_;
118 }
119 return false;
120}
121
122/* Dot Generation
123 **********************************************/
124
126{
127 std::stringstream ss;
128 ss << "digraph {\n";
130 ss << "\n";
131
132 for (const std::unique_ptr<DirectedEdge> &edge : edges_) {
133 edge->export__as_edge_statement(ss);
134 ss << "\n";
135 }
136
137 ss << "}\n";
138 return ss.str();
139}
140
142{
143 std::stringstream ss;
144 ss << "graph {\n";
146 ss << "\n";
147
148 for (const std::unique_ptr<UndirectedEdge> &edge : edges_) {
149 edge->export__as_edge_statement(ss);
150 ss << "\n";
151 }
152
153 ss << "}\n";
154 return ss.str();
155}
156
157void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
158{
159 ss << "graph ";
160 attributes.export__as_bracket_list(ss);
161 ss << "\n\n";
162
163 for (Node *node : top_level_nodes_) {
164 node->export__as_declaration(ss);
165 }
166
167 for (Cluster *cluster : top_level_clusters_) {
168 cluster->export__declare_nodes_and_clusters(ss);
169 }
170}
171
172void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
173{
174 ss << "subgraph " << this->name() << " {\n";
175
176 ss << "graph ";
177 attributes.export__as_bracket_list(ss);
178 ss << "\n\n";
179
180 for (Node *node : nodes_) {
181 node->export__as_declaration(ss);
182 }
183
184 for (Cluster *cluster : children_) {
185 cluster->export__declare_nodes_and_clusters(ss);
186 }
187
188 ss << "}\n";
189}
190
191void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
192{
193 a_.to_dot_string(ss);
194 ss << " -> ";
195 b_.to_dot_string(ss);
196 ss << " ";
197 attributes.export__as_bracket_list(ss);
198}
199
200void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
201{
202 a_.to_dot_string(ss);
203 ss << " -- ";
204 b_.to_dot_string(ss);
205 ss << " ";
206 attributes.export__as_bracket_list(ss);
207}
208
209void Attributes::export__as_bracket_list(std::stringstream &ss) const
210{
211 ss << "[";
212 attributes_.foreach_item([&](StringRef key, StringRef value) {
213 if (StringRef(value).startswith("<")) {
214 /* Don't draw the quotes, this is an HTML-like value. */
215 ss << key << "=" << value << ", ";
216 }
217 else {
218 ss << key << "=\"";
219 for (char c : value) {
220 if (c == '\"') {
221 /* Escape double quotes. */
222 ss << '\\';
223 }
224 ss << c;
225 }
226 ss << "\", ";
227 }
228 });
229 ss << "]";
230}
231
232void Node::export__as_id(std::stringstream &ss) const
233{
234 ss << '"' << uintptr_t(this) << '"';
235}
236
237void Node::export__as_declaration(std::stringstream &ss) const
238{
239 this->export__as_id(ss);
240 ss << " ";
241 attributes.export__as_bracket_list(ss);
242 ss << "\n";
243}
244
245void NodePort::to_dot_string(std::stringstream &ss) const
246{
247 node_->export__as_id(ss);
248 if (port_name_.has_value()) {
249 ss << ":" << *port_name_;
250 }
251 if (port_position_.has_value()) {
252 ss << ":" << *port_position_;
253 }
254}
255
256std::string color_attr_from_hsv(float h, float s, float v)
257{
258 std::stringstream ss;
259 ss << std::setprecision(4) << h << ' ' << s << ' ' << v;
260 return ss.str();
261}
262
264{
265 std::stringstream ss;
266
267 ss << R"(<<table border="0" cellspacing="3">)";
268
269 /* Header */
270 ss << R"(<tr><td colspan="3" align="center"><b>)";
271 ss << (data.node_name.empty() ? "No Name" : data.node_name);
272 ss << "</b></td></tr>";
273
274 /* Sockets */
275 int socket_max_amount = std::max(data.inputs.size(), data.outputs.size());
276 for (int i = 0; i < socket_max_amount; i++) {
277 ss << "<tr>";
278 if (i < data.inputs.size()) {
279 const NodeWithSockets::Input &input = data.inputs[i];
280 ss << R"(<td align="left" port="in)" << i << "\">";
281 if (input.fontcolor) {
282 ss << R"(<font color=")" << *input.fontcolor << "\">";
283 }
284 ss << (input.name.empty() ? "No Name" : input.name);
285 if (input.fontcolor) {
286 ss << "</font>";
287 }
288 ss << "</td>";
289 }
290 else {
291 ss << "<td></td>";
292 }
293 ss << "<td></td>";
294 if (i < data.outputs.size()) {
295 const NodeWithSockets::Output &output = data.outputs[i];
296 ss << R"(<td align="right" port="out)" << i << "\">";
297 if (output.fontcolor) {
298 ss << R"(<font color=")" << *output.fontcolor << "\">";
299 }
300 ss << (output.name.empty() ? "No Name" : output.name);
301 if (output.fontcolor) {
302 ss << "</font>";
303 }
304 ss << "</td>";
305 }
306 else {
307 ss << "<td></td>";
308 }
309 ss << "</tr>";
310 }
311
312 ss << "</table>>";
313
314 node_->attributes.set("label", ss.str());
315 node_->set_shape(Attr_shape::Rectangle);
316}
317
318} // namespace blender::dot
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its hue
ATTR_WARN_UNUSED_RESULT const BMVert * v
void export__as_bracket_list(std::stringstream &ss) const
void set(StringRef key, StringRef value)
void set_parent_cluster(Cluster *new_parent)
Definition dot_export.cc:48
bool contains(Node &node) const
std::string name() const
void export__declare_nodes_and_clusters(std::stringstream &ss) const
void set_random_cluster_bgcolors()
Definition dot_export.cc:98
void export__as_edge_statement(std::stringstream &ss) const
DirectedEdge & new_edge(NodePort from, NodePort to)
Definition dot_export.cc:41
std::string to_dot_string() const
Cluster & new_cluster(StringRef label="")
Definition dot_export.cc:25
void set_random_cluster_bgcolors()
Definition dot_export.cc:91
Node & new_node(StringRef label)
Definition dot_export.cc:16
void export__declare_nodes_and_clusters(std::stringstream &ss) const
void to_dot_string(std::stringstream &ss) const
NodePort output(int index) const
NodeWithSocketsRef(Node &node, const NodeWithSockets &data)
NodePort input(int index) const
void export__as_declaration(std::stringstream &ss) const
Cluster * parent_cluster()
void export__as_id(std::stringstream &ss) const
void set_parent_cluster(Cluster *cluster)
Definition dot_export.cc:68
void export__as_edge_statement(std::stringstream &ss) const
UndirectedEdge & new_edge(NodePort a, NodePort b)
Definition dot_export.cc:34
std::string to_dot_string() const
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
std::string color_attr_from_hsv(float h, float s, float v)
_W64 unsigned int uintptr_t
Definition stdint.h:119