use crate::vertex_2d::{ColoredVertex2D, Vertex2D}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use std::collections::HashMap; use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer}; use std::sync::Arc; use vulkano::format::{ClearValue, Format}; use vulkano::framebuffer::{FramebufferAbstract, Framebuffer}; use vulkano::device::{Device, Queue}; use vulkano::instance::PhysicalDevice; use vulkano::image::immutable::ImmutableImage; use vulkano::image::{Dimensions, ImageAccess, ImageDimensions, SwapchainImage, ImageUsage, AttachmentImage}; use vulkano::sampler::{Sampler, SamplerAddressMode, MipmapMode, Filter}; use vulkano::descriptor::DescriptorSet; use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; use std::path::PathBuf; use image::GenericImageView; use std::iter::FromIterator; use vulkano::swapchain::Capabilities; use winit::Window; use vulkano::pipeline::viewport::Viewport; use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer; use crate::canvas_frame::CanvasFrame; use std::hash::Hash; use crate::canvas_shader::CanvasShader; use crate::canvas_buffer::{CanvasImage, CanvasTexture}; // Canvas is the accumulator of Sprites for drawing // Needs to know: // textured? // colored? // vertices /* If it is textured. It needs to be rendered with the texture shader which requires a separate graphics pipeline. Might as well have a new render pass as well. So framebuffer is tied to the swapchains images as well as the renderpass it appears that renderpass is tied to the individual shader */ // I want to be able to draw 2d sprites. // These sprites might be textured or a single color // All of the single colors will be grouped into one batch using colored vertices. // The rest will be grouped by their texture and run individually pub trait Vertex { fn position(&self) -> (f32, f32) { (0.0, 0.0) } fn color(&self) -> Option<(f32, f32, f32, f32)> { Some((0., 0., 0., 0.)) } } impl Vertex for ColoredVertex2D { fn position(&self) -> (f32, f32) { (0.0, 0.0) } fn color(&self) -> Option<(f32, f32, f32, f32)> { Some((0., 0., 0., 0.)) } } pub trait Drawable { fn get_vertices(&self) -> Vec<(f32, f32)>; fn get_color(&self) -> (f32, f32, f32, f32); fn get_texture_handle(&self) -> Option>; fn get_image_handle(&self) -> Option>; } // Need three types of shaders. Solid, Textured, Image #[derive(PartialEq, Eq, Hash, Clone)] pub enum ShaderType { SOLID = 0, TEXTURED = 1, IMAGE = 2, } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasTextureHandle { pub handle: u32 } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasImageHandle { pub handle: u32 } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasShaderHandle { pub handle: u32 } #[derive(Clone)] pub struct CanvasState { dynamic_state: DynamicState, sampler: Arc, // hold the image, texture, and shader buffers the same was as we do CompuState image_buffers: Vec>, texture_buffers: Vec>, shader_buffers: HashMap>, // Hold onto the vertices we get from the Compu and Canvas Frames // When the run comes around, push the vertices to the GPU colored_drawables: Vec, colored_vertex_buffer: Vec>, textured_drawables: HashMap, Vec>>, textured_vertex_buffer: HashMap, Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync)>>, image_drawables: HashMap, Vec>>, image_vertex_buffer: HashMap, Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync)>>, // Looks like we gotta hold onto the queue for managing textures queue: Arc, device: Arc, } impl CanvasState { // This method is called once during initialization, then again whenever the window is resized pub fn window_size_dependent_setup(&mut self, images: &[Arc>]) -> Vec> { let dimensions = images[0].dimensions(); self.dynamic_state.viewports = Some(vec![Viewport { origin: [0.0, 0.0], dimensions: [dimensions.width() as f32, dimensions.height() as f32], depth_range: 0.0..1.0, }]); images.iter().map(|image| { Arc::new( Framebuffer::start(self.shader_buffers.get("color-passthrough").unwrap().render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap() ) as Arc }).collect::>() } // needs to take in the texture list pub fn new(queue: Arc, device: Arc, physical: PhysicalDevice, capabilities: Capabilities) -> CanvasState { let solid_color_kernel = String::from("color-passthrough"); let texture_kernel = String::from("simple_texture"); CanvasState { dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, sampler: Sampler::new(device.clone(), Filter::Linear, Filter::Linear, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(), image_buffers: vec![], texture_buffers: vec![], shader_buffers: HashMap::from_iter(vec![ (solid_color_kernel.clone(), Arc::new(CanvasShader::new_colored(solid_color_kernel.clone(), capabilities.clone(), queue.clone(), physical.clone(), device.clone())) ), (texture_kernel.clone(), Arc::new(CanvasShader::new_textured(texture_kernel.clone(), capabilities.clone(), queue.clone(), physical.clone(), device.clone())) ), ]), colored_drawables: vec![], colored_vertex_buffer: vec![], textured_drawables: HashMap::default(), textured_vertex_buffer: Default::default(), image_drawables: Default::default(), image_vertex_buffer: Default::default(), queue: queue.clone(), device: device.clone(), } } pub fn create_image(&mut self, dimensions: (u32, u32), usage: ImageUsage) -> Arc { let handle = Arc::new(CanvasImageHandle { handle: self.image_buffers.len() as u32 }); let image = CanvasImage { handle: handle.clone(), buffer: AttachmentImage::with_usage( self.device.clone(), [dimensions.0, dimensions.1], Format::R8G8B8A8Uint, usage).unwrap(), size: dimensions, }; self.image_buffers.push(Arc::new(image)); handle } pub fn get_image(&self, image_handle: Arc) -> Arc { self.image_buffers.get((*image_handle).clone().handle as usize).unwrap() .clone().buffer.clone() } // TODO Handle file not found gracefully fn get_texture_from_file(&self, image_filename: String) -> Arc> { let project_root = std::env::current_dir() .expect("failed to get root directory"); let mut compute_path = project_root.clone(); compute_path.push(PathBuf::from("resources/images/")); compute_path.push(PathBuf::from(image_filename)); let img = image::open(compute_path).expect("Couldn't find image"); let xy = img.dimensions(); let data_length = xy.0 * xy.1 * 4; let pixel_count = img.raw_pixels().len(); let mut image_buffer = Vec::new(); if pixel_count != data_length as usize { println!("Creating apha channel..."); for i in img.raw_pixels().iter() { if (image_buffer.len() + 1) % 4 == 0 { image_buffer.push(255); } image_buffer.push(*i); } image_buffer.push(255); } else { image_buffer = img.raw_pixels(); } let (texture, tex_future) = ImmutableImage::from_iter( image_buffer.iter().cloned(), Dimensions::Dim2d { width: xy.0, height: xy.1 }, Format::R8G8B8A8Srgb, self.queue.clone(), ).unwrap(); texture } pub fn load_texture(&mut self, filename: String) -> Option> { let texture_buffer = self.get_texture_from_file(filename.clone()); let handle = Arc::new(CanvasTextureHandle { handle: self.texture_buffers.len() as u32 }); let texture = Arc::new(CanvasTexture { handle: handle.clone(), buffer: self.get_texture_from_file(filename.clone()), name: filename.clone(), size: (0, 0), }); self.texture_buffers.push(texture); Some(handle) } pub fn get_texture_handle(&self, texture_name: String) -> Option> { for i in self.texture_buffers.clone() { if i.name == texture_name { return Some(i.handle.clone()); } } None } pub fn get_texture(&self, texture_handle: Arc) -> Arc> { let handle = texture_handle.handle as usize; if let Some(i) = self.texture_buffers.get(handle) { return i.clone().buffer.clone(); } else { panic!("{} : Texture not loaded", handle); } } // After done using this, need to call allocated vertex buffers pub fn draw(&mut self, canvas_frame: CanvasFrame) { self.textured_drawables = canvas_frame.textured_drawables; self.colored_drawables = canvas_frame.colored_drawables; self.image_drawables = canvas_frame.image_drawables; self.allocate_vertex_buffers(self.device.clone()); } fn allocate_vertex_buffers(&mut self, device: Arc) { self.image_vertex_buffer.clear(); /* So a bit of brainstorming with the shaders: I compile shaders into their respective buffers and add them to a descriptor set along with the textures or whatever other resource buffer So I'm gonna fix that texturing issue by adding vertex texture coordinate attributes Still don't really know how I'm gonna do this... * Going to definitely need to use the CpuAccessbileBuffer * Maybe calculate deltas between frames??? * */ self.colored_vertex_buffer.clear(); { let g = hprof::enter("Colored Vertex Buffer"); self.colored_vertex_buffer.push( ImmutableBuffer::from_iter( self.colored_drawables.iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), ).unwrap().0 ); } self.textured_vertex_buffer.clear(); { let g = hprof::enter("Textured Vertex Buffer"); for (k, v) in self.textured_drawables.drain() { self.textured_vertex_buffer.insert( k.clone(), ImmutableBuffer::from_iter( v.first().unwrap().iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), ).unwrap().0, ); } } } fn get_solid_color_descriptor_set(&self, kernel: Arc) -> Box { let o: Box = Box::new( PersistentDescriptorSet::start( kernel.clone().get_pipeline().clone(), 0, ).build().unwrap()); o } pub fn draw_commands(&self, mut command_buffer: AutoCommandBufferBuilder, framebuffers: Vec>, image_num: usize) -> AutoCommandBufferBuilder { // Specify the color to clear the framebuffer with i.e. blue let clear_values = vec!(ClearValue::Float([0.0, 0.0, 1.0, 1.0])); let mut command_buffer = command_buffer.begin_render_pass( framebuffers[image_num].clone(), false, clear_values.clone(), ).unwrap(); // Solid colors let mut shader = self.shader_buffers.get("color-passthrough").unwrap().clone(); // This looks a little weird as colored_vertex_buffer is a vec of GPU allocated vecs. // But we can pass in multiple vertex buffers if !self.colored_vertex_buffer.is_empty() { command_buffer = command_buffer.draw( shader.get_pipeline().clone(), &self.dynamic_state.clone(), self.colored_vertex_buffer.clone(), (), (), ).unwrap(); } // Images let mut shader = self.shader_buffers.get("simple_texture").unwrap().clone(); if !self.textured_vertex_buffer.is_empty() { let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone(); // TODO : BAD BAD BAD. SELECTS FIRST TEXTURE ONLY!!!!!!!!!!!! let descriptor_set = self.texture_buffers.first().clone().unwrap().clone() .get_descriptor_set(shader.clone(), self.sampler.clone()); let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone(); command_buffer = command_buffer.draw( shader.get_pipeline().clone(), &self.dynamic_state.clone(), vec![vertex_buffer], vec![descriptor_set], (), ).unwrap(); } /*for (shader_type, kernel) in self.shader_kernels.clone().iter() { match shader_type { ShaderType::SOLID => { } ShaderType::TEXTURED => { command_buffer = command_buffer.draw( kernel.clone().get_pipeline().clone(), &dynamic_state.clone(), self.textured_vertex_buffer.clone(), vec![self.get_textured_descriptor_set(String::from("funky-bird.jpg"))], () ).unwrap(); } ShaderType::IMAGE => {} } }*/ command_buffer .end_render_pass() .unwrap() } }