diff --git a/src/lib.rs b/src/lib.rs index f293da9..0f96ae8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod ds; pub mod object; pub mod material; -pub mod wgpu_handler; \ No newline at end of file +pub mod wgpu_handler; +pub mod ui; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 431bb01..18a7f83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; use clap::Parser; +use image::ImageReader; +use render_engine::ui::{self, UIElement}; use winit::application::ApplicationHandler; use winit::event::{ElementState, KeyEvent, WindowEvent, DeviceEvent, DeviceId}; use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; @@ -54,8 +56,9 @@ impl Arguments { struct App { // window - window: Option>, - gpu: wgpu_handler::GpuHandler, + window: Option>, + gpu: wgpu_handler::GpuHandler, + ui: Vec, // scene player: RwLock, @@ -77,9 +80,18 @@ struct App { impl App { pub fn new(config: Arguments, player: object::Player, objects: Vec>) -> Self { - Self { - window: None, - gpu: wgpu_handler::GpuHandler::default(), + let this: Self = Self { + window: None, + gpu: wgpu_handler::GpuHandler::default(), + ui: vec![ + ui::UIElement::new( + ui::Image::new( + ImageReader::open("./textures/crosshair.png").expect("No image").decode().expect("Bad decode").to_rgba8().into_raw(), + 16, 16 + ).unwrap(), + ui::VerticalAnchor::Middle, ui::HorizontalAnchor::Center + ) + ], player: RwLock::new(player), objects: objects, @@ -94,7 +106,9 @@ impl App { fps_stat: 0, deltatime_stat: 0, statistics_timer: std::time::Instant::now(), - } + }; + + this } pub fn handle_movement(&mut self) { @@ -149,8 +163,10 @@ impl App { .filter_map(|o| o.as_any().downcast_ref::()) .map(|s| s.to_gpu()) .collect(); + + let gpu_ui: Vec = self.ui.iter().map(|s| s.to_gpu()).collect(); - return self.gpu.draw_frame(&gpu_spheres, &gpu_quads, &mut uniform); + return self.gpu.draw_frame(&gpu_spheres, &gpu_quads, &gpu_ui, &mut uniform); } } @@ -174,7 +190,8 @@ impl ApplicationHandler for App { self.gpu.init( window.clone(), self.config.width as u32, - self.config.height as u32, + self.config.height as u32, + &mut self.ui, vec!["textures/dirt.png", "textures/grass_side.png", "textures/grass_top.png"]) ); diff --git a/src/object/camera.rs b/src/object/camera.rs index d22ef86..5c22707 100644 --- a/src/object/camera.rs +++ b/src/object/camera.rs @@ -30,7 +30,8 @@ pub struct GpuUniform { pub sphere_count: u32, pub pixel_delta_h: [f32; 3], pub quad_count: u32, - pub _pad_end: [u32; 48], // pad to 256 bytes + pub texture_count: u32, + pub _pad_end: [u32; 47], // pad to 256 bytes } impl Camera { @@ -125,7 +126,8 @@ impl Camera { height: self.window_dimensions.1 as u32, sphere_count: 0, quad_count: 0, - _pad_end: [0u32; 48], + texture_count: 0, + _pad_end: [0u32; 47], } } diff --git a/src/shaders/main.wgsl b/src/shaders/main.wgsl index a1a98ce..5d4153d 100644 --- a/src/shaders/main.wgsl +++ b/src/shaders/main.wgsl @@ -10,7 +10,6 @@ fn main( return; } - let pixel_center = uniforms.pixel00_loc + f32(x) * uniforms.pixel_delta_w + f32(y) * uniforms.pixel_delta_h; @@ -18,19 +17,66 @@ fn main( let ray_dir = pixel_center - uniforms.pos; let idx = y * uniforms.width + x; - - if uniforms.sphere_count == 0u && uniforms.quad_count == 0u { - output[idx] = 0x00FF0000u; - return; - } output[idx] = ray_color(uniforms.pos, ray_dir); } -// not sure what these do but docs say i need them +// fragment shader is the second pass @fragment fn fs_main(@builtin(position) pos: vec4) -> @location(0) vec4 { let idx = u32(pos.y) * uniforms.width + u32(pos.x); + + for (var i = 0u; i < uniforms.texture_count; i++) { + var ui_element = ui_info[i]; + + var top_left_y = ui_element.v_anchor * ((uniforms.height-ui_element.height)/2); + var top_left_x = ui_element.h_anchor * ((uniforms.width-ui_element.width)/2); + + // shorthand for this kinda thing + // switch ui_element.v_anchor { + // case 0: + // break; + // case 1: + // top_left_y = uniforms.height/2 - ui_element.height/2; + // break; + // case 2: + // top_left_y = uniforms.height - ui_element.height; + // } + + if( + u32(pos.x) >= top_left_x && + u32(pos.x) < top_left_x+ui_element.width && + u32(pos.y) >= top_left_y && + u32(pos.y) < top_left_y+ui_element.height + ) { + // we are inbound of the image, so draw the corresponding pixel + + let rel_x = u32(pos.x) - top_left_x; + let rel_y = u32(pos.y) - top_left_y; + + var c = ui_textures[ui_element.pointer + rel_x + rel_y*ui_element.width]; + let r = f32((c ) & 0xFFu) / 255.0; // u8s are written as little endian, so i read it backwards + let g = f32((c >> 8u ) & 0xFFu) / 255.0; + let b = f32((c >> 16u) & 0xFFu) / 255.0; + let a = f32((c >> 24u) & 0xFFu) / 255.0; + + c = output[idx]; + let bg = vec4( + f32((c >> 16u) & 0xFFu) / 255.0, + f32((c >> 8u) & 0xFFu) / 255.0, + f32( c & 0xFFu) / 255.0, + 1.0 + ); + + return vec4( + r * a + bg.r * (1.0 - a), + g * a + bg.g * (1.0 - a), + b * a + bg.b * (1.0 - a), + 1.0 + ); + } + } + let c = output[idx]; let r = f32((c >> 16u) & 0xFFu) / 255.0; let g = f32((c >> 8u) & 0xFFu) / 255.0; @@ -38,6 +84,7 @@ fn fs_main(@builtin(position) pos: vec4) -> @location(0) vec4 { return vec4(r, g, b, 1.0); } +// not sure what this does but docs say i need it @vertex fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4 { var positions = array, 3>( diff --git a/src/shaders/types.wgsl b/src/shaders/types.wgsl index 13150dd..30aa2bd 100644 --- a/src/shaders/types.wgsl +++ b/src/shaders/types.wgsl @@ -7,6 +7,7 @@ struct Uniform { sphere_count: u32, pixel_delta_h: vec3, quad_count: u32, + texture_count: u32, } struct Sphere { @@ -43,11 +44,21 @@ struct Material { texture_id: i32, } +struct UIElement { + v_anchor: u32, + h_anchor: u32, + width: u32, + height: u32, + pointer: u32 +} + @group(0) @binding(0) var uniforms: Uniform; @group(0) @binding(1) var output: array; @group(0) @binding(2) var spheres: array; @group(0) @binding(3) var quads: array; @group(0) @binding(4) var textures: texture_2d; +@group(0) @binding(5) var ui_info: array; +@group(0) @binding(6) var ui_textures: array; fn ray_at(ray_pos: vec3, ray_dir: vec3, t: f32) -> vec3 { return ray_pos + t * ray_dir; diff --git a/src/ui/anchor.rs b/src/ui/anchor.rs new file mode 100644 index 0000000..8e26835 --- /dev/null +++ b/src/ui/anchor.rs @@ -0,0 +1,46 @@ +pub struct Anchor { + pub v_anchor: VerticalAnchor, + pub h_anchor: HorizontalAnchor +} + +impl Anchor { + pub fn new(v: VerticalAnchor, h: HorizontalAnchor) -> Self { + Self { + v_anchor: v, + h_anchor: h, + } + } +} +#[derive(Copy, Clone)] +pub enum VerticalAnchor { + Top, + Middle, + Bottom +} + +impl From for u32 { + fn from(a: VerticalAnchor) -> u32 { + return match a { + VerticalAnchor::Top => 0, + VerticalAnchor::Middle => 1, + VerticalAnchor::Bottom => 2, + } + } +} + +#[derive(Copy, Clone)] +pub enum HorizontalAnchor { + Left, + Center, + Right +} + +impl From for u32 { + fn from(a: HorizontalAnchor) -> u32 { + return match a { + HorizontalAnchor::Left => 0, + HorizontalAnchor::Center => 1, + HorizontalAnchor::Right => 2, + } + } +} \ No newline at end of file diff --git a/src/ui/image.rs b/src/ui/image.rs new file mode 100644 index 0000000..e8c934c --- /dev/null +++ b/src/ui/image.rs @@ -0,0 +1,62 @@ +pub struct Image { + bytes: Vec, + width: usize, + height: usize, +} + +#[derive(Debug)] +pub enum ImageError { + UncaughtException, + TooManyBytes, + NotEnoughBytes +} + +impl Image { + pub fn new(bytes: Vec, width: usize, height: usize) -> Result { + return match width*height*4 { + d if d > bytes.len() => Err(ImageError::NotEnoughBytes), + d if d < bytes.len() => Err(ImageError::TooManyBytes), + d if d == bytes.len() => { + Ok(Self { + bytes: bytes, + width: width, + height: height, + }) + } + _ => Err(ImageError::UncaughtException), + } + } + + pub fn at(&self, x: usize, y: usize) -> Option<&[u8]> { + let i = x*4 + y*self.width*4; + if i+4 > self.bytes.len() { + return None + } + + Some(&self.bytes[i..i+4]) + } + + pub fn row(&self, y: usize) -> Option<&[u8]> { + if y >= self.height { + return None + } + + Some(&self.bytes[y*self.width*4..(y+1)*self.width*4]) + } + + pub fn size(&self) -> usize { + self.width * self.height * 4 + } + + pub fn width(&self) -> usize { + self.width + } + + pub fn height(&self) -> usize { + self.height + } + + pub fn bytes(&self) -> &[u8] { + &self.bytes + } +} \ No newline at end of file diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 0000000..e2ecf3c --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,9 @@ +pub mod anchor; +pub mod image; +pub mod ui_element; + +pub use anchor::Anchor; +pub use anchor::VerticalAnchor; +pub use anchor::HorizontalAnchor; +pub use image::Image; +pub use ui_element::UIElement; \ No newline at end of file diff --git a/src/ui/ui_element.rs b/src/ui/ui_element.rs new file mode 100644 index 0000000..ab38bde --- /dev/null +++ b/src/ui/ui_element.rs @@ -0,0 +1,54 @@ +use crate::object::renderable::ToGpu; +use crate::ui::Anchor; +use crate::ui::Image; +use crate::ui::anchor; + +pub struct UIElement { + image: Image, + anchor: Anchor, + gpu_offset: Option +} + +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct GPUUIElement { + pub v_anchor: u32, + pub h_anchor: u32, + pub width: u32, + pub height: u32, + pub pointer: u32 +} + +impl<'a> UIElement { + pub fn new(image: Image, v_anchor: anchor::VerticalAnchor, h_anchor: anchor::HorizontalAnchor) -> UIElement { + Self { + image: image, + anchor: Anchor::new(v_anchor, h_anchor), + gpu_offset: None + } + } + + pub fn get_image(&self) -> &Image { + &self.image + } + + pub fn get_anchor(&'a self) -> &'a Anchor { + &self.anchor + } + + pub fn set_pointer(&mut self, p: Option) { + self.gpu_offset = p; + } +} + +impl ToGpu for UIElement { + fn to_gpu(&self) -> GPUUIElement { + GPUUIElement { + v_anchor: self.anchor.v_anchor.into(), + h_anchor: self.anchor.h_anchor.into(), + width: self.image.width() as u32, + height: self.image.height() as u32, + pointer: if self.gpu_offset.is_none() { 0 } else { self.gpu_offset.unwrap() } + } + } +} \ No newline at end of file diff --git a/src/wgpu_handler.rs b/src/wgpu_handler.rs index 3040576..90c38ba 100644 --- a/src/wgpu_handler.rs +++ b/src/wgpu_handler.rs @@ -5,55 +5,71 @@ use wgpu::{SurfaceTexture, Texture, TextureView}; use winit::window::{Window}; use crate::object::{self, camera::GpuUniform, quad::GpuQuad, sphere::GpuSphere}; +use crate::ui::ui_element::GPUUIElement; +use crate::ui::{self, UIElement}; pub struct GpuHandler { - pub device: Option, - pub queue: Option, - pub surface: Option>, - pub surface_config: Option, - pub compute_pipeline: Option, - pub render_pipeline: Option, - pub bind_group: Option, - pub uniform_buf: Option, - pub output_buf: Option, - pub spheres_buf: Option, - pub quads_buf: Option, - pub output_buf_size: Option, - texture: Option, - view: Option + pub device: Option, + pub queue: Option, + pub surface: Option>, + pub surface_config: Option, + pub compute_pipeline: Option, + pub render_pipeline: Option, + pub bind_group: Option, + + pub uniform_buf: Option, + pub output_buf: Option, + pub spheres_buf: Option, + pub quads_buf: Option, + pub ui_element_info: Option, + pub ui_element_textures: Option, + + pub output_buf_size: Option, + texture: Option, + view: Option } #[allow(unused)] pub struct GpuState<'a> { // makes my life infinitely easier - pub device: &'a wgpu::Device, - pub queue: &'a wgpu::Queue, - pub surface: &'a wgpu::Surface<'static>, - pub surface_config: &'a wgpu::SurfaceConfiguration, - pub compute_pipeline: &'a wgpu::ComputePipeline, - pub render_pipeline: &'a wgpu::RenderPipeline, - pub bind_group: &'a wgpu::BindGroup, - pub uniform_buf: &'a wgpu::Buffer, - pub output_buf: &'a wgpu::Buffer, - pub spheres_buf: &'a wgpu::Buffer, - pub quads_buf: &'a wgpu::Buffer, - pub output_buf_size: &'a u64 + pub device: &'a wgpu::Device, + pub queue: &'a wgpu::Queue, + pub surface: &'a wgpu::Surface<'static>, + pub surface_config: &'a wgpu::SurfaceConfiguration, + pub compute_pipeline: &'a wgpu::ComputePipeline, + pub render_pipeline: &'a wgpu::RenderPipeline, + pub bind_group: &'a wgpu::BindGroup, + + pub uniform_buf: &'a wgpu::Buffer, + pub output_buf: &'a wgpu::Buffer, + pub spheres_buf: &'a wgpu::Buffer, + pub quads_buf: &'a wgpu::Buffer, + pub ui_element_info: &'a wgpu::Buffer, + pub ui_element_textures: &'a wgpu::Buffer, + + pub output_buf_size: &'a u64, + pub view: &'a TextureView, + } #[allow(unused)] pub struct GpuStateMut<'a> { // makes my life infinitely easier - pub device: &'a mut wgpu::Device, - pub queue: &'a mut wgpu::Queue, - pub surface: &'a mut wgpu::Surface<'static>, - pub surface_config: &'a mut wgpu::SurfaceConfiguration, - pub compute_pipeline: &'a mut wgpu::ComputePipeline, - pub render_pipeline: &'a mut wgpu::RenderPipeline, - pub bind_group: &'a mut wgpu::BindGroup, - pub uniform_buf: &'a mut wgpu::Buffer, - pub output_buf: &'a mut wgpu::Buffer, - pub spheres_buf: &'a mut wgpu::Buffer, - pub quads_buf: &'a mut wgpu::Buffer, - pub output_buf_size: &'a mut u64, - pub view: &'a mut TextureView, + pub device: &'a mut wgpu::Device, + pub queue: &'a mut wgpu::Queue, + pub surface: &'a mut wgpu::Surface<'static>, + pub surface_config: &'a mut wgpu::SurfaceConfiguration, + pub compute_pipeline: &'a mut wgpu::ComputePipeline, + pub render_pipeline: &'a mut wgpu::RenderPipeline, + pub bind_group: &'a mut wgpu::BindGroup, + + pub uniform_buf: &'a mut wgpu::Buffer, + pub output_buf: &'a mut wgpu::Buffer, + pub spheres_buf: &'a mut wgpu::Buffer, + pub quads_buf: &'a mut wgpu::Buffer, + pub ui_element_info: &'a mut wgpu::Buffer, + pub ui_element_textures: &'a mut wgpu::Buffer, + + pub output_buf_size: &'a mut u64, + pub view: &'a mut TextureView, } impl GpuHandler { @@ -62,19 +78,23 @@ impl GpuHandler { fn get_state_mut(&mut self) -> Option> { Some( GpuStateMut { - device: self.device.as_mut()?, - queue: self.queue.as_mut()?, - surface: self.surface.as_mut()?, - surface_config: self.surface_config.as_mut()?, - compute_pipeline: self.compute_pipeline.as_mut()?, - render_pipeline: self.render_pipeline.as_mut()?, - bind_group: self.bind_group.as_mut()?, - uniform_buf: self.uniform_buf.as_mut()?, - output_buf: self.output_buf.as_mut()?, - spheres_buf: self.spheres_buf.as_mut()?, - quads_buf: self.quads_buf.as_mut()?, - output_buf_size: self.output_buf_size.as_mut()?, - view: self.view.as_mut()?, + device: self.device.as_mut()?, + queue: self.queue.as_mut()?, + surface: self.surface.as_mut()?, + surface_config: self.surface_config.as_mut()?, + compute_pipeline: self.compute_pipeline.as_mut()?, + render_pipeline: self.render_pipeline.as_mut()?, + bind_group: self.bind_group.as_mut()?, + + uniform_buf: self.uniform_buf.as_mut()?, + output_buf: self.output_buf.as_mut()?, + spheres_buf: self.spheres_buf.as_mut()?, + quads_buf: self.quads_buf.as_mut()?, + ui_element_info: self.ui_element_info.as_mut()?, + ui_element_textures: self.ui_element_textures.as_mut()?, + + output_buf_size: self.output_buf_size.as_mut()?, + view: self.view.as_mut()?, } ) } @@ -82,18 +102,23 @@ impl GpuHandler { pub fn get_state(&self) -> Option> { Some( GpuState { - device: self.device.as_ref()?, - queue: self.queue.as_ref()?, - surface: self.surface.as_ref()?, - surface_config: self.surface_config.as_ref()?, - compute_pipeline: self.compute_pipeline.as_ref()?, - render_pipeline: self.render_pipeline.as_ref()?, - bind_group: self.bind_group.as_ref()?, - uniform_buf: self.uniform_buf.as_ref()?, - output_buf: self.output_buf.as_ref()?, - spheres_buf: self.spheres_buf.as_ref()?, - quads_buf: self.quads_buf.as_ref()?, - output_buf_size: self.output_buf_size.as_ref()?, + device: self.device.as_ref()?, + queue: self.queue.as_ref()?, + surface: self.surface.as_ref()?, + surface_config: self.surface_config.as_ref()?, + compute_pipeline: self.compute_pipeline.as_ref()?, + render_pipeline: self.render_pipeline.as_ref()?, + bind_group: self.bind_group.as_ref()?, + + uniform_buf: self.uniform_buf.as_ref()?, + output_buf: self.output_buf.as_ref()?, + spheres_buf: self.spheres_buf.as_ref()?, + quads_buf: self.quads_buf.as_ref()?, + ui_element_info: self.ui_element_info.as_ref()?, + ui_element_textures: self.ui_element_textures.as_ref()?, + + output_buf_size: self.output_buf_size.as_ref()?, + view: self.view.as_ref()?, } ) } @@ -127,6 +152,8 @@ impl GpuHandler { wgpu::BindGroupEntry { binding: 2, resource: gpu.spheres_buf.as_entire_binding() }, wgpu::BindGroupEntry { binding: 3, resource: gpu.quads_buf.as_entire_binding() }, wgpu::BindGroupEntry { binding: 4, resource: wgpu::BindingResource::TextureView(gpu.view)}, + wgpu::BindGroupEntry { binding: 5, resource: gpu.ui_element_info.as_entire_binding() }, + wgpu::BindGroupEntry { binding: 6, resource: gpu.ui_element_textures.as_entire_binding() }, ], }); @@ -134,7 +161,7 @@ impl GpuHandler { } } - pub fn draw_frame(&self, spheres: &Vec, quads: &Vec, uniform: &mut GpuUniform) -> Option { + pub fn draw_frame(&self, spheres: &Vec, quads: &Vec, ui_elements: &Vec, uniform: &mut GpuUniform) -> Option { let gpu = match self.get_state() { Some(t) => t, None => return None @@ -143,11 +170,13 @@ impl GpuHandler { // ensure these are correct uniform.sphere_count = spheres.len() as u32; uniform.quad_count = quads.len() as u32; + uniform.texture_count = ui_elements.len() as u32; // upload to buffer gpu.queue.write_buffer(gpu.uniform_buf, 0, bytemuck::bytes_of(uniform)); gpu.queue.write_buffer(gpu.spheres_buf, 0, bytemuck::cast_slice(spheres)); gpu.queue.write_buffer(gpu.quads_buf, 0, bytemuck::cast_slice(quads)); + gpu.queue.write_buffer(gpu.ui_element_info, 0, bytemuck::cast_slice(ui_elements)); // surface that we draw to let frame = match gpu.surface.get_current_texture() { @@ -164,7 +193,7 @@ impl GpuHandler { label: Some("frame") }); - // step 1 — compute pass, ray traces into output[] + // step 1 - compute pass, ray traces into output[] { let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: Some("raytrace"), @@ -179,7 +208,7 @@ impl GpuHandler { ); } - // step 2 — render pass, copies output[] to screen + // step 2 - render pass, copies output[] to screen { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("blit"), @@ -208,7 +237,7 @@ impl GpuHandler { } // vibecoded but man thats a lot - pub async fn init(&mut self, window: Arc, width: u32, height: u32, texture_paths: Vec<&str>) { + pub async fn init(&mut self, window: Arc, width: u32, height: u32, ui_elements: &mut Vec, texture_paths: Vec<&str>) { // --- get a handle to the graphics card --- let instance = wgpu::Instance::default(); let surface = instance.create_surface(window).unwrap(); @@ -241,8 +270,6 @@ impl GpuHandler { surface.configure(&device, &surface_config); - // --- textures --- - let mut rgba_data: Vec = vec![]; for path in &texture_paths { @@ -317,6 +344,33 @@ impl GpuHandler { mapped_at_creation: false, }); + let ui_element_info = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("ui_element_info"), + size: (std::mem::size_of::() * 512) as u64, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let ui_element_textures = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("ui_element_textures"), + size: (16*16*4*128) as u64, // eehh fix later + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + // --- UI Elements --- + // really just write textures here. They are (for now) immutable, but ill change this sometime in the future. + + let mut texture_pointer: u32 = 0; + + for element in ui_elements { + element.set_pointer(Some(texture_pointer)); + + queue.write_buffer(&ui_element_textures, texture_pointer as u64, bytemuck::cast_slice(element.get_image().bytes())); + + texture_pointer += element.get_image().size() as u32; + } + // --- pipelines --- let source = format!( @@ -382,13 +436,35 @@ impl GpuHandler { // textures wgpu::BindGroupLayoutEntry { binding: 4, - visibility: wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::COMPUTE, // Usually read in fragment shaders + visibility: wgpu::ShaderStages::COMPUTE, ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D2, sample_type: wgpu::TextureSampleType::Float { filterable: false }, }, count: None, + }, + // ui element info + wgpu::BindGroupLayoutEntry { + binding: 5, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new(512), + }, + count: None, + }, + // ui element textures + wgpu::BindGroupLayoutEntry { + binding: 6, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: wgpu::BufferSize::new(512), + }, + count: None, } ], }); @@ -402,6 +478,9 @@ impl GpuHandler { wgpu::BindGroupEntry { binding: 2, resource: spheres_buf.as_entire_binding() }, wgpu::BindGroupEntry { binding: 3, resource: quads_buf.as_entire_binding() }, wgpu::BindGroupEntry { binding: 4, resource: wgpu::BindingResource::TextureView(self.view.as_ref().expect(""))}, + wgpu::BindGroupEntry { binding: 5, resource: ui_element_info.as_entire_binding() }, + wgpu::BindGroupEntry { binding: 6, resource: ui_element_textures.as_entire_binding() }, + ], }); @@ -435,7 +514,7 @@ impl GpuHandler { entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format: surface_config.format, - blend: None, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], compilation_options: Default::default(), @@ -457,10 +536,14 @@ impl GpuHandler { self.compute_pipeline = Some(compute_pipeline); self.render_pipeline = Some(render_pipeline); self.bind_group = Some(bind_group); + self.uniform_buf = Some(uniform_buf); self.output_buf = Some(output_buf); self.spheres_buf = Some(spheres_buf); self.quads_buf = Some(quads_buf); + self.ui_element_info = Some(ui_element_info); + self.ui_element_textures = Some(ui_element_textures); + self.output_buf_size = Some((width as u64)*(height as u64)); } } @@ -468,20 +551,24 @@ impl GpuHandler { impl Default for GpuHandler { fn default() -> Self { Self { - device: None, - queue: None, - surface: None, - surface_config: None, - compute_pipeline: None, - render_pipeline: None, - bind_group: None, - uniform_buf: None, - output_buf: None, - spheres_buf: None, - quads_buf: None, - output_buf_size: None, - texture: None, - view: None + device: None, + queue: None, + surface: None, + surface_config: None, + compute_pipeline: None, + render_pipeline: None, + bind_group: None, + + uniform_buf: None, + output_buf: None, + spheres_buf: None, + quads_buf: None, + output_buf_size: None, + ui_element_info: None, + ui_element_textures: None, + + texture: None, + view: None } } } diff --git a/textures/crosshair.png b/textures/crosshair.png new file mode 100644 index 0000000..b817a06 Binary files /dev/null and b/textures/crosshair.png differ