From 1a61aab218ac956b5c578e418cae2eaf58ac526d Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sat, 7 Jun 2025 20:25:45 +0200 Subject: [PATCH] Add traits --- src/core/render/primitives/buffer.rs | 83 ++++++++++ src/core/render/primitives/camera.rs | 9 +- src/core/render/primitives/command.rs | 110 +++++++++++++ src/core/render/primitives/mod.rs | 7 + src/core/render/primitives/mvp.rs | 43 +++-- src/core/render/primitives/resource.rs | 208 ++++++++++++++++++++++++ src/core/render/primitives/transform.rs | 58 ++++--- src/core/render/primitives/vertex.rs | 83 +++++++++- src/game/assets/square.rs | 156 ++++++++++++------ 9 files changed, 663 insertions(+), 94 deletions(-) create mode 100644 src/core/render/primitives/buffer.rs create mode 100644 src/core/render/primitives/command.rs create mode 100644 src/core/render/primitives/resource.rs diff --git a/src/core/render/primitives/buffer.rs b/src/core/render/primitives/buffer.rs new file mode 100644 index 0000000..e01226f --- /dev/null +++ b/src/core/render/primitives/buffer.rs @@ -0,0 +1,83 @@ +use std::{error::Error, sync::Arc}; + +use vulkano::{ + Validated, + buffer::{AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, Subbuffer}, + memory::allocator::{AllocationCreateInfo, StandardMemoryAllocator}, +}; + +pub trait AsBindableBuffer { + type BufferData: BufferContents + Clone; + + fn buffer_create_info() -> BufferCreateInfo; + + fn allocation_create_info() -> AllocationCreateInfo; + + fn to_buffer_data(data: &T) -> Self::BufferData; + + fn create_buffer( + memory_allocator: &Arc, + data: &T, + ) -> Result, Validated> { + let buffer_data = Self::to_buffer_data(data); + Buffer::from_iter( + memory_allocator.clone(), + Self::buffer_create_info(), + Self::allocation_create_info(), + [buffer_data], + ) + } + + fn update_buffer( + buffer: &Subbuffer<[Self::BufferData]>, + data: &T, + ) -> Result<(), Box> { + let buffer_data = Self::to_buffer_data(data); + let mut write_guard = buffer.write()?; + write_guard[0] = buffer_data; + Ok(()) + } +} + +pub trait AsUniformBuffer: AsBindableBuffer { + fn create_uniform_buffer( + memory_allocator: &Arc, + data: &T, + ) -> Result, Validated> { + Self::create_buffer(memory_allocator, data) + } +} + +pub trait AsVertexBuffer: AsBindableBuffer { + fn create_vertex_buffer( + memory_allocator: &Arc, + vertices: &[T], + ) -> Result, Validated> { + let buffer_data: Vec = + vertices.iter().map(|v| Self::to_buffer_data(v)).collect(); + + Buffer::from_iter( + memory_allocator.clone(), + Self::buffer_create_info(), + Self::allocation_create_info(), + buffer_data, + ) + } +} + +pub trait AsIndexBuffer: AsBindableBuffer { + fn create_index_buffer( + memory_allocator: &Arc, + indices: &[T], + ) -> Result, Validated> { + let buffer_data: Vec = + indices.iter().map(|i| Self::to_buffer_data(i)).collect(); + + Buffer::from_iter( + memory_allocator.clone(), + Self::buffer_create_info(), + Self::allocation_create_info(), + buffer_data, + ) + } +} diff --git a/src/core/render/primitives/camera.rs b/src/core/render/primitives/camera.rs index f27622a..4fdf1ae 100644 --- a/src/core/render/primitives/camera.rs +++ b/src/core/render/primitives/camera.rs @@ -9,7 +9,7 @@ use vulkano::{ use crate::core::{input::InputManager, timer::Timer}; -use super::mvp::Mvp; +use super::{AsUniformBuffer, mvp::Mvp}; // See docs/OPENGL_VULKAN_DIFF.md const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 { @@ -112,11 +112,12 @@ impl Camera3D { Vec3::Y, ); - Mvp { + let mvp = Mvp { model: OPENGL_TO_VULKAN_Y_AXIS_FLIP.to_cols_array_2d(), view: view_matrix.to_cols_array_2d(), projection: self.projection.to_cols_array_2d(), - } - .into_buffer(memory_allocator) + }; + + Mvp::create_uniform_buffer(memory_allocator, &mvp) } } diff --git a/src/core/render/primitives/command.rs b/src/core/render/primitives/command.rs new file mode 100644 index 0000000..37970a1 --- /dev/null +++ b/src/core/render/primitives/command.rs @@ -0,0 +1,110 @@ +use std::{error::Error, sync::Arc}; + +use vulkano::{ + command_buffer::{ + AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo, + SubpassEndInfo, + }, + descriptor_set::DescriptorSet, + pipeline::{GraphicsPipeline, Pipeline}, + render_pass::{Framebuffer, RenderPass}, +}; + +pub trait AsRecordable { + fn record_render_commands( + builder: &mut AutoCommandBufferBuilder, + data: &T, + pipeline: &Arc, + descriptor_sets: &[Arc], + ) -> Result<(), Box>; +} + +pub trait AsDrawable { + type VertexBuffer; + type IndexBuffer; + + fn vertex_buffer(data: &T) -> &Self::VertexBuffer; + + fn index_buffer(_data: &T) -> Option<&Self::IndexBuffer> { + None + } + + fn vertex_count(data: &T) -> u32; + + fn index_count(_data: &T) -> u32 { + 0 + } + + fn instance_count(_data: &T) -> u32 { + 1 + } + + fn first_vertex(_data: &T) -> u32 { + 0 + } + + fn first_index(_data: &T) -> u32 { + 0 + } + + fn first_instance(_data: &T) -> u32 { + 0 + } +} + +pub trait AsRenderPassRecordable { + fn begin_render_pass( + builder: &mut AutoCommandBufferBuilder, + _render_pass: &Arc, + framebuffer: &Arc, + clear_values: Vec>, + ) -> Result<(), Box> { + builder.begin_render_pass( + RenderPassBeginInfo { + clear_values, + ..RenderPassBeginInfo::framebuffer(framebuffer.clone()) + }, + SubpassBeginInfo { + contents: vulkano::command_buffer::SubpassContents::Inline, + ..Default::default() + }, + )?; + Ok(()) + } + + fn end_render_pass( + builder: &mut AutoCommandBufferBuilder, + ) -> Result<(), Box> { + builder.end_render_pass(SubpassEndInfo::default())?; + Ok(()) + } + + fn record_render_pass_commands( + builder: &mut AutoCommandBufferBuilder, + data: &T, + ) -> Result<(), Box>; +} + +pub trait AsRenderableObject: AsRecordable + AsDrawable { + fn record_complete_render( + builder: &mut AutoCommandBufferBuilder, + data: &T, + pipeline: &Arc, + descriptor_sets: &[Arc], + ) -> Result<(), Box> { + builder.bind_pipeline_graphics(pipeline.clone())?; + + if !descriptor_sets.is_empty() { + builder.bind_descriptor_sets( + vulkano::pipeline::PipelineBindPoint::Graphics, + pipeline.layout().clone(), + 0, + descriptor_sets.iter().cloned().collect::>(), + )?; + } + + Self::record_render_commands(builder, data, pipeline, descriptor_sets)?; + + Ok(()) + } +} diff --git a/src/core/render/primitives/mod.rs b/src/core/render/primitives/mod.rs index 5ab8266..8ef9dd7 100644 --- a/src/core/render/primitives/mod.rs +++ b/src/core/render/primitives/mod.rs @@ -14,6 +14,13 @@ pub mod mvp; pub mod transform; pub mod vertex; +pub mod buffer; +pub mod command; +pub mod resource; + +pub use buffer::{AsBindableBuffer, AsIndexBuffer, AsUniformBuffer, AsVertexBuffer}; +pub use command::{AsDrawable, AsRecordable}; + pub trait AsBindableDescriptorSet { fn as_descriptor_set_layout_bindings() -> BTreeMap; diff --git a/src/core/render/primitives/mvp.rs b/src/core/render/primitives/mvp.rs index d05307e..0f47ce3 100644 --- a/src/core/render/primitives/mvp.rs +++ b/src/core/render/primitives/mvp.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use vulkano::buffer::{ - AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, + AllocateBufferError, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, }; use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::descriptor_set::layout::{ @@ -13,7 +13,7 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, Standar use vulkano::shader::ShaderStages; use vulkano::{Validated, VulkanError}; -use crate::core::render::primitives::AsBindableDescriptorSet; +use crate::core::render::primitives::{AsBindableBuffer, AsBindableDescriptorSet, AsUniformBuffer}; #[derive(BufferContents, Clone, Copy)] #[repr(C)] @@ -28,22 +28,35 @@ impl Mvp { self, memory_allocator: &Arc, ) -> Result, Validated> { - Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::UNIFORM_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - [self], - ) + Self::create_uniform_buffer(memory_allocator, &self) } } +impl AsBindableBuffer for Mvp { + type BufferData = Mvp; + + fn buffer_create_info() -> BufferCreateInfo { + BufferCreateInfo { + usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + } + } + + fn allocation_create_info() -> AllocationCreateInfo { + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + } + + fn to_buffer_data(data: &Mvp) -> Self::BufferData { + *data + } +} + +impl AsUniformBuffer for Mvp {} + impl AsBindableDescriptorSet> for Mvp { fn as_descriptor_set_layout_bindings() -> BTreeMap { BTreeMap::::from_iter([( diff --git a/src/core/render/primitives/resource.rs b/src/core/render/primitives/resource.rs new file mode 100644 index 0000000..7ea75e7 --- /dev/null +++ b/src/core/render/primitives/resource.rs @@ -0,0 +1,208 @@ +use std::{ + collections::HashMap, + error::Error, + fmt::{self, Debug, Display}, + hash::Hash, + sync::Arc, +}; + +#[derive(Debug, Clone)] +pub struct ResourceLoadError { + pub message: String, +} + +impl Display for ResourceLoadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Resource load error: {}", self.message) + } +} + +impl Error for ResourceLoadError {} + +impl ResourceLoadError { + pub fn new(message: impl Into) -> Self { + Self { + message: message.into(), + } + } +} + +pub trait AsResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + /// Type d'erreur lors du chargement + type LoadError: Error; + + /// Charge une ressource avec l'handle donné + fn load(&mut self, handle: THandle, resource: TResource) -> Result<(), Self::LoadError>; + + /// Récupère une ressource par son handle + fn get(&self, handle: &THandle) -> Option<&TResource>; + + /// Récupère une ressource mutable par son handle + fn get_mut(&mut self, handle: &THandle) -> Option<&mut TResource>; + + /// Supprime une ressource + fn unload(&mut self, handle: &THandle) -> Option; + + /// Vérifie si une ressource est chargée + fn is_loaded(&self, handle: &THandle) -> bool; + + /// Retourne tous les handles chargés + fn loaded_handles(&self) -> Vec; + + /// Nettoie toutes les ressources + fn clear(&mut self); +} + +/// Implémentation basique d'un gestionnaire de ressources +pub struct BasicResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + resources: HashMap, +} + +impl BasicResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + pub fn new() -> Self { + Self { + resources: HashMap::new(), + } + } + + pub fn with_capacity(capacity: usize) -> Self { + Self { + resources: HashMap::with_capacity(capacity), + } + } +} + +impl Default for BasicResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + fn default() -> Self { + Self::new() + } +} + +impl AsResourceManager + for BasicResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + type LoadError = ResourceLoadError; + + fn load(&mut self, handle: THandle, resource: TResource) -> Result<(), Self::LoadError> { + self.resources.insert(handle, resource); + Ok(()) + } + + fn get(&self, handle: &THandle) -> Option<&TResource> { + self.resources.get(handle) + } + + fn get_mut(&mut self, handle: &THandle) -> Option<&mut TResource> { + self.resources.get_mut(handle) + } + + fn unload(&mut self, handle: &THandle) -> Option { + self.resources.remove(handle) + } + + fn is_loaded(&self, handle: &THandle) -> bool { + self.resources.contains_key(handle) + } + + fn loaded_handles(&self) -> Vec { + self.resources.keys().cloned().collect() + } + + fn clear(&mut self) { + self.resources.clear(); + } +} + +pub struct ThreadSafeResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + resources: Arc>>>, +} + +impl ThreadSafeResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + pub fn new() -> Self { + Self { + resources: Arc::new(std::sync::RwLock::new(HashMap::new())), + } + } + + pub fn load(&self, handle: THandle, resource: TResource) -> Result<(), ResourceLoadError> { + let mut resources = self + .resources + .write() + .map_err(|_| ResourceLoadError::new("Failed to acquire write lock"))?; + resources.insert(handle, Arc::new(resource)); + Ok(()) + } + + pub fn get(&self, handle: &THandle) -> Option> { + let resources = self.resources.read().ok()?; + resources.get(handle).cloned() + } + + pub fn unload(&self, handle: &THandle) -> Option> { + let mut resources = self.resources.write().ok()?; + resources.remove(handle) + } + + pub fn is_loaded(&self, handle: &THandle) -> bool { + if let Ok(resources) = self.resources.read() { + resources.contains_key(handle) + } else { + false + } + } + + pub fn loaded_handles(&self) -> Vec { + if let Ok(resources) = self.resources.read() { + resources.keys().cloned().collect() + } else { + Vec::new() + } + } + + pub fn clear(&self) { + if let Ok(mut resources) = self.resources.write() { + resources.clear(); + } + } +} + +impl Clone for ThreadSafeResourceManager +where + THandle: Clone + Eq + Hash + Debug, +{ + fn clone(&self) -> Self { + Self { + resources: Arc::clone(&self.resources), + } + } +} + +pub trait AsAsyncLoadable +where + THandle: Clone + Eq + Hash + Debug + Send + Sync, +{ + type Resource: Send + Sync; + type LoadError: Error + Send + Sync; + + async fn load_async(handle: THandle) -> Result; +} diff --git a/src/core/render/primitives/transform.rs b/src/core/render/primitives/transform.rs index 4d870b0..a108d14 100644 --- a/src/core/render/primitives/transform.rs +++ b/src/core/render/primitives/transform.rs @@ -3,20 +3,20 @@ use std::sync::Arc; use glam::{Mat4, Quat, Vec3}; use vulkano::{ Validated, - buffer::{ - AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, - }, + buffer::{AllocateBufferError, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}, memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, pipeline::graphics::vertex_input::Vertex, }; +use crate::core::render::primitives::{AsBindableBuffer, AsVertexBuffer}; + pub struct Transform { pub position: Vec3, pub rotation: Quat, pub scale: Vec3, } -#[derive(BufferContents, Vertex)] +#[derive(BufferContents, Vertex, Clone, Copy)] #[repr(C)] pub struct TransformRaw { #[format(R32G32B32A32_SFLOAT)] @@ -59,23 +59,37 @@ impl Transform { memory_allocator: &Arc, transforms: &[Transform], ) -> Result, Validated> { - let transform_raws: Vec = - transforms.iter().map(|t| t.to_raw_tranform()).collect(); - - let buffer = Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - transform_raws, - )?; - - Ok(buffer) + TransformRaw::create_vertex_buffer( + memory_allocator, + &transforms + .iter() + .map(|t| t.to_raw_tranform()) + .collect::>(), + ) } } + +impl AsBindableBuffer for TransformRaw { + type BufferData = TransformRaw; + + fn buffer_create_info() -> BufferCreateInfo { + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + } + } + + fn allocation_create_info() -> AllocationCreateInfo { + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + } + + fn to_buffer_data(data: &TransformRaw) -> Self::BufferData { + *data + } +} + +impl AsVertexBuffer for TransformRaw {} diff --git a/src/core/render/primitives/vertex.rs b/src/core/render/primitives/vertex.rs index 166ac44..2a27b36 100644 --- a/src/core/render/primitives/vertex.rs +++ b/src/core/render/primitives/vertex.rs @@ -1,7 +1,11 @@ use vulkano::buffer::BufferContents; +use vulkano::buffer::{BufferCreateInfo, BufferUsage}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}; use vulkano::pipeline::graphics::vertex_input::Vertex; -#[derive(BufferContents, Vertex)] +use crate::core::render::primitives::{AsBindableBuffer, AsIndexBuffer, AsVertexBuffer}; + +#[derive(BufferContents, Vertex, Clone, Copy)] #[repr(C)] pub struct Vertex2D { #[format(R32G32_SFLOAT)] @@ -11,7 +15,7 @@ pub struct Vertex2D { pub uv: [f32; 2], } -#[derive(BufferContents, Vertex)] +#[derive(BufferContents, Vertex, Clone, Copy)] #[repr(C)] pub struct Vertex3D { #[format(R32G32B32_SFLOAT)] @@ -20,3 +24,78 @@ pub struct Vertex3D { #[format(R32G32_SFLOAT)] pub uv: [f32; 2], } + +impl AsBindableBuffer for Vertex2D { + type BufferData = Vertex2D; + + fn buffer_create_info() -> BufferCreateInfo { + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + } + } + + fn allocation_create_info() -> AllocationCreateInfo { + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + } + + fn to_buffer_data(data: &Vertex2D) -> Self::BufferData { + *data + } +} + +impl AsVertexBuffer for Vertex2D {} + +impl AsBindableBuffer for Vertex3D { + type BufferData = Vertex3D; + + fn buffer_create_info() -> BufferCreateInfo { + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + } + } + + fn allocation_create_info() -> AllocationCreateInfo { + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + } + + fn to_buffer_data(data: &Vertex3D) -> Self::BufferData { + *data + } +} + +impl AsVertexBuffer for Vertex3D {} + +impl AsBindableBuffer for u32 { + type BufferData = u32; + + fn buffer_create_info() -> BufferCreateInfo { + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + } + } + + fn allocation_create_info() -> AllocationCreateInfo { + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + } + } + + fn to_buffer_data(data: &u32) -> Self::BufferData { + *data + } +} + +impl AsIndexBuffer for u32 {} diff --git a/src/game/assets/square.rs b/src/game/assets/square.rs index c4a33ad..57e4138 100644 --- a/src/game/assets/square.rs +++ b/src/game/assets/square.rs @@ -1,16 +1,15 @@ -use std::{collections::BTreeMap, error::Error, sync::Arc}; +use std::{error::Error, sync::Arc}; use vulkano::{ - buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}, + buffer::Subbuffer, command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, descriptor_set::{ - DescriptorSet, WriteDescriptorSet, - allocator::StandardDescriptorSetAllocator, - layout::{DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType}, + DescriptorSet, allocator::StandardDescriptorSetAllocator, + layout::DescriptorSetLayoutCreateInfo, }, device::Device, format::Format, - memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, + memory::allocator::StandardMemoryAllocator, pipeline::{ DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, PipelineShaderStageCreateInfo, @@ -27,11 +26,13 @@ use vulkano::{ }, layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}, }, - shader::ShaderStages, }; use crate::core::render::{ - primitives::{AsBindableDescriptorSet, mvp::Mvp, transform::TransformRaw, vertex::Vertex3D}, + primitives::{ + AsBindableDescriptorSet, AsDrawable, AsIndexBuffer, AsRecordable, AsVertexBuffer, mvp::Mvp, + transform::TransformRaw, vertex::Vertex3D, + }, texture::Texture, }; @@ -80,6 +81,14 @@ pub struct Square { pipeline: Arc, } +/// Structure pour encapsuler les données de rendu du Square +pub struct SquareRenderData<'a> { + pub square: &'a Square, + pub mvp_uniform: &'a Subbuffer<[Mvp]>, + pub transform_uniform: &'a Subbuffer<[TransformRaw]>, + pub texture: &'a Texture, +} + impl Square { pub fn new( device: &Arc, @@ -87,32 +96,9 @@ impl Square { swapchain_format: Format, depth_format: Format, ) -> Result> { - let vertex_buffer = Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - Vec::from_iter(VERTICES), - )?; - let index_buffer = Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::INDEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - Vec::from_iter(INDICES), - )?; + let vertex_buffer = Vertex3D::create_vertex_buffer(memory_allocator, &VERTICES)?; + + let index_buffer = u32::create_index_buffer(memory_allocator, &INDICES)?; let vs = shaders::vs::load(device.clone())? .entry_point("main") @@ -197,6 +183,13 @@ impl Square { transform_uniform: &Subbuffer<[TransformRaw]>, texture: &Texture, ) -> Result<(), Box> { + let render_data = SquareRenderData { + square: self, + mvp_uniform, + transform_uniform, + texture, + }; + let layouts = self.pipeline.layout().set_layouts(); let uniform_descriptor_set = @@ -205,25 +198,86 @@ impl Square { let texture_descriptor_set = Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?; - command_buffer.bind_pipeline_graphics(self.pipeline.clone())?; - command_buffer.bind_descriptor_sets( - PipelineBindPoint::Graphics, - self.pipeline.layout().clone(), - 0, - vec![uniform_descriptor_set, texture_descriptor_set], + // Utiliser les nouveaux traits pour le rendu + Self::record_render_commands( + command_buffer, + &render_data, + &self.pipeline, + &[uniform_descriptor_set, texture_descriptor_set], )?; - command_buffer - .bind_vertex_buffers(0, (self.vertex_buffer.clone(), transform_uniform.clone()))?; - command_buffer.bind_index_buffer(self.index_buffer.clone())?; - unsafe { - command_buffer.draw_indexed( - INDICES.len() as u32, - transform_uniform.len() as u32, - 0, - 0, - 0, - )?; + Ok(()) + } +} + +// Implémentation des nouveaux traits pour Square +impl<'a> AsDrawable> for Square { + type VertexBuffer = Subbuffer<[Vertex3D]>; + type IndexBuffer = Subbuffer<[u32]>; + + fn vertex_buffer(data: &SquareRenderData<'a>) -> &'a Self::VertexBuffer { + &data.square.vertex_buffer + } + + fn index_buffer(data: &SquareRenderData<'a>) -> Option<&'a Self::IndexBuffer> { + Some(&data.square.index_buffer) + } + + fn vertex_count(_data: &SquareRenderData<'a>) -> u32 { + VERTICES.len() as u32 + } + + fn index_count(_data: &SquareRenderData<'a>) -> u32 { + INDICES.len() as u32 + } + + fn instance_count(data: &SquareRenderData<'a>) -> u32 { + data.transform_uniform.len() as u32 + } +} + +impl<'a> AsRecordable> for Square { + fn record_render_commands( + builder: &mut AutoCommandBufferBuilder, + data: &SquareRenderData<'a>, + pipeline: &Arc, + descriptor_sets: &[Arc], + ) -> Result<(), Box> { + // Bind pipeline + builder.bind_pipeline_graphics(pipeline.clone())?; + + // Bind descriptor sets + builder.bind_descriptor_sets( + PipelineBindPoint::Graphics, + pipeline.layout().clone(), + 0, + descriptor_sets.iter().cloned().collect::>(), + )?; + + // Bind buffers + builder.bind_vertex_buffers( + 0, + ( + Self::vertex_buffer(data).clone(), + data.transform_uniform.clone(), + ), + )?; + + if let Some(index_buffer) = Self::index_buffer(data) { + builder.bind_index_buffer(index_buffer.clone())?; + unsafe { + builder.draw_indexed( + Self::index_count(data), + Self::instance_count(data), + 0, + 0, + 0, + )?; + } + } else { + unsafe { + builder.draw(Self::vertex_count(data), Self::instance_count(data), 0, 0)?; + } } Ok(())