diff options
Diffstat (limited to 'engine/src/window.rs')
-rw-r--r-- | engine/src/window.rs | 755 |
1 files changed, 0 insertions, 755 deletions
diff --git a/engine/src/window.rs b/engine/src/window.rs deleted file mode 100644 index f191c06..0000000 --- a/engine/src/window.rs +++ /dev/null @@ -1,755 +0,0 @@ -use std::borrow::Cow; -use std::ffi::{CStr, CString}; - -use bitflags::bitflags; -use ecs::actions::Actions; -use ecs::extension::Collector as ExtensionCollector; -use ecs::pair::{ChildOf, Pair}; -use ecs::phase::{Phase, START as START_PHASE}; -use ecs::sole::Single; -use ecs::{declare_entity, Sole}; -use glfw::window::{Hint as WindowCreationHint, HintValue as WindowCreationHintValue}; -use glfw::WindowSize; -use util_macros::VariantArr; - -use crate::data_types::dimens::Dimens; -use crate::renderer::RENDER_PHASE; -use crate::vector::Vec2; - -declare_entity!( - pub UPDATE_PHASE, - (Phase, Pair::builder().relation::<ChildOf>().target_id(*RENDER_PHASE).build()) -); - -#[derive(Debug, Sole)] -/// Has to be dropped last since it holds the OpenGL context. -#[sole(drop_last)] -pub struct Window -{ - inner: glfw::Window, -} - -impl Window -{ - /// Returns a new Window builder. - #[must_use] - pub fn builder() -> Builder - { - Builder::default() - } - - /// Sets the value of a input mode. - /// - /// # Errors - /// Returns `Err` if the input mode is unsupported on the current system. - pub fn set_input_mode( - &self, - input_mode: InputMode, - enabled: bool, - ) -> Result<(), Error> - { - Ok(self - .inner - .set_input_mode(input_mode.to_glfw_input_mode(), enabled)?) - } - - /// Sets the cursor mode. - /// - /// # Errors - /// If a platform error occurs. - pub fn set_cursor_mode(&self, cursor_mode: CursorMode) -> Result<(), Error> - { - Ok(self - .inner - .set_cursor_mode(cursor_mode.to_glfw_cursor_mode())?) - } - - /// Returns whether or not the window should close. Will return true when the user has - /// attempted to close the window. - #[must_use] - pub fn should_close(&self) -> bool - { - self.inner.should_close() - } - - /// Processes all pending events. - /// - /// # Errors - /// If a platform error occurs. - pub fn poll_events(&self) -> Result<(), Error> - { - Ok(self.inner.poll_events()?) - } - - /// Swaps the front and back buffers of the window. - /// - /// # Errors - /// Will return `Err` if a platform error occurs or if no OpenGL window context - /// is present. - pub fn swap_buffers(&self) -> Result<(), Error> - { - Ok(self.inner.swap_buffers()?) - } - - /// Returns the size of the window. - /// - /// # Errors - /// Will return `Err` if a platform error occurs. - pub fn size(&self) -> Result<Dimens<u32>, Error> - { - let size = self.inner.size()?; - - Ok(Dimens { - width: size.width, - height: size.height, - }) - } - - /// Returns the address of the specified OpenGL function, if it is supported by the - /// current OpenGL context. - /// - /// # Errors - /// Will return `Err` if a platform error occurs or if no current context has - /// been set. - /// - /// # Panics - /// Will panic if the `proc_name` argument contains a nul byte. - pub fn get_proc_address( - &self, - proc_name: &str, - ) -> Result<unsafe extern "C" fn(), Error> - { - let proc_name_c: Cow<CStr> = CStr::from_bytes_with_nul(proc_name.as_bytes()) - .map(Cow::Borrowed) - .or_else(|_| CString::new(proc_name).map(Cow::Owned)) - .expect("OpenGL function name contains a nul byte"); - - Ok(self.inner.get_proc_address(&proc_name_c)?) - } - - /// Makes the OpenGL context of the window current for the calling thread. - /// - /// # Errors - /// Will return `Err` if a platform error occurs or if no OpenGL context is - /// present. - pub fn make_context_current(&self) -> Result<(), Error> - { - Ok(self.inner.make_context_current()?) - } - - /// Sets the window's framebuffer size callback. - pub fn set_framebuffer_size_callback(&self, callback: impl Fn(Dimens<u32>) + 'static) - { - self.inner.set_framebuffer_size_callback(move |size| { - callback(Dimens { - width: size.width, - height: size.height, - }); - }); - } - - /// Sets the window's key size callback. - pub fn set_key_callback( - &self, - callback: impl Fn(Key, i32, KeyState, KeyModifiers) + 'static, - ) - { - self.inner - .set_key_callback(move |key, scancode, key_state, key_modifiers| { - let Some(key_state) = KeyState::from_glfw_key_state(key_state) else { - return; - }; - - callback( - Key::from_glfw_key(key), - scancode, - key_state, - KeyModifiers::from_bits_truncate(key_modifiers.bits()), - ) - }); - } - - /// Sets the window's cursor position callback. - pub fn set_cursor_pos_callback(&self, callback: impl Fn(Vec2<f64>) + 'static) - { - self.inner - .set_cursor_pos_callback(move |pos| callback(Vec2 { x: pos.x, y: pos.y })); - } - - /// Sets the window's mouse button callback. The given function is called when a mouse - /// button enters a new state. - pub fn set_mouse_button_callback( - &self, - callback: impl Fn(MouseButton, MouseButtonState, KeyModifiers) + 'static, - ) - { - self.inner.set_mouse_button_callback( - move |mouse_button, mouse_button_state, key_modifiers| { - callback( - MouseButton::from_glfw_mouse_button(mouse_button), - MouseButtonState::from_glfw_mouse_button_state(mouse_button_state), - KeyModifiers::from_bits_truncate(key_modifiers.bits()), - ) - }, - ); - } - - /// Sets the window's close callback. - pub fn set_close_callback(&self, callback: impl Fn() + 'static) - { - self.inner.set_close_callback(callback); - } - - /// Sets the window's focus callback. The callback is called when the window loses or - /// gains input focus. - pub fn set_focus_callback(&self, callback: impl Fn(bool) + 'static) - { - self.inner.set_focus_callback(callback); - } -} - -/// [`Window`] builder. -#[derive(Debug, Clone, Default)] -pub struct Builder -{ - inner: glfw::WindowBuilder, -} - -impl Builder -{ - /// Sets whether the OpenGL context should be created in debug mode, which may - /// provide additional error and diagnostic reporting functionality. - pub fn opengl_debug_context(mut self, enabled: bool) -> Self - { - self.inner = self.inner.hint( - WindowCreationHint::OpenGLDebugContext, - WindowCreationHintValue::Bool(enabled), - ); - - self - } - - /// Set the desired number of samples to use for multisampling. Zero disables - /// multisampling. - pub fn multisampling_sample_count(mut self, sample_count: u16) -> Self - { - self.inner = self.inner.hint( - WindowCreationHint::Samples, - WindowCreationHintValue::Number(sample_count as i32), - ); - - self - } - - /// Creates a new window. - /// - /// # Errors - /// Will return `Err` if the title contains a internal nul byte or if a platform error - /// occurs. - pub fn create(&self, size: Dimens<u32>, title: &str) -> Result<Window, Error> - { - let builder = self.inner.clone().hint( - WindowCreationHint::OpenGLDebugContext, - WindowCreationHintValue::Bool(true), - ); - - let window = builder.create( - &WindowSize { - width: size.width, - height: size.height, - }, - title, - )?; - - Ok(Window { inner: window }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, VariantArr)] -#[variant_arr(name = KEYS)] -pub enum Key -{ - Space, - Apostrophe, - Comma, - Minus, - Period, - Slash, - Digit0, - Digit1, - Digit2, - Digit3, - Digit4, - Digit5, - Digit6, - Digit7, - Digit8, - Digit9, - Semicolon, - Equal, - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - LeftBracket, - Backslash, - RightBracket, - GraveAccent, - World1, - World2, - Escape, - Enter, - Tab, - Backspace, - Insert, - Delete, - Right, - Left, - Down, - Up, - PageUp, - PageDown, - Home, - End, - CapsLock, - ScrollLock, - NumLock, - PrintScreen, - Pause, - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - F13, - F14, - F15, - F16, - F17, - F18, - F19, - F20, - F21, - F22, - F23, - F24, - F25, - Kp0, - Kp1, - Kp2, - Kp3, - Kp4, - Kp5, - Kp6, - Kp7, - Kp8, - Kp9, - KpDecimal, - KpDivide, - KpMultiply, - KpSubtract, - KpAdd, - KpEnter, - KpEqual, - LeftShift, - LeftControl, - LeftAlt, - LeftSuper, - RightShift, - RightControl, - RightAlt, - RightSuper, - Menu, -} - -impl Key -{ - fn from_glfw_key(glfw_key: glfw::window::Key) -> Self - { - match glfw_key { - glfw::window::Key::Space => Self::Space, - glfw::window::Key::Apostrophe => Self::Apostrophe, - glfw::window::Key::Comma => Self::Comma, - glfw::window::Key::Minus => Self::Minus, - glfw::window::Key::Period => Self::Period, - glfw::window::Key::Slash => Self::Slash, - glfw::window::Key::Digit0 => Self::Digit0, - glfw::window::Key::Digit1 => Self::Digit1, - glfw::window::Key::Digit2 => Self::Digit2, - glfw::window::Key::Digit3 => Self::Digit3, - glfw::window::Key::Digit4 => Self::Digit4, - glfw::window::Key::Digit5 => Self::Digit5, - glfw::window::Key::Digit6 => Self::Digit6, - glfw::window::Key::Digit7 => Self::Digit7, - glfw::window::Key::Digit8 => Self::Digit8, - glfw::window::Key::Digit9 => Self::Digit9, - glfw::window::Key::Semicolon => Self::Semicolon, - glfw::window::Key::Equal => Self::Equal, - glfw::window::Key::A => Self::A, - glfw::window::Key::B => Self::B, - glfw::window::Key::C => Self::C, - glfw::window::Key::D => Self::D, - glfw::window::Key::E => Self::E, - glfw::window::Key::F => Self::F, - glfw::window::Key::G => Self::G, - glfw::window::Key::H => Self::H, - glfw::window::Key::I => Self::I, - glfw::window::Key::J => Self::J, - glfw::window::Key::K => Self::K, - glfw::window::Key::L => Self::L, - glfw::window::Key::M => Self::M, - glfw::window::Key::N => Self::N, - glfw::window::Key::O => Self::O, - glfw::window::Key::P => Self::P, - glfw::window::Key::Q => Self::Q, - glfw::window::Key::R => Self::R, - glfw::window::Key::S => Self::S, - glfw::window::Key::T => Self::T, - glfw::window::Key::U => Self::U, - glfw::window::Key::V => Self::V, - glfw::window::Key::W => Self::W, - glfw::window::Key::X => Self::X, - glfw::window::Key::Y => Self::Y, - glfw::window::Key::Z => Self::Z, - glfw::window::Key::LeftBracket => Self::LeftBracket, - glfw::window::Key::Backslash => Self::Backslash, - glfw::window::Key::RightBracket => Self::RightBracket, - glfw::window::Key::GraveAccent => Self::GraveAccent, - glfw::window::Key::World1 => Self::World1, - glfw::window::Key::World2 => Self::World2, - glfw::window::Key::Escape => Self::Escape, - glfw::window::Key::Enter => Self::Enter, - glfw::window::Key::Tab => Self::Tab, - glfw::window::Key::Backspace => Self::Backspace, - glfw::window::Key::Insert => Self::Insert, - glfw::window::Key::Delete => Self::Delete, - glfw::window::Key::Right => Self::Right, - glfw::window::Key::Left => Self::Left, - glfw::window::Key::Down => Self::Down, - glfw::window::Key::Up => Self::Up, - glfw::window::Key::PageUp => Self::PageUp, - glfw::window::Key::PageDown => Self::PageDown, - glfw::window::Key::Home => Self::Home, - glfw::window::Key::End => Self::End, - glfw::window::Key::CapsLock => Self::CapsLock, - glfw::window::Key::ScrollLock => Self::ScrollLock, - glfw::window::Key::NumLock => Self::NumLock, - glfw::window::Key::PrintScreen => Self::PrintScreen, - glfw::window::Key::Pause => Self::Pause, - glfw::window::Key::F1 => Self::F1, - glfw::window::Key::F2 => Self::F2, - glfw::window::Key::F3 => Self::F3, - glfw::window::Key::F4 => Self::F4, - glfw::window::Key::F5 => Self::F5, - glfw::window::Key::F6 => Self::F6, - glfw::window::Key::F7 => Self::F7, - glfw::window::Key::F8 => Self::F8, - glfw::window::Key::F9 => Self::F9, - glfw::window::Key::F10 => Self::F10, - glfw::window::Key::F11 => Self::F11, - glfw::window::Key::F12 => Self::F12, - glfw::window::Key::F13 => Self::F13, - glfw::window::Key::F14 => Self::F14, - glfw::window::Key::F15 => Self::F15, - glfw::window::Key::F16 => Self::F16, - glfw::window::Key::F17 => Self::F17, - glfw::window::Key::F18 => Self::F18, - glfw::window::Key::F19 => Self::F19, - glfw::window::Key::F20 => Self::F20, - glfw::window::Key::F21 => Self::F21, - glfw::window::Key::F22 => Self::F22, - glfw::window::Key::F23 => Self::F23, - glfw::window::Key::F24 => Self::F24, - glfw::window::Key::F25 => Self::F25, - glfw::window::Key::Kp0 => Self::Kp0, - glfw::window::Key::Kp1 => Self::Kp1, - glfw::window::Key::Kp2 => Self::Kp2, - glfw::window::Key::Kp3 => Self::Kp3, - glfw::window::Key::Kp4 => Self::Kp4, - glfw::window::Key::Kp5 => Self::Kp5, - glfw::window::Key::Kp6 => Self::Kp6, - glfw::window::Key::Kp7 => Self::Kp7, - glfw::window::Key::Kp8 => Self::Kp8, - glfw::window::Key::Kp9 => Self::Kp9, - glfw::window::Key::KpDecimal => Self::KpDecimal, - glfw::window::Key::KpDivide => Self::KpDivide, - glfw::window::Key::KpMultiply => Self::KpMultiply, - glfw::window::Key::KpSubtract => Self::KpSubtract, - glfw::window::Key::KpAdd => Self::KpAdd, - glfw::window::Key::KpEnter => Self::KpEnter, - glfw::window::Key::KpEqual => Self::KpEqual, - glfw::window::Key::LeftShift => Self::LeftShift, - glfw::window::Key::LeftControl => Self::LeftControl, - glfw::window::Key::LeftAlt => Self::LeftAlt, - glfw::window::Key::LeftSuper => Self::LeftSuper, - glfw::window::Key::RightShift => Self::RightShift, - glfw::window::Key::RightControl => Self::RightControl, - glfw::window::Key::RightAlt => Self::RightAlt, - glfw::window::Key::RightSuper => Self::RightSuper, - glfw::window::Key::Menu => Self::Menu, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum KeyState -{ - Pressed, - Released, -} - -impl KeyState -{ - fn from_glfw_key_state(glfw_key_state: glfw::window::KeyState) -> Option<Self> - { - match glfw_key_state { - glfw::window::KeyState::Pressed => Some(Self::Pressed), - glfw::window::KeyState::Released => Some(Self::Released), - glfw::window::KeyState::Repeat => None, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum MouseButton -{ - One, - Two, - Three, - Four, - Five, - Six, - Seven, - Eight, -} - -impl MouseButton -{ - pub const LEFT: Self = Self::One; - pub const MIDDLE: Self = Self::Three; - pub const RIGHT: Self = Self::Two; - - fn from_glfw_mouse_button(mouse_button: glfw::window::MouseButton) -> Self - { - match mouse_button { - glfw::window::MouseButton::One => Self::One, - glfw::window::MouseButton::Two => Self::Two, - glfw::window::MouseButton::Three => Self::Three, - glfw::window::MouseButton::Four => Self::Four, - glfw::window::MouseButton::Five => Self::Five, - glfw::window::MouseButton::Six => Self::Six, - glfw::window::MouseButton::Seven => Self::Seven, - glfw::window::MouseButton::Eight => Self::Eight, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum MouseButtonState -{ - Pressed, - Released, -} - -impl MouseButtonState -{ - fn from_glfw_mouse_button_state( - mouse_button_state: glfw::window::MouseButtonState, - ) -> Self - { - match mouse_button_state { - glfw::window::MouseButtonState::Pressed => Self::Pressed, - glfw::window::MouseButtonState::Released => Self::Released, - } - } -} - -bitflags! { - #[derive(Debug, Clone, Copy)] - pub struct KeyModifiers: i32 { - const SHIFT = glfw::window::KeyModifiers::SHIFT.bits(); - const CONTROL = glfw::window::KeyModifiers::CONTROL.bits(); - const ALT = glfw::window::KeyModifiers::ALT.bits(); - const SUPER = glfw::window::KeyModifiers::SUPER.bits(); - const CAPS_LOCK = glfw::window::KeyModifiers::CAPS_LOCK.bits(); - const NUM_LOCK = glfw::window::KeyModifiers::NUM_LOCK.bits(); - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum CursorMode -{ - /// Hides and grabs the cursor, providing virtual and unlimited cursor movement. - Disabled, - - /// Makes the cursor invisible when it is over the content area of the window but - /// does not restrict the cursor from leaving. - Hidden, - - /// Makes the cursor visible and behaving normally. - Normal, -} - -impl CursorMode -{ - fn to_glfw_cursor_mode(self) -> glfw::window::CursorMode - { - match self { - Self::Disabled => glfw::window::CursorMode::Disabled, - Self::Hidden => glfw::window::CursorMode::Hidden, - Self::Normal => glfw::window::CursorMode::Normal, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum InputMode -{ - /// When the cursor is disabled, raw (unscaled and unaccelerated) mouse motion can be - /// enabled if available. - /// - /// Raw mouse motion is closer to the actual motion of the mouse across a surface. It - /// is not affected by the scaling and acceleration applied to the motion of the - /// desktop cursor. That processing is suitable for a cursor while raw motion is - /// better for controlling for example a 3D camera. Because of this, raw mouse motion - /// is only provided when the cursor is disabled. - RawMouseMotion, -} - -impl InputMode -{ - fn to_glfw_input_mode(self) -> glfw::window::InputMode - { - match self { - Self::RawMouseMotion => glfw::window::InputMode::RawMouseMotion, - } - } -} - -#[derive(Debug)] -pub struct Extension -{ - window_builder: Builder, - window_size: Dimens<u32>, - window_title: String, -} - -impl Extension -{ - #[must_use] - pub fn new(window_builder: Builder) -> Self - { - Self { window_builder, ..Default::default() } - } - - #[must_use] - pub fn window_size(mut self, window_size: Dimens<u32>) -> Self - { - self.window_size = window_size; - - self - } - - #[must_use] - pub fn window_title(mut self, window_title: impl Into<String>) -> Self - { - self.window_title = window_title.into(); - - self - } -} - -impl ecs::extension::Extension for Extension -{ - fn collect(self, mut collector: ExtensionCollector<'_>) - { - collector.add_declared_entity(&self::UPDATE_PHASE); - - collector.add_system(*START_PHASE, initialize); - collector.add_system(*self::UPDATE_PHASE, update); - - let window = self - .window_builder - .create(self.window_size, &self.window_title) - .unwrap(); - - window.set_cursor_mode(CursorMode::Normal).unwrap(); - - collector.add_sole(window).ok(); - } -} - -impl Default for Extension -{ - fn default() -> Self - { - Self { - window_builder: Builder::default(), - window_size: Dimens { width: 1920, height: 1080 }, - window_title: String::new(), - } - } -} - -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct Error(glfw::Error); - -impl From<glfw::Error> for Error -{ - fn from(err: glfw::Error) -> Self - { - Self(err) - } -} - -fn initialize(window: Single<Window>, actions: Actions) -{ - let actions_weak_ref = actions.to_weak_ref(); - - window.set_close_callback(move || { - let actions_weak_ref = actions_weak_ref.clone(); - - let actions_ref = actions_weak_ref.access().expect("No world"); - - actions_ref.to_actions().stop(); - }); -} - -fn update(window: Single<Window>) -{ - window - .swap_buffers() - .expect("Failed to swap window buffers"); - - window.poll_events().expect("Failed to poll window events"); -} |