MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NodeQuery.cpp
Go to the documentation of this file.
1#include "Inspector.hpp"
2
9
11
12namespace {
13
14 std::string_view role_label(Nodes::ModulatorRole role)
15 {
16 switch (role) {
18 return "freq";
20 return "amp";
22 return "sig";
24 return "lhs";
26 return "rhs";
28 return "->";
29 default:
30 return "mod";
31 }
32 }
33
34} // namespace
35
37 const Nodes::ModulatorTree& tree,
38 Surface& surface,
39 LayoutCursor& cursor,
40 float x_min, float x_max, float row_h, int depth)
41{
42 const float ind = x_min + static_cast<float>(depth) * k_inspect_indent;
43
44 const std::string header_label = std::string(role_label(tree.role))
46
47 auto node_ref = tree.node;
48 std::vector<ValueSpec> values {
49 ValueSpec {
50 .label = "out",
51 .reader = [node_ref] { return std::to_string(node_ref->get_last_output()); },
52 },
53 };
54
55 const auto dims = row_pixel_dims(surface.window(), ind, x_max, row_h);
56 auto hbuf = make_row_buffer(surface.window(), header_label, dims);
57 std::vector<RowBuffer> rbufs;
58 rbufs.reserve(values.size());
59 for (const auto& spec : values)
60 rbufs.push_back(make_row_buffer(surface.window(), spec.label, dims));
61
62 auto group = make_value_group(values, std::move(hbuf), rbufs,
63 surface, cursor, ind, x_max, row_h, false);
64
65 InspectResult result;
66 result.group = std::move(group);
67
68 for (const auto& child : tree.modulators) {
69 auto child_result = inspect_modulator_tree(
70 child, surface, cursor,
71 x_min, x_max, row_h, depth + 1);
72 surface.layer().relate(
73 result.group.header.header_id,
74 child_result.group.header.header_id);
75 result.children.push_back(std::move(child_result));
76 }
77
78 return result;
79}
80
81// -----------------------------------------------------------------------------
82// Single node
83// -----------------------------------------------------------------------------
84
86 const std::shared_ptr<Nodes::Node>& n,
87 Surface& surface,
88 LayoutCursor& cursor,
89 float x_min, float x_max, float row_h, int depth)
90{
91 const float ind = x_min + static_cast<float>(depth) * k_inspect_indent;
92 const std::string header_label = Reflect::short_dynamic_type_name(*n);
93
94 auto node_ref = n;
95 std::vector<ValueSpec> values {
96 ValueSpec {
97 .label = "out",
98 .reader = [node_ref] { return std::to_string(node_ref->get_last_output()); },
99 },
100 };
101
102 const auto dims = row_pixel_dims(surface.window(), ind, x_max, row_h);
103 auto hbuf = make_row_buffer(surface.window(), header_label, dims);
104 std::vector<RowBuffer> rbufs;
105 rbufs.reserve(values.size());
106 for (const auto& spec : values)
107 rbufs.push_back(make_row_buffer(surface.window(), spec.label, dims));
108
109 auto group = make_value_group(values, std::move(hbuf), rbufs,
110 surface, cursor, ind, x_max, row_h, false);
111
112 InspectResult result;
113 result.group = std::move(group);
114
115 for (const auto& tree : n->get_modulator_tree()) {
116 auto child = inspect_modulator_tree(
117 tree, surface, cursor,
118 x_min, x_max, row_h, depth + 1);
119 surface.layer().relate(
120 result.group.header.header_id,
121 child.group.header.header_id);
122 result.children.push_back(std::move(child));
123 }
124
125 return result;
126}
127
128// -----------------------------------------------------------------------------
129// RootNode: single channel
130// -----------------------------------------------------------------------------
131
133 Nodes::ProcessingToken token, uint32_t channel,
134 Surface& surface,
135 LayoutCursor& cursor,
136 float x_min, float x_max, float row_h, int depth)
137{
138 auto& root = m_ngm.get_root_node(token, channel);
139
140 const float ind = x_min + static_cast<float>(depth) * k_inspect_indent;
141 const std::string header_label = token == Nodes::ProcessingToken::AUDIO_RATE
142 ? "root [ch " + std::to_string(channel) + "]"
143 : "root";
144
145 std::vector<ValueSpec> values {
146 ValueSpec {
147 .label = "nodes",
148 .reader = [&root] { return std::to_string(root.get_node_size()); },
149 },
150 };
151
152 const auto dims = row_pixel_dims(surface.window(), ind, x_max, row_h);
153 auto hbuf = make_row_buffer(surface.window(), header_label, dims);
154 std::vector<RowBuffer> rbufs;
155 rbufs.reserve(values.size());
156 for (const auto& spec : values)
157 rbufs.push_back(make_row_buffer(surface.window(), spec.label, dims));
158
159 auto group = make_value_group(values, std::move(hbuf), rbufs,
160 surface, cursor, ind, x_max, row_h, false);
161
162 InspectResult result;
163 result.group = std::move(group);
164
165 for (const auto& n : root.nodes()) {
166 if (!n)
167 continue;
168 auto node_result = node(
169 n, surface, cursor,
170 x_min, x_max, row_h, depth + 1);
171 surface.layer().relate(result.group.header.header_id, node_result.group.header.header_id);
172 result.children.push_back(std::move(node_result));
173 }
174
175 return result;
176}
177
178// -----------------------------------------------------------------------------
179// RootNode: all channels (or single root for non-audio tokens)
180// -----------------------------------------------------------------------------
181
184 Surface& surface,
185 LayoutCursor& cursor,
186 float x_min, float x_max, float row_h, int depth)
187{
189 return root_node(token, 0, surface, cursor, x_min, x_max, row_h, depth);
190
191 auto channels = m_ngm.get_all_channels(token);
192 std::ranges::sort(channels);
193
194 InspectResult result;
195 for (const auto ch : channels) {
196 result.children.push_back(
197 root_node(token, ch, surface, cursor, x_min, x_max, row_h, depth));
198 }
199 return result;
200}
201// -----------------------------------------------------------------------------
202// Single network
203// -----------------------------------------------------------------------------
204
206 const std::shared_ptr<Nodes::Network::NodeNetwork>& net,
207 Surface& surface,
208 LayoutCursor& cursor,
209 float x_min, float x_max, float row_h, int depth)
210{
211 const float ind = x_min + static_cast<float>(depth) * k_inspect_indent;
212
213 const std::string header_label
214 = std::string(Reflect::enum_to_string(net->get_topology()))
215 + " / "
216 + std::string(Reflect::enum_to_string(net->get_output_mode()));
217
218 auto net_ref = net;
219 std::vector<ValueSpec> values {
220 ValueSpec {
221 .label = "nodes",
222 .reader = [net_ref] { return std::to_string(net_ref->get_node_count()); },
223 },
224 ValueSpec {
225 .label = "enabled",
226 .reader = [net_ref] { return net_ref->is_enabled() ? "true" : "false"; },
227 },
228 ValueSpec {
229 .label = "channels",
230 .reader = [net_ref] {
231 const auto ch = net_ref->get_registered_channels();
232 std::string s;
233 for (size_t i = 0; i < ch.size(); ++i) {
234 if (i)
235 s += ',';
236 s += std::to_string(ch[i]);
237 }
238 return s.empty() ? "-" : s;
239 },
240 },
241 };
242
243 const auto dims = row_pixel_dims(surface.window(), ind, x_max, row_h);
244 auto hbuf = make_row_buffer(surface.window(), header_label, dims);
245 std::vector<RowBuffer> rbufs;
246 rbufs.reserve(values.size());
247 for (const auto& spec : values)
248 rbufs.push_back(make_row_buffer(surface.window(), spec.label, dims));
249
250 auto group = make_value_group(values, std::move(hbuf), rbufs,
251 surface, cursor, ind, x_max, row_h, false);
252
253 InspectResult result;
254 result.group = std::move(group);
255 return result;
256}
257
258// -----------------------------------------------------------------------------
259// NodeGraphManager
260// -----------------------------------------------------------------------------
261
263 Surface& surface,
264 LayoutCursor& cursor,
265 float x_min, float x_max, float row_h)
266{
268 return *s_node_graph_result;
269 }
270
271 const auto tokens = m_ngm.get_active_tokens();
272
273 const std::string root_label = "NodeGraphManager ["
274 + std::to_string(tokens.size()) + " token"
275 + (tokens.size() == 1 ? "" : "s") + "]";
276
277 auto& ngm = m_ngm;
278 std::vector<ValueSpec> root_values {
279 ValueSpec {
280 .label = "tokens",
281 .reader = [&ngm] { return std::to_string(ngm.get_active_tokens().size()); },
282 },
283 };
284
285 const auto dims = row_pixel_dims(surface.window(), x_min, x_max, row_h);
286 auto hbuf = make_row_buffer(surface.window(), root_label, dims);
287 std::vector<RowBuffer> rbufs;
288 rbufs.reserve(root_values.size());
289 for (const auto& spec : root_values)
290 rbufs.push_back(make_row_buffer(surface.window(), spec.label, dims));
291
292 auto root_group = make_value_group(root_values, std::move(hbuf), rbufs,
293 surface, cursor, x_min, x_max, row_h, false);
294
295 InspectResult& result = s_node_graph_result.emplace();
296 result.group = std::move(root_group);
297
298 for (const auto tok : tokens) {
299 const std::string tok_label = std::string(Reflect::enum_to_string(tok));
300 const bool multichannel = tok == Nodes::ProcessingToken::AUDIO_RATE;
301 auto channels = m_ngm.get_all_channels(tok);
302 if (multichannel)
303 std::ranges::sort(channels);
304
305 std::vector<ValueSpec> tok_values {
306 ValueSpec {
307 .label = "nodes",
308 .reader = [&ngm, tok] { return std::to_string(ngm.get_node_count(tok)); },
309 },
310 ValueSpec {
311 .label = "networks",
312 .reader = [&ngm, tok] { return std::to_string(ngm.get_network_count(tok)); },
313 },
314 };
315
316 const auto tok_dims = row_pixel_dims(surface.window(), x_min + k_inspect_indent, x_max, row_h);
317 auto tok_hbuf = make_row_buffer(surface.window(), tok_label, tok_dims);
318 std::vector<RowBuffer> tok_rbufs;
319 tok_rbufs.reserve(tok_values.size());
320 for (const auto& spec : tok_values)
321 tok_rbufs.push_back(make_row_buffer(surface.window(), spec.label, tok_dims));
322
323 auto tok_group = make_value_group(tok_values, std::move(tok_hbuf), tok_rbufs,
324 surface, cursor, x_min + k_inspect_indent, x_max, row_h, false);
325
326 InspectResult tok_result;
327 tok_result.group = std::move(tok_group);
328 surface.layer().relate(result.group.header.header_id, tok_result.group.header.header_id);
329
330 // ----- Networks section -----
331 {
332 const auto net_dims = row_pixel_dims(surface.window(), x_min + 2.F * k_inspect_indent, x_max, row_h);
333 auto net_hbuf = make_row_buffer(surface.window(), "Networks", net_dims);
334 auto net_group = make_value_group({}, std::move(net_hbuf), {},
335 surface, cursor, x_min + 2.F * k_inspect_indent, x_max, row_h, false);
336
337 InspectResult net_section;
338 net_section.group = std::move(net_group);
339 surface.layer().relate(tok_result.group.header.header_id, net_section.group.header.header_id);
340
341 if (multichannel) {
342 for (const auto ch : channels) {
343 const auto ch_dims = row_pixel_dims(surface.window(), x_min + 3.F * k_inspect_indent, x_max, row_h);
344 auto ch_hbuf = make_row_buffer(surface.window(), "ch " + std::to_string(ch), ch_dims);
345 auto ch_group = make_value_group({}, std::move(ch_hbuf), {},
346 surface, cursor, x_min + 3.F * k_inspect_indent, x_max, row_h, false);
347
348 InspectResult ch_result;
349 ch_result.group = std::move(ch_group);
350 surface.layer().relate(net_section.group.header.header_id, ch_result.group.header.header_id);
351
352 for (const auto& net : m_ngm.get_networks(tok, ch)) {
353 if (!net)
354 continue;
355 auto nr = node_network(net, surface, cursor, x_min, x_max, row_h, 4);
356 surface.layer().relate(ch_result.group.header.header_id, nr.group.header.header_id);
357 ch_result.children.push_back(std::move(nr));
358 }
359
360 net_section.children.push_back(std::move(ch_result));
361 }
362 } else {
363 for (const auto& net : m_ngm.get_networks(tok, 0)) {
364 if (!net)
365 continue;
366 auto nr = node_network(net, surface, cursor, x_min, x_max, row_h, 3);
367 surface.layer().relate(net_section.group.header.header_id, nr.group.header.header_id);
368 net_section.children.push_back(std::move(nr));
369 }
370 }
371
372 tok_result.children.push_back(std::move(net_section));
373 }
374
375 // ----- Nodes section -----
376 {
377 const auto nodes_dims = row_pixel_dims(surface.window(), x_min + 2.F * k_inspect_indent, x_max, row_h);
378 auto nodes_hbuf = make_row_buffer(surface.window(), "Nodes", nodes_dims);
379 auto nodes_group = make_value_group({}, std::move(nodes_hbuf), {},
380 surface, cursor, x_min + 2.F * k_inspect_indent, x_max, row_h, false);
381
382 InspectResult nodes_section;
383 nodes_section.group = std::move(nodes_group);
384 surface.layer().relate(tok_result.group.header.header_id, nodes_section.group.header.header_id);
385
386 if (multichannel) {
387 for (const auto ch : channels) {
388 auto rn = root_node(tok, ch, surface, cursor, x_min, x_max, row_h, 3);
389 surface.layer().relate(nodes_section.group.header.header_id, rn.group.header.header_id);
390 nodes_section.children.push_back(std::move(rn));
391 }
392 } else {
393 auto rn = root_node(tok, 0, surface, cursor, x_min, x_max, row_h, 3);
394 surface.layer().relate(nodes_section.group.header.header_id, rn.group.header.header_id);
395 nodes_section.children.push_back(std::move(rn));
396 }
397
398 tok_result.children.push_back(std::move(nodes_section));
399 }
400
401 result.children.push_back(std::move(tok_result));
402 }
403
404 return result;
405}
406
407} // namespace MayaFlux::Portal::Forma
RootNode & get_root_node(ProcessingToken token, unsigned int channel)
Gets or creates the root node for a specific token and channel.
std::vector< ProcessingToken > get_active_tokens() const
Gets all currently active processing tokens (domains)
std::vector< std::shared_ptr< Network::NodeNetwork > > get_networks(ProcessingToken token, uint32_t channel=0) const
Get all networks for a specific token.
std::vector< unsigned int > get_all_channels(ProcessingToken token) const
Gets all channel indices for a given processing token.
Nodes::NodeGraphManager & m_ngm
InspectResult inspect_modulator_tree(const Nodes::ModulatorTree &tree, Surface &surface, LayoutCursor &cursor, float x_min, float x_max, float row_h, int depth)
Definition NodeQuery.cpp:36
InspectResult & node_graph_manager(Surface &surface, LayoutCursor &cursor, float x_min=-0.95F, float x_max=0.95F, float row_h=0.05F)
Inspect the full NodeGraphManager state across all active tokens.
static std::optional< InspectResult > s_node_graph_result
RowBuffer make_row_buffer(const std::shared_ptr< Core::Window > &window, std::string_view text, glm::uvec2 pixel_dims) const
Definition Inspector.cpp:13
InspectResult node_network(const std::shared_ptr< Nodes::Network::NodeNetwork > &net, Surface &surface, LayoutCursor &cursor, float x_min=-0.95F, float x_max=0.95F, float row_h=0.05F, int depth=0)
Inspect a NodeNetwork and its per-network metadata.
InspectResult root_node(Nodes::ProcessingToken token, uint32_t channel, Surface &surface, LayoutCursor &cursor, float x_min=-0.95F, float x_max=0.95F, float row_h=0.05F, int depth=0)
Inspect a single RootNode for a specific token and channel.
InspectResult node(const std::shared_ptr< Nodes::Node > &n, Surface &surface, LayoutCursor &cursor, float x_min=-0.95F, float x_max=0.95F, float row_h=0.05F, int depth=0)
Inspect a single Node and its full modulator tree.
Definition NodeQuery.cpp:85
bool relate(uint32_t primary_id, uint32_t related_id)
Record that related_id belongs with primary_id.
Definition Layer.cpp:152
Reactive Y-position accumulator for vertical primitive stacking.
const std::shared_ptr< Core::Window > & window() const noexcept
Access the rendering target window.
Definition Surface.hpp:126
Layer & layer() noexcept
Access the spatial registry.
Definition Surface.hpp:107
Named owner of a (Window, Layer, Context) triple - the Forma canvas.
Definition Surface.hpp:58
ProcessingToken
Enumerates the different processing domains for nodes.
@ AUDIO_RATE
Nodes that process at the audio sample rate.
ModulatorRole
Describes the role a modulator node plays relative to its owner.
Definition Node.hpp:21
ValueGroup make_value_group(std::span< const ValueSpec > values, RowBuffer header_buf, std::span< const RowBuffer > row_bufs, Surface &surface, LayoutCursor &cursor, float x_min, float x_max, float row_h, bool initially_open)
Construct a collapsible header followed by N value rows under it.
constexpr float k_inspect_indent
glm::uvec2 row_pixel_dims(const std::shared_ptr< Core::Window > &window, float x_min, float x_max, float row_h)
Convert an NDC row rect into integer pixel dimensions.
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
std::string short_dynamic_type_name(const T &obj) noexcept
Returns the unqualified dynamic type name of obj.
Definition TypeInfo.hpp:95
std::vector< ModulatorTree > modulators
Definition Node.hpp:37
std::shared_ptr< Node > node
Definition Node.hpp:36
Recursive tree node describing a modulator and all of its own modulators.
Definition Node.hpp:34
uint32_t header_id
Element id of the header strip. Valid after place().
std::vector< InspectResult > children
Result of an introspect call.
A single value to display in a ValueGroup body row.