MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Forma.cpp
Go to the documentation of this file.
1#include "Forma.hpp"
2
9
11
12#include "Inspect/Inspector.hpp"
13
15
17
19
20namespace {
21 bool g_initialized {};
22 std::shared_ptr<Nodes::NodeGraphManager> g_node_graph_manager;
23 std::shared_ptr<Buffers::BufferManager> g_buffer_manager;
24 std::shared_ptr<Vruta::TaskScheduler> g_scheduler;
25 std::shared_ptr<Vruta::EventManager> g_event_manager;
26 std::shared_ptr<Core::WindowManager> g_window_manager;
27 std::unique_ptr<Bridge> g_bridge;
28 std::unique_ptr<Inspector> g_inspect;
29
30 std::shared_ptr<Core::Window> g_inspect_nodes_window;
31 std::shared_ptr<Core::Window> g_inspect_buffers_window;
32 std::shared_ptr<Core::Window> g_inspect_scheduler_window;
33 std::shared_ptr<Core::Window> g_inspect_events_window;
34
35 constexpr uint32_t k_inspect_w = 480;
36 constexpr uint32_t k_inspect_h = 900;
37
38 constexpr size_t k_text_label_capacity = static_cast<size_t>(6) * sizeof(Kakshya::MeshVertex);
39 constexpr size_t k_rect_capacity = static_cast<size_t>(4) * sizeof(Kakshya::Vertex);
40
41 void place_plot_adornments(
42 Surface& surface,
43 const Plot::SeriesSpec& spec,
44 uint32_t relate_to)
45 {
46 const auto& win = surface.window();
47
48 for (const auto& label : spec.labels) {
50 win,
51 k_text_label_capacity,
53 {},
54 { { "text", nullptr } });
55
56 (void)Plot::place_label(surface, std::move(buf), label, relate_to);
57 }
58
59 for (const auto& ticks : spec.tick_labels) {
60 for (const auto& label : Plot::plot_tick_labels(ticks)) {
62 win,
63 k_text_label_capacity,
65 {},
66 { { "text", nullptr } });
67
68 (void)Plot::place_label(surface, std::move(buf), label, relate_to);
69 }
70 }
71
72 if (spec.legend) {
73 auto layout = Plot::layout_legend(*spec.legend);
74
75 for (const auto& swatch : layout.swatches) {
77 win,
78 k_rect_capacity,
80
81 (void)Plot::place_rect(surface, std::move(buf), swatch, relate_to);
82 }
83
84 for (const auto& label : layout.labels) {
86 win,
87 k_text_label_capacity,
89 {},
90 { { "text", nullptr } });
91
92 (void)Plot::place_label(surface, std::move(buf), label, relate_to);
93 }
94 }
95 }
96
97} // namespace
98
99namespace internal {
100
101 std::shared_ptr<Buffers::FormaBuffer> create_buffer_impl(
102 std::shared_ptr<Core::Window> window,
103 size_t capacity,
105 const std::string& texture_binding,
106 std::vector<std::pair<std::string, std::shared_ptr<Core::VKImage>>> additional_textures)
107 {
108 auto buf = std::make_shared<Buffers::FormaBuffer>(capacity, topology);
109 g_buffer_manager->add_buffer(buf, Buffers::ProcessingToken::GRAPHICS_BACKEND);
110
111 if (!additional_textures.empty()) {
112 buf->setup_rendering({
113 .target_window = std::move(window),
114 .additional_textures = std::move(additional_textures),
115 });
116 } else if (!texture_binding.empty()) {
117 buf->setup_rendering({
118 .target_window = std::move(window),
119 .default_texture_binding = texture_binding,
120 });
121 } else {
122 buf->setup_rendering({ .target_window = std::move(window) });
123 }
124 return buf;
125 }
126} // namespace internal
127
128// =============================================================================
129// Lifecycle
130// =============================================================================
131
133 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
134 std::shared_ptr<Buffers::BufferManager> buffer_manager,
135 std::shared_ptr<Vruta::TaskScheduler> scheduler,
136 std::shared_ptr<Vruta::EventManager> event_manager,
137 std::shared_ptr<Core::WindowManager> window_manager)
138{
139 if (g_initialized) {
141 "Portal::Forma already initialized");
142 return true;
143 }
144
145 g_node_graph_manager = std::move(node_graph_manager);
146 g_buffer_manager = std::move(buffer_manager);
147 g_scheduler = std::move(scheduler);
148 g_event_manager = std::move(event_manager);
149 g_window_manager = std::move(window_manager);
150 g_bridge = std::make_unique<Bridge>(*g_scheduler, *g_buffer_manager);
151 g_inspect = std::make_unique<Inspector>(*g_node_graph_manager, *g_buffer_manager, *g_scheduler, *g_event_manager);
152 g_initialized = true;
153
155 "Portal::Forma initialized");
156 return true;
157}
158
160{
161 if (!g_initialized) {
162 error<std::runtime_error>(Journal::Component::Portal, Journal::Context::API, std::source_location::current(),
163 "Portal::Forma not initialized - cannot get inspector");
164 }
165 return *g_inspect;
166}
167
169{
170 if (!g_initialized) {
171 return;
172 }
173
174 g_bridge.reset();
175 g_inspect.reset();
176 g_node_graph_manager = nullptr;
177 g_buffer_manager = nullptr;
178 g_scheduler = nullptr;
179 g_event_manager = nullptr;
180 g_window_manager = nullptr;
181 g_initialized = false;
182
183 g_inspect_nodes_window.reset();
184 g_inspect_buffers_window.reset();
185 g_inspect_scheduler_window.reset();
186 g_inspect_events_window.reset();
187
189 "Portal::Forma shutdown");
190}
191
193{
194 return g_initialized;
195}
196
197// =============================================================================
198// Layer
199// =============================================================================
200
201std::pair<std::shared_ptr<Layer>, std::shared_ptr<Context>>
203 const std::shared_ptr<Core::Window>& window,
204 std::string name)
205{
206 auto layer = std::make_shared<Layer>();
207 auto ctx = std::make_shared<Context>(layer, window, *g_event_manager, std::move(name));
208
209 MayaFlux::store(ctx);
210
211 return { std::move(layer), std::move(ctx) };
212}
213
214// =============================================================================
215// Standalone buffer
216// =============================================================================
217
218std::shared_ptr<Buffers::FormaBuffer> create_buffer(
219 std::shared_ptr<Core::Window> window,
221 const std::string& texture_binding)
222{
223 return internal::create_buffer_impl(std::move(window), internal::k_capacity_bytes, topology, texture_binding);
224}
225
226std::shared_ptr<Buffers::FormaBuffer> create_buffer(
227 std::shared_ptr<Core::Window> window,
229 std::vector<std::pair<std::string, std::shared_ptr<Core::VKImage>>> additional_textures)
230{
231 return internal::create_buffer_impl(std::move(window), internal::k_capacity_bytes, topology, {}, std::move(additional_textures));
232}
233
235 std::shared_ptr<Core::Window> window,
236 std::string name)
237{
238 auto [layer, ctx] = create_layer(window, std::move(name));
239 return { std::move(window), std::move(layer), std::move(ctx) };
240}
241
242// =============================================================================
243// Plot
244// =============================================================================
245
246std::pair<Mapped<std::shared_ptr<Kakshya::PlotContainer>>, Surface>
248 std::string title,
249 uint32_t width,
250 uint32_t height,
251 std::shared_ptr<Kakshya::PlotContainer> container,
252 Plot::SeriesSpec spec)
253{
254 const uint64_t N = container->series_count() > 0
255 ? container->series_size(0)
256 : 0;
257
258 auto window = g_window_manager->create_window(
259 Core::WindowCreateInfo { .title = std::move(title), .width = width, .height = height });
260 window->show();
261
262 auto surface = create_surface(window, window->get_create_info().title);
263
264 if (spec.background_fn) {
265 auto bg = create_element<float>(
266 surface.layer(), window,
267 *spec.background_fn,
268 0.F,
270 static_cast<size_t>(4) * Kakshya::VertexLayout::for_meshes().stride_bytes);
271
272 const auto bg_id = bg.element.id;
273 auto buf = internal::create_buffer_impl(window, spec.capacity_for(N), spec.topology);
274 auto mapped = Plot::place(surface, std::move(buf), spec, std::move(container));
275 surface.layer().relate(mapped.element.id, bg_id);
276 surface.layer().send_to_back(bg_id);
277
278 place_plot_adornments(surface, spec, mapped.element.id);
279
280 return { std::move(mapped), std::move(surface) };
281 }
282
283 auto buf = internal::create_buffer_impl(window, spec.capacity_for(N), spec.topology);
284 auto mapped = Plot::place(surface, std::move(buf), spec, std::move(container));
285
286 place_plot_adornments(surface, spec, mapped.element.id);
287
288 return { std::move(mapped), std::move(surface) };
289}
290
291// =============================================================================
292// Bridge
293// =============================================================================
294
296{
297 return *g_bridge;
298}
299
301{
302 if (g_inspect_nodes_window) {
303 g_inspect_nodes_window->show();
304 return;
305 }
306 g_inspect_nodes_window = g_window_manager->create_window(
307 Core::WindowCreateInfo { .title = "NodeGraphManager", .width = k_inspect_w, .height = k_inspect_h });
308 g_inspect_nodes_window->show();
309 auto surface = create_surface(g_inspect_nodes_window, "NodeGraphManager");
310 LayoutCursor cursor;
311 auto& result = g_inspect->node_graph_manager(surface, cursor);
312 g_bridge->spawn_sync(result.group.header.header_id, [&result] { result.tap_all(); });
313}
314
316{
317 if (g_inspect_buffers_window) {
318 g_inspect_buffers_window->show();
319 return;
320 }
321 g_inspect_buffers_window = g_window_manager->create_window(
322 Core::WindowCreateInfo { .title = "BufferManager", .width = k_inspect_w, .height = k_inspect_h });
323 g_inspect_buffers_window->show();
324 auto surface = create_surface(g_inspect_buffers_window, "BufferManager");
325 LayoutCursor cursor;
326 auto& result = g_inspect->buffer_manager(surface, cursor);
327 g_bridge->spawn_sync(result.group.header.header_id, [&result] { result.tap_all(); });
328}
329
331{
332 if (g_inspect_scheduler_window) {
333 g_inspect_scheduler_window->show();
334 return;
335 }
336 g_inspect_scheduler_window = g_window_manager->create_window(
337 Core::WindowCreateInfo { .title = "TaskScheduler", .width = k_inspect_w, .height = k_inspect_h });
338 g_inspect_scheduler_window->show();
339 auto surface = create_surface(g_inspect_scheduler_window, "TaskScheduler");
340 LayoutCursor cursor;
341 auto& result = g_inspect->scheduler(surface, cursor);
342 g_bridge->spawn_sync(result.group.header.header_id, [&result] { result.tap_all(); });
343}
344
346{
347 if (g_inspect_events_window) {
348 g_inspect_events_window->show();
349 return;
350 }
351 g_inspect_events_window = g_window_manager->create_window(
352 Core::WindowCreateInfo { .title = "EventManager", .width = k_inspect_w, .height = k_inspect_h });
353 g_inspect_events_window->show();
354 auto surface = create_surface(g_inspect_events_window, "EventManager");
355 LayoutCursor cursor;
356 auto& result = g_inspect->event_manager(surface, cursor);
357 g_bridge->spawn_sync(result.group.header.header_id, [&result] { result.tap_all(); });
358}
359
360void inspect(const std::shared_ptr<Nodes::Node>& node)
361{
362 const std::string title = Reflect::short_dynamic_type_name(node);
363 auto window = g_window_manager->create_window(
364 Core::WindowCreateInfo { .title = title, .width = k_inspect_w, .height = k_inspect_h });
365 window->show();
366 auto surface = create_surface(window, title);
367 LayoutCursor cursor;
368 auto result = std::make_shared<InspectResult>(g_inspect->node(node, surface, cursor));
369 g_bridge->spawn_sync(result->group.header.header_id, [result] { result->tap_all(); });
370}
371
372void inspect(const std::shared_ptr<Buffers::Buffer>& buf)
373{
374 const std::string title = Reflect::short_dynamic_type_name(buf);
375 auto window = g_window_manager->create_window(
376 Core::WindowCreateInfo { .title = title, .width = k_inspect_w, .height = k_inspect_h });
377 window->show();
378 auto surface = create_surface(window, title);
379 LayoutCursor cursor;
380 auto result = std::make_shared<InspectResult>(g_inspect->buffer(buf, surface, cursor));
381 g_bridge->spawn_sync(result->group.header.header_id, [result] { result->tap_all(); });
382}
383
384void inspect(const std::shared_ptr<Nodes::Network::NodeNetwork>& net)
385{
386 auto window = g_window_manager->create_window(
387 Core::WindowCreateInfo { .title = "NodeNetwork", .width = k_inspect_w, .height = k_inspect_h });
388 window->show();
389 auto surface = create_surface(window, "NodeNetwork");
390 LayoutCursor cursor;
391 auto result = std::make_shared<InspectResult>(g_inspect->node_network(net, surface, cursor));
392 g_bridge->spawn_sync(result->group.header.header_id, [result] { result->tap_all(); });
393}
394
395void inspect(const std::shared_ptr<Vruta::Event>& ev, std::string_view name)
396{
397 const std::string title = name.empty() ? "Event" : "Event: " + std::string(name);
398 auto window = g_window_manager->create_window(
399 Core::WindowCreateInfo { .title = title, .width = k_inspect_w, .height = k_inspect_h });
400 window->show();
401 auto surface = create_surface(window, title);
402 LayoutCursor cursor;
403 auto result = std::make_shared<InspectResult>(g_inspect->event(ev, name, surface, cursor));
404 g_bridge->spawn_sync(result->group.header.header_id, [result] { result->tap_all(); });
405}
406
407} // namespace MayaFlux::Portal::Forma
#define MF_INFO(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define N(method_name, full_type_name)
Definition Creator.hpp:106
uint32_t width
Definition Decoder.cpp:59
Factory free functions for the Forma surface system.
Two-way binding orchestrator for Forma elements.
Definition Bridge.hpp:65
Forma subsystem for live introspection.
Definition Inspector.hpp:39
Reactive Y-position accumulator for vertical primitive stacking.
Named owner of a (Window, Layer, Context) triple - the Forma canvas.
Definition Surface.hpp:58
void initialize()
Definition main.cpp:11
@ GRAPHICS_BACKEND
Standard graphics processing backend configuration.
@ API
API calls from external code.
@ Portal
High-level user-facing API layer.
LegendLayout layout_legend(const LegendSpec &spec)
Expand a legend spec into swatch rectangle specs and text label specs.
Definition PlotSpec.cpp:346
std::vector< LabelSpec > plot_tick_labels(const TickLabelsSpec &spec)
Generate construction-free tick label specs.
Definition PlotSpec.cpp:237
uint32_t place_label(Surface &surface, std::shared_ptr< Buffers::FormaBuffer > buf, const LabelSpec &spec, uint32_t relate_to)
Place a text label element onto surface using a pre-built buffer.
Definition Plot.cpp:15
Mapped< std::shared_ptr< Kakshya::PlotContainer > > place(Surface &surface, std::shared_ptr< Buffers::FormaBuffer > buf, SeriesSpec spec, std::shared_ptr< Kakshya::PlotContainer > container)
Place a plot element onto a Surface using a pre-built FormaBuffer.
Definition Plot.cpp:81
uint32_t place_rect(Surface &surface, std::shared_ptr< Buffers::FormaBuffer > buf, const RectSpec &spec, uint32_t relate_to)
Place a filled rectangle element onto surface using a pre-built buffer.
Definition Plot.cpp:53
std::shared_ptr< Buffers::FormaBuffer > create_buffer_impl(std::shared_ptr< Core::Window > window, size_t capacity, Graphics::PrimitiveTopology topology, const std::string &texture_binding, std::vector< std::pair< std::string, std::shared_ptr< Core::VKImage > > > additional_textures)
Core buffer construction — capacity-explicit path for internal use.
Definition Forma.cpp:101
constexpr size_t k_capacity_bytes
Definition Forma.hpp:50
std::pair< Mapped< std::shared_ptr< Kakshya::PlotContainer > >, Surface > plot(std::string title, uint32_t width, uint32_t height, std::shared_ptr< Kakshya::PlotContainer > container, Plot::SeriesSpec spec)
Create a live plot in a new window.
Definition Forma.cpp:247
void inspect_buffers()
Open or show the BufferManager inspection window.
Definition Forma.cpp:315
void shutdown()
Release stored references.
Definition Forma.cpp:168
std::shared_ptr< Buffers::FormaBuffer > create_buffer(std::shared_ptr< Core::Window > window, Graphics::PrimitiveTopology topology, const std::string &texture_binding)
Construct and register a FormaBuffer without creating a Mapped<T>.
Definition Forma.cpp:218
void inspect_node_graph()
Open or show the NodeGraphManager inspection window.
Definition Forma.cpp:300
bool is_initialized()
Whether initialize() has been called successfully.
Definition Forma.cpp:192
Surface create_surface(std::shared_ptr< Core::Window > window, std::string name)
Construct a Surface, creating Layer and Context internally.
Definition Forma.cpp:234
Inspector & inspector()
Access the Forma introspection subsystem.
Definition Forma.cpp:159
void inspect_scheduler()
Open or show the TaskScheduler inspection window.
Definition Forma.cpp:330
std::pair< std::shared_ptr< Layer >, std::shared_ptr< Context > > create_layer(const std::shared_ptr< Core::Window > &window, std::string name)
Construct a Layer and a Context wired to window.
Definition Forma.cpp:202
Bridge & bridge()
Return the application-level Bridge instance.
Definition Forma.cpp:295
void inspect(const std::shared_ptr< Nodes::Node > &node)
Open a dedicated window inspecting a single Node and its modulator tree.
Definition Forma.cpp:360
void inspect_events()
Open or show the EventManager inspection window.
Definition Forma.cpp:345
PrimitiveTopology
Vertex assembly primitive topology.
std::string short_dynamic_type_name(const T &obj) noexcept
Returns the unqualified dynamic type name of obj.
Definition TypeInfo.hpp:95
std::shared_ptr< T > store(std::shared_ptr< T > obj)
Transfer ownership of an existing object to the persistent store for process lifetime.
Definition Persist.hpp:28
std::string title
Window title/identifier.
Configuration for creating a single window instance.
uint32_t stride_bytes
Total bytes per vertex (stride in Vulkan terms) e.g., 3 floats (position) + 3 floats (normal) = 24 by...
static VertexLayout for_meshes(uint32_t stride=60)
Factory: layout for MeshVertex (position, color, weight, uv, normal, tangent)
std::optional< GeometryFn< float > > background_fn
std::function< size_t(uint64_t sample_count)> capacity_for