diff --git a/examples/open_window.rs b/examples/open_window.rs index 88a9ae0..95141b9 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -36,6 +36,10 @@ fn main() { title: "baseview".into(), size: baseview::Size::new(512.0, 512.0), scale: WindowScalePolicy::SystemScaleFactor, + + // TODO: Add an example that uses the OpenGL context + #[cfg(feature = "opengl")] + gl_config: None, }; let (mut tx, rx) = RingBuffer::new(128); diff --git a/src/macos/window.rs b/src/macos/window.rs index bfe8316..fd23379 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -26,6 +26,9 @@ use crate::{ use super::keyboard::KeyboardState; use super::view::{create_view, BASEVIEW_STATE_IVAR}; +#[cfg(feature = "opengl")] +use crate::gl::{GlConfig, GlContext}; + pub struct WindowHandle { raw_window_handle: Option, close_requested: Arc, @@ -102,6 +105,9 @@ pub struct Window { /// Our subclassed NSView ns_view: id, close_requested: bool, + + #[cfg(feature = "opengl")] + gl_context: Option, } impl Window { @@ -122,7 +128,15 @@ impl Window { let ns_view = unsafe { create_view(&options) }; - let window = Window { ns_app: None, ns_window: None, ns_view, close_requested: false }; + let window = Window { + ns_app: None, + ns_window: None, + ns_view, + close_requested: false, + + #[cfg(feature = "opengl")] + gl_context: options.gl_config.map(Self::create_gl_context), + }; let window_handle = Self::init(true, window, build); @@ -146,7 +160,15 @@ impl Window { let ns_view = unsafe { create_view(&options) }; - let window = Window { ns_app: None, ns_window: None, ns_view, close_requested: false }; + let window = Window { + ns_app: None, + ns_window: None, + ns_view, + close_requested: false, + + #[cfg(feature = "opengl")] + gl_context: options.gl_config.map(Self::create_gl_context), + }; let window_handle = Self::init(true, window, build); @@ -217,6 +239,9 @@ impl Window { ns_window: Some(ns_window), ns_view, close_requested: false, + + #[cfg(feature = "opengl")] + gl_context: options.gl_config.map(Self::create_gl_context), }; let _ = Self::init(false, window, build); @@ -266,6 +291,16 @@ impl Window { pub fn close(&mut self) { self.close_requested = true; } + + #[cfg(feature = "opengl")] + pub fn gl_context(&self) -> Option<&GlContext> { + self.gl_context.as_ref() + } + + #[cfg(feature = "opengl")] + fn create_gl_context(config: GlConfig) -> GlContext { + todo!("Create the macOS OpenGL context"); + } } pub(super) struct WindowState { diff --git a/src/win/window.rs b/src/win/window.rs index 08720f0..59e0e26 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -34,6 +34,9 @@ use crate::{ use super::keyboard::KeyboardState; +#[cfg(feature = "opengl")] +use crate::gl::GlContext; + unsafe fn generate_guid() -> String { let mut guid: GUID = std::mem::zeroed(); CoCreateGuid(&mut guid); @@ -124,7 +127,9 @@ unsafe extern "system" fn wnd_proc( let window_state_ptr = GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *mut RefCell; if !window_state_ptr.is_null() { - let mut window = Window { hwnd }; + let mut window_state = (*window_state_ptr).borrow_mut(); + + let mut window = window_state.create_window(hwnd); let mut window = crate::Window::new(&mut window); match msg { @@ -134,8 +139,6 @@ unsafe extern "system" fn wnd_proc( let physical_pos = PhyPoint { x, y }; - let mut window_state = (&*window_state_ptr).borrow_mut(); - let logical_pos = physical_pos.to_logical(&window_state.window_info); window_state.handler.on_event( @@ -149,8 +152,6 @@ unsafe extern "system" fn wnd_proc( let value = value as i32; let value = value as f32 / WHEEL_DELTA as f32; - let mut window_state = (&*window_state_ptr).borrow_mut(); - window_state.handler.on_event( &mut window, Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines { @@ -162,7 +163,7 @@ unsafe extern "system" fn wnd_proc( } WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN | WM_RBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP => { - let mut mouse_button_counter = (&*window_state_ptr).borrow().mouse_button_counter; + let mut mouse_button_counter = (*window_state_ptr).borrow().mouse_button_counter; let button = match msg { WM_LBUTTONDOWN | WM_LBUTTONUP => Some(MouseButton::Left), @@ -198,44 +199,33 @@ unsafe extern "system" fn wnd_proc( } }; - (&*window_state_ptr).borrow_mut().mouse_button_counter = mouse_button_counter; + window_state.mouse_button_counter = mouse_button_counter; - (&*window_state_ptr) - .borrow_mut() - .handler - .on_event(&mut window, Event::Mouse(event)); + window_state.handler.on_event(&mut window, Event::Mouse(event)); } } WM_TIMER => { match wparam { WIN_FRAME_TIMER => { - (&*window_state_ptr).borrow_mut().handler.on_frame(&mut window); + window_state.handler.on_frame(&mut window); } _ => (), } return 0; } WM_CLOSE => { - (&*window_state_ptr) - .borrow_mut() - .handler - .on_event(&mut window, Event::Window(WindowEvent::WillClose)); + window_state.handler.on_event(&mut window, Event::Window(WindowEvent::WillClose)); // DestroyWindow(hwnd); // return 0; return DefWindowProcW(hwnd, msg, wparam, lparam); } WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP | WM_INPUTLANGCHANGE => { - let opt_event = (&*window_state_ptr) - .borrow_mut() - .keyboard_state - .process_message(hwnd, msg, wparam, lparam); + let opt_event = + window_state.keyboard_state.process_message(hwnd, msg, wparam, lparam); if let Some(event) = opt_event { - (&*window_state_ptr) - .borrow_mut() - .handler - .on_event(&mut window, Event::Keyboard(event)); + window_state.handler.on_event(&mut window, Event::Keyboard(event)); } if msg != WM_SYSKEYDOWN { @@ -246,8 +236,6 @@ unsafe extern "system" fn wnd_proc( let width = (lparam & 0xFFFF) as u16 as u32; let height = ((lparam >> 16) & 0xFFFF) as u16 as u32; - let mut window_state = (&*window_state_ptr).borrow_mut(); - window_state.window_info = WindowInfo::from_physical_size( PhySize { width, height }, window_state.window_info.scale(), @@ -262,8 +250,6 @@ unsafe extern "system" fn wnd_proc( WM_DPICHANGED => { // To avoid weirdness with the realtime borrow checker. let new_rect = { - let mut window_state = (&*window_state_ptr).borrow_mut(); - if let WindowScalePolicy::SystemScaleFactor = window_state.scale_policy { let dpi = (wparam & 0xFFFF) as u16 as u32; let scale_factor = dpi as f64 / 96.0; @@ -319,7 +305,7 @@ unsafe extern "system" fn wnd_proc( } } - return DefWindowProcW(hwnd, msg, wparam, lparam); + DefWindowProcW(hwnd, msg, wparam, lparam) } unsafe fn register_wnd_class() -> ATOM { @@ -357,10 +343,28 @@ struct WindowState { handler: Box, scale_policy: WindowScalePolicy, dw_style: u32, + + #[cfg(feature = "opengl")] + gl_context: Arc>, +} + +impl WindowState { + #[cfg(not(feature = "opengl"))] + fn create_window(&self, hwnd: HWND) -> Window { + Window { hwnd } + } + + #[cfg(feature = "opengl")] + fn create_window(&self, hwnd: HWND) -> Window { + Window { hwnd, gl_context: self.gl_context.clone() } + } } pub struct Window { hwnd: HWND, + + #[cfg(feature = "opengl")] + gl_context: Arc>, } impl Window { @@ -478,7 +482,17 @@ impl Window { ); // todo: manage error ^ + #[cfg(feature = "opengl")] + let gl_context: Arc> = + Arc::new(todo!("Create the Windows OpenGL context")); + + #[cfg(not(feature = "opengl"))] let handler = Box::new(build(&mut crate::Window::new(&mut Window { hwnd }))); + #[cfg(feature = "opengl")] + let handler = Box::new(build(&mut crate::Window::new(&mut Window { + hwnd, + gl_context: gl_context.clone(), + }))); let (parent_handle, window_handle) = ParentHandle::new(hwnd); let parent_handle = if parented { Some(parent_handle) } else { None }; @@ -492,6 +506,9 @@ impl Window { handler, scale_policy: options.scale, dw_style: flags, + + #[cfg(feature = "opengl")] + gl_context, })); // Only works on Windows 10 unfortunately. @@ -556,6 +573,11 @@ impl Window { PostMessageW(self.hwnd, BV_WINDOW_MUST_CLOSE, 0, 0); } } + + #[cfg(feature = "opengl")] + pub fn gl_context(&self) -> Option<&GlContext> { + self.gl_context.as_ref().as_ref() + } } unsafe impl HasRawWindowHandle for Window { diff --git a/src/window.rs b/src/window.rs index 9b5dfbb..091a594 100644 --- a/src/window.rs +++ b/src/window.rs @@ -91,6 +91,13 @@ impl<'a> Window<'a> { pub fn close(&mut self) { self.window.close(); } + + /// If provided, then an OpenGL context will be created for this window. You'll be able to + /// access this context through [crate::Window::gl_context]. + #[cfg(feature = "opengl")] + pub fn gl_context(&self) -> Option<&crate::gl::GlContext> { + self.window.gl_context() + } } unsafe impl<'a> HasRawWindowHandle for Window<'a> { diff --git a/src/window_open_options.rs b/src/window_open_options.rs index c4abf74..7c5cd19 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -21,4 +21,9 @@ pub struct WindowOpenOptions { /// The dpi scaling policy pub scale: WindowScalePolicy, + + /// If provided, then an OpenGL context will be created for this window. You'll be able to + /// access this context through [crate::Window::gl_context]. + #[cfg(feature = "opengl")] + pub gl_config: Option, } diff --git a/src/x11/window.rs b/src/x11/window.rs index f9cff75..9bae212 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -16,6 +16,9 @@ use crate::{ use super::keyboard::{convert_key_press_event, convert_key_release_event}; +#[cfg(feature = "opengl")] +use crate::gl::GlContext; + pub struct WindowHandle { raw_window_handle: Option, close_requested: Arc, @@ -96,6 +99,9 @@ pub struct Window { new_physical_size: Option, parent_handle: Option, + + #[cfg(feature = "opengl")] + gl_context: Option, } // Hack to allow sending a RawWindowHandle between threads. Do not make public @@ -306,6 +312,9 @@ impl Window { new_physical_size: None, parent_handle, + + #[cfg(feature = "opengl")] + gl_context: todo!("Create the X11 OpenGL context"), }; let mut handler = build(&mut crate::Window::new(&mut window)); @@ -346,6 +355,11 @@ impl Window { self.close_requested = true; } + #[cfg(feature = "opengl")] + pub fn gl_context(&self) -> Option<&crate::gl::GlContext> { + self.gl_context.as_ref() + } + #[inline] fn drain_xcb_events(&mut self, handler: &mut dyn WindowHandler) { // the X server has a tendency to send spurious/extraneous configure notify events when a