MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Element.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Core {
7class VKImage;
8}
9namespace MayaFlux::Buffers {
10class TextureBuffer;
11}
12namespace MayaFlux::Portal::Text {
13struct PressParams;
14}
18
20
21/**
22 * @struct Element
23 * @brief A bounded, renderable region on a window surface.
24 *
25 * An Element pairs a spatial description with a GPU buffer whose output
26 * occupies that region. The spatial description is deliberately open:
27 *
28 * - @c bounds_hint: optional AABB2D in NDC space, used as a fast-reject
29 * pre-filter before @c contains is evaluated. Not required.
30 *
31 * - @c contains: authoritative point-in-element test. If absent and
32 * @c bounds_hint is set, @c bounds_hint::contains is used directly.
33 * If both are absent the element never hits. For a rectangle, set only
34 * @c bounds_hint. For a circle, arbitrary polygon, or curve region, set
35 * @c contains (and optionally @c bounds_hint as the circumscribed rect
36 * for performance).
37 *
38 * @c buffer is optional. An Element with no buffer is a pure spatial
39 * registration: it participates in hit testing and relation cascades but
40 * contributes no rendered output. A voice node with a spatial position,
41 * a named region driving a compute shader, an invisible trigger zone; all
42 * are valid Elements with no buffer.
43 *
44 * Fluent setters return @c Element& for chained construction:
45 * @code
46 * auto el = Element{}
47 * .with_name("kick_voice")
48 * .with_bounds(region)
49 * .non_interactive();
50 * @endcode
51 *
52 * Layer::add() assigns the stable id. All setters that affect spatial or
53 * visibility state can also be applied post-registration via Layer::Slot.
54 *
55 * @note Elements do not participate in the graphics subsystem scheduler
56 * directly. The caller registers the underlying buffer with the
57 * BufferManager and attaches a RenderProcessor as usual. Element
58 * holds only the spatial and identity metadata that Layer and
59 * Context need.
60 */
61struct MAYAFLUX_API Element {
62 /// @brief Stable id assigned by Layer::add. Never zero.
63 uint32_t id { 0 };
64
65 /// @brief Optional fast-reject bounds in NDC space.
66 /// When set, Layer evaluates this before @c contains.
67 std::optional<Kinesis::AABB2D> bounds_hint;
68
69 /// @brief Optional region outside which hit testing rejects the element.
70 /// Independent of @c bounds_hint and @c contains, so geometry
71 /// functions that rewrite those never lift it. Set by containers
72 /// such as Scrollable to confine a child to its viewport.
73 std::optional<Kinesis::AABB2D> clip;
74
75 /// @brief Authoritative containment test in NDC space.
76 /// When absent, @c bounds_hint is used as the sole test.
77 std::function<bool(glm::vec2)> contains;
78
79 /// @brief Where this region's rendered output is written: a buffer of its
80 /// own, or a slice of one it shares. Empty for non-rendering
81 /// elements (pure hit-test regions).
83
84 /// @brief Optional GPU texture to bind to the attached buffer. Used for
85 std::shared_ptr<Core::VKImage> texture;
86
87 /// @brief Text drawn into the attached buffer by with_text(). Copies of
88 /// the element share it.
89 std::shared_ptr<internal::TextSlice> text_slice;
90
91 /// @brief When false, hit testing skips this element.
92 bool interactive { true };
93
94 /// @brief When false, the element is excluded from Layer iteration.
95 bool visible { true };
96
97 /// @brief Optional human-readable label for Lila introspection and
98 /// debug logging. Not used by Layer or Context internally.
99 std::string name;
100
101 // =========================================================================
102 // Spatial
103 // =========================================================================
104
105 /**
106 * @brief Set the fast-reject AABB. For rectangular regions this is
107 * sufficient on its own — leave @c with_contains unset.
108 */
110 {
111 bounds_hint = b;
112 return *this;
113 }
114
115 /**
116 * @brief Set an explicit containment predicate.
117 *
118 * Use for any non-rectangular region: circles, polygons, strokes,
119 * Voronoi cells, audio waveform envelopes. Pair with @c with_bounds
120 * for a circumscribed AABB fast-reject when the predicate is expensive.
121 *
122 * Kinesis::circular_bounds, polygon_bounds, stroke_bounds, union_bounds,
123 * subtract_bounds, and intersect_bounds are all valid arguments.
124 */
125 Element& with_contains(std::function<bool(glm::vec2)> fn)
126 {
127 contains = std::move(fn);
128 return *this;
129 }
130
131 /**
132 * @brief Convenience: rectangular region specified as two NDC corners.
133 * Equivalent to with_bounds(AABB2D{min, max}).
134 */
135 Element& with_rect(glm::vec2 ndc_min, glm::vec2 ndc_max)
136 {
137 bounds_hint = Kinesis::AABB2D { .min = ndc_min, .max = ndc_max };
138 return *this;
139 }
140
141 /**
142 * @brief Set a circular containment predicate.
143 *
144 * @c bounds_hint is independent — set it separately if a cheap pre-filter
145 * is useful. For a plain circle it is often the circumscribed rect via
146 * AABB2D::from_ndc(center, glm::vec2(radius)), but that decision belongs
147 * to the caller.
148 */
149 Element& with_circle(glm::vec2 center, float radius)
150 {
151 contains = Kinesis::circular_bounds(center, radius);
152 return *this;
153 }
154
155 /**
156 * @brief Set a polygon containment predicate.
157 *
158 * Uses the winding number algorithm, covering both convex and non-convex
159 * shapes. Vertices are in NDC, ordered CW or CCW.
160 *
161 * @c bounds_hint is independent — set it separately if a cheap pre-filter
162 * is useful for this region.
163 */
164 Element& with_polygon(std::span<const glm::vec2> verts)
165 {
166 contains = Kinesis::polygon_bounds(verts);
167 return *this;
168 }
169
170 /**
171 * @brief Set a stroke-based containment predicate.
172 *
173 * A point is inside if its perpendicular distance to any segment of
174 * @p pts is within @p half_thickness NDC units. Covers paths, wires,
175 * cable routes, waveform traces, and any open or closed curve.
176 *
177 * @c bounds_hint is independent — set it separately if a cheap pre-filter
178 * is useful for this region.
179 */
180 Element& with_stroke(std::span<const glm::vec2> pts, float half_thickness)
181 {
182 contains = Kinesis::stroke_bounds(pts, half_thickness);
183 return *this;
184 }
185
186 // =========================================================================
187 // Buffer
188 // =========================================================================
189
190 /**
191 * @brief Attach a FormaBuffer, or a slice of one, as the rendered output
192 * for this region. nullptr is valid for pure hit-test or
193 * pure-spatial elements.
194 */
196 {
197 buffer = std::move(target);
198 return *this;
199 }
200
201 // =========================================================================
202 // Buffer
203 // =========================================================================
204
205 /**
206 * @brief Submit a UV quad covering @p region and bind @p image as
207 * "texSampler" on the attached FormaBuffer.
208 *
209 * @p buffer must already be set and created with an additional_textures slot at index 0.
210 * Any source is valid: a loaded PNG, a render target, a TextureBuffer
211 * or TextBuffer via get_texture().
212 *
213 * @param image GPU-resident VKImage in shader-read layout.
214 * @param region NDC quad extent. Defaults to fullscreen.
215 */
216 Element& with_texture(
217 const std::shared_ptr<Core::VKImage>& image,
218 Kinesis::AABB2D region = { .min = glm::vec2(-1.F), .max = glm::vec2(1.F) });
219
220 /**
221 * @brief Convenience overload extracting the GPU texture from a
222 * TextureBuffer (or TextBuffer, which inherits it).
223 *
224 * Equivalent to with_texture(buf->get_texture(), region).
225 */
226 Element& with_texture(
227 const std::shared_ptr<Buffers::TextureBuffer>& buf,
228 Kinesis::AABB2D region = { .min = glm::vec2(-1.F), .max = glm::vec2(1.F) });
229
230 /**
231 * @brief Draw @p text as glyph quads into the attached buffer.
232 *
233 * The glyphs are sampled from the glyph atlas, which is bound at texture
234 * slot 0, so @p buffer must already be set and created with an
235 * additional_textures slot at index 0. The text is retained for
236 * subsequent set_text() and retarget() calls.
237 *
238 * @param text UTF-8 string to draw.
239 * @param params PressParams (color, spans, background, render_bounds, atlas).
240 * render_bounds is the layout size in pixels, fitted onto
241 * @p region. Defaults apply when omitted.
242 * @param region NDC extent. Defaults to fullscreen.
243 */
244 Element& with_text(
245 std::string_view text,
246 std::optional<Portal::Text::PressParams> params,
247 Kinesis::AABB2D region = { .min = glm::vec2(-1.F), .max = glm::vec2(1.F) });
248
249 /**
250 * @brief Replace the text drawn by with_text().
251 *
252 * No-op when the element was not constructed via with_text().
253 *
254 * @param text New UTF-8 string.
255 * @param params PressParams. Defaults apply when omitted.
256 */
257 void set_text(std::string_view text, std::optional<Portal::Text::PressParams> params);
258
259 /**
260 * @brief Move the element's output to a new NDC region.
261 *
262 * The geometry-only half of a scroll reflow. Text from with_text() is laid
263 * out again into @p region; a texture from with_texture() has its quad
264 * rewritten there. No-op when buffer is null.
265 *
266 * @param region New NDC extent.
267 */
268 Element& retarget(Kinesis::AABB2D region);
269
270 // =========================================================================
271 // Flags
272 // =========================================================================
273
274 /**
275 * @brief Exclude from hit testing. Use for passive outputs — particle
276 * emitters, waveform displays, camera regions — that have spatial
277 * identity but accept no pointer events.
278 */
280 {
281 interactive = false;
282 return *this;
283 }
284
285 /**
286 * @brief Start hidden. Layer::set_visible or a relation cascade will
287 * reveal it. Use for elements that are conditionally visible or
288 * controlled by a parent collapsible.
289 */
291 {
292 visible = false;
293 return *this;
294 }
295
296 // =========================================================================
297 // Identity
298 // =========================================================================
299
300 /**
301 * @brief Set the human-readable name used in Lila introspection and
302 * debug output. Has no effect on Layer or Context behaviour.
303 */
304 Element& with_name(std::string n)
305 {
306 name = std::move(n);
307 return *this;
308 }
309};
310
311} // namespace MayaFlux::Portal::Forma
Expanse::ContainsFn contains
Definition Decoder.cpp:517
IO::ImageData image
Definition Decoder.cpp:47
float radius
std::shared_ptr< NetworkGeometryBuffer > buffer
size_t b
std::string name
Definition VKDevice.cpp:123
Where an element's geometry and texture are written.
Definition Target.hpp:22
Text drawn as glyph quads into one FormaTarget.
Definition TextSlice.hpp:27
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
Element & with_rect(glm::vec2 ndc_min, glm::vec2 ndc_max)
Convenience: rectangular region specified as two NDC corners.
Definition Element.hpp:135
Element & with_bounds(Kinesis::AABB2D b)
Set the fast-reject AABB.
Definition Element.hpp:109
Element & non_interactive()
Exclude from hit testing.
Definition Element.hpp:279
Element & with_buffer(FormaTarget target)
Attach a FormaBuffer, or a slice of one, as the rendered output for this region.
Definition Element.hpp:195
Element & with_circle(glm::vec2 center, float radius)
Set a circular containment predicate.
Definition Element.hpp:149
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
std::shared_ptr< internal::TextSlice > text_slice
Text drawn into the attached buffer by with_text().
Definition Element.hpp:89
std::optional< Kinesis::AABB2D > clip
Optional region outside which hit testing rejects the element.
Definition Element.hpp:73
std::shared_ptr< Core::VKImage > texture
Optional GPU texture to bind to the attached buffer. Used for.
Definition Element.hpp:85
Element & hidden()
Start hidden.
Definition Element.hpp:290
std::string name
Optional human-readable label for Lila introspection and debug logging.
Definition Element.hpp:99
Element & with_contains(std::function< bool(glm::vec2)> fn)
Set an explicit containment predicate.
Definition Element.hpp:125
std::optional< Kinesis::AABB2D > bounds_hint
Optional fast-reject bounds in NDC space.
Definition Element.hpp:67
Element & with_name(std::string n)
Set the human-readable name used in Lila introspection and debug output.
Definition Element.hpp:304
Element & with_polygon(std::span< const glm::vec2 > verts)
Set a polygon containment predicate.
Definition Element.hpp:164
Element & with_stroke(std::span< const glm::vec2 > pts, float half_thickness)
Set a stroke-based containment predicate.
Definition Element.hpp:180
A bounded, renderable region on a window surface.
Definition Element.hpp:61