use std::{error::Error, sync::Arc}; use vulkano::{ buffer::Subbuffer, command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, descriptor_set::{ DescriptorSet, allocator::StandardDescriptorSetAllocator, layout::DescriptorSetLayoutCreateInfo, }, device::Device, format::Format, memory::allocator::StandardMemoryAllocator, pipeline::{ DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, PipelineShaderStageCreateInfo, graphics::{ GraphicsPipelineCreateInfo, color_blend::{ColorBlendAttachmentState, ColorBlendState}, depth_stencil::{DepthState, DepthStencilState}, input_assembly::InputAssemblyState, multisample::MultisampleState, rasterization::RasterizationState, subpass::PipelineRenderingCreateInfo, vertex_input::{Vertex, VertexDefinition}, viewport::ViewportState, }, layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}, }, }; use crate::core::render::{ primitives::{ AsBindableDescriptorSet, AsDrawable, AsIndexBuffer, AsRecordable, AsVertexBuffer, mvp::Mvp, transform::TransformRaw, vertex::Vertex3D, }, texture::Texture, }; const VERTICES: [Vertex3D; 4] = [ Vertex3D { position: [-0.5, -0.5, 0.0], uv: [0.0, 0.0], }, Vertex3D { position: [-0.5, 0.5, 0.0], uv: [0.0, 1.0], }, Vertex3D { position: [0.5, -0.5, 0.0], uv: [1.0, 0.0], }, Vertex3D { position: [0.5, 0.5, 0.0], uv: [1.0, 1.0], }, ]; const INDICES: [u32; 6] = [0, 2, 1, 2, 3, 1]; pub mod shaders { pub mod vs { vulkano_shaders::shader! { ty: "vertex", path: r"res/shaders/vertex.vert", generate_structs: false, } } pub mod fs { vulkano_shaders::shader! { ty: "fragment", path: r"res/shaders/vertex.frag", generate_structs: false, } } } pub struct Square { vertex_buffer: Subbuffer<[Vertex3D]>, index_buffer: Subbuffer<[u32]>, 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 descriptor_sets: &'a [Arc], pub texture: &'a Texture, } impl Square { pub fn new( device: &Arc, memory_allocator: &Arc, swapchain_format: Format, depth_format: Format, ) -> Result> { 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") .ok_or("Failed find main entry point of vertex shader".to_string())?; let fs = shaders::fs::load(device.clone())? .entry_point("main") .ok_or("Failed find main entry point of fragment shader".to_string())?; let vertex_input_state = [Vertex3D::per_vertex(), TransformRaw::per_instance()].definition(&vs)?; let stages = [ PipelineShaderStageCreateInfo::new(vs), PipelineShaderStageCreateInfo::new(fs), ]; let vertex_bindings = Mvp::as_descriptor_set_layout_bindings(); let texture_bindings = Texture::as_descriptor_set_layout_bindings(); let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo { bindings: vertex_bindings, ..Default::default() }; let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo { bindings: texture_bindings, ..Default::default() }; let create_info = PipelineDescriptorSetLayoutCreateInfo { set_layouts: vec![vertex_descriptor_set_layout, fragment_descriptor_set_layout], flags: PipelineLayoutCreateFlags::default(), push_constant_ranges: vec![], } .into_pipeline_layout_create_info(device.clone())?; let layout = PipelineLayout::new(device.clone(), create_info)?; let subpass = PipelineRenderingCreateInfo { color_attachment_formats: vec![Some(swapchain_format)], depth_attachment_format: Some(depth_format), ..Default::default() }; let pipeline = GraphicsPipeline::new( device.clone(), None, GraphicsPipelineCreateInfo { stages: stages.into_iter().collect(), vertex_input_state: Some(vertex_input_state), input_assembly_state: Some(InputAssemblyState::default()), viewport_state: Some(ViewportState::default()), rasterization_state: Some(RasterizationState::default()), multisample_state: Some(MultisampleState::default()), color_blend_state: Some(ColorBlendState::with_attachment_states( subpass.color_attachment_formats.len() as u32, ColorBlendAttachmentState::default(), )), depth_stencil_state: Some(DepthStencilState { depth: Some(DepthState::simple()), ..Default::default() }), dynamic_state: [DynamicState::Viewport].into_iter().collect(), subpass: Some(subpass.into()), ..GraphicsPipelineCreateInfo::layout(layout) }, )?; Ok(Self { vertex_buffer, index_buffer, pipeline, }) } pub fn render( &self, command_buffer: &mut AutoCommandBufferBuilder, descriptor_set_allocator: &Arc, mvp_uniform: &Subbuffer<[Mvp]>, transform_uniform: &Subbuffer<[TransformRaw]>, texture: &Texture, ) -> Result<(), Box> { let layouts = self.pipeline.layout().set_layouts(); let uniform_descriptor_set = Mvp::as_descriptor_set(descriptor_set_allocator, &layouts[0], mvp_uniform)?; let texture_descriptor_set = Texture::as_descriptor_set(descriptor_set_allocator, &layouts[1], texture)?; let render_data = SquareRenderData { square: self, mvp_uniform, transform_uniform, texture, descriptor_sets: &[uniform_descriptor_set, texture_descriptor_set], }; // Utiliser les nouveaux traits pour le rendu Self::record_render_commands(command_buffer, &self.pipeline, &render_data)?; Ok(()) } } impl<'a> AsRecordable> for Square { fn record_render_commands( builder: &mut AutoCommandBufferBuilder, pipeline: &Arc, data: &SquareRenderData<'a>, ) -> Result<(), Box> { // Bind pipeline builder.bind_pipeline_graphics(pipeline.clone())?; // Bind descriptor sets builder.bind_descriptor_sets( PipelineBindPoint::Graphics, pipeline.layout().clone(), 0, data.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(()) } }