diff --git a/resources/images/button.png b/resources/images/button.png new file mode 100644 index 00000000..fe1cd4aa Binary files /dev/null and b/resources/images/button.png differ diff --git a/src/canvas.rs b/src/canvas.rs index 8c2266d7..fdbb0b90 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,5 +1,21 @@ - - +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; // Canvas is the accumulator of Sprites for drawing // Needs to know: @@ -12,34 +28,283 @@ 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. -Need to pull recreate swapchain out of shader_kernels.rs - 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 + } +} -trait Drawable { - fn draw() { +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; +} + + + pub struct Canvas { + colored_drawables : Vec, + + textured_drawables: HashMap>, + + vertex_buffers: Vec>, + + shader_kernels: Vec, + 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: Vec::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() -> + 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() + ); + } + + // The image set is the containing object for all texture and image hooks. + fn get_texture_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(0).unwrap().clone().unwrap().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_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(0).unwrap().clone().unwrap().get_pipeline(), 0 + ) + .add_image(self.compute_image.clone().unwrap().clone().get_swap_buffer().clone()).unwrap() + .build().unwrap()); + o + } + + + /* + + + So I need the image set in order to get my texture or compute texture + + compute image currently holds the set for compute and its swap buffer + + vkprocessor creates the image sets for draw calls + + takes the pipeline from the ShaderKernel + adds vk processor owned texture + adds compute image taken from the ComputeImage + + 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() + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 663f2d65..0b1c325f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,15 +47,17 @@ use winit::dpi::LogicalSize; use vulkano_win::VkSurfaceBuild; use sprite::Sprite; +mod util; + mod slider; mod timer; mod input; mod vkprocessor; -mod util; mod button; mod vertex_2d; mod vertex_3d; mod sprite; +mod canvas; fn main() { @@ -87,10 +89,8 @@ fn main() { let mut mouse_xy = Vector2i::new(0,0); - Sprite::new_with_color((0.,0.), (0,0), (0.,0.,0.,0.)); - while let Some(p) = window.get_position() { elapsed_time = timer.elap_time(); diff --git a/src/sprite.rs b/src/sprite.rs index a43ff910..49f376ff 100644 --- a/src/sprite.rs +++ b/src/sprite.rs @@ -1,9 +1,18 @@ use crate::vertex_2d::ColoredVertex2D; +use crate::canvas::Drawable; #[derive(Debug, Clone)] pub struct Sprite { - vertices: [ColoredVertex2D; 6], - color: [f32; 4], + pub vertices: [(f32, f32); 6], + + position: (f32, f32), + size: (u32, u32), + color: (f32, f32, f32, f32), + + textured: bool, + texture_id: i32, + + } impl Sprite { @@ -14,21 +23,80 @@ impl Sprite { pub fn new_with_color(position: (f32, f32), size: (u32, u32), color: (f32, f32, f32, f32)) -> Sprite { - let size = (size.0 as f32, size.1 as f32); - - let color = [color.0, color.1, color.2, color.3]; + let fsize = (size.0 as f32, size.1 as f32); Sprite { vertices: [ - ColoredVertex2D { position: [ position.0, position.1 ], color }, // top left - ColoredVertex2D { position: [ position.0, position.1 + size.1], color }, // bottom left - ColoredVertex2D { position: [ position.0 + size.0, position.1 + size.1 ], color }, // bottom right - - ColoredVertex2D { position: [ position.0, position.1 ], color }, // top left - ColoredVertex2D { position: [ position.0 + size.0, position.1 + size.1 ], color }, // bottom right - ColoredVertex2D { position: [ position.0 + size.0, position.1 ], color }, // top right + (position.0, position.1 ), // top left + (position.0, position.1 + fsize.1), // bottom left + (position.0 + fsize.0, position.1 + fsize.1 ), // bottom right + (position.0, position.1 ), // top left + (position.0 + fsize.0, position.1 + fsize.1 ), // bottom right + (position.0 + fsize.0, position.1 ), // top right ], + + position: position, + size: size, color: color, + textured: false, + texture_id: 0 + } + } + + pub fn new_with_texture(position: (f32, f32), size: (u32, u32), texture_id: i32) -> Sprite { + + let fsize = (size.0 as f32, size.1 as f32); + + Sprite { + vertices: [ + (position.0, position.1 ), // top left + (position.0, position.1 + fsize.1), // bottom left + (position.0 + fsize.0, position.1 + fsize.1 ), // bottom right + (position.0, position.1 ), // top left + (position.0 + fsize.0, position.1 + fsize.1 ), // bottom right + (position.0 + fsize.0, position.1 ), // top right + ], + position, + size, + color: (0.0, 0.0, 0.0, 0.0), + textured: false, + texture_id } } -} \ No newline at end of file + + + +} + +impl Drawable for Sprite { + fn get_vertices(&self) -> Vec<(f32,f32)> { + self.vertices.to_vec() + } + + fn get_color(&self) -> (f32, f32, f32, f32) { + self.color.clone() + } + + fn get_texture_id(&self) -> Option { + match self.textured { + true => { + Some(self.texture_id.clone()) + }, + false => None, + } + } +} + +/* + + let vertex_buffer = { + + CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::all(), [ + ColoredVertex2D { position: [ 1.0, 1.0 ], color }, + ColoredVertex2D { position: [ 1.0, 0.5 ], color }, + ColoredVertex2D { position: [ 0.5, 0.5 ], color }, + ColoredVertex2D { position: [ 0.5, 1.0 ], color }, + ].iter().cloned()).unwrap() + }; + +*/ \ No newline at end of file diff --git a/src/util.rs b/src/util.rs deleted file mode 100644 index e8c2a924..00000000 --- a/src/util.rs +++ /dev/null @@ -1,34 +0,0 @@ -//use crate::error::CompileError; -//use shaderc::{IncludeType, ResolvedInclude}; -//use shaderc::{ShaderKind, CompileOptions}; -//use std::fs::File; -//use std::io::Read; -//use std::path::{Path, PathBuf}; -// -// -// -//pub fn compile(path: T, shader_kind: ShaderKind) -> Result, CompileError> -// where -// T: AsRef, -//{ -// // TODO Probably shouldn't create this every time. -// let mut compiler = shaderc::Compiler::new().ok_or(CompileError::CreateCompiler)?; -// let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler)?; -// let mut f = File::open(&path).map_err(CompileError::Open)?; -// let mut src = String::new(); -// f.read_to_string(&mut src).map_err(CompileError::Open)?; -// options.set_include_callback(|path, include_type, folder_path, depth| { -// get_include(path, include_type, folder_path, depth) -// }); -// let result = compiler -// .compile_into_spirv( -// src.as_str(), -// shader_kind, -// path.as_ref().to_str().ok_or(CompileError::InvalidPath)?, -// "main", -// Some(&options), -// ) -// .map_err(CompileError::Compile)?; -// let data = result.as_binary(); -// Ok(data.to_owned()) -//} \ No newline at end of file diff --git a/src/vkprocessor/compute_image.rs b/src/util/compute_image.rs similarity index 100% rename from src/vkprocessor/compute_image.rs rename to src/util/compute_image.rs diff --git a/src/vkprocessor/compute_kernel.rs b/src/util/compute_kernel.rs similarity index 100% rename from src/vkprocessor/compute_kernel.rs rename to src/util/compute_kernel.rs diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 00000000..b9d1e648 --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,3 @@ +pub mod compute_image; +pub mod compute_kernel; +pub mod shader_kernels; \ No newline at end of file diff --git a/src/vkprocessor/shader_kernels.rs b/src/util/shader_kernels.rs similarity index 100% rename from src/vkprocessor/shader_kernels.rs rename to src/util/shader_kernels.rs diff --git a/src/vertex_2d.rs b/src/vertex_2d.rs index 92996d70..2bee1a0a 100644 --- a/src/vertex_2d.rs +++ b/src/vertex_2d.rs @@ -10,4 +10,13 @@ pub struct ColoredVertex2D { pub color : [f32; 4], } -vulkano::impl_vertex!(ColoredVertex2D, position, color); \ No newline at end of file +vulkano::impl_vertex!(ColoredVertex2D, position, color); +vulkano::impl_vertex!(Vertex2D, position); + + + +impl From<(f32, f32)> for Vertex2D { + fn from(item: (f32, f32)) -> Self { + Vertex2D { position: [item.0, item.1] } + } +} \ No newline at end of file diff --git a/src/vertex_3d.rs b/src/vertex_3d.rs index ac822cfd..b1afc5b5 100644 --- a/src/vertex_3d.rs +++ b/src/vertex_3d.rs @@ -8,4 +8,8 @@ pub struct Vertex3D { pub struct ColoredVertex3D { position: [f32; 3], color : [u8; 4], -} \ No newline at end of file +} + +vulkano::impl_vertex!(ColoredVertex3D, position, color); +vulkano::impl_vertex!(Vertex3D, position); + diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index b9fa02c6..5a8f229e 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -35,22 +35,19 @@ use vulkano::image::immutable::ImmutableImage; use vulkano::image::attachment::AttachmentImage; use vulkano::image::{Dimensions, ImageUsage, ImageAccess, ImageDimensions}; use vulkano::format::Format; +use vulkano::format::ClearValue; use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode}; use image::flat::NormalForm::ColumnMajorPacked; -mod compute_kernel; -use crate::vkprocessor::compute_kernel::ComputeKernel; - -mod shader_kernels; -use crate::vkprocessor::shader_kernels::ShaderKernels; - -mod compute_image; -use crate::vkprocessor::compute_image::ComputeImage; +use crate::util::compute_kernel::ComputeKernel; +use crate::util::shader_kernels::ShaderKernels; +use crate::util::compute_image::ComputeImage; use vulkano::descriptor::descriptor::DescriptorDesc; use crate::vertex_2d::ColoredVertex2D; + /// This method is called once during initialization, then again whenever the window is resized fn window_size_dependent_setup( images: &[Arc>], @@ -100,6 +97,8 @@ pub struct VkProcessor<'a> { pub swapchain: Option>>, pub swapchain_images: Option>>>, + swapchain_recreate_needed: bool, + } @@ -137,7 +136,8 @@ impl<'a> VkProcessor<'a> { textures: vec![], compute_image: None, swapchain: None, - swapchain_images: None + swapchain_images: None, + swapchain_recreate_needed: false, } } @@ -176,7 +176,7 @@ impl<'a> VkProcessor<'a> { Swapchain::new(self.device.clone(), surface.clone(), - capabilities.min_image_count, + capabilities.min_image_count, // number of attachment images format, initial_dimensions, 1, // Layers @@ -287,6 +287,9 @@ impl<'a> VkProcessor<'a> { ].iter().cloned()).unwrap() }; + + + self.vertex_buffer = Some(vertex_buffer); self.vertex_buffer2 = Some(vertex_buffer2); @@ -344,20 +347,17 @@ impl<'a> VkProcessor<'a> { self.shader_kernels.clone().unwrap().render_pass.clone(), &mut self.dynamic_state); - let mut recreate_swapchain = false; - // The docs said to call this on each loop. frame_future.cleanup_finished(); // Whenever the window resizes we need to recreate everything dependent on the window size. // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. - if recreate_swapchain { + if self.swapchain_recreate_needed { self.recreate_swapchain(surface); framebuffers = window_size_dependent_setup(&self.swapchain_images.clone().unwrap().clone(), self.shader_kernels.clone().unwrap().render_pass.clone(), - //self.render_pass.clone().unwrap().clone(), &mut self.dynamic_state); - recreate_swapchain = false; + self.swapchain_recreate_needed = false; } // This function can block if no image is available. The parameter is an optional timeout @@ -365,15 +365,14 @@ impl<'a> VkProcessor<'a> { let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(self.swapchain.clone().unwrap().clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - //continue; - panic!("Weird thing"); + self.swapchain_recreate_needed = true; + return Box::new(sync::now(self.device.clone())) as Box<_>; } Err(err) => panic!("{:?}", err) }; // Specify the color to clear the framebuffer with i.e. blue - let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into()); + let clear_values = vec!(ClearValue::Float([0.0, 0.0, 1.0, 1.0])); let mut v = Vec::new(); v.push(self.vertex_buffer.clone().unwrap().clone()); @@ -383,7 +382,7 @@ impl<'a> VkProcessor<'a> { let xy = self.compute_image.clone().unwrap().get_size(); - let command_buffer = + let mut command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(self.device.clone(), self.queue.family()) .unwrap() @@ -395,19 +394,20 @@ impl<'a> VkProcessor<'a> { .copy_buffer_to_image(self.compute_image.clone().unwrap().clone().rw_buffers.get(0).unwrap().clone(), self.compute_image.clone().unwrap().clone().get_swap_buffer().clone()).unwrap() - .begin_render_pass(framebuffers[image_num].clone(), false, clear_values) + .begin_render_pass(framebuffers[image_num].clone(), false, clear_values.clone()) .unwrap() .draw(self.shader_kernels.clone().unwrap().get_pipeline(), &self.dynamic_state.clone(), v, vec![self.get_image_set()], ()) - .unwrap() + .unwrap(); - .draw(self.shader_kernels.clone().unwrap().get_pipeline(), + command_buffer = command_buffer.draw(self.shader_kernels.clone().unwrap().get_pipeline(), &self.dynamic_state.clone(), v2, vec![self.get_gui_image_set()], ()) - .unwrap() + .unwrap(); + let command_buffer = command_buffer .end_render_pass() .unwrap() @@ -424,7 +424,7 @@ impl<'a> VkProcessor<'a> { (Box::new(future) as Box<_>) } Err(FlushError::OutOfDate) => { - recreate_swapchain = true; + self.swapchain_recreate_needed = true; (Box::new(sync::now(self.device.clone())) as Box<_>) } Err(e) => {