use std::{iter, sync::{Arc, RwLock}};
use vulkano::{buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool}, command_buffer::AutoCommandBufferBuilder, command_buffer::{AutoCommandBuffer, DynamicState}, descriptor::{DescriptorSet, descriptor_set::PersistentDescriptorSet}, device::Queue, framebuffer::{RenderPassAbstract, Subpass}, pipeline::{GraphicsPipeline, GraphicsPipelineAbstract}};
use crate::{components::{Normal, TextureIndex, Vertex}, scene::game_object::camera::Camera, shaders::{fs_draw, vs_draw}};
use vulkano::pipeline::viewport::Viewport;
use super::three_vertex_buffers_definition::ThreeBuffersDefinition;
pub struct DrawPassManager {
gfx_queue: Arc<Queue>,
pub(crate) pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub(crate) vertex_buffers: Vec<Arc<CpuAccessibleBuffer<[Vertex]>>>,
pub(crate) normal_buffers: Vec<Arc<CpuAccessibleBuffer<[Normal]>>>,
pub(crate) texture_index_buffers: Vec<Arc<CpuAccessibleBuffer<[TextureIndex]>>>,
pub(crate) scene_buffer: CpuBufferPool<vs_draw::ty::Camera>,
pub(crate) scene_set: Option<Arc<dyn DescriptorSet + Send + Sync>>,
pub(crate) world_buffers: CpuBufferPool<vs_draw::ty::World>,
pub(crate) world_sets: Vec<Arc<dyn DescriptorSet + Send + Sync>>,
pub(crate) material_buffers: CpuBufferPool<fs_draw::ty::Material>,
pub(crate) material_sets: Vec<Arc<dyn DescriptorSet + Send + Sync>>,
}
impl DrawPassManager {
pub fn new<R>(gfx_queue: Arc<Queue>, subpass: Subpass<R>, viewport_dimensions: [u32; 2]) -> DrawPassManager
where R: RenderPassAbstract + Send + Sync + 'static {
let scene_buffer = CpuBufferPool::<vs_draw::ty::Camera>::new(gfx_queue.device().clone(), BufferUsage::all());
let world_buffers = CpuBufferPool::<vs_draw::ty::World>::new(gfx_queue.device().clone(), BufferUsage::all());
let material_buffers = CpuBufferPool::<fs_draw::ty::Material>::new(gfx_queue.device().clone(), BufferUsage::all());
let vs = vs_draw::Shader::load(gfx_queue.device().clone()).unwrap();
let fs = fs_draw::Shader::load(gfx_queue.device().clone()).unwrap();
let pipeline = Arc::new(
GraphicsPipeline::start()
.vertex_input(ThreeBuffersDefinition::<Vertex, Normal, TextureIndex>::new()) .vertex_shader(vs.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.viewports(iter::once(Viewport {
origin: [0.0, 0.0],
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
depth_range: 0.0..1.0,
}))
.fragment_shader(fs.main_entry_point(), ())
.depth_write(true)
.depth_stencil_simple_depth()
.render_pass(subpass)
.build(gfx_queue.device().clone()).unwrap()
);
DrawPassManager {
gfx_queue,
pipeline: pipeline as Arc<_>,
vertex_buffers: Vec::new(),
normal_buffers: Vec::new(),
texture_index_buffers: Vec::new(),
scene_buffer,
scene_set: None,
world_buffers,
world_sets: Vec::new(),
material_buffers,
material_sets: Vec::new(),
}
}
pub fn recreate_camera_set(&mut self, camera: Arc<RwLock<dyn Camera>>){
self.scene_set = Some({
let uniform_buffer_subbuffer = {
let camera = camera.clone();
let camera = camera.read().expect("Unable to acquire read lock on main camera"); let uniform_data: vs_draw::ty::Camera = camera.create_uniforms();
self.scene_buffer.next(uniform_data).unwrap()
};
let layout = self.pipeline.descriptor_set_layout(0).unwrap();
Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(uniform_buffer_subbuffer).unwrap()
.build().unwrap()
)
});
}
#[inline]
pub fn clear(&mut self){
self.vertex_buffers = Vec::new();
self.normal_buffers = Vec::new();
self.texture_index_buffers = Vec::new();
self.world_sets = Vec::new();
self.material_sets = Vec::new();
self.scene_set = None;
}
pub fn draw(&self) -> AutoCommandBuffer {
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),
self.pipeline.clone().subpass().clone(),
).unwrap();
(0..self.vertex_buffers.len()).for_each(|i| {
builder.draw(
self.pipeline.clone(),
&DynamicState::none(),
vec![
self.vertex_buffers[i].clone(),
self.normal_buffers[i].clone(),
self.texture_index_buffers[i].clone()
],
vec![
self.scene_set.clone().unwrap(),
self.world_sets[i].clone(),
self.material_sets[i].clone(),
],
(),
vec![],
).unwrap();
});
builder.build().unwrap()
}
pub fn rebuild(
&mut self,
dimensions: &[u32; 2],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) {
let vs = vs_draw::Shader::load(self.gfx_queue.device().clone()).unwrap();
let fs = fs_draw::Shader::load(self.gfx_queue.device().clone()).unwrap();
self.pipeline = Arc::new(
GraphicsPipeline::start()
.vertex_input(ThreeBuffersDefinition::<Vertex, Normal, TextureIndex>::new()) .vertex_shader(vs.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.viewports(iter::once(Viewport {
origin: [0.0, 0.0],
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
depth_range: 0.0..1.0,
}))
.fragment_shader(fs.main_entry_point(), ())
.depth_write(true)
.depth_stencil_simple_depth()
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.build(self.gfx_queue.device().clone())
.unwrap()
);
}
}