From 04348d96f30b8fd5cd6226e4ce0e241fea81214a Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Sat, 27 Apr 2024 14:13:00 +0100 Subject: [PATCH] Add basic fullscreen quad renderer --- res/quad.wgsl | 33 +++++++++++++++++++++++ src/main.rs | 50 +++++----------------------------- src/renderer.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 44 deletions(-) create mode 100644 res/quad.wgsl create mode 100644 src/renderer.rs diff --git a/res/quad.wgsl b/res/quad.wgsl new file mode 100644 index 0000000..1e8f19e --- /dev/null +++ b/res/quad.wgsl @@ -0,0 +1,33 @@ +var DATA: array, 6> = array, 6>( + vec4( -1.0, 1.0, 0.0, 1.0 ), + vec4( -1.0, -1.0, 0.0, 0.0 ), + vec4( 1.0, -1.0, 1.0, 0.0 ), + vec4( -1.0, 1.0, 0.0, 1.0 ), + vec4( 1.0, -1.0, 1.0, 0.0 ), + vec4( 1.0, 1.0, 1.0, 1.0 ) +); + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) tex_coords: vec2, +}; + +@vertex +fn vertex( + @builtin(vertex_index) in_vertex_index: u32, +) -> VertexOutput { + var out: VertexOutput; + out.clip_position = vec4(DATA[in_vertex_index].xy, 0.0, 1.0); + out.tex_coords = DATA[in_vertex_index].zw; + return out; +} + +@group(0) @binding(0) +var t_diffuse: texture_2d; +@group(0) @binding(1) +var s_diffuse: sampler; + +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4 { + return textureSample(t_diffuse, s_diffuse, in.tex_coords); +} diff --git a/src/main.rs b/src/main.rs index bd72131..701af27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,8 @@ +mod renderer; + use anyhow::Result; -use crawl::{ - wgpu, - winit::event::{Event, WindowEvent}, -}; - -fn render(ctx: &mut crawl::Context) -> Result<()> { - let frame = ctx.surface.get_current_texture()?; - let view = frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - let mut encoder = ctx - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Base Render Encoder"), - }); - - let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.4, - g: 0.4, - b: 0.4, - a: 1.0, - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - }); - drop(_render_pass); - - ctx.queue.submit(Some(encoder.finish())); - frame.present(); - - Ok(()) -} +use crawl::winit::event::{Event, WindowEvent}; +use renderer::VoxelRenderer; fn main() -> Result<()> { env_logger::init(); @@ -51,6 +12,7 @@ fn main() -> Result<()> { .with_vsync(false) .build(), )?; + let renderer = VoxelRenderer::new(&context)?; event_loop.run(|event, elwt| match event { Event::WindowEvent { window_id, event } if window_id == context.window.id() => { @@ -59,7 +21,7 @@ fn main() -> Result<()> { } if let WindowEvent::RedrawRequested = event { - if let Err(err) = render(&mut context) { + if let Err(err) = renderer.render(&context) { log::error!("{err:?}"); } diff --git a/src/renderer.rs b/src/renderer.rs new file mode 100644 index 0000000..abf54e0 --- /dev/null +++ b/src/renderer.rs @@ -0,0 +1,71 @@ +use anyhow::Result; +use crawl::wgpu; + +pub struct VoxelRenderer { + render_texture: crawl::Texture, + render_pipeline: wgpu::RenderPipeline, +} + +impl VoxelRenderer { + pub fn new(context: &crawl::Context) -> Result { + let shader = context + .device + .create_shader_module(wgpu::include_wgsl!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/res/quad.wgsl" + ))); + + let render_texture = crawl::TextureBuilder::new() + .with_size(context.size.width, context.size.height, 1) + .with_format(wgpu::TextureFormat::Rgba8Unorm) + .with_usage( + wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::STORAGE_BINDING, + ) + .with_shader_visibility(wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::COMPUTE) + .build(context)?; + + let render_pipeline = crawl::RenderPipelineBuilder::new("Raycast Quad", &shader) + .with_layout("Draw", &[&render_texture.bind_group_layout], &[]) + .with_fragment_targets(&[Some(context.surface_config.format.into())]) + .build(context); + + Ok(Self { + render_texture, + render_pipeline, + }) + } + + pub fn render(&self, context: &crawl::Context) -> Result<()> { + let frame = context.surface.get_current_texture()?; + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = context + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Base Render Encoder"), + }); + + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations::default(), + })], + ..Default::default() + }); + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &self.render_texture.bind_group, &[]); + render_pass.draw(0..6, 0..1); + drop(render_pass); + + context.queue.submit(Some(encoder.finish())); + frame.present(); + + Ok(()) + } +}