MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
6
7namespace MayaFlux::Core {
8class VKImage;
9}
10
11namespace MayaFlux::Buffers {
12
13class MeshProcessor;
14class RenderProcessor;
15
16/**
17 * @class MeshBuffer
18 * @brief VKBuffer subclass that owns a MeshData and manages its GPU upload.
19 *
20 * MeshBuffer is to indexed triangle geometry what TextureBuffer is to pixel
21 * data: it owns the CPU-side storage, creates a dedicated processor for
22 * GPU upload, and exposes setup_rendering() to attach a RenderProcessor.
23 *
24 * The VKBuffer base manages the vertex Vulkan buffer (Usage::VERTEX).
25 * MeshProcessor allocates and owns a separate Usage::INDEX VKBuffer and
26 * links both into VKBufferResources via set_index_resources(), making the
27 * indexed draw path available to RenderProcessor transparently.
28 *
29 * Two independent dirty flags govern re-upload:
30 * - m_vertices_dirty: set when vertex bytes change (deformation, morph, etc.)
31 * - m_indices_dirty: set when connectivity changes (topology mutation)
32 *
33 * Typical usage:
34 * @code
35 * auto buf = std::make_shared<MeshBuffer>(mesh_data);
36 * buf->setup_rendering({ .target_window = window });
37 * // Register with graphics subsystem — MeshProcessor uploads on first cycle.
38 * @endcode
39 *
40 * Deformation:
41 * @code
42 * buf->set_vertex_data(new_bytes); // marks vertices dirty
43 * // MeshProcessor re-uploads vertex buffer on next graphics cycle.
44 * @endcode
45 */
46class MAYAFLUX_API MeshBuffer : public VKBuffer {
47public:
48 /**
49 * @brief Construct from an owning MeshData.
50 *
51 * The VKBuffer base is sized to vertex_bytes. MeshProcessor allocates
52 * the index buffer separately on on_attach.
53 *
54 * @param data Loaded or generated mesh. Must be valid (is_valid() == true).
55 */
56 explicit MeshBuffer(Kakshya::MeshData data);
57
58 ~MeshBuffer() override = default;
59
60 /**
61 * @brief Create and attach MeshProcessor as the default processor.
62 */
63 void setup_processors(ProcessingToken token) override;
64
65 /**
66 * @brief Attach a RenderProcessor targeting the given window.
67 *
68 * Always uses triangle.vert.spv / triangle.frag.spv unless overridden.
69 * Topology is always TRIANGLE_LIST.
70 */
71 void setup_rendering(const RenderConfig& config);
72
73 // -------------------------------------------------------------------------
74 // CPU-side data access
75 // -------------------------------------------------------------------------
76
77 /**
78 * @brief Produce a non-owning MeshAccess view over the internal MeshData.
79 */
80 [[nodiscard]] std::optional<Kakshya::MeshAccess> access() const
81 {
82 return m_mesh_data.access();
83 }
84
85 [[nodiscard]] uint32_t get_vertex_count() const noexcept
86 {
87 return m_mesh_data.vertex_count();
88 }
89
90 [[nodiscard]] uint32_t get_index_count() const noexcept
91 {
92 const auto* ib = std::get_if<std::vector<uint32_t>>(
93 &m_mesh_data.index_variant);
94 return ib ? static_cast<uint32_t>(ib->size()) : 0;
95 }
96
97 [[nodiscard]] uint32_t get_face_count() const noexcept
98 {
99 return m_mesh_data.face_count();
100 }
101
102 [[nodiscard]] const Kakshya::VertexLayout& get_vertex_layout_ref() const noexcept
103 {
104 return m_mesh_data.layout;
105 }
106
107 [[nodiscard]] const std::optional<Kakshya::RegionGroup>& get_submeshes() const noexcept
108 {
109 return m_mesh_data.submeshes;
110 }
111
112 // -------------------------------------------------------------------------
113 // Mutation (deformation path)
114 // -------------------------------------------------------------------------
115
116 /**
117 * @brief Replace vertex bytes entirely and mark vertices dirty.
118 *
119 * Intended for deformation: caller writes new interleaved bytes (same
120 * stride as the original layout) and the next graphics cycle re-uploads.
121 * Does not change index data or layout.
122 *
123 * @param bytes Raw interleaved vertex bytes. Size must be a multiple of
124 * m_mesh_data.layout.stride_bytes.
125 */
126 void set_vertex_data(std::span<const uint8_t> bytes);
127
128 /**
129 * @brief Replace index data entirely and mark indices dirty.
130 *
131 * For topology mutation. Size must be a multiple of 3.
132 *
133 * @param indices New triangle index list.
134 */
135 void set_index_data(std::span<const uint32_t> indices);
136
137 /**
138 * @brief Replace both vertex and index data atomically and mark both dirty.
139 */
140 void set_mesh_data(Kakshya::MeshData data);
141
142 // -------------------------------------------------------------------------
143 // Dirty flag queries (read by MeshProcessor)
144 // -------------------------------------------------------------------------
145
146 [[nodiscard]] bool vertices_dirty() const noexcept
147 {
148 return m_vertices_dirty.load(std::memory_order_acquire);
149 }
150
151 [[nodiscard]] bool indices_dirty() const noexcept
152 {
153 return m_indices_dirty.load(std::memory_order_acquire);
154 }
155
156 void clear_vertices_dirty() noexcept
157 {
158 m_vertices_dirty.store(false, std::memory_order_release);
159 }
160
161 void clear_indices_dirty() noexcept
162 {
163 m_indices_dirty.store(false, std::memory_order_release);
164 }
165
166 // -------------------------------------------------------------------------
167 // Processor / renderer access
168 // -------------------------------------------------------------------------
169
170 [[nodiscard]] std::shared_ptr<MeshProcessor> get_mesh_processor() const
171 {
172 return m_mesh_processor;
173 }
174
175 [[nodiscard]] std::shared_ptr<RenderProcessor> get_render_processor() const override
176 {
177 return m_render_processor;
178 }
179
180 /**
181 * @brief Bind a diffuse texture to the render processor, if present.
182 *
183 * The binding name must match a descriptor slot in the shader. If the
184 * render processor is not yet created, the texture will be bound on
185 * creation if the default_texture_binding matches.
186 */
187 void bind_diffuse_texture(
188 std::shared_ptr<Core::VKImage> image,
189 std::string_view binding_name = "diffuseTex");
190
191 /* Check if a diffuse texture is bound. */
192 [[nodiscard]] bool has_diffuse_texture() const noexcept { return m_diffuse_texture != nullptr; }
193
194 /* Diffuse texture is optional, so may return nullptr. */
195 [[nodiscard]] std::shared_ptr<Core::VKImage> get_diffuse_texture() const noexcept { return m_diffuse_texture; }
196
197private:
198 friend class MeshProcessor;
199
201 std::shared_ptr<Core::VKImage> m_diffuse_texture;
202 std::string m_diffuse_binding { "diffuseTex" };
203
204 std::atomic<bool> m_vertices_dirty { true };
205 std::atomic<bool> m_indices_dirty { true };
206
207 std::shared_ptr<MeshProcessor> m_mesh_processor;
208 std::shared_ptr<RenderProcessor> m_render_processor;
209};
210
211} // namespace MayaFlux::Buffers
IO::ImageData image
uint32_t get_face_count() const noexcept
std::shared_ptr< RenderProcessor > get_render_processor() const override
Get a RenderProcessor suitable for rendering this buffer.
const Kakshya::VertexLayout & get_vertex_layout_ref() const noexcept
std::shared_ptr< RenderProcessor > m_render_processor
std::shared_ptr< Core::VKImage > m_diffuse_texture
bool has_diffuse_texture() const noexcept
std::shared_ptr< Core::VKImage > get_diffuse_texture() const noexcept
~MeshBuffer() override=default
const std::optional< Kakshya::RegionGroup > & get_submeshes() const noexcept
std::optional< Kakshya::MeshAccess > access() const
Produce a non-owning MeshAccess view over the internal MeshData.
void clear_indices_dirty() noexcept
std::shared_ptr< MeshProcessor > m_mesh_processor
std::shared_ptr< MeshProcessor > get_mesh_processor() const
bool indices_dirty() const noexcept
bool vertices_dirty() const noexcept
uint32_t get_vertex_count() const noexcept
uint32_t get_index_count() const noexcept
void clear_vertices_dirty() noexcept
Kakshya::MeshData m_mesh_data
VKBuffer subclass that owns a MeshData and manages its GPU upload.
Default processor for MeshBuffer: handles CPU-to-GPU upload of vertex and index data with selective d...
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:67
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
Owning CPU-side representation of a loaded or generated mesh.
Definition MeshData.hpp:33
Complete description of vertex data layout in a buffer.
Unified rendering configuration for graphics buffers.