MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VertexAccess.cpp
Go to the documentation of this file.
1#include "VertexAccess.hpp"
2
4
5namespace MayaFlux::Kakshya {
6
7namespace {
8
9 void floats_to_waveform(std::span<const float> src, std::byte* dst)
10 {
11 const size_t count = src.size();
12 auto* out = reinterpret_cast<glm::vec3*>(dst);
13 const float inv = (count > 1) ? (2.0F / static_cast<float>(count - 1)) : 0.0F;
14
15 for (size_t i = 0; i < count; ++i) {
16 out[i] = glm::vec3(static_cast<float>(i) * inv - 1.0F, src[i], 0.0F);
17 }
18 }
19
20 VertexLayout position_only_layout(uint32_t count)
21 {
22 VertexLayout layout;
23 layout.vertex_count = count;
24 layout.stride_bytes = sizeof(glm::vec3);
25 layout.attributes.push_back({ .component_modality = DataModality::VERTEX_POSITIONS_3D,
26 .offset_in_vertex = 0,
27 .name = "position" });
28 return layout;
29 }
30
31 VertexLayout position_2d_layout(uint32_t count)
32 {
33 VertexLayout layout;
34 layout.vertex_count = count;
35 layout.stride_bytes = sizeof(glm::vec2);
36 layout.attributes.push_back({ .component_modality = DataModality::TEXTURE_COORDS_2D,
37 .offset_in_vertex = 0,
38 .name = "position2d" });
39 return layout;
40 }
41
42 VertexLayout position_w_layout(uint32_t count)
43 {
44 VertexLayout layout;
45 layout.vertex_count = count;
46 layout.stride_bytes = sizeof(glm::vec4);
47 layout.attributes.push_back({ .component_modality = DataModality::VERTEX_COLORS_RGBA,
48 .offset_in_vertex = 0,
49 .name = "position_w" });
50 return layout;
51 }
52
53 VertexLayout waveform_layout(uint32_t count)
54 {
55 VertexLayout layout;
56 layout.vertex_count = count;
57 layout.stride_bytes = sizeof(glm::vec3);
58 layout.attributes.push_back({ .component_modality = DataModality::VERTEX_POSITIONS_3D,
59 .offset_in_vertex = 0,
60 .name = "position" });
61 return layout;
62 }
63
64 // =========================================================================
65 // Shared interleaved write helpers
66 // =========================================================================
67
68 /**
69 * Write N point vertices into dst.
70 * positions must have exactly count elements.
71 * dst must be pre-sized to count * 60 bytes.
72 */
73 void write_point_vertices(
74 std::span<const glm::vec3> positions,
75 const VertexAccessConfig& cfg,
76 std::byte* dst)
77 {
78 for (size_t i = 0; i < positions.size(); ++i) {
79 std::byte* v = dst + i * 60;
80 std::memcpy(v, &positions[i], 12);
81 std::memcpy(v + 12, &cfg.default_color, 12);
82 std::memcpy(v + 24, &cfg.default_size, 4);
83 std::memcpy(v + 28, &cfg.default_uv, 8);
84 std::memcpy(v + 36, &cfg.default_normal, 12);
85 std::memcpy(v + 48, &cfg.default_tangent, 12);
86 }
87 }
88
89 /**
90 * Write N line vertices into dst.
91 * positions must have exactly count elements.
92 * dst must be pre-sized to count * 60 bytes.
93 */
94 void write_line_vertices(
95 std::span<const glm::vec3> positions,
96 const VertexAccessConfig& cfg,
97 std::byte* dst)
98 {
99 for (size_t i = 0; i < positions.size(); ++i) {
100 std::byte* v = dst + i * 60;
101 std::memcpy(v, &positions[i], 12);
102 std::memcpy(v + 12, &cfg.default_color, 12);
103 std::memcpy(v + 24, &cfg.default_thickness, 4);
104 std::memcpy(v + 28, &cfg.default_uv, 8);
105 std::memcpy(v + 36, &cfg.default_normal, 12);
106 std::memcpy(v + 48, &cfg.default_tangent, 12);
107 }
108 }
109
110 /**
111 * Write N mesh vertices into dst.
112 * positions must have exactly count elements.
113 * dst must be pre-sized to count * 60 bytes.
114 */
115 void write_mesh_vertices(
116 std::span<const glm::vec3> positions,
117 const VertexAccessConfig& cfg,
118 std::byte* dst)
119 {
120 for (size_t i = 0; i < positions.size(); ++i) {
121 std::byte* v = dst + i * 60;
122 std::memcpy(v, &positions[i], 12);
123 std::memcpy(v + 12, &cfg.default_color, 12);
124 std::memcpy(v + 24, &cfg.default_weight, 4);
125 std::memcpy(v + 28, &cfg.default_uv, 8);
126 std::memcpy(v + 36, &cfg.default_normal, 12);
127 std::memcpy(v + 48, &cfg.default_tangent, 12);
128 }
129 }
130
131 // =========================================================================
132 // Shared position extraction — reuses existing waveform + DataConverter paths
133 // =========================================================================
134
135 /**
136 * Extract positions from any DataVariant into a vector<vec3>.
137 * GLM types are mapped directly; scalar/integer/complex go through
138 * the same waveform path as as_vertex_access().
139 * Returns empty on rejected types (complex<double>, mat4).
140 */
141 std::vector<glm::vec3> extract_positions(const DataVariant& variant)
142 {
143 return std::visit([variant](const auto& vec) -> std::vector<glm::vec3> {
144 using V = typename std::decay_t<decltype(vec)>::value_type;
145 const size_t count = vec.size();
146
147 if (count == 0) {
148 return {};
149 }
150
151 if constexpr (std::is_same_v<V, glm::vec3>) {
152 return std::vector<glm::vec3>(vec.begin(), vec.end());
153 }
154
155 if constexpr (std::is_same_v<V, glm::vec2>) {
156 std::vector<glm::vec3> out(count);
157 for (size_t i = 0; i < count; ++i) {
158 out[i] = glm::vec3(vec[i].x, vec[i].y, 0.0F);
159 }
160 return out;
161 }
162
163 if constexpr (std::is_same_v<V, glm::vec4>) {
164 std::vector<glm::vec3> out(count);
165 for (size_t i = 0; i < count; ++i) {
166 out[i] = glm::vec3(vec[i].x, vec[i].y, vec[i].z);
167 }
168 return out;
169 }
170
171 if constexpr (DecimalData<V> || IntegerData<V>) {
172 std::vector<float> floats;
173 extract_from_variant<float>(variant, floats);
174
175 const float inv = count > 1
176 ? 2.0F / static_cast<float>(count - 1)
177 : 0.0F;
178
179 std::vector<glm::vec3> out(count);
180 for (size_t i = 0; i < count; ++i) {
181 out[i] = glm::vec3(static_cast<float>(i) * inv - 1.0F,
182 floats[i], 0.0F);
183 }
184 return out;
185 }
186
187 if constexpr (std::is_same_v<V, std::complex<float>>) {
188 std::vector<float> magnitudes;
189 extract_from_variant<float>(variant, magnitudes,
191
192 constexpr float inv_pi = std::numbers::inv_pi_v<float>;
193 const float inv = count > 1
194 ? 2.0F / static_cast<float>(count - 1)
195 : 0.0F;
196
197 std::vector<glm::vec3> out(count);
198 for (size_t i = 0; i < count; ++i) {
199 out[i] = glm::vec3(static_cast<float>(i) * inv - 1.0F,
200 magnitudes[i],
201 std::arg(vec[i]) * inv_pi);
202 }
203 return out;
204 }
205
206 // complex<double> and mat4 rejected
207 return {};
208 },
209 variant);
210 }
211
212} // namespace
213
214std::optional<VertexAccess> as_vertex_access(const DataVariant& variant)
215{
216 return std::visit([&variant](const auto& vec) -> std::optional<VertexAccess> {
217 using V = typename std::decay_t<decltype(vec)>::value_type;
218 const size_t count = vec.size();
219
220 if (count == 0) {
222 "as_vertex_access: empty variant");
223 return std::nullopt;
224 }
225
226 if constexpr (std::is_same_v<V, glm::vec3>) {
227 return VertexAccess { vec.data(), count * sizeof(glm::vec3),
228 position_only_layout(static_cast<uint32_t>(count)) };
229 }
230
231 if constexpr (std::is_same_v<V, glm::vec2>) {
232 return VertexAccess { vec.data(), count * sizeof(glm::vec2),
233 position_2d_layout(static_cast<uint32_t>(count)) };
234 }
235
236 if constexpr (std::is_same_v<V, glm::vec4>) {
237 return VertexAccess { vec.data(), count * sizeof(glm::vec4),
238 position_w_layout(static_cast<uint32_t>(count)) };
239 }
240
241 if constexpr (DecimalData<V> || IntegerData<V>) {
242 if constexpr (std::is_same_v<V, double>) {
244 "as_vertex_access: double narrowed to float for vertex waveform");
245 }
246
247 std::vector<float> floats;
248 extract_from_variant<float>(variant, floats);
249
250 VertexAccess va;
251 va.conversion_buffer.resize(count * sizeof(glm::vec3));
252 floats_to_waveform(floats, va.conversion_buffer.data());
253 va.data_ptr = va.conversion_buffer.data();
254 va.byte_count = va.conversion_buffer.size();
255 va.layout = waveform_layout(static_cast<uint32_t>(count));
256 return va;
257 }
258
259 if constexpr (std::is_same_v<V, std::complex<float>>) {
260 std::vector<float> magnitudes;
261 extract_from_variant<float>(variant, magnitudes,
263
264 constexpr float inv_pi = std::numbers::inv_pi_v<float>;
265 const float inv = (count > 1) ? (2.0F / static_cast<float>(count - 1)) : 0.0F;
266
267 VertexAccess va;
268 va.conversion_buffer.resize(count * sizeof(glm::vec3));
269 auto* out = reinterpret_cast<glm::vec3*>(va.conversion_buffer.data());
270
271 for (size_t i = 0; i < count; ++i) {
272 out[i] = glm::vec3(
273 static_cast<float>(i) * inv - 1.0F,
274 magnitudes[i],
275 std::arg(vec[i]) * inv_pi);
276 }
277
278 va.data_ptr = va.conversion_buffer.data();
279 va.byte_count = va.conversion_buffer.size();
280 va.layout = waveform_layout(static_cast<uint32_t>(count));
281 return va;
282 }
283
284 if constexpr (std::is_same_v<V, std::complex<double>>) {
286 "as_vertex_access: complex<double> rejected: convert to "
287 "complex<float> or extract components manually");
288 return std::nullopt;
289 }
290
291 if constexpr (std::is_same_v<V, glm::mat4>) {
293 "as_vertex_access: glm::mat4 rejected: unpack to vec4 columns first");
294 return std::nullopt;
295 }
296
297 return std::nullopt;
298 },
299 variant);
300}
301
302std::optional<VertexAccess> as_point_vertex_access(
303 const DataVariant& variant,
304 const VertexAccessConfig& config)
305{
306 auto positions = extract_positions(variant);
307 if (positions.empty()) {
309 "as_point_vertex_access: unsupported or empty variant");
310 return std::nullopt;
311 }
312
313 const auto count = static_cast<uint32_t>(positions.size());
314 VertexAccess va;
315 va.conversion_buffer.resize((size_t)count * 60);
316 write_point_vertices(positions, config, va.conversion_buffer.data());
317 va.data_ptr = va.conversion_buffer.data();
318 va.byte_count = va.conversion_buffer.size();
321
322 return va;
323}
324
325std::optional<VertexAccess> as_line_vertex_access(
326 const DataVariant& variant,
327 const VertexAccessConfig& config)
328{
329 auto positions = extract_positions(variant);
330 if (positions.empty()) {
332 "as_line_vertex_access: unsupported or empty variant");
333 return std::nullopt;
334 }
335
336 const auto count = static_cast<uint32_t>(positions.size());
337 VertexAccess va;
338 va.conversion_buffer.resize((size_t)count * 60);
339 write_line_vertices(positions, config, va.conversion_buffer.data());
340 va.data_ptr = va.conversion_buffer.data();
341 va.byte_count = va.conversion_buffer.size();
344 return va;
345}
346
347std::optional<VertexAccess> as_mesh_vertex_access(
348 const DataVariant& variant,
349 const VertexAccessConfig& config)
350{
351 auto positions = extract_positions(variant);
352 if (positions.empty()) {
354 "as_mesh_vertex_access: unsupported or empty variant");
355 return std::nullopt;
356 }
357
358 const auto count = static_cast<uint32_t>(positions.size());
359 VertexAccess va;
360 va.conversion_buffer.resize((size_t)count * 60);
361 write_mesh_vertices(positions, config, va.conversion_buffer.data());
362 va.data_ptr = va.conversion_buffer.data();
363 va.byte_count = va.conversion_buffer.size();
366 return va;
367}
368
369} // namespace MayaFlux::Kakshya
#define MF_ERROR(comp, ctx,...)
#define MF_TRACE(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Eigen::Index count
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
std::optional< VertexAccess > as_line_vertex_access(const DataVariant &variant, const VertexAccessConfig &config)
Convert DataVariant to line-vertex-compatible bytes.
std::optional< VertexAccess > as_mesh_vertex_access(const DataVariant &variant, const VertexAccessConfig &config)
Convert DataVariant to mesh-vertex-compatible bytes.
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:76
@ MAGNITUDE
|z| = sqrt(real² + imag²)
std::optional< VertexAccess > as_vertex_access(const DataVariant &variant)
Extract a VertexAccess from a DataVariant.
std::optional< VertexAccess > as_point_vertex_access(const DataVariant &variant, const VertexAccessConfig &config)
Convert DataVariant to point-vertex-compatible bytes.
Default attribute values for shader-compatible vertex conversion.
std::vector< std::byte > conversion_buffer
Conversion buffer.
Memory-compatible view of a DataVariant for vertex buffer upload.
uint32_t vertex_count
Total number of vertices in this buffer.
static VertexLayout for_lines(uint32_t stride=60)
Factory: layout for LineVertex (position, color, thickness, uv, normal, tangent)
static VertexLayout for_meshes(uint32_t stride=60)
Factory: layout for MeshVertex (position, color, weight, uv, normal, tangent)
static VertexLayout for_points(uint32_t stride=60)
Factory: layout for PointVertex (position, color, size, uv, normal, tangent)