MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GeometryWriterNode.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "GpuSync.hpp"
5
7
8/**
9 * @class GeometryWriterNode
10 * @brief Base class for nodes that generate 3D geometry data
11 *
12 * Analogous to TextureNode but for vertex geometry instead of pixel data.
13 * Each frame (at VISUAL_RATE), compute_frame() is called to generate new vertex data.
14 * Vertex data is stored as a flat array in configurable interleaved or non-interleaved format.
15 *
16 * Subclasses implement compute_frame() to populate m_vertex_buffer with vertex data.
17 * The buffer follows a user-defined stride (bytes per vertex) allowing flexible vertex formats:
18 * - Positions only (3 floats = 12 bytes per vertex)
19 * - Positions + Colors (3 + 3 floats = 24 bytes per vertex)
20 * - Positions + Normals + Texcoords (3 + 3 + 2 floats = 32 bytes per vertex)
21 * - Any custom interleaved format
22 *
23 * Usage:
24 * ```cpp
25 * class MyParticleSystem : public GeometryWriterNode {
26 * void compute_frame() override {
27 * std::vector<glm::vec3> positions;
28 * for (int i = 0; i < 1000; i++) {
29 * positions.push_back(generate_particle(i));
30 * }
31 *
32 * set_vertex_stride(sizeof(glm::vec3));
33 * resize_vertex_buffer(positions.size());
34 * memcpy(m_vertex_buffer.data(), positions.data(),
35 * positions.size() * sizeof(glm::vec3));
36 * m_vertex_count = positions.size();
37 * }
38 * };
39 * ```
40 */
41class MAYAFLUX_API GeometryWriterNode : public GpuSync {
42protected:
43 /// @brief Vertex data buffer (flat array of bytes)
44 std::vector<uint8_t> m_vertex_buffer;
45
46 /// @brief Number of vertices in buffer
47 uint32_t m_vertex_count {};
48
49 /// @brief Bytes per vertex (stride for vertex buffer binding)
50 size_t m_vertex_stride {};
51
52 /// @brief Cached vertex layout for descriptor binding
53 std::optional<Kakshya::VertexLayout> m_vertex_layout;
54
55 /// @brief Flag indicating if layout needs update
56 bool m_needs_layout_update {};
57
58 /**
59 * @brief Flag: vertex data or layout changed since last GPU upload
60 *
61 * Set to true whenever compute_frame() modifies vertex buffer or layout.
62 * Checked by GeometryBindingsProcessor before staging GPU transfer.
63 * Cleared by processor after successful upload.
64 */
65 bool m_vertex_data_dirty { true };
66
67public:
68 /**
69 * @brief Constructor
70 * @param initial_capacity Initial number of vertices to reserve space for
71 */
72 GeometryWriterNode(uint32_t initial_capacity = 1024);
73
74 ~GeometryWriterNode() override = default;
75
76 /**
77 * @brief Process batch for geometry generation
78 * @param num_samples Number of frames to process
79 * @return Empty vector (geometry nodes don't produce audio output)
80 *
81 * Calls compute_frame() once per batch.
82 * Subclasses can override for custom batch behavior.
83 */
84 std::vector<double> process_batch(unsigned int num_samples) override;
85
86 /**
87 * @brief Get raw vertex buffer data
88 * @return Span of float data (interpreted as bytes, stride-aligned)
89 */
90 [[nodiscard]] std::span<const uint8_t> get_vertex_data() const { return m_vertex_buffer; }
91
92 /**
93 * @brief Get vertex buffer size in bytes
94 * @return Total size of vertex data buffer
95 */
96 [[nodiscard]] size_t get_vertex_buffer_size_bytes() const;
97
98 /**
99 * @brief Get number of vertices
100 * @return Current vertex count
101 */
102 [[nodiscard]] uint32_t get_vertex_count() const { return m_vertex_count; }
103
104 /**
105 * @brief Get stride (bytes per vertex)
106 * @return Stride in bytes
107 */
108 [[nodiscard]] size_t get_vertex_stride() const { return m_vertex_stride; }
109
110 /**
111 * @brief Set vertex stride (bytes per vertex)
112 * @param stride Stride in bytes
113 *
114 * Must be called before filling buffer. Common values:
115 * - 12 (vec3 positions only)
116 * - 24 (vec3 positions + vec3 colors)
117 * - 32 (vec3 positions + vec3 normals + vec2 texcoords)
118 */
119 void set_vertex_stride(size_t stride);
120
121 /**
122 * @brief Resize vertex buffer to hold specified number of vertices
123 * @param vertex_count Number of vertices
124 * @param preserve_data If true, keep existing data; if false, clear buffer
125 *
126 * Allocates/reallocates buffer to hold vertex_count vertices at current stride.
127 * If stride is 0, logs error and does nothing.
128 */
129 void resize_vertex_buffer(uint32_t vertex_count, bool preserve_data = false);
130
131 /**
132 * @brief Copy raw vertex data into buffer
133 * @param data Pointer to vertex data
134 * @param size_bytes Number of bytes to copy
135 *
136 * Direct memory copy into m_vertex_buffer.
137 * User is responsible for ensuring data format matches stride.
138 */
139 void set_vertex_data(const void* data, size_t size_bytes);
140
141 /**
142 * @brief Set a single vertex by index
143 * @param vertex_index Index of vertex to set
144 * @param data Pointer to vertex data
145 * @param size_bytes Size of vertex data (should match stride)
146 *
147 * Copies size_bytes starting at (vertex_index * stride).
148 */
149 void set_vertex(uint32_t vertex_index, const void* data, size_t size_bytes);
150
151 /**
152 * @brief Get a single vertex by index
153 * @param vertex_index Index of vertex
154 * @return Span covering this vertex's data
155 */
156 [[nodiscard]] std::span<const uint8_t> get_vertex(uint32_t vertex_index) const;
157
158 /**
159 * @brief Set multiple vertices from typed array
160 * @tparam T Vertex type
161 * @param vertices Span of vertex data
162 *
163 * Sets vertex stride to sizeof(T), resizes buffer, and copies data.
164 */
165 template <typename T>
166 void set_vertices(std::span<const T> vertices)
167 {
168 set_vertex_stride(sizeof(T));
169 resize_vertex_buffer(vertices.size());
170 std::memcpy(m_vertex_buffer.data(), vertices.data(),
171 vertices.size() * sizeof(T));
172 m_vertex_count = static_cast<uint32_t>(vertices.size());
173 m_needs_layout_update = true;
174 m_vertex_data_dirty = true;
175 }
176
177 /**
178 * @brief Set a single vertex by index from typed data
179 * @tparam T Vertex type
180 * @param index Index of vertex to set
181 * @param vertex Vertex data
182 */
183 template <typename T>
184 void set_vertex_typed(uint32_t index, const T& vertex)
185 {
186 set_vertex(index, &vertex, sizeof(T));
187 }
188
189 /**
190 * @brief Get a single vertex by index as typed data
191 * @tparam T Vertex type
192 * @param index Index of vertex
193 * @return Vertex data of type T
194 */
195 template <typename T>
196 T get_vertex_typed(uint32_t index) const
197 {
198 auto data = get_vertex(index);
199 if (data.size_bytes() < sizeof(T)) {
200 return T {};
201 }
202 T result;
203 std::memcpy(&result, data.data(), sizeof(T));
204 return result;
205 }
206
207 /**
208 * @brief Clear vertex buffer and reset count
209 */
210 void clear();
211
212 /**
213 * @brief Clear vertex buffer and resize to specified count
214 * @param vertex_count Number of vertices
215 */
216 void clear_and_resize(uint32_t vertex_count);
217
218 /**
219 * @brief Set cached vertex layout
220 * @param layout VertexLayout describing attribute structure
221 *
222 * Called internally or by GeometryBindingsProcessor to describe
223 * the semantic meaning of vertex data (positions, colors, normals, etc.)
224 */
225 void set_vertex_layout(const Kakshya::VertexLayout& layout) { m_vertex_layout = layout; }
226
227 /**
228 * @brief Get cached vertex layout
229 * @return Optional containing layout if set
230 */
231 [[nodiscard]] std::optional<Kakshya::VertexLayout> get_vertex_layout() const { return m_vertex_layout; }
232
233 /**
234 * @brief Check if layout needs update
235 * @return True if stride or vertex count changed
236 */
237 [[nodiscard]] bool needs_layout_update() const { return m_needs_layout_update; }
238
239 /**
240 * @brief Clear layout update flag
241 */
242 void clear_layout_update_flag() { m_needs_layout_update = false; }
243
244 /**
245 * @brief Save current geometry state
246 *
247 * Saves vertex buffer, count, stride, and layout.
248 * Subclasses can override to save additional state.
249 */
250 void save_state() override;
251
252 /**
253 * @brief Restore saved geometry state
254 *
255 * Restores vertex buffer, count, stride, and layout.
256 * Subclasses can override to restore additional state.
257 */
258 void restore_state() override;
259
260 /**
261 * @brief Check if vertex data or layout changed since last GPU sync
262 * @return True if m_vertex_buffer or m_vertex_layout has been modified
263 *
264 * For geometry, this combines data mutation (vertex_buffer changed) and
265 * structural change (stride or layout changed).
266 */
267 [[nodiscard]] bool needs_gpu_update() const override
268 {
269 return m_vertex_data_dirty || m_needs_layout_update;
270 }
271
272 /**
273 * @brief Clear the dirty flag after GPU upload completes
274 *
275 * Called by GeometryBindingsProcessor after it stages the vertex data
276 * into a GPU transfer buffer and submits the command.
277 */
278 void clear_gpu_update_flag() override
279 {
280 m_vertex_data_dirty = false;
281 m_needs_layout_update = false;
282 }
283
284private:
286 std::vector<uint8_t> vertex_buffer;
287 uint32_t vertex_count;
289 std::optional<Kakshya::VertexLayout> vertex_layout;
290 };
291
292 std::optional<GeometryState> m_saved_state;
293};
294
295} // namespace MayaFlux::Nodes
uint32_t get_vertex_count() const
Get number of vertices.
std::vector< uint8_t > m_vertex_buffer
Vertex data buffer (flat array of bytes)
void clear_gpu_update_flag() override
Clear the dirty flag after GPU upload completes.
bool needs_layout_update() const
Check if layout needs update.
std::optional< Kakshya::VertexLayout > get_vertex_layout() const
Get cached vertex layout.
void set_vertex_layout(const Kakshya::VertexLayout &layout)
Set cached vertex layout.
void set_vertices(std::span< const T > vertices)
Set multiple vertices from typed array.
std::optional< Kakshya::VertexLayout > m_vertex_layout
Cached vertex layout for descriptor binding.
void clear_layout_update_flag()
Clear layout update flag.
size_t get_vertex_stride() const
Get stride (bytes per vertex)
bool needs_gpu_update() const override
Check if vertex data or layout changed since last GPU sync.
void set_vertex_typed(uint32_t index, const T &vertex)
Set a single vertex by index from typed data.
std::span< const uint8_t > get_vertex_data() const
Get raw vertex buffer data.
T get_vertex_typed(uint32_t index) const
Get a single vertex by index as typed data.
Base class for nodes that generate 3D geometry data.
Complete description of vertex data layout in a buffer.