use crate::vertex_2d::{ColoredVertex2D, Vertex2D}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use crate::Sprite; use std::collections::HashMap; use vulkano::buffer::{BufferAccess, CpuAccessibleBuffer, BufferUsage}; use std::sync::Arc; use vulkano::format::{ClearValue, Format}; use vulkano::framebuffer::FramebufferAbstract; use vulkano::device::{Device, Queue}; use vulkano::instance::PhysicalDevice; use vulkano::image::immutable::ImmutableImage; use crate::util::shader_kernels::ShaderKernels; use vulkano::image::{Dimensions, ImageUsage, ImageAccess, ImageDimensions}; 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 crate::util::compute_image::ComputeImage; // 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. I need a second version of shaderkernels 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 /* vertex count differing is a big nono ColoredVertex2D Non-Textured Vertex2D Textured Colored, vs non-colored: Calling the color() field or not I just wanna */ 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.)) } fn textured(&self) -> bool { false } } 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.)) } fn textured(&self) -> bool { false } } pub trait Drawable { fn get_vertices(&self) -> Vec<(f32, f32)>; fn get_color(&self) -> (f32, f32, f32, f32); fn get_texture_id(&self) -> Option; } /* OASIJDOQIWEJFOWIEJFOWIEJFOWEIJFOIWEJFOIW Right now I'm in the middle of adding texture ownership to the canvas. I'm aiming at being able to load them on the fly from what texture name (String) the sprite is requesting. This might be too slow though as I can't really avoid a lookup table somewhere in the code. */ // Need three types of shaders. Solid, Textured, Compute #[derive(PartialEq)] #[derive(Eq)] #[derive(Hash)] pub enum ShaderType { SOLID = 0, TEXTURED = 1, COMPUTE = 2 } pub struct Canvas { colored_drawables : Vec, textured_drawables: HashMap>, vertex_buffers: Vec>, shader_kernels: HashMap, textures: Vec>>, } impl Canvas { // needs to take in the texture list pub fn new() -> Canvas { Canvas { colored_drawables: vec![], textured_drawables: Default::default(), vertex_buffers: vec![], shader_kernels: HashMap::new(), textures: vec![] } } fn get_texture_from_file(image_filename: String, queue: Arc) -> 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, queue.clone() ).unwrap(); texture } pub fn load_texture_from_filename(&mut self, filename: String, queue: Arc) { let texture = Canvas::get_texture_from_file(filename.clone(), queue.clone()); self.textures.push(texture); let texture1 = Canvas::get_texture_from_file(String::from("button.png"), queue.clone()); self.textures.push(texture1); } pub fn draw(&mut self, drawable: &dyn Drawable) { match drawable.get_texture_id() { Some(id) => { // This dont work self.textured_drawables.get(&id).unwrap(); }, None => { let colors = drawable.get_color(); self.colored_drawables.extend( drawable.get_vertices().iter().map(|n| ColoredVertex2D { position: [n.0, n.1], color: [colors.0, colors.1, colors.2, colors.3] } ) ); } } } pub fn allocate_vertex_buffers(&mut self, device: Arc) { self.vertex_buffers.push( CpuAccessibleBuffer::from_iter( device.clone(), BufferUsage::vertex_buffer(), self.colored_drawables.iter().cloned() ).unwrap() ); } // I guess these go out as an array. So I can add multiple descriptor sets // So probably needs to know which shaders are for textures // needs to associate this descriptor set to a texture (key-pair, tuple) // // So this is fine for now. But I want to be able to: // Choose which texture I want to add to this descriptor set. // Add multiple textures // Choose which shader and pipeline it should run on fn get_texture_descriptor_set(&mut self, device: Arc) -> Box { let 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(); let o : Box = Box::new( PersistentDescriptorSet::start( self.shader_kernels.get(&ShaderType::TEXTURED).unwrap().clone().get_pipeline(), 0 ) .add_sampled_image(self.textures.get(0).unwrap().clone(), sampler.clone()).unwrap() .build().unwrap()); o } // The image set is the containing object for all texture and image hooks. fn get_compute_swap_descriptor_set(&mut self, device: Arc, compute_image: &ComputeImage) -> Box { let 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(); let o : Box = Box::new( PersistentDescriptorSet::start( self.shader_kernels.get(&ShaderType::COMPUTE).clone().unwrap().clone().get_pipeline(), 0 ) .add_image(compute_image.clone().get_swap_buffer().clone()).unwrap() .build().unwrap()); o } /* So I need the image set in order to get my texture or compute texture Done compute image currently holds the set for compute and its swap buffer but during a descriptor set build, we corrow the compute_image and take it's swap buffer vkprocessor creates the image sets for draw calls takes the pipeline from the ShaderKernel - Which we own adds vk processor owned texture - Not any more adds compute image taken from the ComputeImage - Still true we have shaderkernel in here so thats fine Who should own the texture? I would need to borrow it each time I created an image set... These are tied very closely to the input output of a shader, which we would own I just need to add a third option on sprite and allow it to have a swap buffer */ pub fn draw_commands(&mut self, 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 dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; let mut command_buffer = command_buffer.begin_render_pass( framebuffers[image_num].clone(), false, clear_values.clone() ).unwrap(); // for i in self.shader_kernels { // command_buffer = command_buffer.draw( // i.clone().unwrap().get_pipeline(), // &dynamic_state.clone(), self.vertex_buffers, // vec![self.get_image_set()], () // ).unwrap(); // } // // .draw(self.shader_kernels.clone().unwrap().get_pipeline(), // &dynamic_state.clone(), self.vertex_buffers, // vec![self.get_gui_image_set()], ()) // .unwrap(); // command_buffer .end_render_pass() .unwrap() } }