diff --git a/Cargo.lock b/Cargo.lock index 3ff66621d..d54934b39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -728,6 +728,7 @@ dependencies = [ "fj-math", "fj-operations", "fj-viewer", + "fj-window", "serde", "tracing-subscriber", ] @@ -804,15 +805,25 @@ name = "fj-viewer" version = "0.6.0" dependencies = [ "bytemuck", - "fj-host", "fj-interop", "fj-math", - "fj-operations", - "futures", + "raw-window-handle", "thiserror", "tracing", "wgpu", "wgpu_glyph", +] + +[[package]] +name = "fj-window" +version = "0.6.0" +dependencies = [ + "fj-host", + "fj-operations", + "fj-viewer", + "futures", + "thiserror", + "tracing", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index 4acbafbe6..192258230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "crates/fj-math", "crates/fj-operations", "crates/fj-viewer", + "crates/fj-window", "models/cuboid", "models/spacer", @@ -28,4 +29,5 @@ default-members = [ "crates/fj-math", "crates/fj-operations", "crates/fj-viewer", + "crates/fj-window", ] diff --git a/README.md b/README.md index 5ca2a40df..3c4ecb037 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Here's an overview over all of the crates, with a short description of what they - `fj-export`: Exports Fornjot models to external data formats. - `fj-host`: Loads Fornjot models and watches them for changes. - `fj-viewer`: Displays Fornjot models. +- `fj-window`: Embed `fj-viewer` in a Winit-based window. - `fj-app`: The Fornjot CAD application. - `fj`: End-user API for defining Fornjot models. diff --git a/crates/fj-app/Cargo.toml b/crates/fj-app/Cargo.toml index 05410ea6b..6c13a0eba 100644 --- a/crates/fj-app/Cargo.toml +++ b/crates/fj-app/Cargo.toml @@ -51,6 +51,10 @@ path = "../fj-operations" version = "0.6.0" path = "../fj-viewer" +[dependencies.fj-window] +version = "0.6.0" +path = "../fj-window" + [dependencies.serde] version = "1.0.137" features = ["derive"] diff --git a/crates/fj-app/src/main.rs b/crates/fj-app/src/main.rs index 0788d887b..34c62a675 100644 --- a/crates/fj-app/src/main.rs +++ b/crates/fj-app/src/main.rs @@ -21,7 +21,7 @@ use anyhow::{anyhow, Context as _}; use fj_export::export; use fj_host::{Model, Parameters}; use fj_operations::shape_processor::ShapeProcessor; -use fj_viewer::run::run; +use fj_window::run::run; use tracing_subscriber::fmt::format; use tracing_subscriber::EnvFilter; diff --git a/crates/fj-viewer/Cargo.toml b/crates/fj-viewer/Cargo.toml index 76746d747..d35a4eaf7 100644 --- a/crates/fj-viewer/Cargo.toml +++ b/crates/fj-viewer/Cargo.toml @@ -14,16 +14,11 @@ categories = ["encoding", "mathematics", "rendering"] [dependencies] bytemuck = "1.9.1" -futures = "0.3.21" +raw-window-handle = "0.4.3" thiserror = "1.0.31" tracing = "0.1.34" wgpu = "0.12.0" wgpu_glyph = "0.16.0" -winit = "0.26.1" - -[dependencies.fj-host] -version = "0.6.0" -path = "../fj-host" [dependencies.fj-interop] version = "0.6.0" @@ -32,7 +27,3 @@ path = "../fj-interop" [dependencies.fj-math] version = "0.6.0" path = "../fj-math" - -[dependencies.fj-operations] -version = "0.6.0" -path = "../fj-operations" diff --git a/crates/fj-viewer/src/camera.rs b/crates/fj-viewer/src/camera.rs index 54481ae6a..0a3d5f8a3 100644 --- a/crates/fj-viewer/src/camera.rs +++ b/crates/fj-viewer/src/camera.rs @@ -3,9 +3,8 @@ use std::f64::consts::FRAC_PI_2; use fj_interop::mesh::Mesh; use fj_math::{Aabb, Point, Scalar, Transform, Triangle, Vector}; -use winit::dpi::PhysicalPosition; -use crate::window::Window; +use crate::screen::{Position, Size}; /// The camera abstraction /// @@ -108,11 +107,10 @@ impl Camera { /// Transform the position of the cursor on the near plane to model space. pub fn cursor_to_model_space( &self, - cursor: PhysicalPosition, - window: &Window, + cursor: Position, + size: Size, ) -> Point<3> { - let width = window.width() as f64; - let height = window.height() as f64; + let [width, height] = size.as_f64(); let aspect_ratio = width / height; // Cursor position in normalized coordinates (-1 to +1) with @@ -131,8 +129,8 @@ impl Camera { /// Compute the point on the model, that the cursor currently points to. pub fn focus_point( &self, - window: &Window, - cursor: Option>, + size: Size, + cursor: Option, mesh: &Mesh>, ) -> FocusPoint { let cursor = match cursor { @@ -142,7 +140,7 @@ impl Camera { // Transform camera and cursor positions to model space. let origin = self.position(); - let cursor = self.cursor_to_model_space(cursor, window); + let cursor = self.cursor_to_model_space(cursor, size); let dir = (cursor - origin).normalize(); let mut min_t = None; diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index 670bc76ae..636b96601 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -5,9 +5,11 @@ use thiserror::Error; use tracing::debug; use wgpu::util::DeviceExt as _; use wgpu_glyph::ab_glyph::InvalidFont; -use winit::dpi::PhysicalSize; -use crate::{camera::Camera, window::Window}; +use crate::{ + camera::Camera, + screen::{Screen, Size}, +}; use super::{ config_ui::ConfigUi, draw_config::DrawConfig, drawables::Drawables, @@ -36,26 +38,11 @@ pub struct Renderer { impl Renderer { /// Returns a new `Renderer`. - /// - /// # Arguments - /// - `window` - a `crate::window::Window` with a surface to render onto. - /// - /// # Examples - /// ```rust no_run - /// use fj_viewer::{graphics, window}; - /// - /// // Create window - /// let event_loop = winit::event_loop::EventLoop::new(); - /// let window = window::Window::new(&event_loop).unwrap(); - /// - /// // Attach renderer to the window - /// let mut renderer = graphics::Renderer::new(&window); - /// ``` - pub async fn new(window: &Window) -> Result { + pub async fn new(screen: &impl Screen) -> Result { let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); // This is sound, as `window` is an object to create a surface upon. - let surface = unsafe { instance.create_surface(window.inner()) }; + let surface = unsafe { instance.create_surface(screen.window()) }; let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { @@ -87,11 +74,12 @@ impl Renderer { .get_preferred_format(&adapter) .expect("Error determining preferred color format"); + let Size { width, height } = screen.size(); let surface_config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: color_format, - width: window.width(), - height: window.height(), + width, + height, present_mode: wgpu::PresentMode::Mailbox, }; surface.configure(&device, &surface_config); @@ -182,7 +170,7 @@ impl Renderer { /// /// # Arguments /// - `size`: The target size for the render surface. - pub fn handle_resize(&mut self, size: PhysicalSize) { + pub fn handle_resize(&mut self, size: Size) { self.surface_config.width = size.width; self.surface_config.height = size.height; diff --git a/crates/fj-viewer/src/input/event.rs b/crates/fj-viewer/src/input/event.rs new file mode 100644 index 000000000..48542fc4d --- /dev/null +++ b/crates/fj-viewer/src/input/event.rs @@ -0,0 +1,43 @@ +use crate::screen::Position; + +/// An input event +pub enum Event { + /// The cursor has moved to another position + CursorMoved(Position), + + /// A key has been pressed or released + Key(Key, KeyState), + + /// The user scrolled + Scroll(f64), +} + +/// A keyboard or mouse key +pub enum Key { + /// The escape key + Escape, + + /// The numerical key `1` + Key1, + + /// The numerical key `2` + Key2, + + /// The numerical key `3` + Key3, + + /// The left mouse key + MouseLeft, + + /// The right mouse key + MouseRight, +} + +/// Defines the meaning of a key event +pub enum KeyState { + /// A key was pressed + Pressed, + + /// A key was released + Released, +} diff --git a/crates/fj-viewer/src/input/handler.rs b/crates/fj-viewer/src/input/handler.rs index 883ff195f..7b7987ac8 100644 --- a/crates/fj-viewer/src/input/handler.rs +++ b/crates/fj-viewer/src/input/handler.rs @@ -2,26 +2,22 @@ use std::time::Instant; use fj_interop::mesh::Mesh; use fj_math::{Point, Transform, Vector}; -use winit::{ - dpi::PhysicalPosition, - event::{ - ElementState, KeyboardInput, MouseButton, MouseScrollDelta, - VirtualKeyCode, - }, -}; use crate::{ camera::{Camera, FocusPoint}, - window::Window, + screen::{Position, Size}, }; -use super::{movement::Movement, rotation::Rotation, zoom::Zoom}; +use super::{ + event::KeyState, movement::Movement, rotation::Rotation, zoom::Zoom, Event, + Key, +}; /// Input handling abstraction /// /// Takes user input and applies them to application state. pub struct Handler { - cursor: Option>, + cursor: Option, movement: Movement, rotation: Rotation, @@ -48,88 +44,63 @@ impl Handler { } /// Returns the state of the cursor position. - pub fn cursor(&self) -> Option> { + pub fn cursor(&self) -> Option { self.cursor } - /// Applies user input to `actions`. - pub fn handle_keyboard_input( + /// Handle an input event + pub fn handle_event( &mut self, - input: KeyboardInput, + event: Event, + screen_size: Size, + focus_point: FocusPoint, + now: Instant, + camera: &mut Camera, actions: &mut Actions, ) { - if let KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(virtual_key_code), - .. - } = input - { - match virtual_key_code { - VirtualKeyCode::Escape => actions.exit = true, - - VirtualKeyCode::Key1 => actions.toggle_model = true, - VirtualKeyCode::Key2 => actions.toggle_mesh = true, - VirtualKeyCode::Key3 => actions.toggle_debug = true, - - _ => (), - } - } - } + match event { + Event::CursorMoved(position) => { + if let Some(previous) = self.cursor { + let diff_x = position.x - previous.x; + let diff_y = position.y - previous.y; - /// Applies cursor movement to `camera`. - pub fn handle_cursor_moved( - &mut self, - cursor: PhysicalPosition, - camera: &mut Camera, - window: &Window, - ) { - if let Some(previous) = self.cursor { - let diff_x = cursor.x - previous.x; - let diff_y = cursor.y - previous.y; + self.movement.apply(self.cursor, camera, screen_size); + self.rotation.apply(diff_x, diff_y, camera); + } - self.movement.apply(self.cursor, camera, window); - self.rotation.apply(diff_x, diff_y, camera); - } + self.cursor = Some(position); + } + Event::Key(Key::Escape, KeyState::Pressed) => actions.exit = true, - self.cursor = Some(cursor); - } + Event::Key(Key::Key1, KeyState::Pressed) => { + actions.toggle_model = true + } + Event::Key(Key::Key2, KeyState::Pressed) => { + actions.toggle_mesh = true + } + Event::Key(Key::Key3, KeyState::Pressed) => { + actions.toggle_debug = true + } - /// Updates `state` and `focus_point` when mouse is clicked. - pub fn handle_mouse_input( - &mut self, - button: MouseButton, - state: ElementState, - focus_point: FocusPoint, - ) { - match (button, state) { - (MouseButton::Left, ElementState::Pressed) => { + Event::Key(Key::MouseLeft, KeyState::Pressed) => { self.rotation.start(focus_point); } - (MouseButton::Left, ElementState::Released) => { + Event::Key(Key::MouseLeft, KeyState::Released) => { self.rotation.stop(); } - (MouseButton::Right, ElementState::Pressed) => { + Event::Key(Key::MouseRight, KeyState::Pressed) => { self.movement.start(focus_point, self.cursor); } - (MouseButton::Right, ElementState::Released) => { + Event::Key(Key::MouseRight, KeyState::Released) => { self.movement.stop(); } - _ => {} - } - } - /// Updates zoom state from the scroll wheel. - pub fn handle_mouse_wheel( - &mut self, - delta: MouseScrollDelta, - now: Instant, - ) { - let delta = match delta { - MouseScrollDelta::LineDelta(_, y) => y as f64 * 10.0, - MouseScrollDelta::PixelDelta(PhysicalPosition { y, .. }) => y, - }; + Event::Scroll(delta) => { + self.zoom.push_input_delta(delta, now); + } - self.zoom.push_input_delta(delta, now); + _ => {} + } } /// Update application state from user input. @@ -138,10 +109,10 @@ impl Handler { delta_t: f64, now: Instant, camera: &mut Camera, - window: &Window, + size: Size, mesh: &Mesh>, ) { - let focus_point = camera.focus_point(window, self.cursor, mesh); + let focus_point = camera.focus_point(size, self.cursor, mesh); self.zoom.discard_old_events(now); self.zoom.update_speed(now, delta_t, focus_point, camera); diff --git a/crates/fj-viewer/src/input/mod.rs b/crates/fj-viewer/src/input/mod.rs index 38c18673f..3de606fe4 100644 --- a/crates/fj-viewer/src/input/mod.rs +++ b/crates/fj-viewer/src/input/mod.rs @@ -1,8 +1,12 @@ //! User input parsing and propagation. +mod event; mod handler; mod movement; mod rotation; mod zoom; -pub use self::handler::{Actions, Handler}; +pub use self::{ + event::{Event, Key, KeyState}, + handler::{Actions, Handler}, +}; diff --git a/crates/fj-viewer/src/input/movement.rs b/crates/fj-viewer/src/input/movement.rs index c71f76160..b1e4aeba8 100644 --- a/crates/fj-viewer/src/input/movement.rs +++ b/crates/fj-viewer/src/input/movement.rs @@ -1,14 +1,13 @@ use fj_math::{Point, Scalar, Transform, Vector}; -use winit::dpi::PhysicalPosition; use crate::{ camera::{Camera, FocusPoint}, - window::Window, + screen::{Position, Size}, }; pub struct Movement { focus_point: FocusPoint, - cursor: Option>, + cursor: Option, } impl Movement { @@ -19,11 +18,7 @@ impl Movement { } } - pub fn start( - &mut self, - focus_point: FocusPoint, - cursor: Option>, - ) { + pub fn start(&mut self, focus_point: FocusPoint, cursor: Option) { self.focus_point = focus_point; self.cursor = cursor; } @@ -34,13 +29,13 @@ impl Movement { pub fn apply( &mut self, - cursor: Option>, + cursor: Option, camera: &mut Camera, - window: &Window, + size: Size, ) { if let (Some(previous), Some(cursor)) = (self.cursor, cursor) { - let previous = camera.cursor_to_model_space(previous, window); - let cursor = camera.cursor_to_model_space(cursor, window); + let previous = camera.cursor_to_model_space(previous, size); + let cursor = camera.cursor_to_model_space(cursor, size); if let Some(focus_point) = self.focus_point.0 { let d1 = Point::distance(&camera.position(), &cursor); diff --git a/crates/fj-viewer/src/lib.rs b/crates/fj-viewer/src/lib.rs index 5c2d045f9..b6b4be702 100644 --- a/crates/fj-viewer/src/lib.rs +++ b/crates/fj-viewer/src/lib.rs @@ -17,5 +17,4 @@ pub mod camera; pub mod graphics; pub mod input; -pub mod run; -pub mod window; +pub mod screen; diff --git a/crates/fj-viewer/src/screen.rs b/crates/fj-viewer/src/screen.rs new file mode 100644 index 000000000..5b3e8678e --- /dev/null +++ b/crates/fj-viewer/src/screen.rs @@ -0,0 +1,42 @@ +//! Types that describe aspects of the screen + +pub use raw_window_handle::HasRawWindowHandle; + +/// Needs to be implemented by types that can serve as a screen to render to +pub trait Screen { + /// The window + type Window: HasRawWindowHandle; + + /// Access the size of the screen + fn size(&self) -> Size; + + /// Access the window + fn window(&self) -> &Self::Window; +} + +/// A position on the screen +#[derive(Clone, Copy, Debug)] +pub struct Position { + /// The x coordinate of the position + pub x: f64, + + /// The y coordinate of the position + pub y: f64, +} + +/// The size of the screen +#[derive(Clone, Copy, Debug)] +pub struct Size { + /// The width of the screen + pub width: u32, + + /// The height of the screen + pub height: u32, +} + +impl Size { + /// Convert size to `f64` + pub fn as_f64(&self) -> [f64; 2] { + [self.width, self.height].map(Into::into) + } +} diff --git a/crates/fj-window/Cargo.toml b/crates/fj-window/Cargo.toml new file mode 100644 index 000000000..954b354ce --- /dev/null +++ b/crates/fj-window/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "fj-window" +version = "0.6.0" +edition = "2021" + +description = "The world needs another CAD program." +readme = "../../README.md" +homepage = "https://www.fornjot.app/" +repository = "https://github.com/hannobraun/fornjot" +license = "0BSD" +keywords = ["cad", "programmatic", "code-cad"] +categories = ["encoding", "mathematics", "rendering"] + + +[dependencies] +futures = "0.3.21" +thiserror = "1.0.31" +tracing = "0.1.34" +winit = "0.26.1" + +[dependencies.fj-host] +version = "0.6.0" +path = "../fj-host" + +[dependencies.fj-operations] +version = "0.6.0" +path = "../fj-operations" + +[dependencies.fj-viewer] +version = "0.6.0" +path = "../fj-viewer" diff --git a/crates/fj-window/src/lib.rs b/crates/fj-window/src/lib.rs new file mode 100644 index 000000000..b67bc34ac --- /dev/null +++ b/crates/fj-window/src/lib.rs @@ -0,0 +1,17 @@ +//! # Fornjot Window Abstraction +//! +//! This library is part of the [Fornjot] ecosystem. Fornjot is an open-source, +//! code-first CAD application; and collection of libraries that make up the CAD +//! application, but can be used independently. +//! +//! This library is an internal component of Fornjot. It is not relevant to end +//! users that just want to create CAD models. +//! +//! This library provides a window abstraction based on Winit. +//! +//! [Fornjot]: https://www.fornjot.app/ + +#![warn(missing_docs)] + +pub mod run; +pub mod window; diff --git a/crates/fj-viewer/src/run.rs b/crates/fj-window/src/run.rs similarity index 59% rename from crates/fj-viewer/src/run.rs rename to crates/fj-window/src/run.rs index 77bd1c944..9e801c274 100644 --- a/crates/fj-viewer/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -7,19 +7,24 @@ use std::{error, time::Instant}; use fj_host::Watcher; use fj_operations::shape_processor::ShapeProcessor; +use fj_viewer::{ + camera::Camera, + graphics::{self, DrawConfig, Renderer}, + input::{self, KeyState}, + screen::{Position, Screen as _, Size}, +}; use futures::executor::block_on; use tracing::{trace, warn}; use winit::{ - event::{Event, WindowEvent}, + dpi::PhysicalPosition, + event::{ + ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, + VirtualKeyCode, WindowEvent, + }, event_loop::{ControlFlow, EventLoop}, }; -use crate::{ - camera::Camera, - graphics::{self, DrawConfig, Renderer}, - input, - window::{self, Window}, -}; +use crate::window::{self, Window}; /// Initializes a model viewer for a given model and enters its process loop. pub fn run( @@ -79,57 +84,96 @@ pub fn run( } } - match event { + let event = match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { *control_flow = ControlFlow::Exit; + None } Event::WindowEvent { event: WindowEvent::Resized(size), .. } => { + let size = Size { + width: size.width, + height: size.height, + }; renderer.handle_resize(size); + + None } Event::WindowEvent { - event: WindowEvent::KeyboardInput { input, .. }, + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(virtual_key_code), + .. + }, + .. + }, .. - } => { - input_handler.handle_keyboard_input(input, &mut actions); - } + } => match virtual_key_code { + VirtualKeyCode::Escape => Some(input::Event::Key( + input::Key::Escape, + KeyState::Pressed, + )), + VirtualKeyCode::Key1 => { + Some(input::Event::Key(input::Key::Key1, KeyState::Pressed)) + } + VirtualKeyCode::Key2 => { + Some(input::Event::Key(input::Key::Key2, KeyState::Pressed)) + } + VirtualKeyCode::Key3 => { + Some(input::Event::Key(input::Key::Key3, KeyState::Pressed)) + } + + _ => None, + }, Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. } => { - if let Some(camera) = &mut camera { - input_handler - .handle_cursor_moved(position, camera, &window); - } + let position = Position { + x: position.x, + y: position.y, + }; + Some(input::Event::CursorMoved(position)) } Event::WindowEvent { event: WindowEvent::MouseInput { state, button, .. }, .. } => { - if let (Some(shape), Some(camera)) = (&shape, &camera) { - let focus_point = camera.focus_point( - &window, - input_handler.cursor(), - &shape.mesh, - ); - - input_handler.handle_mouse_input( - button, - state, - focus_point, - ); + let state = match state { + ElementState::Pressed => input::KeyState::Pressed, + ElementState::Released => input::KeyState::Released, + }; + + match button { + MouseButton::Left => { + Some(input::Event::Key(input::Key::MouseLeft, state)) + } + MouseButton::Right => { + Some(input::Event::Key(input::Key::MouseRight, state)) + } + _ => None, } } Event::WindowEvent { event: WindowEvent::MouseWheel { delta, .. }, .. } => { - input_handler.handle_mouse_wheel(delta, now); + let delta = match delta { + MouseScrollDelta::LineDelta(_, y) => y as f64 * 10.0, + MouseScrollDelta::PixelDelta(PhysicalPosition { + y, + .. + }) => y, + }; + Some(input::Event::Scroll(delta)) } Event::MainEventsCleared => { let delta_t = now.duration_since(previous_time); @@ -140,12 +184,14 @@ pub fn run( delta_t.as_secs_f64(), now, camera, - &window, + window.size(), &shape.mesh, ); } - window.inner().request_redraw(); + window.window().request_redraw(); + + None } Event::RedrawRequested(_) => { if let (Some(shape), Some(camera)) = (&shape, &mut camera) { @@ -155,8 +201,29 @@ pub fn run( warn!("Draw error: {}", err); } } + + None } - _ => {} + _ => None, + }; + + if let (Some(event), Some(shape), Some(camera)) = + (event, &shape, &mut camera) + { + let focus_point = camera.focus_point( + window.size(), + input_handler.cursor(), + &shape.mesh, + ); + + input_handler.handle_event( + event, + window.size(), + focus_point, + now, + camera, + &mut actions, + ); } if actions.exit { diff --git a/crates/fj-viewer/src/window.rs b/crates/fj-window/src/window.rs similarity index 61% rename from crates/fj-viewer/src/window.rs rename to crates/fj-window/src/window.rs index b65e09415..3f28b1169 100644 --- a/crates/fj-viewer/src/window.rs +++ b/crates/fj-window/src/window.rs @@ -1,5 +1,6 @@ //! CAD viewer utility windowing abstraction +use fj_viewer::screen::{Screen, Size}; use winit::{event_loop::EventLoop, window::WindowBuilder}; /// Window abstraction providing details such as the width or height and easing initialization. @@ -7,12 +8,6 @@ pub struct Window(winit::window::Window); impl Window { /// Returns a new window with the given `EventLoop`. - /// - /// # Examples - /// ```rust no_run - /// let event_loop = winit::event_loop::EventLoop::new(); - /// let window = fj_viewer::window::Window::new(&event_loop); - /// ``` pub fn new(event_loop: &EventLoop<()>) -> Result { let window = WindowBuilder::new() .with_title("Fornjot") @@ -23,20 +18,22 @@ impl Window { Ok(Self(window)) } +} - /// Returns a shared reference to the wrapped window - pub fn inner(&self) -> &winit::window::Window { - &self.0 - } +impl Screen for Window { + type Window = winit::window::Window; - /// Returns the width of the window - pub fn width(&self) -> u32 { - self.0.inner_size().width + fn size(&self) -> Size { + let size = self.0.inner_size(); + + Size { + width: size.width, + height: size.height, + } } - /// Returns the height of the window - pub fn height(&self) -> u32 { - self.0.inner_size().height + fn window(&self) -> &winit::window::Window { + &self.0 } }