MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Schema.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <nlohmann/json.hpp>
7
9
10/**
11 * @brief Current schema version written by StateEncoder and accepted by StateDecoder.
12 *
13 * History:
14 * 1 - initial (positions only)
15 * 2 - added color, size, wiring
16 * 3 - added audio_sinks, render_sinks
17 * 4 - added sink_type pixel row
18 * 5 - added subkind, locus_nav fields, expanses array
19 */
20inline constexpr uint32_t k_schema_version = 5;
21
22/**
23 * @brief RGBA32F EXR layout constants shared between encoder and decoder.
24 *
25 * Row 0: position.xyz, intensity
26 * Row 1: color.rgb, size
27 * Row 2: radius, query_radius, entity_type_norm, 0
28 * Row 3: trigger_kind, time_kind, sink_type_bits, first_audio_channel
29 * Row 4: locus_nav.fov, locus_nav.near, locus_nav.far, locus_nav.speed
30 */
31inline constexpr uint32_t k_exr_rows = 5;
32inline constexpr uint32_t k_channels = 4;
33
34// =============================================================================
35// Range normalization records
36// =============================================================================
37
38struct Range {
39 float min { 0.0F };
40 float max { 1.0F };
41
42 static constexpr auto describe()
43 {
44 return std::make_tuple(
45 IO::member("min", &Range::min),
46 IO::member("max", &Range::max));
47 }
48};
49
50struct RangeSet {
57
58 static constexpr auto describe()
59 {
60 return std::make_tuple(
61 IO::member("position.x", &RangeSet::pos_x),
62 IO::member("position.y", &RangeSet::pos_y),
63 IO::member("position.z", &RangeSet::pos_z),
64 IO::member("intensity", &RangeSet::intensity),
65 IO::member("color.r", &RangeSet::color_r),
66 IO::member("color.g", &RangeSet::color_g),
67 IO::member("color.b", &RangeSet::color_b),
68 IO::member("size", &RangeSet::size),
69 IO::member("radius", &RangeSet::radius),
70 IO::member("query_radius", &RangeSet::query_radius));
71 }
72};
73
74// =============================================================================
75// Wiring records
76// =============================================================================
77
78/**
79 * @brief Serializable wiring strategies.
80 *
81 * Enumerator names are lowercased by Reflect:: for JSON: commit_driven,
82 * every, move_to, unsupported. The decoder treats Unsupported as a
83 * commit_driven fallback with a warning.
84 */
85enum class WiringKind : uint8_t {
87 Every,
88 MoveTo,
90};
91
92struct WiringStep {
93 glm::vec3 position {};
94 double delay_seconds { 0.0 };
95
96 static constexpr auto describe()
97 {
98 return std::make_tuple(
99 IO::member("position", &WiringStep::position),
101 }
102};
103
106 std::optional<double> interval;
107 std::optional<double> duration;
108 std::optional<size_t> times;
109 std::optional<std::vector<WiringStep>> steps;
110
111 static constexpr auto describe()
112 {
113 return std::make_tuple(
119 }
120};
121
122// =============================================================================
123// Sink records
124// =============================================================================
125
127 uint32_t channel {};
128 std::string fn_name;
129
130 static constexpr auto describe()
131 {
132 return std::make_tuple(
135 }
136};
137
139 std::string fn_name;
140
141 static constexpr auto describe()
142 {
143 return std::make_tuple(
145 }
146};
147
148// =============================================================================
149// Locus navigation fields
150// =============================================================================
151
152/**
153 * @brief Serializable subset of Kinesis::NavigationConfig sufficient to seed
154 * a Locus on reconstruct. Dynamic nav state (velocity, yaw accumulation)
155 * is transient and is not encoded.
156 *
157 * @note view_targets are live RenderProcessor pointers and cannot be serialized.
158 * StateDecoder warns on reconstruct; the caller must reconnect them.
159 */
161 glm::vec3 eye {};
162 glm::vec3 target {};
163 glm::vec3 up { 0.0F, 1.0F, 0.0F };
164 float fov { 60.0F };
165 float near_plane { 0.01F };
166 float far_plane { 1000.0F };
167 float speed { 1.0F };
168
169 static constexpr auto describe()
170 {
171 return std::make_tuple(
179 }
180};
181
182// =============================================================================
183// Entity record
184// =============================================================================
185
186/**
187 * @brief Per-entity JSON record.
188 *
189 * `kind` is one of "emitter", "sensor", "agent".
190 * `subkind` is empty for plain Agent, "locus" for Locus, "presence" for Presence.
191 * `locus_nav` is present only when subkind == "locus".
192 */
194 uint32_t id {};
195 std::string kind;
196 std::string subkind;
197 glm::vec3 position {};
198 float intensity { 0.0F };
199 float radius { 0.0F };
200 float query_radius { 0.0F };
201 std::optional<glm::vec3> color;
202 std::optional<float> size;
203 std::string influence_fn_name;
205 std::string radiate_fn_name;
207 std::vector<AudioSinkRecord> audio_sinks;
208 std::vector<RenderSinkRecord> render_sinks;
209 std::optional<LocusNavRecord> locus_nav;
211 std::optional<float> falloff_radius;
212
213 static constexpr auto describe()
214 {
215 return std::make_tuple(
220 IO::member("intensity", &EntityRecord::intensity),
222 IO::member("query_radius", &EntityRecord::query_radius),
225 IO::member("influence_fn_name", &EntityRecord::influence_fn_name),
226 IO::member("perception_fn_name", &EntityRecord::perception_fn_name),
227 IO::member("radiate_fn_name", &EntityRecord::radiate_fn_name),
229 IO::member("audio_sinks", &EntityRecord::audio_sinks),
230 IO::member("render_sinks", &EntityRecord::render_sinks),
233 IO::opt_member("falloff_radius", &EntityRecord::falloff_radius));
234 }
235};
236
237// =============================================================================
238// Expanse record
239// =============================================================================
240
241/**
242 * @brief Per-expanse JSON record.
243 *
244 * Only the function names are serializable; the containment predicate and
245 * crossing callbacks are closures that must be resolved from the Fabric's
246 * function registry on reconstruct. If fn_name is empty the expanse cannot
247 * be reconstructed and the decoder skips it with a warning.
248 */
250 uint32_t id {};
251 std::string fn_name;
252 std::string on_enter_fn_name;
253 std::string on_exit_fn_name;
254
255 static constexpr auto describe()
256 {
257 return std::make_tuple(
260 IO::member("on_enter_fn_name", &ExpanseRecord::on_enter_fn_name),
261 IO::member("on_exit_fn_name", &ExpanseRecord::on_exit_fn_name));
262 }
263};
264
265// =============================================================================
266// Fabric schema
267// =============================================================================
268
271 std::string fabric_name;
272 std::vector<EntityRecord> entities;
273 std::vector<ExpanseRecord> expanses;
275
276 static constexpr auto describe()
277 {
278 return std::make_tuple(
280 IO::member("fabric_name", &FabricSchema::fabric_name),
283 IO::member("ranges", &FabricSchema::ranges));
284 }
285};
286
287// =============================================================================
288// Tapestry schema
289// =============================================================================
290
291/**
292 * @brief Entry in the Tapestry envelope pointing to one Fabric's EXR+JSON pair.
293 */
294struct FabricRef {
295 std::string name;
296 std::string base_path;
297
298 static constexpr auto describe()
299 {
300 return std::make_tuple(
301 IO::member("name", &FabricRef::name),
302 IO::member("base_path", &FabricRef::base_path));
303 }
304};
305
306/**
307 * @brief Tapestry-level named Expanse record. Lives in tapestry.json rather
308 * than any individual fabric file because Tapestry-owned Expanses may
309 * be registered on multiple Fabrics.
310 *
311 * `fabric_ids` lists the runtime Fabric ids that had this Expanse registered
312 * at encode time. On reconstruct the decoder resolves Fabrics by name and
313 * calls Fabric::add_expanse for each.
314 */
316 std::string name;
317 std::string fn_name;
318 std::string on_enter_fn_name;
319 std::string on_exit_fn_name;
320 std::vector<std::string> fabric_names;
321
322 static constexpr auto describe()
323 {
324 return std::make_tuple(
330 }
331};
332
335 std::vector<FabricRef> fabrics;
336 std::vector<TapestryExpanseRecord> expanses;
337 nlohmann::json user_state;
338
339 static constexpr auto describe()
340 {
341 return std::make_tuple(
345 IO::member("user_state", &TapestrySchema::user_state));
346 }
347};
348
349// =============================================================================
350// Kind helpers shared between encoder and decoder
351// =============================================================================
352
353/**
354 * @brief Map Fabric::Kind to its lowercase JSON string token via magic_enum.
355 */
356inline std::string kind_to_string(Fabric::Kind k)
357{
359}
360
361/**
362 * @brief Return true if @p s maps to a known Fabric::Kind token.
363 *
364 * Call this as a gate before parse_kind. Unrecognised strings should be
365 * warned and skipped at the call site; parse_kind assumes the string is valid.
366 */
367inline bool kind_known(std::string_view s)
368{
369 return Reflect::string_to_enum_case_insensitive<Fabric::Kind>(s).has_value();
370}
371
372/**
373 * @brief Parse a JSON kind token to Fabric::Kind (case-insensitive).
374 *
375 * Precondition: kind_known(s) is true. Behaviour is undefined for
376 * unrecognised strings; guard with kind_known before calling.
377 */
378inline Fabric::Kind parse_kind(std::string_view s)
379{
380 return *Reflect::string_to_enum_case_insensitive<Fabric::Kind>(s);
381}
382
383} // namespace MayaFlux::Nexus::State
constexpr auto member(std::string_view key, T Class::*ptr)
constexpr auto opt_member(std::string_view key, std::optional< T > Class::*ptr)
constexpr uint32_t k_schema_version
Current schema version written by StateEncoder and accepted by StateDecoder.
Definition Schema.hpp:20
bool kind_known(std::string_view s)
Return true if s maps to a known Fabric::Kind token.
Definition Schema.hpp:367
Fabric::Kind parse_kind(std::string_view s)
Parse a JSON kind token to Fabric::Kind (case-insensitive).
Definition Schema.hpp:378
constexpr uint32_t k_exr_rows
RGBA32F EXR layout constants shared between encoder and decoder.
Definition Schema.hpp:31
constexpr uint32_t k_channels
Definition Schema.hpp:32
WiringKind
Serializable wiring strategies.
Definition Schema.hpp:85
std::string kind_to_string(Fabric::Kind k)
Map Fabric::Kind to its lowercase JSON string token via magic_enum.
Definition Schema.hpp:356
std::string enum_to_lowercase_string(EnumType value) noexcept
Universal enum to lowercase string converter using magic_enum.
static constexpr auto describe()
Definition Schema.hpp:130
std::optional< LocusNavRecord > locus_nav
Definition Schema.hpp:209
static constexpr auto describe()
Definition Schema.hpp:213
std::optional< float > size
Definition Schema.hpp:202
std::optional< glm::vec3 > color
Definition Schema.hpp:201
std::vector< AudioSinkRecord > audio_sinks
Definition Schema.hpp:207
std::optional< float > falloff_radius
Definition Schema.hpp:211
std::vector< RenderSinkRecord > render_sinks
Definition Schema.hpp:208
Per-entity JSON record.
Definition Schema.hpp:193
static constexpr auto describe()
Definition Schema.hpp:255
Per-expanse JSON record.
Definition Schema.hpp:249
static constexpr auto describe()
Definition Schema.hpp:298
Entry in the Tapestry envelope pointing to one Fabric's EXR+JSON pair.
Definition Schema.hpp:294
static constexpr auto describe()
Definition Schema.hpp:276
std::vector< EntityRecord > entities
Definition Schema.hpp:272
std::vector< ExpanseRecord > expanses
Definition Schema.hpp:273
static constexpr auto describe()
Definition Schema.hpp:169
Serializable subset of Kinesis::NavigationConfig sufficient to seed a Locus on reconstruct.
Definition Schema.hpp:160
static constexpr auto describe()
Definition Schema.hpp:58
static constexpr auto describe()
Definition Schema.hpp:42
static constexpr auto describe()
Definition Schema.hpp:141
std::vector< std::string > fabric_names
Definition Schema.hpp:320
Tapestry-level named Expanse record.
Definition Schema.hpp:315
std::vector< FabricRef > fabrics
Definition Schema.hpp:335
std::vector< TapestryExpanseRecord > expanses
Definition Schema.hpp:336
static constexpr auto describe()
Definition Schema.hpp:339
std::optional< size_t > times
Definition Schema.hpp:108
std::optional< double > interval
Definition Schema.hpp:106
static constexpr auto describe()
Definition Schema.hpp:111
std::optional< std::vector< WiringStep > > steps
Definition Schema.hpp:109
std::optional< double > duration
Definition Schema.hpp:107
static constexpr auto describe()
Definition Schema.hpp:96