MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Emitter.hpp
Go to the documentation of this file.
1#pragma once
2
6
7namespace MayaFlux::Buffers {
8class VKBuffer;
9}
10
11namespace MayaFlux::Nexus {
12
13/**
14 * @class Emitter
15 * @brief Object that acts on existing MayaFlux objects when committed.
16 *
17 * Constructed with an optional influence function. Position is optional: call
18 * @c set_position before registering with @c Fabric if spatial indexing is
19 * required. Entities without a position are committed normally but are not
20 * inserted into the spatial index.
21 *
22 * The id is assigned by @c Fabric::wire and is stable for the object's
23 * lifetime. It is zero until the object has been registered.
24 *
25 * RenderConfig takes a designated initializer.
26 *
27 * @code
28 * emitter->set_influence<InfluenceBlock>(InfluenceBlock::from, bind_influence_block(proc));
29 * emitter->render(mgr, { .target_window = window });
30 * @endcode
31 */
32class MAYAFLUX_API Emitter {
33public:
34 using InfluenceFn = std::function<void(const InfluenceContext&)>;
35
36 /**
37 * @brief Construct with no function, for an Emitter whose behaviour comes
38 * from a typed influence.
39 */
40 Emitter() = default;
41
42 /**
43 * @brief Construct with an influence function.
44 * @param fn Called on every commit with the current context.
45 */
46 explicit Emitter(InfluenceFn fn)
47 : m_fn(std::move(fn))
48 {
49 }
50
51 /**
52 * @brief Construct with a named influence function.
53 * @param fn_name Identifier used for state encoding.
54 * @param fn Called on every commit with the current context.
55 */
56 Emitter(std::string fn_name, InfluenceFn fn)
57 : m_fn_name(std::move(fn_name))
58 , m_fn(std::move(fn))
59 {
60 }
61
62 /** @brief Identifier assigned to the influence function, empty if anonymous. */
63 [[nodiscard]] const std::string& fn_name() const { return m_fn_name; }
64
65 /** @brief Set or replace the influence function's identifier. */
66 void set_fn_name(std::string name) { m_fn_name = std::move(name); }
67
68 /** @brief The influence function itself. */
69 [[nodiscard]] const InfluenceFn& fn() const { return m_fn; }
70
71 /**
72 * @brief Return the current position, if set.
73 */
74 [[nodiscard]] const std::optional<glm::vec3>& position() const { return m_position; }
75
76 /**
77 * @brief Set the position, enabling spatial indexing for this object.
78 * @param p World-space coordinates.
79 */
80 void set_position(const glm::vec3& p) { m_position = p; }
81
82 /**
83 * @brief Clear the position, removing this object from spatial queries.
84 */
85 void clear_position() { m_position.reset(); }
86
87 /**
88 * @brief Return the stable object id assigned by Fabric.
89 */
90 [[nodiscard]] uint32_t id() const { return m_id; }
91
92 // =========================================================================
93 // Output sinks
94 // =========================================================================
95
96 /** @brief Register an audio output on @p channel. */
97 void sink_audio(Buffers::BufferManager& mgr, uint32_t channel)
98 {
99 add_audio_sink(m_audio_sinks, mgr, channel);
100 }
101
102 /** @brief Register an audio output on @p channel with a producer function. */
103 void sink_audio(Buffers::BufferManager& mgr, uint32_t channel,
104 std::function<Kakshya::DataVariant(const InfluenceContext&)> fn,
105 std::string fn_name = "")
106 {
107 add_audio_sink(m_audio_sinks, mgr, channel, std::move(fn), std::move(fn_name));
108 }
109
110 /** @brief Unregister the audio sink on @p channel. */
111 void remove_audio_sink(Buffers::BufferManager& mgr, uint32_t channel)
112 {
113 Nexus::remove_audio_sink(m_audio_sinks, mgr, channel);
114 }
115
116 /** @brief Register a render output targeting @p window. */
118 {
119 add_render_sink(m_render_sinks, mgr, config, {}, "", m_position);
120 }
121
122 /** @brief Register a render output targeting @p window with a producer function. */
124 std::string fn_name, RenderFn fn)
125 {
126 add_render_sink(m_render_sinks, mgr, config, std::move(fn), std::move(fn_name), m_position);
127 }
128
129 [[nodiscard]] const std::vector<AudioSink>& audio_sinks() const { return m_audio_sinks; }
130 [[nodiscard]] const std::vector<RenderSink>& render_sinks() const { return m_render_sinks; }
131
132 /* @brief Return the render processor for the sink targeting @p window, or nullptr if not found. */
133 std::shared_ptr<Buffers::RenderProcessor> get_render_processor(
134 const std::shared_ptr<Core::Window>& window) const
135 {
136 auto it = std::ranges::find_if(m_render_sinks,
137 [&window](const RenderSink& s) { return s.window == window; });
138 return it != m_render_sinks.end() ? it->renderer : nullptr;
139 }
140
141 /** @brief Unregister the render sink targeting @p window. */
142 void remove_render(Buffers::BufferManager& mgr, const std::shared_ptr<Core::Window>& window)
143 {
144 remove_render_sink(m_render_sinks, mgr, window);
145 }
146
147 /** @brief Push @p samples to all registered audio sinks. */
148 void set_audio_data(std::span<const double> samples)
149 {
150 push_audio_data(m_audio_sinks, samples);
151 }
152
153 /**
154 * @brief Set pre-packed interleaved vertex bytes to all registered render sinks.
155 *
156 * data must point to N contiguous 60-byte Vertex records.
157 * byte_count must be a multiple of 60.
158 */
159 void set_vertices(const void* data, size_t byte_count);
160
161 /**
162 * @brief Set typed vertex data to all registered render sinks.
163 * @tparam T One of Kakshya::PointVertex, Kakshya::LineVertex, Kakshya::MeshVertex, Kakshya::Vertex.
164 */
165 template <typename T>
166 void set_vertices(std::span<const T> vertices)
167 {
168 static_assert(sizeof(T) == 60, "set_vertices: T must be a 60-byte vertex type");
169 set_vertices(vertices.data(), vertices.size_bytes());
170 }
171
172 /** @brief Set the intensity, a general-purpose parameter for influence functions. */
173 void set_intensity(float i) { m_intensity = i; }
174
175 /** @brief Get the current intensity. */
176 [[nodiscard]] float intensity() const { return m_intensity; }
177
178 /** @brief Set the radius, a general-purpose parameter for influence functions. */
179 void set_radius(float r) { m_radius = r; }
180
181 /** @brief Get the current radius. */
182 [[nodiscard]] float radius() const { return m_radius; }
183
184 /** @brief Set the color, a general-purpose parameter for influence functions. */
185 void set_color(const glm::vec3& c) { m_color = c; }
186
187 /** @brief Clear the color, resetting it to an unset state. */
188 void clear_color() { m_color.reset(); }
189
190 /** @brief Get the current color, if set. */
191 [[nodiscard]] const std::optional<glm::vec3>& color() const { return m_color; }
192
193 /** @brief Set the size, a general-purpose parameter for influence functions. */
194 void set_size(float s) { m_size = s; }
195
196 /** @brief Clear the size, resetting it to an unset state. */
197 void clear_size() { m_size.reset(); }
198
199 /** @brief Get the current size, if set. */
200 [[nodiscard]] const std::optional<float>& size() const { return m_size; }
201
202 /**
203 * @brief Make an existing, already rendered buffer the look of this object.
204 *
205 * Works as Agent::attach does, except that an Emitter has no orientation:
206 * every render processor the buffer has is moved to the object's position
207 * and never rotated. If the object already has a position, that position is
208 * kept and becomes the offset. Replaces any previous attachment. An
209 * attachment is not part of encoded state and must be made again after
210 * decoding.
211 *
212 * @param buf Buffer to attach. Ignored if null.
213 * @param config Anchor vertex, offset and move behaviour.
214 */
215 void attach(const std::shared_ptr<Buffers::VKBuffer>& buf, const AttachConfig& config = {});
216
217 /** @brief Release the attached buffer and reset its placement. */
218 void detach();
219
220 /**
221 * @brief Read the attached buffer's geometry again and move the anchor to match.
222 *
223 * The object keeps its position. Blocks for a ComputeMeshBuffer, so call it
224 * off the graphics thread.
225 */
226 void recenter();
227
228 /** @brief True while a buffer is attached. */
229 [[nodiscard]] bool attached() const { return m_attachment.has_value(); }
230
231 /**
232 * @brief Set the one target of an influence of any type.
233 * @tparam T Type the producer returns; whatever the target takes.
234 * @param producer Builds the value from the influence context.
235 * @param target Takes the value and decides what it affects.
236 *
237 * An Emitter has a single target: setting another replaces it. Runs on
238 * every invoke after the influence function, independent of the render
239 * processor target. Not part of encoded state.
240 */
241 template <typename T>
242 void set_influence(typename Influence<T>::Producer producer, typename Influence<T>::Target target)
243 {
244 auto influence = std::make_shared<Influence<T>>(std::move(producer));
245 influence->add_target(std::move(target));
246 m_influence = [influence](const InfluenceContext& ctx) { influence->invoke(ctx); };
247 }
248
249 /** @brief Remove the target set with set_influence(). */
250 void clear_influence() { m_influence = nullptr; }
251
252 /**
253 * @brief Invoke the influence function with the supplied context.
254 * @param ctx Populated context for this commit.
255 */
256 void invoke(const InfluenceContext& ctx) const
257 {
258 if (m_fn) {
259 m_fn(ctx);
260 }
261 dispatch_audio_sinks(m_audio_sinks, ctx);
262 dispatch_render_sinks(m_render_sinks, ctx);
263 if (m_attachment)
264 apply_attachment(*m_attachment, ctx);
265 if (m_influence) {
266 m_influence(ctx);
267 }
268 }
269
270private:
271 std::optional<glm::vec3> m_position;
272 std::optional<glm::vec3> m_color;
273 std::optional<float> m_size;
274 float m_intensity { 1.0F };
275 float m_radius { 1.0F };
276
278 uint32_t m_id {};
279 std::string m_fn_name;
280
281 mutable std::vector<AudioSink> m_audio_sinks;
282 mutable std::vector<RenderSink> m_render_sinks;
284 mutable std::optional<Attachment> m_attachment;
285
286 void follow_attachment();
287
288 friend class Fabric;
289};
290
291} // namespace MayaFlux::Nexus
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
std::string name
Definition VKDevice.cpp:123
Token-based multimodal buffer management system for unified data stream processing.
const std::string & fn_name() const
Identifier assigned to the influence function, empty if anonymous.
Definition Emitter.hpp:63
const std::optional< glm::vec3 > & position() const
Return the current position, if set.
Definition Emitter.hpp:74
void set_influence(typename Influence< T >::Producer producer, typename Influence< T >::Target target)
Set the one target of an influence of any type.
Definition Emitter.hpp:242
float radius() const
Get the current radius.
Definition Emitter.hpp:182
std::optional< float > m_size
Definition Emitter.hpp:273
const std::vector< AudioSink > & audio_sinks() const
Definition Emitter.hpp:129
const InfluenceFn & fn() const
The influence function itself.
Definition Emitter.hpp:69
std::optional< glm::vec3 > m_color
Definition Emitter.hpp:272
void sink_audio(Buffers::BufferManager &mgr, uint32_t channel)
Register an audio output on channel.
Definition Emitter.hpp:97
void clear_size()
Clear the size, resetting it to an unset state.
Definition Emitter.hpp:197
uint32_t id() const
Return the stable object id assigned by Fabric.
Definition Emitter.hpp:90
std::function< void(const InfluenceContext &)> InfluenceFn
Definition Emitter.hpp:34
std::optional< glm::vec3 > m_position
Definition Emitter.hpp:271
void set_intensity(float i)
Set the intensity, a general-purpose parameter for influence functions.
Definition Emitter.hpp:173
const std::optional< float > & size() const
Get the current size, if set.
Definition Emitter.hpp:200
void set_size(float s)
Set the size, a general-purpose parameter for influence functions.
Definition Emitter.hpp:194
void render(Buffers::BufferManager &mgr, const Portal::Graphics::RenderConfig &config)
Register a render output targeting window.
Definition Emitter.hpp:117
void set_radius(float r)
Set the radius, a general-purpose parameter for influence functions.
Definition Emitter.hpp:179
const std::vector< RenderSink > & render_sinks() const
Definition Emitter.hpp:130
void render(Buffers::BufferManager &mgr, const Portal::Graphics::RenderConfig &config, std::string fn_name, RenderFn fn)
Register a render output targeting window with a producer function.
Definition Emitter.hpp:123
std::optional< Attachment > m_attachment
Definition Emitter.hpp:284
std::vector< AudioSink > m_audio_sinks
Definition Emitter.hpp:281
Emitter()=default
Construct with no function, for an Emitter whose behaviour comes from a typed influence.
void sink_audio(Buffers::BufferManager &mgr, uint32_t channel, std::function< Kakshya::DataVariant(const InfluenceContext &)> fn, std::string fn_name="")
Register an audio output on channel with a producer function.
Definition Emitter.hpp:103
void set_vertices(std::span< const T > vertices)
Set typed vertex data to all registered render sinks.
Definition Emitter.hpp:166
void remove_render(Buffers::BufferManager &mgr, const std::shared_ptr< Core::Window > &window)
Unregister the render sink targeting window.
Definition Emitter.hpp:142
std::vector< RenderSink > m_render_sinks
Definition Emitter.hpp:282
const std::optional< glm::vec3 > & color() const
Get the current color, if set.
Definition Emitter.hpp:191
bool attached() const
True while a buffer is attached.
Definition Emitter.hpp:229
void invoke(const InfluenceContext &ctx) const
Invoke the influence function with the supplied context.
Definition Emitter.hpp:256
Emitter(std::string fn_name, InfluenceFn fn)
Construct with a named influence function.
Definition Emitter.hpp:56
std::shared_ptr< Buffers::RenderProcessor > get_render_processor(const std::shared_ptr< Core::Window > &window) const
Definition Emitter.hpp:133
void clear_color()
Clear the color, resetting it to an unset state.
Definition Emitter.hpp:188
void clear_influence()
Remove the target set with set_influence().
Definition Emitter.hpp:250
void clear_position()
Clear the position, removing this object from spatial queries.
Definition Emitter.hpp:85
float intensity() const
Get the current intensity.
Definition Emitter.hpp:176
void set_color(const glm::vec3 &c)
Set the color, a general-purpose parameter for influence functions.
Definition Emitter.hpp:185
void set_audio_data(std::span< const double > samples)
Push samples to all registered audio sinks.
Definition Emitter.hpp:148
void set_fn_name(std::string name)
Set or replace the influence function's identifier.
Definition Emitter.hpp:66
void set_position(const glm::vec3 &p)
Set the position, enabling spatial indexing for this object.
Definition Emitter.hpp:80
Emitter(InfluenceFn fn)
Construct with an influence function.
Definition Emitter.hpp:46
void remove_audio_sink(Buffers::BufferManager &mgr, uint32_t channel)
Unregister the audio sink on channel.
Definition Emitter.hpp:111
Object that acts on existing MayaFlux objects when committed.
Definition Emitter.hpp:32
Orchestrates spatial indexing and scheduling for Nexus objects.
Definition Fabric.hpp:38
std::function< T(const Context &)> Producer
Definition Influence.hpp:93
std::function< void(const T &)> Target
Definition Influence.hpp:94
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:70
void apply_attachment(Attachment &attachment, const InfluenceContext &ctx)
Rebuild the transform from ctx and place every render processor of the buffer.
std::function< void(const InfluenceContext &)> RenderFn
Definition Sinks.hpp:26
void remove_render_sink(std::vector< RenderSink > &sinks, Buffers::BufferManager &mgr, const std::shared_ptr< Core::Window > &window)
Unregister and destroy the render sink targeting window.
Definition Sinks.cpp:194
void follow_attachment(Attachment &attachment, std::optional< glm::vec3 > &position, const std::optional< glm::quat > &orientation)
Set position from the buffer, or fold an outside move into the attachment.
void dispatch_render_sinks(std::vector< RenderSink > &sinks, const InfluenceContext &ctx)
For each sink that has a producer fn, call it and push the result.
Definition Sinks.cpp:215
void push_audio_data(std::vector< AudioSink > &sinks, std::span< const double > samples)
Push samples to every audio sink in sinks.
Definition Sinks.cpp:64
void dispatch_audio_sinks(std::vector< AudioSink > &sinks, const InfluenceContext &ctx)
For each sink that has a producer fn, call it and push the result.
Definition Sinks.cpp:71
void add_audio_sink(std::vector< AudioSink > &sinks, Buffers::BufferManager &mgr, uint32_t channel, std::function< Kakshya::DataVariant(const InfluenceContext &)> fn, std::string fn_name)
Create and register an audio sink on channel.
Definition Sinks.cpp:18
void add_render_sink(std::vector< RenderSink > &sinks, Buffers::BufferManager &mgr, const Portal::Graphics::RenderConfig &config, RenderFn fn, std::string fn_name, const std::optional< glm::vec3 > &initial_position)
Create and register a render sink targeting window.
Definition Sinks.cpp:95
How an Agent attaches to a buffer that already exists.
Data passed to an Emitter or Agent influence function on each commit.
Definition Influence.hpp:17
std::shared_ptr< Core::Window > window
Definition Sinks.hpp:69
Holds the plumbing for one graphics output registered from a Nexus object.
Definition Sinks.hpp:63
Unified rendering configuration for graphics buffers.