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#include "MeshProcessor.hpp"
3
8
9namespace MayaFlux::Buffers {
10
11// =============================================================================
12// Construction
13// =============================================================================
14
16 : VKBuffer(
17 [&data]() -> size_t {
18 const auto* vb = std::get_if<std::vector<uint8_t>>(
19 &data.vertex_variant);
20 return vb ? vb->size() : 0;
21 }(),
22 Usage::VERTEX,
23 Kakshya::DataModality::VERTEX_POSITIONS_3D)
24 , m_mesh_data(std::move(data))
25{
26 if (!m_mesh_data.is_valid()) {
27 MF_WARN(Journal::Component::Buffers, Journal::Context::Init,
28 "MeshBuffer constructed with invalid MeshData — "
29 "GPU upload will be skipped until valid data is provided");
30 }
31
32 RenderConfig defaults;
33 defaults.vertex_shader = "triangle.vert.spv";
34 defaults.topology = Portal::Graphics::PrimitiveTopology::TRIANGLE_LIST;
35 set_default_render_config(defaults);
36
37 set_needs_depth_attachment(true);
38
39 MF_INFO(Journal::Component::Buffers, Journal::Context::Init,
40 "MeshBuffer: {} vertices, {} indices ({} faces), stride {} bytes",
41 m_mesh_data.vertex_count(),
42 get_index_count(),
43 m_mesh_data.face_count(),
44 m_mesh_data.layout.stride_bytes);
45}
46
47// =============================================================================
48// setup_processors
49// =============================================================================
50
51void MeshBuffer::setup_processors(ProcessingToken token)
52{
53 m_mesh_processor = std::make_shared<MeshProcessor>();
54 m_mesh_processor->set_processing_token(token);
55 set_default_processor(m_mesh_processor);
56
57 auto chain = get_processing_chain();
58 if (!chain) {
59 chain = std::make_shared<BufferProcessingChain>();
60 set_processing_chain(chain);
61 }
62 chain->set_preferred_token(token);
63
64 MF_DEBUG(Journal::Component::Buffers, Journal::Context::Init,
65 "MeshBuffer::setup_processors with token {}",
66 static_cast<int>(token));
67}
68
69// =============================================================================
70// setup_rendering
71// =============================================================================
72
73void MeshBuffer::setup_rendering(const RenderConfig& config)
74{
75 if (!config.vertex_shader.empty()) {
76 m_render_config.vertex_shader = config.vertex_shader;
77 }
78 if (!config.fragment_shader.empty()) {
79 m_render_config.fragment_shader = config.fragment_shader;
80 }
81 if (!config.default_texture_binding.empty()) {
82 m_render_config.default_texture_binding = config.default_texture_binding;
83 }
84
85 if (!m_render_config.default_texture_binding.empty()
86 && m_diffuse_binding != m_render_config.default_texture_binding) {
87 m_diffuse_binding = m_render_config.default_texture_binding;
88 }
89
90 m_render_config.target_window = config.target_window;
91 m_render_config.topology = Portal::Graphics::PrimitiveTopology::TRIANGLE_LIST;
92
93 if (!config.additional_textures.empty()) {
94 for (const auto& [name, texture] : config.additional_textures) {
95 m_render_config.additional_textures.emplace_back(name, texture);
96 }
97 }
98
99 const bool textured = m_diffuse_texture != nullptr
100 || !m_render_config.default_texture_binding.empty();
101
102 if (textured && m_render_config.default_texture_binding.empty()) {
103 m_render_config.default_texture_binding = m_diffuse_binding;
104 }
105
106 if (m_render_config.fragment_shader.empty()) {
107 m_render_config.fragment_shader = textured
108 ? "mesh_textured.frag.spv"
109 : "triangle.frag.spv";
110 }
111
112 if (!m_render_processor) {
113 ShaderConfig sc { m_render_config.vertex_shader };
114
115 if (textured && !m_render_config.default_texture_binding.empty()) {
116 sc.bindings[m_render_config.default_texture_binding] = ShaderBinding(
117 0, 1, vk::DescriptorType::eCombinedImageSampler);
118 }
119
120 uint32_t binding_index = 1;
121 for (const auto& [name, _] : m_render_config.additional_textures) {
122 sc.bindings[name] = ShaderBinding(
123 1, binding_index++, vk::DescriptorType::eCombinedImageSampler);
124 }
125
126 m_render_processor = std::make_shared<RenderProcessor>(sc);
127 }
128
129 m_render_processor->set_fragment_shader(m_render_config.fragment_shader);
130 m_render_processor->set_target_window(
131 m_render_config.target_window,
132 std::dynamic_pointer_cast<VKBuffer>(shared_from_this()));
133 m_render_processor->set_primitive_topology(m_render_config.topology);
134
135 if (m_diffuse_texture && !m_render_config.default_texture_binding.empty()) {
136 m_render_processor->bind_texture(
137 m_render_config.default_texture_binding,
138 m_diffuse_texture);
139 }
140
141 for (const auto& [name, texture] : m_render_config.additional_textures) {
142 m_render_processor->bind_texture(name, texture);
143 }
144
145 get_processing_chain()->add_final_processor(
146 m_render_processor,
147 shared_from_this());
148
149 MF_INFO(Journal::Component::Buffers, Journal::Context::Init,
150 "MeshBuffer::setup_rendering: vert={} frag={} textured={}",
151 m_render_config.vertex_shader,
152 m_render_config.fragment_shader,
153 textured);
154}
155
156// =============================================================================
157// bind_diffuse_texture
158// =============================================================================
159
160void MeshBuffer::bind_diffuse_texture(
161 std::shared_ptr<Core::VKImage> image,
162 std::string_view binding_name)
163{
164 m_diffuse_texture = std::move(image);
165 m_diffuse_binding = std::string(binding_name);
166
167 if (m_render_processor) {
168 if (m_render_config.default_texture_binding == m_diffuse_binding) {
169 m_render_processor->bind_texture(m_diffuse_binding, m_diffuse_texture);
170 } else {
171 MF_WARN(Journal::Component::Buffers, Journal::Context::BufferProcessing,
172 "MeshBuffer::bind_diffuse_texture: pipeline was created without "
173 "binding '{}' — call before setup_rendering() for correct results",
174 m_diffuse_binding);
175 }
176 }
177}
178
179// =============================================================================
180// Mutation
181// =============================================================================
182
183void MeshBuffer::set_vertex_data(std::span<const uint8_t> bytes)
184{
185 if (m_mesh_data.layout.stride_bytes > 0
186 && bytes.size() % m_mesh_data.layout.stride_bytes != 0) {
187 MF_ERROR(Journal::Component::Buffers, Journal::Context::BufferProcessing,
188 "MeshBuffer::set_vertex_data: byte count {} not a multiple of stride {}",
189 bytes.size(), m_mesh_data.layout.stride_bytes);
190 return;
191 }
192
193 m_mesh_data.vertex_variant = std::vector<uint8_t>(bytes.begin(), bytes.end());
194 m_mesh_data.layout.vertex_count = m_mesh_data.layout.stride_bytes > 0
195 ? static_cast<uint32_t>(bytes.size() / m_mesh_data.layout.stride_bytes)
196 : 0;
197
198 m_vertices_dirty.store(true, std::memory_order_release);
199}
200
201void MeshBuffer::set_index_data(std::span<const uint32_t> indices)
202{
203 if (indices.size() % 3 != 0) {
204 MF_ERROR(Journal::Component::Buffers, Journal::Context::BufferProcessing,
205 "MeshBuffer::set_index_data: index count {} is not a multiple of 3",
206 indices.size());
207 return;
208 }
209
210 m_mesh_data.index_variant = std::vector<uint32_t>(indices.begin(), indices.end());
211 m_indices_dirty.store(true, std::memory_order_release);
212}
213
214void MeshBuffer::set_mesh_data(Kakshya::MeshData data)
215{
216 m_mesh_data = std::move(data);
217 m_vertices_dirty.store(true, std::memory_order_release);
218 m_indices_dirty.store(true, std::memory_order_release);
219}
220
221} // 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
MeshBuffer(Kakshya::MeshData data)
Construct from an owning MeshData.
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:67
ProcessingToken
Bitfield enum defining processing characteristics and backend requirements for buffer operations.
Describes how a VKBuffer binds to a shader descriptor.
std::unordered_map< std::string, ShaderBinding > bindings
Owning CPU-side representation of a loaded or generated mesh.
Definition MeshData.hpp:33
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.