MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Atelier.hpp
Go to the documentation of this file.
1#pragma once
2
7
9
11
12namespace MayaFlux::Nodes {
13class NodeGraphManager;
14}
15
16namespace MayaFlux::Core {
17class Window;
18class WindowManager;
19struct WindowCreateInfo;
20}
21
22namespace MayaFlux::Vruta {
23class TaskScheduler;
24class EventManager;
25}
26
27namespace MayaFlux::Buffers {
28class BufferManager;
29}
30
32
33class Inspector;
34
35namespace internal {
36
37 constexpr size_t k_capacity_bytes = 4096;
38
39 /**
40 * @class Atelier
41 * @brief Process-wide Forma workshop. Not part of the public surface.
42 *
43 * Holds the engine references stored by Portal::Forma::initialize and
44 * owns every construction path that depends on them: buffers, layers,
45 * contexts, surfaces, elements, windows.
46 *
47 * Everything under Internal/ is implementation detail and carries no
48 * stability guarantee. The public entry points in Forma.hpp are thin
49 * wrappers over the methods here. User code calls those, not these.
50 *
51 * Lifetime follows the Portal::Graphics singleton contract: the Meyers
52 * instance is never destroyed, and shutdown() releases the held
53 * references explicitly before static teardown.
54 */
55 class MAYAFLUX_API Atelier {
56 public:
57 static Atelier& instance();
58
59 Atelier(const Atelier&) = delete;
60 Atelier& operator=(const Atelier&) = delete;
61 Atelier(Atelier&&) = delete;
63
64 // =====================================================================
65 // Lifecycle
66 // =====================================================================
67
68 bool initialize(
69 std::shared_ptr<Nodes::NodeGraphManager> node_graph_manager,
70 std::shared_ptr<Buffers::BufferManager> buffer_manager,
71 std::shared_ptr<Vruta::TaskScheduler> scheduler,
72 std::shared_ptr<Vruta::EventManager> event_manager,
73 std::shared_ptr<Core::WindowManager> window_manager);
74
75 void shutdown();
76
77 [[nodiscard]] bool is_initialized() const noexcept { return m_initialized; }
78
79 /**
80 * @brief Bridge instance constructed during initialize.
81 * @throws std::runtime_error if called before initialize().
82 */
83 [[nodiscard]] Bridge& bridge();
84
85 /**
86 * @brief Inspector instance constructed during initialize.
87 * @throws std::runtime_error if called before initialize().
88 */
89 [[nodiscard]] Inspector& inspector();
90
91 /**
92 * @brief The GPU image of @p atlas, shared by every text slice drawing from it.
93 *
94 * One per atlas, so slices on different atlases never replace each
95 * other's image, and a growth of an atlas is seen by all text on it at
96 * once. Released by shutdown().
97 */
98 [[nodiscard]] Text::AtlasImage& atlas_image(const Text::GlyphAtlas& atlas)
99 {
100 return m_atlas_images[&atlas];
101 }
102
103 // =====================================================================
104 // Construction
105 // =====================================================================
106
107 /**
108 * @brief Create a window through the stored WindowManager and show it.
109 *
110 * Present so that callers needing a window do not reach the manager
111 * directly.
112 */
113 [[nodiscard]] std::shared_ptr<Core::Window> create_window(
114 const Core::WindowCreateInfo& info);
115
116 /**
117 * @brief The single buffer construction path.
118 *
119 * Registers a FormaBuffer with the stored BufferManager under
120 * GRAPHICS_BACKEND and sets up rendering. The buffer always triangulates
121 * with TRIANGLE_LIST: what it draws is expressed by the topology of the
122 * slices made on it with FormaTarget::slice_of. Line and point slices
123 * are milled into NDC ribbons whose scalar is a width in pixels of the
124 * window's height at creation.
125 *
126 * @param render Render settings; build it with Surface::render_config.
127 * Its topology and triangulate are set here.
128 */
129 [[nodiscard]] std::shared_ptr<Buffers::FormaBuffer> create_buffer(
131
132 /**
133 * @brief Construct a Layer and a Context wired to @p window.
134 *
135 * The Context is stored so its event coroutines outlive the call.
136 */
137 [[nodiscard]] std::pair<std::shared_ptr<Layer>, std::shared_ptr<Context>>
138 create_layer(const std::shared_ptr<Core::Window>& window, std::string name);
139
140 /**
141 * @brief Build a Surface from a SurfaceConfig, creating Layer and
142 * Context when config.layer/config.ctx are unset.
143 */
144 [[nodiscard]] Surface create_surface(SurfaceConfig config);
145
146 /**
147 * @brief Build a window through create_window, then a Surface on it.
148 *
149 * One step further back than create_surface(SurfaceConfig): for
150 * when there is no window yet either. Uses default close-handling
151 * behavior (SurfaceConfig::detach_on_close true, no on_close). Call
152 * create_surface(SurfaceConfig) directly instead when that needs
153 * configuring.
154 */
155 [[nodiscard]] Surface create_surface(
156 const Core::WindowCreateInfo& window_info, std::string name);
157
158 /**
159 * @brief create_element on a buffer of its own, as a slice of
160 * @p topology, followed by one sync so bounds_hint and contains
161 * from the geometry function reach the Layer before the first
162 * frame.
163 */
164 template <typename T>
166 Surface& surface,
167 GeometryFn<T> geom,
168 T initial,
169 Graphics::PrimitiveTopology topology = Graphics::PrimitiveTopology::TRIANGLE_STRIP,
170 std::function<float(T)> project = {})
171 {
172 return create_element<T>(
173 surface,
174 FormaTarget::slice_of(create_buffer(surface.render_config()), topology),
175 std::move(geom), std::move(initial), std::move(project));
176 }
177
178 /**
179 * @brief create_element writing into @p target, which may be a slice
180 * shared with other elements.
181 */
182 template <typename T>
184 Surface& surface,
185 FormaTarget target,
186 GeometryFn<T> geom,
187 T initial,
188 std::function<float(T)> project = {})
189 {
190 auto mapped = make_mapped<T>(
191 std::move(initial), std::move(geom), std::move(target));
192 mapped.element.id = surface.layer().add(mapped.element);
194 surface.layer(), mapped, std::move(project));
195
196 mapped.sync(&surface.layer());
197
198 return mapped;
199 }
200
201 /**
202 * @brief Register mapped's element for scroll reflow in panel.
203 *
204 * When reposition is empty, one is built from mapped's own buffer,
205 * geometry_fn, and state: it reruns geometry_fn unconditionally
206 * (assumes the Form was built with live_offset wired to panel's own
207 * offset, so it reads the new position itself) and pushes the
208 * resulting bounds_hint/contains to layer. These are the same two
209 * effects Mapped<T>::sync(Layer*) has, replicated rather than
210 * called through, so the closure captures only independently-owned
211 * pieces (buffer and state are shared_ptr, geometry_fn is a
212 * copyable std::function), never a pointer back to mapped itself,
213 * since the closure outlives this call, stored inside panel.
214 *
215 * @param panel Scrollable to track into.
216 * @param layer Layer both panel and mapped's element were
217 * registered on.
218 * @param mapped Element to track. Only buffer/geometry_fn/
219 * state/element.id are read, nothing is stored.
220 * Its buffer is scissored to the panel's viewport,
221 * so it is not drawn outside it.
222 * @param base_bounds mapped's current on-screen NDC bounds.
223 * @param reposition Called with the scrolled bounds on every
224 * scroll. Built as described above when empty.
225 */
226 template <typename T>
227 void track(
228 Scrollable& panel,
229 Layer& layer,
230 const Mapped<T>& mapped,
231 Kinesis::AABB2D base_bounds,
232 std::function<void(Kinesis::AABB2D)> reposition = {})
233 {
234 if (!reposition) {
235 auto buffer = mapped.element.buffer;
236 auto geometry_fn = mapped.geometry_fn;
237 auto state = mapped.state;
238 auto id = mapped.element.id;
239 auto* layer_ptr = &layer;
240
241 reposition = [buffer, geometry_fn, state, id, layer_ptr](Kinesis::AABB2D) {
242 if (!buffer || !geometry_fn || !state)
243 return;
244
245 std::vector<uint8_t> bytes;
246 Element el;
247 el.id = id;
248 geometry_fn(state->value, bytes, el);
249 buffer.submit(bytes);
250
251 if (el.bounds_hint)
252 layer_ptr->set_bounds(id, *el.bounds_hint);
253 if (el.contains)
254 layer_ptr->set_contains(id, el.contains);
255 };
256 }
257
258 panel.track(layer, mapped.element.id, base_bounds, std::move(reposition), mapped.element.buffer);
259 }
260
261 /**
262 * @brief Create and place every adornment declared on @p spec.
263 *
264 * Makes a target for each axis label, tick label, legend swatch, and
265 * legend label, then hands each to the corresponding Plot placement
266 * function. Each adornment is related to @p relate_to so removal and
267 * visibility cascade from the series element.
268 *
269 * Lives here rather than in Plot because it constructs buffers,
270 * which requires the BufferManager. Plot composes placement from
271 * arguments it is given.
272 *
273 * @param surface Surface to place on.
274 * @param spec Series spec carrying the adornment declarations.
275 * @param relate_to Element id the adornments are related to.
276 * @param batch Shared plot buffer for swatches and labels. With
277 * labels, it needs a text slot and forma_plot.frag.
278 * When empty, one buffer is created for all adornments.
279 */
280 void place_adornments(
281 Surface& surface,
282 const Plot::SeriesSpec& spec,
283 uint32_t relate_to,
284 const std::shared_ptr<Buffers::FormaBuffer>& batch = {});
285
286 private:
289
290 std::shared_ptr<Nodes::NodeGraphManager> m_node_graph_manager;
291 std::shared_ptr<Buffers::BufferManager> m_buffer_manager;
292 std::shared_ptr<Vruta::TaskScheduler> m_scheduler;
293 std::shared_ptr<Vruta::EventManager> m_event_manager;
294 std::shared_ptr<Core::WindowManager> m_window_manager;
295
296 std::unique_ptr<Bridge> m_bridge;
297 std::unique_ptr<Inspector> m_inspect;
298 std::unordered_map<const Text::GlyphAtlas*, Text::AtlasImage> m_atlas_images;
299
300 bool m_initialized {};
301 };
302
303 /// @brief Accessor for the process-wide Atelier.
304 inline Atelier& atelier() { return Atelier::instance(); }
305
306} // namespace internal
307} // namespace MayaFlux::Portal::Forma
std::shared_ptr< NetworkGeometryBuffer > buffer
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
PrimitiveTopology topology
vk::Instance instance
Definition VKDevice.cpp:39
std::string name
Definition VKDevice.cpp:123
void register_element(const ElementRef &ref, std::shared_ptr< MappedState< T > > state, 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:378
Two-way binding orchestrator for Forma elements.
Definition Bridge.hpp:74
Where an element's geometry and texture are written.
Definition Target.hpp:22
Forma subsystem for live introspection.
Definition Inspector.hpp:39
Slot add(Element element)
Add an element to the layer.
Definition Layer.cpp:9
Flat registry of Elements on a surface.
Definition Layer.hpp:24
Portal::Graphics::RenderConfig render_config(Portal::Graphics::RenderConfig base={}) const
base targeting this Surface's window.
Definition Surface.hpp:227
Layer & layer() noexcept
Access the spatial registry.
Definition Surface.hpp:159
Named owner of a (Window, Layer, Context) triple: the Forma canvas.
Definition Surface.hpp:121
Mapped< T > create_element(Surface &surface, FormaTarget target, GeometryFn< T > geom, T initial, std::function< float(T)> project={})
create_element writing into target, which may be a slice shared with other elements.
Definition Atelier.hpp:183
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
Definition Atelier.hpp:291
Text::AtlasImage & atlas_image(const Text::GlyphAtlas &atlas)
The GPU image of atlas, shared by every text slice drawing from it.
Definition Atelier.hpp:98
std::shared_ptr< Nodes::NodeGraphManager > m_node_graph_manager
Definition Atelier.hpp:290
std::shared_ptr< Vruta::TaskScheduler > m_scheduler
Definition Atelier.hpp:292
Atelier & operator=(Atelier &&)=delete
std::unique_ptr< Bridge > m_bridge
Definition Atelier.hpp:296
Mapped< T > create_element(Surface &surface, GeometryFn< T > geom, T initial, Graphics::PrimitiveTopology topology=Graphics::PrimitiveTopology::TRIANGLE_STRIP, std::function< float(T)> project={})
create_element on a buffer of its own, as a slice of topology, followed by one sync so bounds_hint an...
Definition Atelier.hpp:165
std::unique_ptr< Inspector > m_inspect
Definition Atelier.hpp:297
std::shared_ptr< Core::WindowManager > m_window_manager
Definition Atelier.hpp:294
void track(Scrollable &panel, Layer &layer, const Mapped< T > &mapped, Kinesis::AABB2D base_bounds, std::function< void(Kinesis::AABB2D)> reposition={})
Register mapped's element for scroll reflow in panel.
Definition Atelier.hpp:227
Atelier & operator=(const Atelier &)=delete
std::unordered_map< const Text::GlyphAtlas *, Text::AtlasImage > m_atlas_images
Definition Atelier.hpp:298
std::shared_ptr< Vruta::EventManager > m_event_manager
Definition Atelier.hpp:293
Process-wide Forma workshop.
Definition Atelier.hpp:55
The GPU image of a GlyphAtlas, for anything that samples glyph coverage.
Rasterizes and packs glyphs from a FontFace into a TextureContainer.
void initialize()
Definition main.cpp:10
Contains the node-based computational processing system components.
Definition Chronie.hpp:14
Atelier & atelier()
Accessor for the process-wide Atelier.
Definition Atelier.hpp:304
constexpr size_t k_capacity_bytes
Definition Atelier.hpp:37
void shutdown()
Release stored references.
Definition Forma.cpp:58
Inspector & inspector()
Access the Forma introspection subsystem.
Definition Forma.cpp:73
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:80
Bridge & bridge()
Return the application-level Bridge instance.
Definition Forma.cpp:71
Surface create_surface(SurfaceConfig config)
Construct a Surface from a SurfaceConfig.
Definition Forma.cpp:85
std::function< void(T value, std::vector< uint8_t > &out_bytes, Element &element)> GeometryFn
Geometry function signature.
Definition Mapped.hpp:71
PrimitiveTopology
Vertex assembly primitive topology.
std::shared_ptr< Core::Window > create_window(const Core::WindowCreateInfo &create_info)
Create a new window with specified parameters.
Definition Windowing.cpp:14
auto create_buffer(uint32_t channel, uint32_t buffer_size, Args &&... args) -> std::shared_ptr< BufferType >
creates a new buffer of the specified type and registers it
Definition Graph.hpp:340
Configuration for creating a single window instance.
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
std::function< bool(glm::vec2)> contains
Authoritative containment test in NDC space.
Definition Element.hpp:77
FormaTarget buffer
Where this region's rendered output is written: a buffer of its own, or a slice of one it shares.
Definition Element.hpp:82
uint32_t id
Stable id assigned by Layer::add. Never zero.
Definition Element.hpp:63
std::optional< Kinesis::AABB2D > bounds_hint
Optional fast-reject bounds in NDC space.
Definition Element.hpp:67
A bounded, renderable region on a window surface.
Definition Element.hpp:61
std::shared_ptr< MappedState< T > > state
Shared value carrier. External systems hold a copy of this ptr.
Definition Mapped.hpp:98
GeometryFn< T > geometry_fn
Geometry regeneration function. Set once at construction.
Definition Mapped.hpp:101
Element element
The Element registered with the Layer.
Definition Mapped.hpp:105
Infrastructure for a continuously-mapped value whose GPU geometry tracks it.
Definition Mapped.hpp:96
MAYAFLUX_API Scrollable & track(Layer &layer, uint32_t id, Kinesis::AABB2D base_bounds, std::function< void(Kinesis::AABB2D)> reposition, const FormaTarget &clip_buf={})
Register an element for scroll reflow.
A clipped, scroll-offset viewport over content taller than it.
The single argument every Surface-creating function in this module takes, at every level of abstracti...
Definition Surface.hpp:26
Unified rendering configuration for graphics buffers.