diff options
| -rw-r--r-- | shaders/sprite.wgsl | 18 | ||||
| -rw-r--r-- | src/config.rs | 8 | ||||
| -rw-r--r-- | src/renderer.rs | 98 |
3 files changed, 101 insertions, 23 deletions
diff --git a/shaders/sprite.wgsl b/shaders/sprite.wgsl new file mode 100644 index 0000000..7d2c5ce --- /dev/null +++ b/shaders/sprite.wgsl @@ -0,0 +1,18 @@ + +struct VertexOutput { + @builtin(position) clip_position: vec4<f32> +} + +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput { + var out: VertexOutput; + let x = (1.0 * f32(in_vertex_index % u32(2))) + -0.5; + let y = (1.0 * f32(in_vertex_index / u32(2))) + -0.5; + out.clip_position = vec4<f32>(x, y, 0.0, 1.0); + return out; +} + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { + return vec4<f32>(1.0, 1.0, 1.0, 0.0); +}
\ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 1e8c43e..f321a9b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ use winit::dpi::{LogicalPosition, LogicalSize}; use winit::window::{Fullscreen, WindowBuilder}; /// Describes how a window may be resized -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct Resizable { /// The minimum width of the window, or None if unconstrained pub min_width: Option<NonZeroU32>, @@ -18,7 +18,7 @@ pub struct Resizable { } /// Information about a window, that is not fullscreened -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct WindowInfo { pub default_x: i32, pub default_y: i32, @@ -37,7 +37,7 @@ impl Default for WindowInfo { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum WindowMode { Windowed(WindowInfo), // TODO support choosing a monitor @@ -50,7 +50,7 @@ impl Default for WindowMode { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] // TODO window icon pub struct RenderWindowConfig<'a> { /// The width of the window, once initialized diff --git a/src/renderer.rs b/src/renderer.rs index bf7226d..2264ab5 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,7 @@ use crate::config::RenderWindowConfig; use pollster::FutureExt; use thiserror::Error; +use wgpu::include_wgsl; use winit::{ dpi::PhysicalSize, error::OsError, @@ -10,7 +11,7 @@ use winit::{ }; /// No device could be found which supports the given surface -#[derive(Clone, Copy, Debug, PartialEq, Eq, Error)] +#[derive(Clone, Copy, Debug, Error)] #[error("No GPU could be found on this machine")] pub struct NoGpuError { /// Prevents this type from being constructed @@ -32,11 +33,13 @@ pub enum NewRendererError { WindowInitError(#[from] OsError), } +#[derive(Debug)] pub struct Renderer { surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, - config: wgpu::SurfaceConfiguration, + surface_config: wgpu::SurfaceConfiguration, + render_pipeline: wgpu::RenderPipeline, window: Window, } @@ -100,18 +103,65 @@ impl Renderer { .unwrap(); // configuration for the surface - let config = config.to_surface_configuration( + let surface_config = config.to_surface_configuration( &surface.get_supported_modes(&adapter), surface.get_supported_formats(&adapter)[0], ); - surface.configure(&device, &config); + surface.configure(&device, &surface_config); + + // set up a pipeline for sprite rendering + let shader = device.create_shader_module(include_wgsl!("../shaders/sprite.wgsl")); + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + ..Default::default() + }); + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + // information about the vertex shader + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[], + }, + // information about the fragment shader + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + // save some memory + topology: wgpu::PrimitiveTopology::TriangleStrip, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + // don't render the back of a sprite + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }); Ok(Self { surface, device, queue, - config, + surface_config, + render_pipeline, window, }) } @@ -123,9 +173,9 @@ impl Renderer { return; } - self.config.height = size.height; - self.config.width = size.width; - self.surface.configure(&self.device, &self.config); + self.surface_config.height = size.height; + self.surface_config.width = size.width; + self.surface.configure(&self.device, &self.surface_config); } /// Renders a new frame to the window @@ -150,7 +200,7 @@ impl Renderer { }); { - let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &view, @@ -162,6 +212,9 @@ impl Renderer { })], depth_stencil_attachment: None, }); + + render_pass.set_pipeline(&self.render_pipeline); + render_pass.draw(0..4, 0..1); } // the encoder can't finish building the command buffer until the // render pass is dropped @@ -185,19 +238,26 @@ impl Renderer { } } } - Event::MainEventsCleared => { - match self.render() { - Ok(_) => {} - // reconfigure the surface if it's been lost - Err(wgpu::SurfaceError::Lost) => self.resize_renderer(self.window.inner_size()), - // if we ran out of memory, then we'll die - Err(wgpu::SurfaceError::OutOfMemory) => { - *control_flow = ControlFlow::ExitWithCode(1); + Event::RedrawRequested(window_id) => { + if window_id == self.window.id() { + match self.render() { + Ok(_) => {} + // reconfigure the surface if it's been lost + Err(wgpu::SurfaceError::Lost) => { + self.resize_renderer(self.window.inner_size()); + } + // if we ran out of memory, then we'll die + Err(wgpu::SurfaceError::OutOfMemory) => { + *control_flow = ControlFlow::ExitWithCode(1); + } + // otherwise, we'll just log the error + Err(e) => log::error!("{}", e), } - // otherwise, we'll just log the error - Err(e) => log::error!("{}", e), } } + Event::MainEventsCleared => { + self.window.request_redraw(); + } _ => {} }) } |
