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 // Canonical field layout: vec3 pos(12) | vec3 color(12) | float scalar(4) | vec2 uv(8) | vec3 normal(12) | vec3 tangent(12)
10 // Channel slot -> (offset, size)
11 constexpr std::array<std::pair<size_t, size_t>, 6> k_channel_layout { {
12 { 0, 12 }, // vec3 position
13 { 12, 12 }, // vec3 color
14 { 24, 4 }, // float scalar
15 { 28, 8 }, // vec2 uv
16 { 36, 12 }, // vec3 normal
17 { 48, 12 }, // vec3 tangent
18 } };
19
20 /**
21 * Returns (data pointer, element count, element size in bytes) for a channel variant.
22 * Element size is the sizeof of the stored type, not the canonical field size.
23 */
24 struct ChannelView {
25 const uint8_t* ptr;
26 size_t count;
28 };
29
30 ChannelView channel_view(const DataVariant& v)
31 {
32 return std::visit([](const auto& vec) -> ChannelView {
33 using V = typename std::decay_t<decltype(vec)>::value_type;
34 if (vec.empty())
35 return { .ptr = nullptr, .count = 0, .element_bytes = sizeof(V) };
36 return {
37 reinterpret_cast<const uint8_t*>(vec.data()),
38 vec.size(),
39 sizeof(V)
40 };
41 },
42 v);
43 }
44
45 void assemble_vertices(
46 std::span<const DataVariant> channels,
47 size_t count,
48 const VertexAccessConfig& cfg,
49 float slot24_default,
50 std::byte* dst)
51 {
52 const void* defaults[6] = {
53 nullptr,
54 &cfg.default_color,
55 &slot24_default,
56 &cfg.default_uv,
57 &cfg.default_normal,
58 &cfg.default_tangent,
59 };
60
61 for (size_t i = 0; i < count; ++i) {
62 std::byte* v = dst + i * 60;
63 for (size_t s = 0; s < 6; ++s) {
64 auto [dst_off, dst_sz] = k_channel_layout[s];
65 if (s < channels.size()) {
66 auto cv = channel_view(channels[s]);
67 // copy min(src element size, dst field size) bytes, zero-pad remainder
68 const size_t copy_sz = std::min(cv.element_bytes, dst_sz);
69 std::memcpy(v + dst_off, cv.ptr + i * cv.element_bytes, copy_sz);
70 if (copy_sz < dst_sz) {
71 std::memset(v + dst_off + copy_sz, 0, dst_sz - copy_sz);
72 }
73 } else {
74 std::memcpy(v + dst_off, defaults[s], dst_sz);
75 }
76 }
77 }
78 }
79
80} // namespace
81
82std::optional<VertexAccess> as_vertex_access(
83 std::span<const DataVariant> channels,
84 const VertexAccessConfig& config)
85{
86 return as_point_vertex_access(channels, config);
87}
88
89std::optional<VertexAccess> as_point_vertex_access(
90 std::span<const DataVariant> channels,
91 const VertexAccessConfig& config)
92{
93 if (channels.empty()) {
95 "as_point_vertex_access: no channels supplied");
96 return std::nullopt;
97 }
98
99 // Zero-copy path: single uint8_t channel of N*60 bytes is already interleaved.
100 if (channels.size() == 1) {
101 if (const auto* b = std::get_if<std::vector<uint8_t>>(&channels[0])) {
102 if (b->size() % 60 != 0) {
104 "as_point_vertex_access: uint8_t byte count {} not a multiple of 60",
105 b->size());
106 return std::nullopt;
107 }
108 const auto count = static_cast<uint32_t>(b->size() / 60);
109 auto layout = VertexLayout::for_points();
110 layout.vertex_count = count;
111 return VertexAccess { .data_ptr = b->data(), .byte_count = b->size(), .layout = layout };
112 }
113 }
114
115 const size_t count = channel_view(channels[0]).count;
116 if (count == 0) {
118 "as_point_vertex_access: position channel (slot 0) is empty or unsupported");
119 return std::nullopt;
120 }
121
122 VertexAccess va;
123 va.conversion_buffer.resize(count * 60);
124 assemble_vertices(channels, count, config, config.default_size,
125 va.conversion_buffer.data());
126 va.data_ptr = va.conversion_buffer.data();
127 va.byte_count = va.conversion_buffer.size();
129 va.layout.vertex_count = static_cast<uint32_t>(count);
130 return va;
131}
132
133std::optional<VertexAccess> as_line_vertex_access(
134 std::span<const DataVariant> channels,
135 const VertexAccessConfig& config)
136{
137 if (channels.empty()) {
139 "as_line_vertex_access: no channels supplied");
140 return std::nullopt;
141 }
142
143 if (channels.size() == 1) {
144 if (const auto* b = std::get_if<std::vector<uint8_t>>(&channels[0])) {
145 if (b->size() % 60 != 0) {
147 "as_line_vertex_access: uint8_t byte count {} not a multiple of 60",
148 b->size());
149 return std::nullopt;
150 }
151 const auto count = static_cast<uint32_t>(b->size() / 60);
152 auto layout = VertexLayout::for_lines();
153 layout.vertex_count = count;
154 return VertexAccess { .data_ptr = b->data(), .byte_count = b->size(), .layout = layout };
155 }
156 }
157
158 const size_t count = channel_view(channels[0]).count;
159 if (count == 0) {
161 "as_line_vertex_access: position channel (slot 0) is empty or unsupported");
162 return std::nullopt;
163 }
164
165 VertexAccess va;
166 va.conversion_buffer.resize(count * 60);
167 assemble_vertices(channels, count, config, config.default_thickness,
168 va.conversion_buffer.data());
169 va.data_ptr = va.conversion_buffer.data();
170 va.byte_count = va.conversion_buffer.size();
172 va.layout.vertex_count = static_cast<uint32_t>(count);
173 return va;
174}
175
176std::optional<VertexAccess> as_mesh_vertex_access(
177 std::span<const DataVariant> channels,
178 const VertexAccessConfig& config)
179{
180 if (channels.empty()) {
182 "as_mesh_vertex_access: no channels supplied");
183 return std::nullopt;
184 }
185
186 if (channels.size() == 1) {
187 if (const auto* b = std::get_if<std::vector<uint8_t>>(&channels[0])) {
188 if (b->size() % 60 != 0) {
190 "as_mesh_vertex_access: uint8_t byte count {} not a multiple of 60",
191 b->size());
192 return std::nullopt;
193 }
194 const auto count = static_cast<uint32_t>(b->size() / 60);
195 auto layout = VertexLayout::for_meshes();
196 layout.vertex_count = count;
197 return VertexAccess { .data_ptr = b->data(), .byte_count = b->size(), .layout = layout };
198 }
199 }
200
201 const size_t count = channel_view(channels[0]).count;
202 if (count == 0) {
204 "as_mesh_vertex_access: position channel (slot 0) is empty or unsupported");
205 return std::nullopt;
206 }
207
208 VertexAccess va;
209 va.conversion_buffer.resize(count * 60);
210 assemble_vertices(channels, count, config, config.default_weight,
211 va.conversion_buffer.data());
212 va.data_ptr = va.conversion_buffer.data();
213 va.byte_count = va.conversion_buffer.size();
215 va.layout.vertex_count = static_cast<uint32_t>(count);
216 return va;
217}
218
219} // namespace MayaFlux::Kakshya
#define MF_ERROR(comp, ctx,...)
size_t b
size_t count
const uint8_t * ptr
size_t element_bytes
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
std::optional< VertexAccess > as_line_vertex_access(std::span< const DataVariant > channels, const VertexAccessConfig &config)
Assemble line-vertex-compatible bytes from one or more data channels.
std::optional< VertexAccess > as_point_vertex_access(std::span< const DataVariant > channels, const VertexAccessConfig &config)
Assemble point-vertex-compatible bytes from one or more data channels.
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
std::optional< VertexAccess > as_mesh_vertex_access(std::span< const DataVariant > channels, const VertexAccessConfig &config)
Assemble mesh-vertex-compatible bytes from one or more data channels.
std::optional< VertexAccess > as_vertex_access(std::span< const DataVariant > channels, const VertexAccessConfig &config)
Extract a VertexAccess from a DataVariant.
Default attribute values for shader-compatible vertex conversion.
std::vector< std::byte > conversion_buffer
Conversion buffer.
Memory-compatible view of channel data assembled into full 60-byte vertices.
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)