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