MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VolumeData.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Kakshya {
7
8/**
9 * @struct VolumeField
10 * @brief One named quantity sampled over a lattice, held in host memory.
11 *
12 * Value storage is a variant over float and glm::vec3, chosen by the
13 * producer from the source field's per-cell stride. There is no vec4
14 * variant: padding is a GPU alignment concern and is stripped on the way
15 * out, so no consumer of this struct ever sees a component it must skip.
16 *
17 * Values are stored densely in the lattice's own index order, x fastest,
18 * z slowest, one element per cell with no gaps. Sparsity is a property of
19 * the formats this feeds, not of this struct: a writer decides which cells
20 * are active by thresholding, and the decision does not travel here.
21 *
22 * The name is the producer's own string, taken verbatim from wherever the
23 * field was declared. Consumers that care about conventional names
24 * (density, temperature, velocity) match on it; nothing rewrites it.
25 */
27 using ValueStorage = std::variant<
28 std::vector<float>,
29 std::vector<glm::vec3>>;
30
31 std::string name;
34
35 /**
36 * @brief Whether the active variant holds vectors rather than scalars.
37 */
38 [[nodiscard]] bool is_vector() const
39 {
40 return std::holds_alternative<std::vector<glm::vec3>>(values);
41 }
42
43 /**
44 * @brief Number of cells represented, dispatched on variant.
45 *
46 * One element per cell in both cases, so this is a cell count and not
47 * a component count.
48 */
49 [[nodiscard]] size_t element_count() const
50 {
51 return std::visit(
52 [](const auto& vec) { return vec.size(); },
53 values);
54 }
55
56 /**
57 * @brief Total byte size of value storage, dispatched on variant.
58 */
59 [[nodiscard]] size_t byte_size() const
60 {
61 return std::visit(
62 [](const auto& vec) {
63 return vec.size() * sizeof(typename std::decay_t<decltype(vec)>::value_type);
64 },
65 values);
66 }
67
68 /**
69 * @brief Raw data pointer, dispatched on variant. For writer paths.
70 */
71 [[nodiscard]] const void* data() const
72 {
73 return std::visit(
74 [](const auto& vec) -> const void* { return vec.data(); },
75 values);
76 }
77
78 /**
79 * @brief Typed accessors. Return nullptr if the variant does not match.
80 */
81 [[nodiscard]] const std::vector<float>* as_scalar() const { return std::get_if<std::vector<float>>(&values); }
82 [[nodiscard]] const std::vector<glm::vec3>* as_vector() const { return std::get_if<std::vector<glm::vec3>>(&values); }
83
84 [[nodiscard]] std::vector<float>* as_scalar() { return std::get_if<std::vector<float>>(&values); }
85 [[nodiscard]] std::vector<glm::vec3>* as_vector() { return std::get_if<std::vector<glm::vec3>>(&values); }
86};
87
88/**
89 * @struct VolumeData
90 * @brief A lattice and every field sampled over it, held in host memory.
91 *
92 * The interchange currency between whatever produced the values and
93 * whatever writes them. Parallels ImageData: no Vulkan awareness, no
94 * ownership of GPU resources, no knowledge of any file format. A writer
95 * receives one of these and nothing else.
96 *
97 * All fields share the lattice. A producer wanting fields at differing
98 * resolutions emits several VolumeData rather than one, which matches how
99 * every target format treats a resolution change anyway.
100 *
101 * The lattice carries the world-space bounds and resolution, so a writer
102 * derives voxel size from cell_size() and the index-to-world mapping from
103 * cell_center() without further arguments. There is no time member: a
104 * frame sequence is a sequence of these, numbered by the caller.
105 *
106 * Field order is the producer's order and is preserved. Nothing depends on
107 * it, but a reader diffing two files will thank you.
108 */
111 std::vector<VolumeField> fields;
112
113 /**
114 * @brief Cells in the lattice, which every field's element_count()
115 * must equal.
116 */
117 [[nodiscard]] size_t cell_count() const { return lattice.cell_count(); }
118
119 /**
120 * @brief Resolve a field by name.
121 * @param name Field name, matched exactly.
122 * @return Pointer to the field, or nullptr if no field carries that name.
123 */
124 [[nodiscard]] const VolumeField* find(const std::string& name) const
125 {
126 for (const auto& field : fields) {
127 if (field.name == name) {
128 return &field;
129 }
130 }
131 return nullptr;
132 }
133
134 /**
135 * @brief Check that every field is densely populated over the lattice.
136 *
137 * Verifies a nonzero lattice, at least one field, no empty or duplicated
138 * names, and that each field holds exactly cell_count() elements.
139 *
140 * Producers should invoke this before handing the data to a writer.
141 * Writers should invoke it before trusting any pointer they take from
142 * it, as EXRWriter does with ImageData.
143 */
144 [[nodiscard]] bool is_consistent() const
145 {
146 if (cell_count() == 0 || fields.empty()) {
147 return false;
148 }
149
150 for (size_t i = 0; i < fields.size(); ++i) {
151 if (fields[i].name.empty() || fields[i].element_count() != cell_count()) {
152 return false;
153 }
154 for (size_t j = i + 1; j < fields.size(); ++j) {
155 if (fields[i].name == fields[j].name) {
156 return false;
157 }
158 }
159 }
160
161 return true;
162 }
163};
164
165} // namespace MayaFlux::Kakshya
std::string name
Definition VKDevice.cpp:143
bool is_consistent() const
Check that every field is densely populated over the lattice.
const VolumeField * find(const std::string &name) const
Resolve a field by name.
size_t cell_count() const
Cells in the lattice, which every field's element_count() must equal.
std::vector< VolumeField > fields
A lattice and every field sampled over it, held in host memory.
std::vector< float > * as_scalar()
const std::vector< glm::vec3 > * as_vector() const
Kinesis::LatticeSemantics semantics
std::variant< std::vector< float >, std::vector< glm::vec3 > > ValueStorage
size_t byte_size() const
Total byte size of value storage, dispatched on variant.
const std::vector< float > * as_scalar() const
Typed accessors.
const void * data() const
Raw data pointer, dispatched on variant.
bool is_vector() const
Whether the active variant holds vectors rather than scalars.
std::vector< glm::vec3 > * as_vector()
size_t element_count() const
Number of cells represented, dispatched on variant.
One named quantity sampled over a lattice, held in host memory.
size_t cell_count() const noexcept
Total cell count.
Definition Lattice.hpp:36
A regular subdivision of an AABB3D into a cell count per axis.
Definition Lattice.hpp:25
Interpretation attached to one named quantity sampled over a lattice.