MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
TextureBuffer.cpp
Go to the documentation of this file.
1#include "TextureBuffer.hpp"
2
6
8
9namespace MayaFlux::Buffers {
10
11const std::vector<TextureBuffer::QuadVertex> base_quad = {
12 { { -0.5F, -0.5F, 0.0F }, { 0.0F, 1.0F } }, // Bottom-left
13 { { 0.5F, -0.5F, 0.0F }, { 1.0F, 1.0F } }, // Bottom-right
14 { { -0.5F, 0.5F, 0.0F }, { 0.0F, 0.0F } }, // Top-left
15 { { 0.5F, 0.5F, 0.0F }, { 1.0F, 0.0F } } // Top-right
16};
17
19 uint32_t width,
20 uint32_t height,
22 const void* initial_pixel_data)
23 : VKBuffer(
24 calculate_quad_vertex_size(),
25 Usage::VERTEX,
26 Kakshya::DataModality::VERTEX_POSITIONS_3D)
27 , m_width(width)
28 , m_height(height)
29 , m_format(format)
30{
31 if (initial_pixel_data) {
32 size_t pixel_bytes = static_cast<size_t>(width) * height * Portal::Graphics::TextureLoom::get_bytes_per_pixel(format);
33 m_pixel_data.resize(pixel_bytes);
34 std::memcpy(m_pixel_data.data(), initial_pixel_data, pixel_bytes);
35 }
36
38
40 "Created TextureBuffer: {}x{} ({} pixel bytes, {} vertex bytes)",
42}
43
45{
46 auto self = std::dynamic_pointer_cast<TextureBuffer>(shared_from_this());
47
48 m_texture_processor = std::make_shared<TextureProcessor>();
49 m_texture_processor->set_processing_token(token);
50
52
53 auto chain = get_processing_chain();
54 if (!chain) {
55 chain = std::make_shared<BufferProcessingChain>();
57 }
58 chain->set_preferred_token(token);
59
61 "TextureBuffer setup_processors: TextureProcessor will be attached on first registration");
62}
63
65{
66 if (!m_render_processor) {
67 ShaderProcessorConfig shader_config { config.vertex_shader };
68 shader_config.bindings[config.default_texture_binding] = ShaderBinding(
69 0, 0, vk::DescriptorType::eCombinedImageSampler);
70
71 uint32_t binding_index = 1;
72 for (const auto& [name, _] : config.additional_textures) {
73 shader_config.bindings[name] = ShaderBinding(
74 0, binding_index++, vk::DescriptorType::eCombinedImageSampler);
75 }
76
77 m_render_processor = std::make_shared<RenderProcessor>(shader_config);
78 }
79
80 m_render_processor->set_fragment_shader(config.fragment_shader);
81 m_render_processor->set_target_window(config.target_window);
82 m_render_processor->set_primitive_topology(config.topology);
83
85
86 for (const auto& [name, texture] : config.additional_textures) {
87 m_render_processor->bind_texture(name, texture);
88 }
89
90 get_processing_chain()->add_processor(m_render_processor, shared_from_this());
91}
92
93// =========================================================================
94// Pixel Data Management
95// =========================================================================
96
97void TextureBuffer::set_pixel_data(const void* data, size_t size)
98{
99 if (!data || size == 0) {
101 "set_pixel_data called with null or empty data");
102 return;
103 }
104
105 m_pixel_data.resize(size);
106 std::memcpy(m_pixel_data.data(), data, size);
107 m_texture_dirty = true;
108
110 "TextureBuffer: pixel data updated ({} bytes, marked dirty)", size);
111}
112
117
118// =========================================================================
119// Display Transform
120// =========================================================================
121
122void TextureBuffer::set_position(float x, float y)
123{
124 if (m_position.x != x || m_position.y != y) {
125 m_position = { x, y };
126 m_geometry_dirty = true;
127
129 "TextureBuffer: position set to ({}, {}), geometry marked dirty", x, y);
130 }
131}
132
133void TextureBuffer::set_scale(float width, float height)
134{
135 if (m_scale.x != width || m_scale.y != height) {
136 m_scale = { width, height };
137 m_geometry_dirty = true;
138
140 "TextureBuffer: scale set to ({}, {}), geometry marked dirty", width, height);
141 }
142}
143
144void TextureBuffer::set_rotation(float angle_radians)
145{
146 if (m_rotation != angle_radians) {
147 m_rotation = angle_radians;
148 m_geometry_dirty = true;
149
151 "TextureBuffer: rotation set to {}, geometry marked dirty", angle_radians);
152 }
153}
154
155// =========================================================================
156// Custom Geometry
157// =========================================================================
158
159void TextureBuffer::set_custom_vertices(const std::vector<QuadVertex>& vertices)
160{
161 if (vertices.size() != 4) {
163 "set_custom_vertices: must provide exactly 4 vertices, got {}", vertices.size());
164 return;
165 }
166
167 m_vertex_bytes.resize(vertices.size() * sizeof(QuadVertex));
168 std::memcpy(m_vertex_bytes.data(), vertices.data(), m_vertex_bytes.size());
170 m_geometry_dirty = true;
171
173 "TextureBuffer: custom vertices set, geometry marked dirty");
174}
175
177{
181 m_geometry_dirty = true;
182
184 "TextureBuffer: reset to default quad, geometry marked dirty");
185 }
186}
187
188// =========================================================================
189// Geometry Generation
190// =========================================================================
191
193{
194 return 4 * sizeof(QuadVertex);
195}
196
198{
199 m_vertex_bytes.resize(base_quad.size() * sizeof(QuadVertex));
200 std::memcpy(m_vertex_bytes.data(), base_quad.data(), m_vertex_bytes.size());
201
202 Kakshya::VertexLayout vertex_layout {
203 .vertex_count = 4,
204 .stride_bytes = sizeof(QuadVertex),
205 .attributes = {
206 { .component_modality = Kakshya::DataModality::VERTEX_POSITIONS_3D,
207 .offset_in_vertex = offsetof(QuadVertex, position),
208 .name = "position" },
209 { .component_modality = Kakshya::DataModality::TEXTURE_COORDS_2D,
210 .offset_in_vertex = offsetof(QuadVertex, texcoord),
211 .name = "texcoord" } }
212 };
213
214 set_vertex_layout(vertex_layout);
215
217 "TextureBuffer: generated default fullscreen quad");
218}
219
221{
224 "TextureBuffer: using custom vertices, skipping transform");
225 return;
226 }
227
228 float cos_rot = std::cos(m_rotation);
229 float sin_rot = std::sin(m_rotation);
230
231 std::vector<QuadVertex> transformed(4);
232 for (size_t i = 0; i < 4; ++i) {
233 glm::vec3 pos = base_quad[i].position;
234
235 pos.x *= m_scale.x;
236 pos.y *= m_scale.y;
237
238 float rotated_x = pos.x * cos_rot - pos.y * sin_rot;
239 float rotated_y = pos.x * sin_rot + pos.y * cos_rot;
240
241 pos.x = rotated_x + m_position.x;
242 pos.y = rotated_y + m_position.y;
243
244 transformed[i].position = pos;
245 transformed[i].texcoord = base_quad[i].texcoord;
246 }
247
248 m_vertex_bytes.resize(transformed.size() * sizeof(QuadVertex));
249 std::memcpy(m_vertex_bytes.data(), transformed.data(), m_vertex_bytes.size());
250
252 "TextureBuffer: regenerated quad with transform (pos={},{}, scale={},{}, rot={})",
254}
255
256} // namespace MayaFlux::Buffers
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
static MayaFlux::Nodes::ProcessingToken token
Definition Timers.cpp:8
void setup_processors(ProcessingToken token) override
Setup processors with a processing token.
void use_default_quad()
Reset to default fullscreen quad Uses position and scale to generate quad geometry.
std::shared_ptr< TextureProcessor > m_texture_processor
std::vector< uint8_t > m_pixel_data
std::shared_ptr< RenderProcessor > m_render_processor
void setup_rendering(const RenderConfig &config)
Setup rendering with RenderProcessor.
void mark_pixels_dirty()
Mark pixel data as changed Use this if you modify pixel data in-place without calling set_pixel_data(...
void set_position(float x, float y)
Set screen position (NDC or pixel coords depending on rendering setup)
TextureBuffer(uint32_t width, uint32_t height, Portal::Graphics::ImageFormat format, const void *initial_pixel_data=nullptr)
Create texture buffer with dimensions.
std::shared_ptr< Core::VKImage > get_texture() const
Get GPU texture image Suitable for binding to shaders via RenderProcessor::bind_texture()
std::vector< uint8_t > m_vertex_bytes
void set_rotation(float angle_radians)
Set rotation around center.
void set_scale(float width, float height)
Set display size.
void set_pixel_data(const void *data, size_t size)
Replace pixel data.
void set_custom_vertices(const std::vector< QuadVertex > &vertices)
void set_processing_chain(std::shared_ptr< Buffers::BufferProcessingChain > chain, bool force=false) override
Replace the buffer's processing chain.
Definition VKBuffer.cpp:286
void set_vertex_layout(const Kakshya::VertexLayout &layout)
Set vertex layout for this buffer.
Definition VKBuffer.cpp:368
void resize(size_t new_size, bool preserve_data=false)
Resize buffer and recreate GPU resources if needed.
Definition VKBuffer.cpp:117
void set_default_processor(std::shared_ptr< Buffers::BufferProcessor > processor) override
Set the buffer's default processor.
Definition VKBuffer.cpp:265
std::shared_ptr< Buffers::BufferProcessingChain > get_processing_chain() override
Access the buffer's processing chain.
Definition VKBuffer.cpp:281
Vulkan-backed buffer wrapper used in processing chains.
Definition VKBuffer.hpp:52
static size_t get_bytes_per_pixel(ImageFormat format)
Get bytes per pixel for a format.
const std::vector< TextureBuffer::QuadVertex > base_quad
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.
ImageFormat
User-friendly image format enum.
Describes how a VKBuffer binds to a shader descriptor.
Complete configuration for shader processor.
Use custom vertex geometry instead of default quad.
std::vector< std::pair< std::string, std::shared_ptr< Core::VKImage > > > additional_textures
std::shared_ptr< Core::Window > target_window
Portal::Graphics::PrimitiveTopology topology
uint32_t vertex_count
Total number of vertices in this buffer.
Complete description of vertex data layout in a buffer.