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}; /* 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 */ /// Vertex trait for Drawable Vertices. 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.)) } } /// A drawable object can be passed into a CanvasFrame to be rendered /// Allows Texture or Image drawing via their handles 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>; } /// Legacy ShaderType enum for single type shaders. #[derive(PartialEq, Eq, Hash, Clone)] pub enum ShaderType { SOLID = 0, TEXTURED = 1, IMAGE = 2, } /// Typed wrapper for a u32 texture handle (index id) #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasTextureHandle { pub handle: u32 } /// Typed wrapper for a u32 image handle (index id) #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct CanvasImageHandle { 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 { 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![]), 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) } /// Load and Compile a shader with the filename at resources/shaders /// Takes physical and capabilities as we don't store that in Canvas pub fn load_shader(&mut self, filename: String, physical: PhysicalDevice, capabilities: Capabilities) { self.shader_buffers.insert(filename.clone(), Arc::new(CanvasShader::new_colored(filename.clone(), capabilities.clone(), self.queue.clone(), physical.clone(), self.device.clone()))); } /// Using the texture name, iterates through the stored textures and matches by the name 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 } /// Using the texture handle, grab the stored texture and return the buffer 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); } } /// Scrape all the values from the CanvasFrame and then allocate the 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(); } /// draw(canvas_fame) stored all the intermediate information, this function /// allocates the vertex buffers using that information fn allocate_vertex_buffers(&mut self) { 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, ); } } self.image_vertex_buffer.clear(); { let g = hprof::enter("Image Vertex Buffer"); for (k, v) in self.image_drawables.drain() { self.image_vertex_buffer.insert( k.clone(), ImmutableBuffer::from_iter( v.first().unwrap().iter().cloned(), BufferUsage::vertex_buffer(), self.queue.clone(), ).unwrap().0, ); } } } /// Builds the descriptor set for solid colors using the input kernel (needs to support solid colors) 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 } /// Pushes the draw commands s 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(); } // Textures 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(); } let mut shader = self.shader_buffers.get("simple-image").unwrap().clone(); if !self.image_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(); } command_buffer .end_render_pass() .unwrap() } }