MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Forma.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Bridge.hpp"
4#include "Plot/Plot.hpp"
5#include "Surface.hpp"
6
7namespace MayaFlux::Nodes {
8class NodeGraphManager;
9}
10
11namespace MayaFlux::Core {
12class Window;
13class WindowManager;
14struct WindowCreateInfo;
15}
16
17namespace MayaFlux::Vruta {
18class TaskScheduler;
19class EventManager;
20class Event;
21}
22
23namespace MayaFlux::Buffers {
24class BufferManager;
25}
26
28
29class Inspector;
30
31// =============================================================================
32// Internal
33// =============================================================================
34
35namespace internal {
36
37 /**
38 * @brief Core buffer construction — capacity-explicit path for internal use.
39 *
40 * Called by public create_buffer overloads and by internal .cpp callers
41 * (plot, Collapsible) that know their capacity upfront.
42 */
43 [[nodiscard]] MAYAFLUX_API std::shared_ptr<Buffers::FormaBuffer> create_buffer_impl(
44 std::shared_ptr<Core::Window> window,
45 size_t capacity,
47 const std::string& texture_binding = {},
48 std::vector<std::pair<std::string, std::shared_ptr<Core::VKImage>>> additional_textures = {});
49
50 constexpr size_t k_capacity_bytes = 4096;
51
52} // namespace internal
53
54/**
55 * @file Forma.hpp
56 * @brief Factory free functions for the Forma surface system.
57 *
58 * Call initialize() once after engine startup to store BufferManager,
59 * TaskScheduler, and EventManager references. Subsequent factory calls
60 * require only the arguments that legitimately vary per call (Window,
61 * geometry function, initial value). This matches the Portal::Text and
62 * Portal::Graphics initialization contracts.
63 *
64 * Typical sequence:
65 * @code
66 * Portal::Forma::initialize(buffer_manager, scheduler, event_manager);
67 *
68 * auto [layer, ctx] = Forma::create_layer(window, "hud");
69 *
70 * auto el = Forma::create_element<float>(
71 * *layer, window, geom_fn, 0.5f);
72 *
73 * auto bridge = Forma::create_bridge();
74 * bridge.bind(el.state, envelope);
75 * bridge.write(el.state, compute_proc, offsetof(PC, cutoff));
76 *
77 * ctx->on_press(el.element.id, IO::MouseButtons::LEFT,
78 * [](uint32_t, glm::vec2){});
79 * @endcode
80 */
81
82// =============================================================================
83// Lifecycle
84// =============================================================================
85
86/**
87 * @brief Store engine-level references for use by all subsequent Forma calls.
88 *
89 * Must be called before any create_* call. Safe to call multiple times;
90 * subsequent calls are no-ops and log a warning.
91 *
92 * @param node_graph_manager Engine NodeGraphManager. Must outlive all Forma objects.
93 * @param buffer_manager Engine BufferManager. Must outlive all Forma objects.
94 * @param scheduler Engine TaskScheduler. Must outlive all Bridge instances.
95 * @param event_manager Engine EventManager. Must outlive all Context instances.
96 * @param window_manager Engine WindowManager. Must outlive all Surface instances.
97 * @return True on success, false if any argument is null.
98 */
99MAYAFLUX_API bool initialize(
100 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
101 std::shared_ptr<Buffers::BufferManager> buffer_manager,
102 std::shared_ptr<Vruta::TaskScheduler> scheduler,
103 std::shared_ptr<Vruta::EventManager> event_manager,
104 std::shared_ptr<Core::WindowManager> window_manager);
105
106/**
107 * @brief Release stored references. Does not destroy any Forma objects.
108 *
109 * Call after all Forma objects have been destroyed, before engine shutdown.
110 */
111MAYAFLUX_API void shutdown();
112
113/** @brief Whether initialize() has been called successfully. */
114MAYAFLUX_API bool is_initialized();
115
116/**
117 * @brief Return the application-level Bridge instance.
118 *
119 * Valid only after initialize(). Lifetime is tied to the Forma module.
120 */
121[[nodiscard]] MAYAFLUX_API Bridge& bridge();
122
123/**
124 * @brief Access the Forma introspection subsystem.
125 *
126 * Returns the Inspector instance initialized alongside Bridge during
127 * Portal::Forma::initialize(). The Inspector holds no state beyond
128 * references to BufferManager and NodeGraphManager; it is a stable
129 * entry point into the Inspect:: query functions.
130 *
131 * @pre Portal::Forma::initialize() must have been called.
132 * @return Reference to the singleton Inspector. Lifetime is the Forma module lifetime.
133 * @throws std::runtime_error if called before initialize().
134 */
135[[nodiscard]] MAYAFLUX_API Inspector& inspector();
136
137// =============================================================================
138// Layer
139// =============================================================================
140
141/**
142 * @brief Construct a Layer and a Context wired to @p window.
143 *
144 * EventManager is taken from the stored initialize() state.
145 * The caller owns both returned objects. The Context cancels its event
146 * coroutines on destruction.
147 *
148 * @param window Target window surface.
149 * @param name Unique name scoping the Context's event coroutines.
150 * @return Pair of { shared_ptr<Layer>, shared_ptr<Context> }.
151 */
152[[nodiscard]] MAYAFLUX_API
153 std::pair<std::shared_ptr<Layer>, std::shared_ptr<Context>>
155 const std::shared_ptr<Core::Window>& window,
156 std::string name);
157
158// =============================================================================
159// Standalone buffer
160// =============================================================================
161
162/**
163 * @brief Construct and register a FormaBuffer without creating a Mapped<T>.
164 *
165 * BufferManager is taken from the stored initialize() state.
166 *
167 * @param window Target window.
168 * @param topology Primitive topology.
169 * @param texture_binding Optional descriptor name for a single texture binding
170 * @return Registered, render-ready FormaBuffer.
171 */
172[[nodiscard]] MAYAFLUX_API
173 std::shared_ptr<Buffers::FormaBuffer>
175 std::shared_ptr<Core::Window> window,
177 const std::string& texture_binding = {});
178
179/**
180 * @brief Construct and register a FormaBuffer with additional texture bindings.
181 *
182 * BufferManager is taken from the stored initialize() state.
183 *
184 * @param window Target window.
185 * @param topology Primitive topology.
186 * @param additional_textures Vector of { descriptor name, image } pairs for
187 * additional texture bindings. These are in
188 * addition to any default_texture_binding set
189 * in the RenderConfig passed to setup_rendering().
190 * @return Registered, render-ready FormaBuffer.
191 */
192[[nodiscard]] MAYAFLUX_API
193 std::shared_ptr<Buffers::FormaBuffer>
195 std::shared_ptr<Core::Window> window,
197 std::vector<std::pair<std::string, std::shared_ptr<Core::VKImage>>> additional_textures);
198
199/**
200 * @brief Construct, register, and immediately submit a FormaBuffer from vertices.
201 *
202 * Deduces capacity and topology from the vertex type. PointVertex yields
203 * POINT_LIST, LineVertex yields LINE_LIST, MeshVertex yields TRIANGLE_STRIP.
204 * Topology may be overridden explicitly for cases like LINE_STRIP or
205 * TRIANGLE_LIST from MeshVertex data.
206 *
207 * @tparam V Vertex type: PointVertex, LineVertex, or MeshVertex.
208 * @param window Target window.
209 * @param vertices Vertices to submit immediately after construction.
210 * @param topology Primitive topology. Defaults to the canonical topology for V.
211 * @return Registered, render-ready FormaBuffer with initial geometry submitted.
212 */
213template <typename V>
214 requires std::ranges::contiguous_range<V>
215 && std::is_trivially_copyable_v<std::ranges::range_value_t<V>>
216[[nodiscard]] std::shared_ptr<Buffers::FormaBuffer> create_buffer(
217 std::shared_ptr<Core::Window> window,
218 const V& vertices,
220{
221 using Vertex = std::ranges::range_value_t<V>;
222 const size_t cap = std::ranges::size(vertices) * sizeof(Vertex);
223 auto buf = internal::create_buffer_impl(std::move(window), cap, topology);
224 buf->submit(vertices);
225 return buf;
226}
227
228template <typename V>
229 requires std::is_trivially_copyable_v<V>
230 && (!std::ranges::range<V>)
231[[nodiscard]] std::shared_ptr<Buffers::FormaBuffer> create_buffer(
232 std::shared_ptr<Core::Window> window,
233 const V& vertex,
235{
236 auto buf = internal::create_buffer_impl(std::move(window), sizeof(V), topology);
237 buf->submit(vertex);
238 return buf;
239}
240
241// =============================================================================
242// Element
243// =============================================================================
244
245/**
246 * @brief Construct a Surface, creating Layer and Context internally.
247 *
248 * Builds a fresh Layer and a Context wired to @p window using the
249 * EventManager stored by Portal::Forma::initialize. Equivalent to
250 * Portal::Forma::create_layer(window, name) plus owning the window
251 * pointer alongside.
252 *
253 * For the power-tinkerer case (custom Context subclass, shared Layer
254 * across multiple Contexts, etc.), construct Surface directly via its
255 * (Window, Layer, Context) constructor.
256 *
257 * @param window Target window. Must outlive the Surface.
258 * @param name Unique name scoping the Context's event coroutines.
259 * Must be unique across all live Contexts.
260 * @pre Portal::Forma::initialize() must have been called.
261 * @return A new Surface owning the window pointer plus the freshly
262 * created Layer and Context.
263 */
264[[nodiscard]] MAYAFLUX_API Surface create_surface(
265 std::shared_ptr<Core::Window> window,
266 std::string name);
267
268/**
269 * @brief Build a FormaBuffer, register it, construct a Mapped<T>, and add
270 * the element to @p layer.
271 *
272 * BufferManager is taken from the stored initialize() state.
273 * Returns the fully constructed Mapped<T>. The caller holds it.
274 * element.id is stable and can be passed to Context callbacks and Bridge.
275 *
276 * @tparam T MappedState value type: float, glm::vec2, etc.
277 * @param layer Layer to register the element on.
278 * @param window Target window for rendering.
279 * @param geom Geometry function producing vertex bytes from T.
280 * @param initial Starting value written into MappedState.
281 * @param topology Primitive topology for the FormaBuffer.
282 * @param capacity Initial FormaBuffer capacity in bytes.
283 * @param project Optional T -> float projection for outbound readers.
284 * @return Fully constructed Mapped<T> with element registered in @p layer.
285 */
286template <typename T>
288 Layer& layer,
289 std::shared_ptr<Core::Window> window,
290 GeometryFn<T> geom,
291 T initial,
293 size_t capacity = internal::k_capacity_bytes,
294 std::function<float(T)> project = {})
295{
296 auto buf = create_buffer(std::move(window), capacity, topology);
297 auto mapped = make_mapped<T>(initial, std::move(geom), buf);
298 mapped.element.id = layer.add(mapped.element);
299 bridge().register_element(mapped, std::move(project));
300 return mapped;
301}
302
303/**
304 * @brief Build a FormaBuffer, register it, construct a Mapped<T>, add the
305 * element to @p surface's layer, and register it with the
306 * application Bridge.
307 *
308 * Surface-accepting overload of create_element. Reads the layer and
309 * window from @p surface; everything else matches the existing
310 * (Layer&, Window) overload.
311 *
312 * After registration, one sync() is run so that bounds_hint and contains
313 * populated by the geometry function are visible on the Element before
314 * the first frame. This removes the manual
315 * @code
316 * layer->set_bounds(el.element.id, ...);
317 * layer->set_contains(el.element.id, ...);
318 * @endcode
319 * boilerplate seen at fader-style call sites: those values now arrive
320 * directly from the geometry function on construction. The geometry
321 * function remains the user's; the sync is the same one that runs every
322 * frame.
323 *
324 * @tparam T MappedState value type.
325 * @param surface Canvas to register the element on.
326 * @param geom Geometry function producing vertex bytes from T.
327 * @param initial Starting value written into MappedState.
328 * @param topology Primitive topology for the FormaBuffer.
329 * @param project Optional T -> float projection for outbound readers.
330 * @return Fully constructed Mapped<T> with element registered.
331 */
332template <typename T>
334 Surface& surface,
335 GeometryFn<T> geom,
336 T initial,
338 std::function<float(T)> project = {})
339{
340 auto mapped = create_element<T>(
341 surface.layer(), surface.window(),
342 std::move(geom), std::move(initial),
343 topology, internal::k_capacity_bytes, std::move(project));
344
345 mapped.sync();
346 if (mapped.element.bounds_hint)
347 surface.layer().set_bounds(mapped.element.id, *mapped.element.bounds_hint);
348 if (mapped.element.contains)
349 surface.layer().set_contains(mapped.element.id, mapped.element.contains);
350
351 return mapped;
352}
353
354/**
355 * @brief Create a live plot in a new window.
356 *
357 * Creates the window, shows it, constructs the Surface, builds the
358 * FormaBuffer from the spec capacity and topology, and calls Plot::place.
359 * Returns the Mapped<shared_ptr<PlotContainer>> from Plot::place, plus the
360 * Surface owning the window and layer.
361 *
362 * @param title Window title.
363 * @param width Window width in pixels.
364 * @param height Window height in pixels.
365 * @param container Ready PlotContainer from Plot::source().build().
366 * @param spec SeriesSpec from Plot::series()...done().
367 * @return Pair of { Mapped<shared_ptr<PlotContainer>>, Surface } for the created plot.
368 */
369[[nodiscard]] MAYAFLUX_API
370 std::pair<Mapped<std::shared_ptr<Kakshya::PlotContainer>>, Surface>
371 plot(
372 std::string title,
373 uint32_t width,
374 uint32_t height,
375 std::shared_ptr<Kakshya::PlotContainer> container,
376 Plot::SeriesSpec spec);
377
378// =============================================================================
379// Introspection
380// =============================================================================
381
382/**
383 * @brief Open or show the NodeGraphManager inspection window.
384 *
385 * First call creates a dedicated window, builds the InspectResult, and
386 * schedules tap_all() via Bridge. Subsequent calls show() the existing window.
387 */
388MAYAFLUX_API void inspect_node_graph();
389
390/**
391 * @brief Open or show the BufferManager inspection window.
392 *
393 * First call creates a dedicated window, builds the InspectResult, and
394 * schedules tap_all() via Bridge. Subsequent calls show() the existing window.
395 */
396MAYAFLUX_API void inspect_buffers();
397
398/**
399 * @brief Open or show the TaskScheduler inspection window.
400 *
401 * First call creates a dedicated window, builds the InspectResult, and
402 * schedules tap_all() via Bridge. Subsequent calls show() the existing window.
403 */
404MAYAFLUX_API void inspect_scheduler();
405
406/**
407 * @brief Open or show the EventManager inspection window.
408 *
409 * First call creates a dedicated window, builds the InspectResult, and
410 * schedules tap_all() via Bridge. Subsequent calls show() the existing window.
411 */
412MAYAFLUX_API void inspect_events();
413
414/**
415 * @brief Open a dedicated window inspecting a single Node and its modulator tree.
416 */
417MAYAFLUX_API void inspect(const std::shared_ptr<Nodes::Node>& node);
418
419/**
420 * @brief Open a dedicated window inspecting a single Buffer and its processing chain.
421 */
422MAYAFLUX_API void inspect(const std::shared_ptr<Buffers::Buffer>& buf);
423
424/**
425 * @brief Open a dedicated window inspecting a NodeNetwork.
426 */
427MAYAFLUX_API void inspect(const std::shared_ptr<Nodes::Network::NodeNetwork>& net);
428
429/**
430 * @brief Open a dedicated window inspecting a single Event.
431 */
432MAYAFLUX_API void inspect(const std::shared_ptr<Vruta::Event>& ev, std::string_view name = {});
433
434} // namespace MayaFlux::Portal::Forma
uint32_t width
Definition Decoder.cpp:59
void register_element(std::shared_ptr< MappedState< T > > state, uint32_t id, std::shared_ptr< Buffers::FormaBuffer > buffer, std::function< float(T)> project={})
Register a MappedState<T> so that MappedState overloads and outbound bindings can resolve to the corr...
Definition Bridge.hpp:280
Two-way binding orchestrator for Forma elements.
Definition Bridge.hpp:65
Forma subsystem for live introspection.
Definition Inspector.hpp:39
bool set_bounds(uint32_t id, Kinesis::AABB2D bounds)
Replace the bounds_hint on an existing element.
Definition Layer.cpp:36
Slot add(Element element)
Add an element to the layer.
Definition Layer.cpp:9
bool set_contains(uint32_t id, std::function< bool(glm::vec2)> fn)
Replace the contains callable on an existing element.
Definition Layer.cpp:45
Flat registry of Elements on a surface.
Definition Layer.hpp:21
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
void initialize()
Definition main.cpp:11
Contains the node-based computational processing system components.
Definition Chronie.hpp:14
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
Mapped< T > create_element(Layer &layer, std::shared_ptr< Core::Window > window, GeometryFn< T > geom, T initial, Graphics::PrimitiveTopology topology=Graphics::PrimitiveTopology::TRIANGLE_STRIP, size_t capacity=internal::k_capacity_bytes, std::function< float(T)> project={})
Build a FormaBuffer, register it, construct a Mapped<T>, and add the element to layer.
Definition Forma.hpp:287
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
std::function< void(T value, std::vector< uint8_t > &out_bytes, Element &element)> GeometryFn
Geometry function signature.
Definition Mapped.hpp:64
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.
Infrastructure for a continuously-mapped value whose GPU geometry tracks it.
Definition Mapped.hpp:89