From ec6f2e3c57cd615f1a3cd4a97cd6333797298fd5 Mon Sep 17 00:00:00 2001 From: numzero Date: Thu, 26 Sep 2024 00:29:33 +0300 Subject: [PATCH] Extract viewport --- src/bin/wireframe/main.rs | 94 +++++++---------------------------- src/bin/wireframe/viewport.rs | 80 +++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 75 deletions(-) create mode 100644 src/bin/wireframe/viewport.rs diff --git a/src/bin/wireframe/main.rs b/src/bin/wireframe/main.rs index 22d494d..0e15aee 100644 --- a/src/bin/wireframe/main.rs +++ b/src/bin/wireframe/main.rs @@ -1,6 +1,6 @@ -use std::{iter, time::Instant}; +use std::time::Instant; -use glam::{vec2, vec3, Vec3}; +use glam::{uvec2, vec3, Vec3}; use winit::{ event::*, event_loop::EventLoop, @@ -11,6 +11,7 @@ use winit::{ mod camera; mod lines; mod scene; +mod viewport; // The coordinate system: // * X: forward @@ -112,15 +113,13 @@ static KEYS_ROTATE: &'static [(PhysicalKey, Vec3)] = &[ ]; struct State<'a> { - surface: wgpu::Surface<'a>, device: wgpu::Device, queue: wgpu::Queue, - config: wgpu::SurfaceConfiguration, - size: winit::dpi::PhysicalSize, kbd: keyctl::Keyboard, t1: Instant, + viewport: viewport::Viewport<'a>, cam_loc: camctl::CameraLocation, cam_obj: camera::Camera, line_rend: lines::LineRenderer, @@ -163,23 +162,7 @@ impl<'a> State<'a> { .await .unwrap(); - let surface_caps = surface.get_capabilities(&adapter); - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| !f.is_srgb()) - .unwrap_or(surface_caps.formats[0]); - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width, - height: size.height, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - desired_maximum_frame_latency: 2, - }; + let viewport = viewport::Viewport::new(&adapter, surface, uvec2(size.width, size.height)); let kbd = keyctl::Keyboard::new(); let cam_loc = camctl::CameraLocation::new(); @@ -196,7 +179,7 @@ impl<'a> State<'a> { let line_rend = lines::LineRenderer::new( &device, cam_obj.bind_group_layout(), - config.format, + viewport.format(), depth, msaa, ); @@ -204,11 +187,9 @@ impl<'a> State<'a> { let scene = prepare_scene(&device); Self { - surface, device, queue, - config, - size, + viewport, line_rend, kbd, cam_loc, @@ -225,10 +206,8 @@ impl<'a> State<'a> { fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { - self.size = new_size; - self.config.width = new_size.width; - self.config.height = new_size.height; - self.surface.configure(&self.device, &self.config); + self.viewport + .resize(&self.device, uvec2(new_size.width, new_size.height)); } } @@ -239,7 +218,7 @@ impl<'a> State<'a> { self.t1 = t2; dt.as_secs_f32() }; - let size = vec2(self.config.width as f32, self.config.height as f32); + let size = self.viewport.size().as_vec2(); self.cam_loc .move_rel(100. * dt * self.kbd.control(&KEYS_MOVE)); @@ -249,49 +228,14 @@ impl<'a> State<'a> { } fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - let output = self.surface.get_current_texture()?; - let view = output - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("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 { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0., - g: 0., - b: 0., - a: 1., - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - }); - - self.line_rend.render( - &mut render_pass, - self.cam_obj.bind_group(), - self.scene.iter(), - ); - } - - self.queue.submit(iter::once(encoder.finish())); - output.present(); - - Ok(()) + self.viewport + .render_single_pass(&self.device, &self.queue, |mut render_pass| { + self.line_rend.render( + &mut render_pass, + self.cam_obj.bind_group(), + self.scene.iter(), + ); + }) } } @@ -339,7 +283,7 @@ pub async fn run() { Ok(_) => {} // Reconfigure the surface if it's lost or outdated Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => { - state.resize(state.size) + state.viewport.configure(&state.device); } // The system is out of memory, we should probably quit Err(wgpu::SurfaceError::OutOfMemory) => { diff --git a/src/bin/wireframe/viewport.rs b/src/bin/wireframe/viewport.rs new file mode 100644 index 0000000..012f2b7 --- /dev/null +++ b/src/bin/wireframe/viewport.rs @@ -0,0 +1,80 @@ +use glam::{uvec2, UVec2}; + +pub struct Viewport<'a> { + surface: wgpu::Surface<'a>, + config: wgpu::SurfaceConfiguration, +} + +impl<'a> Viewport<'a> { + pub fn new(adapter: &wgpu::Adapter, surface: wgpu::Surface<'a>, size: UVec2) -> Self { + let caps = surface.get_capabilities(adapter); + let format = wgpu::TextureFormat::Bgra8Unorm; + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format, + width: size.x, + height: size.y, + present_mode: caps.present_modes[0], + alpha_mode: caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + Self { surface, config } + } + + pub fn configure(&mut self, device: &wgpu::Device) { + self.surface.configure(&device, &self.config); + } + + pub fn resize(&mut self, device: &wgpu::Device, size: UVec2) { + self.config.width = size.x; + self.config.height = size.y; + self.configure(&device); + } + + pub fn size(&self) -> UVec2 { + uvec2(self.config.width, self.config.height) + } + + pub fn format(&self) -> wgpu::TextureFormat { + self.config.format + } + + pub fn render_single_pass( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + f: impl FnOnce(wgpu::RenderPass), + ) -> Result<(), wgpu::SurfaceError> { + let output = self.surface.get_current_texture()?; + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render CommandEncoder"), + }); + let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("RenderPass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0., + g: 0., + b: 0., + a: 1., + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, + }); + f(render_pass); + queue.submit(std::iter::once(encoder.finish())); + output.present(); + Ok(()) + } +}