summaryrefslogtreecommitdiff
path: root/alligator_render/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alligator_render/src/config.rs')
-rw-r--r--alligator_render/src/config.rs193
1 files changed, 193 insertions, 0 deletions
diff --git a/alligator_render/src/config.rs b/alligator_render/src/config.rs
new file mode 100644
index 0000000..c73c357
--- /dev/null
+++ b/alligator_render/src/config.rs
@@ -0,0 +1,193 @@
+use std::num::NonZeroU32;
+
+use winit::dpi::{LogicalPosition, LogicalSize};
+use winit::window::{Fullscreen, WindowBuilder};
+
+/// Describes how a window may be resized
+#[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>,
+ /// 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, Hash)]
+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, Hash)]
+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, Hash)]
+// 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: &'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,
+ /// The initial capacity of the instance buffer. The size will increase if
+ /// it's not large enough. Increasing this value may improve performance
+ /// towards the beginning, if a lot of instances are being created.
+ pub instance_capacity: usize,
+}
+
+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",
+ low_power: true,
+ vsync: true,
+ instance_capacity: 0, // TODO this should probably be bigger
+ }
+ }
+}
+
+impl<'a> RenderWindowConfig<'a> {
+ /// Based on the vsync settings, choose a presentation mode
+ pub(crate) fn present_mode(
+ vsync: bool,
+ supported_modes: &[wgpu::PresentMode],
+ ) -> wgpu::PresentMode {
+ if vsync {
+ wgpu::PresentMode::Fifo
+ } else if supported_modes.contains(&wgpu::PresentMode::Mailbox) {
+ wgpu::PresentMode::Mailbox
+ } else if supported_modes.contains(&wgpu::PresentMode::Immediate) {
+ wgpu::PresentMode::Immediate
+ } else {
+ wgpu::PresentMode::Fifo
+ }
+ }
+
+ /// Pick an alpha mode
+ fn alpha_mode(supported_modes: &[wgpu::CompositeAlphaMode]) -> wgpu::CompositeAlphaMode {
+ if supported_modes.contains(&wgpu::CompositeAlphaMode::PostMultiplied) {
+ wgpu::CompositeAlphaMode::PostMultiplied
+ } else {
+ wgpu::CompositeAlphaMode::Auto
+ }
+ }
+
+ /// Create a `WindowBuilder` from the configuration given. This window is
+ /// initially invisible and must later be made visible.
+ pub(crate) fn to_window(&self) -> WindowBuilder {
+ // start building the window
+ let mut builder = WindowBuilder::new()
+ .with_title(self.title)
+ .with_visible(false)
+ .with_inner_size(LogicalSize::new(
+ self.default_width.get(),
+ self.default_height.get(),
+ ));
+
+ match self.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)));
+ }
+ }
+
+ builder
+ }
+
+ /// Gets a surface configuration out of the config.
+ pub(crate) fn to_surface_configuration(
+ &self,
+ supported_present_modes: &[wgpu::PresentMode],
+ supported_alpha_modes: &[wgpu::CompositeAlphaMode],
+ texture_format: wgpu::TextureFormat,
+ ) -> wgpu::SurfaceConfiguration {
+ let present_mode = Self::present_mode(self.vsync, supported_present_modes);
+ let alpha_mode = Self::alpha_mode(supported_alpha_modes);
+
+ // configuration for the surface
+ wgpu::SurfaceConfiguration {
+ usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
+ format: texture_format,
+ width: self.default_width.get(),
+ height: self.default_height.get(),
+ alpha_mode,
+ present_mode,
+ }
+ }
+
+ /// Get the power preference
+ pub(crate) const fn power_preference(&self) -> wgpu::PowerPreference {
+ if self.low_power {
+ wgpu::PowerPreference::LowPower
+ } else {
+ wgpu::PowerPreference::HighPerformance
+ }
+ }
+}