diff options
Diffstat (limited to 'src/renderer.rs')
| -rw-r--r-- | src/renderer.rs | 169 |
1 files changed, 16 insertions, 153 deletions
diff --git a/src/renderer.rs b/src/renderer.rs index c9c51bc..bf7226d 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,13 +1,12 @@ -use std::{borrow::Cow, num::NonZeroU32}; - +use crate::config::RenderWindowConfig; use pollster::FutureExt; use thiserror::Error; use winit::{ - dpi::{LogicalPosition, LogicalSize, PhysicalSize}, + dpi::PhysicalSize, error::OsError, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, - window::{Fullscreen, Window, WindowBuilder}, + window::Window, }; /// No device could be found which supports the given surface @@ -33,83 +32,6 @@ pub enum NewRendererError { WindowInitError(#[from] OsError), } -/// Describes how a window may be resized -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct Resizable { - /// The minimum width of the window, or None if unconstrained - pub min_width: Option<NonZeroU32>, - /// The minimum height of the window, or None if unconstrained - pub min_height: Option<NonZeroU32>, - /// The maximum width of the window, or None if unconstrained - pub max_width: Option<NonZeroU32>, - /// The maximum height of the window, or None if unconstrained - pub max_height: Option<NonZeroU32>, -} - -/// Information about a window, that is not fullscreened -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct WindowInfo { - pub default_x: i32, - pub default_y: i32, - pub resizable: Option<Resizable>, - pub default_maximized: bool, -} - -impl Default for WindowInfo { - fn default() -> Self { - Self { - default_x: 100, - default_y: 100, - resizable: Some(Resizable::default()), - default_maximized: false, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum WindowMode { - Windowed(WindowInfo), - // TODO support choosing a monitor - BorderlessFullscreen, // TODO exclusive fullscreen -} - -impl Default for WindowMode { - fn default() -> Self { - Self::Windowed(WindowInfo::default()) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -// TODO window icon -pub struct RenderWindowConfig<'a> { - /// The width of the window, once initialized - pub default_width: NonZeroU32, - /// The height of the window, once initialized - pub default_height: NonZeroU32, - /// The window may be fullscreen - pub mode: WindowMode, - /// The title for the window - pub title: Cow<'a, str>, - /// If true, a low-power device will be selected as the GPU, if possible - pub low_power: bool, - /// If true, Fifo mode is used to present frames. If false, then Mailbox or - /// Immediate will be used if available. Otherwise, Fifo will be used. - pub vsync: bool, -} - -impl<'a> Default for RenderWindowConfig<'a> { - fn default() -> Self { - Self { - default_width: NonZeroU32::new(640).unwrap(), - default_height: NonZeroU32::new(480).unwrap(), - mode: WindowMode::default(), - title: "Alligator Game".into(), - low_power: true, - vsync: true, - } - } -} - pub struct Renderer { surface: wgpu::Surface, device: wgpu::Device, @@ -126,57 +48,19 @@ impl Renderer { /// /// Returns a [`NoGpu`] error if no device could be detected that can /// display to the window + /// + /// # Panics + /// + /// This function **must** be called on the main thread, or else it may + /// panic on some platforms. // TODO make it possible to use without a window (ie, use a bitmap in memory as a surface) // TODO this function needs to be smaller - #[allow(clippy::missing_panics_doc)] pub fn new( - config: RenderWindowConfig, + config: &RenderWindowConfig, event_loop: &EventLoop<()>, ) -> Result<Self, NewRendererError> { - // start building the window - let mut builder = WindowBuilder::new() - .with_title(config.title) - .with_inner_size(LogicalSize::new( - config.default_width.get(), - config.default_height.get(), - )); - - match config.mode { - WindowMode::Windowed(window_info) => { - builder = builder.with_maximized(window_info.default_maximized); - - if let Some(resizing_options) = window_info.resizable { - if resizing_options.max_height.is_some() || resizing_options.max_width.is_some() - { - builder = builder.with_max_inner_size(LogicalSize::new( - resizing_options.max_width.unwrap_or(NonZeroU32::MAX).get(), - resizing_options.max_height.unwrap_or(NonZeroU32::MAX).get(), - )); - } - - if resizing_options.min_height.is_some() || resizing_options.min_width.is_some() - { - builder = builder.with_min_inner_size(LogicalSize::new( - resizing_options.min_width.unwrap_or(NonZeroU32::MAX).get(), - resizing_options.min_height.unwrap_or(NonZeroU32::MAX).get(), - )); - } - } else { - builder = builder.with_resizable(false); - } - - // TODO clamp the position to the monitor's size - builder = builder.with_position(LogicalPosition::new( - window_info.default_x, - window_info.default_y, - )); - } - WindowMode::BorderlessFullscreen => { - builder = builder.with_fullscreen(Some(Fullscreen::Borderless(None))); - } - } - - let window = builder.build(event_loop)?; + // build the window + let window = config.to_window().build(event_loop)?; // the instance's main purpose is to create an adapter and a surface let instance = wgpu::Instance::new(wgpu::Backends::all()); @@ -184,11 +68,7 @@ impl Renderer { // the surface is the part of the screen we'll draw to let surface = unsafe { instance.create_surface(&window) }; - let power_preference = if config.low_power { - wgpu::PowerPreference::LowPower - } else { - wgpu::PowerPreference::HighPerformance - }; + let power_preference = config.power_preference(); // the adapter is the handle to the GPU let adapter = instance @@ -219,28 +99,11 @@ impl Renderer { .block_on() .unwrap(); - let present_mode = if config.vsync { - wgpu::PresentMode::Fifo - } else { - let modes = surface.get_supported_modes(&adapter); - - if modes.contains(&wgpu::PresentMode::Mailbox) { - wgpu::PresentMode::Mailbox - } else if modes.contains(&wgpu::PresentMode::Immediate) { - wgpu::PresentMode::Immediate - } else { - wgpu::PresentMode::Fifo - } - }; - // configuration for the surface - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface.get_supported_formats(&adapter)[0], - width: config.default_width.get(), - height: config.default_height.get(), - present_mode, - }; + let config = config.to_surface_configuration( + &surface.get_supported_modes(&adapter), + surface.get_supported_formats(&adapter)[0], + ); surface.configure(&device, &config); |
