MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
MeshBuffer.cpp
Go to the documentation of this file.
1#include "MeshBuffer.hpp"
2
3#include "MeshProcessor.hpp"
4
7
12
13namespace MayaFlux::Buffers {
14
15// =============================================================================
16// Construction
17// =============================================================================
18
20 : VKBuffer(
21 [&data]() -> size_t {
22 const auto* vb = std::get_if<std::vector<uint8_t>>(
23 &data.vertex_variant);
24 return vb ? vb->size() : 0;
25 }(),
26 Usage::VERTEX,
27 Kakshya::DataModality::VERTEX_POSITIONS_3D)
28 , m_mesh_data(std::move(data))
29{
30 if (!m_mesh_data.is_valid()) {
31 MF_WARN(Journal::Component::Buffers, Journal::Context::Init,
32 "MeshBuffer constructed with invalid MeshData — "
33 "GPU upload will be skipped until valid data is provided");
34 }
35
36 RenderConfig defaults;
37 defaults.vertex_shader = "triangle.vert.spv";
38 defaults.topology = Portal::Graphics::PrimitiveTopology::TRIANGLE_LIST;
39 set_default_render_config(defaults);
40
41 set_needs_depth_attachment(true);
42
43 MF_INFO(Journal::Component::Buffers, Journal::Context::Init,
44 "MeshBuffer: {} vertices, {} indices ({} faces), stride {} bytes",
45 m_mesh_data.vertex_count(),
46 get_index_count(),
47 m_mesh_data.face_count(),
48 m_mesh_data.layout.stride_bytes);
49}
50
51MeshBuffer::MeshBuffer(std::shared_ptr<Nodes::GpuSync::MeshWriterNode> node)
52 : VKBuffer(
53 node ? node->get_mesh_vertex_count() * sizeof(Kakshya::MeshVertex) : 0,
54 Usage::VERTEX,
55 Kakshya::DataModality::VERTEX_POSITIONS_3D)
56 , m_node(std::move(node))
57{
58 if (m_node) {
59 auto data = Kakshya::MeshData::empty();
60 const auto verts = m_node->get_mesh_vertices();
61 const auto indices = m_node->get_mesh_indices();
62
63 Kakshya::MeshInsertion ins(data.vertex_variant, data.index_variant);
64 ins.insert_flat(
65 std::span<const uint8_t>(
66 reinterpret_cast<const uint8_t*>(verts.data()),
67 verts.size() * sizeof(Kakshya::MeshVertex)),
68 std::span<const uint32_t>(indices),
71 data.layout.vertex_count = static_cast<uint32_t>(verts.size());
72 m_mesh_data = std::move(data);
73 }
74
75 RenderConfig defaults;
76 defaults.vertex_shader = "triangle.vert.spv";
80}
81
82// =============================================================================
83// setup_processors
84// =============================================================================
85
87{
88 m_mesh_processor = std::make_shared<MeshProcessor>();
89 m_mesh_processor->set_processing_token(token);
91
92 auto chain = get_processing_chain();
93 if (!chain) {
94 chain = std::make_shared<BufferProcessingChain>();
96 }
97 chain->set_preferred_token(token);
98
100 "MeshBuffer::setup_processors with token {}",
101 static_cast<int>(token));
102}
103
104// =============================================================================
105// setup_rendering
106// =============================================================================
107
109{
110 if (!config.vertex_shader.empty()) {
112 }
113 if (!config.fragment_shader.empty()) {
115 }
116 if (!config.default_texture_binding.empty()) {
118 }
119
123 }
124
127
128 if (!config.additional_textures.empty()) {
129 for (const auto& [name, texture] : config.additional_textures) {
130 m_render_config.additional_textures.emplace_back(name, texture);
131 }
132 }
133
134 const bool textured = m_diffuse_texture != nullptr
136
137 if (textured && m_render_config.default_texture_binding.empty()) {
139 }
140
141 if (m_render_config.fragment_shader.empty()) {
143 ? "mesh_textured.frag.spv"
144 : "triangle.frag.spv";
145 }
146
148
149 if (textured && !m_render_config.default_texture_binding.empty()) {
151 0, 1, vk::DescriptorType::eCombinedImageSampler);
152 }
153
154 uint32_t binding_index = 1;
155 for (const auto& [name, _] : m_render_config.additional_textures) {
156 sc.bindings[name] = ShaderBinding(
157 1, binding_index++, vk::DescriptorType::eCombinedImageSampler);
158 }
159
161
163 m_render_processor->bind_texture(
166 }
167
168 for (const auto& [name, texture] : m_render_config.additional_textures) {
169 m_render_processor->bind_texture(name, texture);
170 }
171
172 get_processing_chain()->add_final_processor(
174 shared_from_this());
175
177 "MeshBuffer::setup_rendering: vert={} frag={} textured={}",
180 textured);
181}
182
183// =============================================================================
184// bind_diffuse_texture
185// =============================================================================
186
188 std::shared_ptr<Core::VKImage> image,
189 std::string_view binding_name)
190{
191 m_diffuse_texture = std::move(image);
192 m_diffuse_binding = std::string(binding_name);
193
194 if (m_render_processor) {
197 } else {
199 "MeshBuffer::bind_diffuse_texture: pipeline was created without "
200 "binding '{}' — call before setup_rendering() for correct results",
202 }
203 }
204}
205
206// =============================================================================
207// Mutation
208// =============================================================================
209
210void MeshBuffer::set_vertex_data(std::span<const uint8_t> bytes)
211{
213 && bytes.size() % m_mesh_data.layout.stride_bytes != 0) {
215 "MeshBuffer::set_vertex_data: byte count {} not a multiple of stride {}",
216 bytes.size(), m_mesh_data.layout.stride_bytes);
217 return;
218 }
219
220 m_mesh_data.vertex_variant = std::vector<uint8_t>(bytes.begin(), bytes.end());
222 ? static_cast<uint32_t>(bytes.size() / m_mesh_data.layout.stride_bytes)
223 : 0;
224
225 m_vertices_dirty.store(true, std::memory_order_release);
226}
227
228void MeshBuffer::set_index_data(std::span<const uint32_t> indices)
229{
230 if (indices.size() % 3 != 0) {
232 "MeshBuffer::set_index_data: index count {} is not a multiple of 3",
233 indices.size());
234 return;
235 }
236
237 m_mesh_data.index_variant = std::vector<uint32_t>(indices.begin(), indices.end());
238 m_indices_dirty.store(true, std::memory_order_release);
239}
240
242{
243 m_mesh_data = std::move(data);
244 m_vertices_dirty.store(true, std::memory_order_release);
245 m_indices_dirty.store(true, std::memory_order_release);
246}
247
248} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
IO::ImageData image
Definition Decoder.cpp:57
std::shared_ptr< Core::VKImage > m_diffuse_texture
std::shared_ptr< Nodes::GpuSync::MeshWriterNode > m_node
void setup_processors(ProcessingToken token) override
Create and attach MeshProcessor as the default processor.
void set_index_data(std::span< const uint32_t > indices)
Replace index data entirely and mark indices dirty.
std::shared_ptr< MeshProcessor > m_mesh_processor
MeshBuffer(Kakshya::MeshData data)
Construct from an owning MeshData.
void bind_diffuse_texture(std::shared_ptr< Core::VKImage > image, std::string_view binding_name="diffuseTex")
Bind a diffuse texture to the render processor, if present.
void set_mesh_data(Kakshya::MeshData data)
Replace both vertex and index data atomically and mark both dirty.
std::atomic< bool > m_indices_dirty
void set_vertex_data(std::span< const uint8_t > bytes)
Replace vertex bytes entirely and mark vertices dirty.
std::atomic< bool > m_vertices_dirty
void setup_rendering(const RenderConfig &config)
Attach a RenderProcessor targeting the given window.
Kakshya::MeshData m_mesh_data
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
Definition VKBuffer.cpp:286
void set_default_processor(const std::shared_ptr< BufferProcessor > &processor) override
Set the buffer's default processor.
Definition VKBuffer.cpp:270
void set_processing_chain(const std::shared_ptr< BufferProcessingChain > &chain, bool force=false) override
Replace the buffer's processing chain.
Definition VKBuffer.cpp:291
void set_needs_depth_attachment(bool needs)
Mark this buffer as requiring depth testing when rendered.
Definition VKBuffer.hpp:565
void apply_render_config(const RenderConfig &config, const ShaderConfig &shader_config)
Configure the internal m_render_processor from a RenderConfig.
Definition VKBuffer.cpp:359
std::shared_ptr< RenderProcessor > m_render_processor
Definition VKBuffer.hpp:618
void set_default_render_config(const RenderConfig &config)
Called by derived classes to set their context-specific defaults.
Definition VKBuffer.hpp:595
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:67
void insert_flat(std::span< const uint8_t > vertex_bytes, std::span< const uint32_t > index_data, const VertexLayout &layout)
Insert a single flat mesh (no submesh tracking).
Write counterpart to MeshAccess.
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Init
Engine/subsystem initialization.
@ Buffers
Buffers, Managers, processors and processing chains.
Describes how a VKBuffer binds to a shader descriptor.
static MeshData empty()
Construct an empty MeshData with the canonical 60-byte mesh layout.
Definition MeshData.hpp:49
DataVariant vertex_variant
vector<uint8_t>: interleaved vertex bytes
Definition MeshData.hpp:34
DataVariant index_variant
vector<uint32_t>: triangle index list
Definition MeshData.hpp:35
Owning CPU-side representation of a loaded or generated mesh.
Definition MeshData.hpp:33
Vertex type for indexed triangle mesh primitives (TRIANGLE_LIST topology)
uint32_t stride_bytes
Total bytes per vertex (stride in Vulkan terms) e.g., 3 floats (position) + 3 floats (normal) = 24 by...
uint32_t vertex_count
Total number of vertices in this buffer.
static VertexLayout for_meshes(uint32_t stride=60)
Factory: layout for MeshVertex (position, color, weight, uv, normal, tangent)
std::shared_ptr< Core::Window > target_window
std::vector< std::pair< std::string, std::shared_ptr< Core::VKImage > > > additional_textures
For child-specific fields.
Unified rendering configuration for graphics buffers.