1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
use glutin::*; use crate::window::frame_input; use crate::gl; #[derive(Debug)] pub enum Error { WindowCreationError(glutin::CreationError), ContextError(glutin::ContextError) } impl From<glutin::CreationError> for Error { fn from(other: glutin::CreationError) -> Self { Error::WindowCreationError(other) } } impl From<glutin::ContextError> for Error { fn from(other: glutin::ContextError) -> Self { Error::ContextError(other) } } pub struct Window { gl_window: GlWindow, events_loop: EventsLoop, gl: crate::Gl } impl Window { pub fn new_default(title: &str) -> Result<Window, Error> { Window::new(title, 1024, 512) } pub fn new(title: &str, width: u32, height: u32) -> Result<Window, Error> { let window = WindowBuilder::new() .with_title(title) .with_dimensions(dpi::LogicalSize::new(width as f64, height as f64)); let events_loop = EventsLoop::new(); let context = ContextBuilder::new().with_vsync(true); let gl_window = GlWindow::new(window, context, &events_loop)?; unsafe { gl_window.make_current()?; } let gl = gl::Glstruct::load_with(|s| gl_window.get_proc_address(s) as *const std::os::raw::c_void); Ok(Window {gl_window, events_loop, gl}) } pub fn render_loop<F: 'static>(&mut self, mut callback: F) -> Result<(), Error> where F: FnMut(frame_input::FrameInput) { let mut last_time = std::time::Instant::now(); let mut count = 0; let mut accumulated_time = 0.0; let mut error = Ok(()); let mut exit = false; while error.is_ok() && !exit { let mut events = Vec::new(); self.events_loop.poll_events(|event| { exit = Self::handle_window_close_events(&event); if let Some(e) = Self::map_event(&event) { events.push(e); } }); let now = std::time::Instant::now(); let duration = now.duration_since(last_time); last_time = now; let elapsed_time = duration.as_secs() as f64 * 1000.0 + duration.subsec_nanos() as f64 * 1e-6; accumulated_time += elapsed_time; count += 1; if accumulated_time > 1000.0 { println!("FPS: {}", count as f64 / (accumulated_time * 0.001)); count = 0; accumulated_time = 0.0; } let (screen_width, screen_height) = self.framebuffer_size(); let (window_width, window_height) = self.size(); let frame_input = frame_input::FrameInput {events, elapsed_time, screen_width, screen_height, window_width, window_height}; callback(frame_input); error = self.gl_window.swap_buffers(); } error?; Ok(()) } pub fn framebuffer_size(&self) -> (usize, usize) { let t: (u32, u32) = self.gl_window.get_inner_size().unwrap().to_physical(self.gl_window.get_hidpi_factor()).into(); (t.0 as usize, t.1 as usize) } pub fn size(&self) -> (usize, usize) { let t: (u32, u32) = self.gl_window.get_inner_size().unwrap().into(); (t.0 as usize, t.1 as usize) } pub fn aspect(&self) -> f32 { let (width, height) = self.framebuffer_size(); width as f32 / height as f32 } pub fn gl(&self) -> crate::Gl { self.gl.clone() } fn map_event(event: &Event) -> Option<frame_input::Event> { static mut CURSOR_POS: Option<(f64, f64)> = None; match event { Event::WindowEvent{ event, .. } => match event { WindowEvent::KeyboardInput {input, ..} => { if let Some(keycode) = input.virtual_keycode { let state = if input.state == ElementState::Pressed {frame_input::State::Pressed} else {frame_input::State::Released}; return Some(frame_input::Event::Key {state, kind: format!("{:?}", keycode)}); } }, WindowEvent::MouseWheel {delta, ..} => { match delta { MouseScrollDelta::LineDelta(_, y) => { return Some(frame_input::Event::MouseWheel { delta: *y as f64 }); }, MouseScrollDelta::PixelDelta(logical_position) => { return Some(frame_input::Event::MouseWheel { delta: logical_position.y }); } } }, WindowEvent::MouseInput {state, button, ..} => { if let Some(position) = unsafe {CURSOR_POS} { let state = if *state == ElementState::Pressed {frame_input::State::Pressed} else {frame_input::State::Released}; let button = match button { MouseButton::Left => Some(frame_input::MouseButton::Left), MouseButton::Middle => Some(frame_input::MouseButton::Middle), MouseButton::Right => Some(frame_input::MouseButton::Right), _ => None }; return button.map(|b| frame_input::Event::MouseClick { state, button: b, position }); } }, WindowEvent::CursorMoved {position, ..} => { unsafe { CURSOR_POS = Some((position.x, position.y)); } }, _ => () }, Event::DeviceEvent{ event, .. } => match event { DeviceEvent::MouseMotion {delta} => { return Some(frame_input::Event::MouseMotion {delta: *delta}); }, _ => {} } _ => () } None } fn handle_window_close_events(event: &Event) -> bool { match event { Event::WindowEvent{ event, .. } => match event { WindowEvent::CloseRequested => true, WindowEvent::KeyboardInput {input, ..} => Some(VirtualKeyCode::Escape) == input.virtual_keycode, _ => false }, _ => false } } }