MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Mapped.hpp
Go to the documentation of this file.
1#pragma once
2
4
5namespace MayaFlux::Buffers {
6class VKBuffer;
7}
8
10
11/**
12 * @brief Version counter incremented on every value write.
13 *
14 * Plain uint64_t behind a shared_ptr. The graphics tick compares against
15 * its last-seen version to detect changes without polling the value itself.
16 * Not atomic. Everything that touches a MappedState runs on the graphics
17 * thread, in order within one frame: Bridge tasks, buffer processing, then
18 * window polling, which fires Context callbacks. Write it from that thread
19 * only. From any other thread, hand the value over through a Bridge inbound
20 * callable instead.
21 */
22using Version = uint64_t;
23
24/**
25 * @struct MappedState
26 * @brief Value carrier for a Mapped primitive.
27 *
28 * Owns the current value and a version counter. Any writer increments
29 * version after updating value. The graphics tick reads both and decides
30 * whether to regenerate geometry.
31 *
32 * Exposed as shared_ptr<MappedState<T>> so any external system — a node
33 * output reader, a buffer writer, a scheduler callback — can hold a
34 * reference and read or write without knowing about the primitive.
35 *
36 * @tparam T Value type. float for a single continuous parameter,
37 * glm::vec2 for a 2D position, any plain data type.
38 */
39template <typename T>
41 T value {};
43 uint32_t id { 0 };
44
45 /// @brief Layer that issued @c id. Set by Bridge::register_element.
46 std::weak_ptr<Layer> layer;
47
48 void write(T v)
49 {
50 value = v;
51 ++version;
52 }
53};
54
55/**
56 * @brief Geometry function signature.
57 *
58 * Called by the graphics tick when the version has advanced. Receives the
59 * current value and an output byte vector to fill with interleaved vertex
60 * data. Layout, stride, and topology are determined by how the caller
61 * constructed the VKBuffer and RenderProcessor — the function is agnostic
62 * to all of those.
63 *
64 * The function is also responsible for updating the Element's spatial
65 * description if the geometry change affects hit testing (e.g. a handle
66 * that moves). It receives the Element by reference for that purpose.
67 *
68 * @tparam T Value type matching the MappedState.
69 */
70template <typename T>
71using GeometryFn = std::function<void(T value, std::vector<uint8_t>& out_bytes, Element& element)>;
72
73/**
74 * @struct Mapped
75 * @brief Infrastructure for a continuously-mapped value whose GPU geometry
76 * tracks it.
77 *
78 * The geometry function IS the primitive. Mapped provides only the
79 * mechanism: a shared value carrier, a version counter, and a sync()
80 * call that invokes the geometry function when the value changes.
81 *
82 * The geometry function decides everything about shape, topology, and
83 * vertex layout. It can write from any source — mouse pixel coordinates,
84 * microphone energy, another node's output, a tendency field, a computed
85 * function of time — by whatever means the caller chooses. The common
86 * geometry helpers in Geometry.hpp are illustrative, not idiomatic.
87 *
88 * Orchestration (node binding, buffer mapping, scheduler-driven update,
89 * input capture) attaches externally by writing to state and calling
90 * state->write(v). Mapped has no knowledge of or dependency on any
91 * orchestration layer.
92 *
93 * @tparam T Value type.
94 */
95template <typename T>
96struct Mapped {
97 /// @brief Shared value carrier. External systems hold a copy of this ptr.
98 std::shared_ptr<MappedState<T>> state;
99
100 /// @brief Geometry regeneration function. Set once at construction.
102
103 /// @brief The Element registered with the Layer.
104 /// element.id is valid after Layer::add(element) has been called.
106
107 /// @brief Last version seen by sync(). Initialised to a sentinel that
108 /// guarantees one geometry generation on the first sync() call.
109 Version last_version { static_cast<Version>(-1) };
110
111 /// @brief When true, sync() regenerates geometry every call regardless of
112 /// whether state->version has advanced. Set by subsystems where the
113 /// value pointer is stable but the data it references changes each frame.
114 bool force_redraw_on_sync { false };
115
116 /**
117 * @brief Current spatial footprint, satisfying Kinesis::HasBounds.
118 *
119 * Returns the element's bounds_hint as last written by the geometry
120 * function, or a zero region when the geometry function sets none.
121 */
122 [[nodiscard]] Kinesis::AABB2D bounds() const noexcept
123 {
124 return element.bounds_hint.value_or(Kinesis::AABB2D {});
125 }
126
127 /**
128 * @brief Call whenever state may have changed: once per graphics tick
129 * for a continuously-changing source with no discrete trigger
130 * (Bridge::bind's GraphicsRoutine does this), or directly from
131 * the event handler that changed state->value when the trigger
132 * is already known (a click, a scroll, a key) - no polling
133 * needed for the latter, same as Collapsible's own on_press
134 * calling sync() straight from the handler.
135 *
136 * If state->version has advanced since last_version, invokes geometry_fn
137 * with the current value into a local byte buffer, then passes the result
138 * to VKBuffer::set_data so the existing upload path handles GPU transfer.
139 *
140 * @param layer Optional. Layer::add() stored a separate copy of element
141 * when this Mapped was registered, so a geometry_fn that
142 * updates element.bounds_hint/contains (a fader's handle,
143 * a radial indicator) only changes this Mapped's own copy
144 * unless that copy is pushed back. Passing the Layer this
145 * element was registered on does that push after
146 * geometry_fn runs, keeping hit-testing correct past the
147 * first frame instead of just the rendered buffer.
148 */
149 void sync(Layer* layer = nullptr)
150 {
151 if (!state || !geometry_fn || !element.buffer)
152 return;
153 if (state->version == last_version && !force_redraw_on_sync)
154 return;
155
158 last_version = state->version;
159
160 if (layer) {
162 layer->set_bounds(element.id, *element.bounds_hint);
163 if (element.contains)
164 layer->set_contains(element.id, element.contains);
165 }
166 }
167
168private:
169 std::vector<uint8_t> m_bytes;
170};
171
172/**
173 * @brief Construct a Mapped<T> with a freshly allocated MappedState.
174 * @param initial Starting value.
175 * @param geometry Geometry function producing vertex bytes from a value.
176 * @param buffer VKBuffer whose raw bytes the geometry function writes into.
177 * @return Ready-to-use Mapped. Register element with a Layer before first sync().
178 */
179template <typename T>
180[[nodiscard]] Mapped<T> make_mapped(
181 T initial,
182 GeometryFn<T> geometry,
184{
185 auto st = std::make_shared<MappedState<T>>();
186 st->write(initial);
187
188 Element el;
189 el.buffer = std::move(buffer);
190
191 Mapped<T> m;
192 m.state = std::move(st);
193 m.geometry_fn = std::move(geometry);
194 m.element = std::move(el);
195 m.last_version = static_cast<Version>(-1);
196 return m;
197}
198
199} // namespace MayaFlux::Portal::Forma
std::shared_ptr< NetworkGeometryBuffer > buffer
glm::vec3 value
void submit(const std::vector< uint8_t > &bytes) const
Replace this target's geometry.
Definition Target.cpp:51
Where an element's geometry and texture are written.
Definition Target.hpp:22
Flat registry of Elements on a surface.
Definition Layer.hpp:24
Mapped< T > make_mapped(T initial, GeometryFn< T > geometry, FormaTarget buffer)
Construct a Mapped<T> with a freshly allocated MappedState.
Definition Mapped.hpp:180
uint64_t Version
Version counter incremented on every value write.
Definition Mapped.hpp:22
std::function< void(T value, std::vector< uint8_t > &out_bytes, Element &element)> GeometryFn
Geometry function signature.
Definition Mapped.hpp:71
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::weak_ptr< Layer > layer
Layer that issued id. Set by Bridge::register_element.
Definition Mapped.hpp:46
Value carrier for a Mapped primitive.
Definition Mapped.hpp:40
std::shared_ptr< MappedState< T > > state
Shared value carrier. External systems hold a copy of this ptr.
Definition Mapped.hpp:98
void sync(Layer *layer=nullptr)
Call whenever state may have changed: once per graphics tick for a continuously-changing source with ...
Definition Mapped.hpp:149
Kinesis::AABB2D bounds() const noexcept
Current spatial footprint, satisfying Kinesis::HasBounds.
Definition Mapped.hpp:122
std::vector< uint8_t > m_bytes
Definition Mapped.hpp:169
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
bool force_redraw_on_sync
When true, sync() regenerates geometry every call regardless of whether state->version has advanced.
Definition Mapped.hpp:114
Version last_version
Last version seen by sync().
Definition Mapped.hpp:109
Infrastructure for a continuously-mapped value whose GPU geometry tracks it.
Definition Mapped.hpp:96