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