1#![deny(missing_docs)]
2
3extern crate gl;
6extern crate glfw;
7extern crate input;
8extern crate shader_version;
9extern crate window;
10
11use glfw::{Context, Joystick, JoystickId};
13use input::{
14 keyboard, Button, ButtonArgs, ButtonState, CloseArgs, ControllerAxisArgs, ControllerButton,
15 Event, FileDrag, Input, Motion, MouseButton, ResizeArgs,
16};
17use std::collections::VecDeque;
18use std::error::Error;
19use std::time::Duration;
20use std::collections::HashMap;
21use glfw::GlfwReceiver as Receiver;
22use window::{
23 AdvancedWindow, Api, BuildFromWindowSettings, OpenGLWindow, Position, ProcAddress, Size,
24 UnsupportedGraphicsApiError, Window, WindowSettings,
25};
26
27pub use shader_version::OpenGL;
28
29const JOYSTICKS: [JoystickId; 16] = [
31 JoystickId::Joystick1,
32 JoystickId::Joystick2,
33 JoystickId::Joystick3,
34 JoystickId::Joystick4,
35 JoystickId::Joystick5,
36 JoystickId::Joystick6,
37 JoystickId::Joystick7,
38 JoystickId::Joystick8,
39 JoystickId::Joystick9,
40 JoystickId::Joystick10,
41 JoystickId::Joystick11,
42 JoystickId::Joystick12,
43 JoystickId::Joystick13,
44 JoystickId::Joystick14,
45 JoystickId::Joystick15,
46 JoystickId::Joystick16,
47];
48
49pub struct GlfwWindow {
51 pub window: glfw::PWindow,
53 events: Receiver<(f64, glfw::WindowEvent)>,
55 pub glfw: glfw::Glfw,
57 event_queue: VecDeque<Input>,
58 last_mouse_pos: Option<(f64, f64)>,
60 title: String,
62 exit_on_esc: bool,
63 automatic_close: bool,
64
65 pub joystick_deadzone: f64,
67 joysticks: Vec<JoystickHelper>,
68}
69
70impl GlfwWindow {
71 pub fn from_pieces(
73 mut win: glfw::PWindow,
74 glfw: glfw::Glfw,
75 events: Receiver<(f64, glfw::WindowEvent)>,
76 exit_on_esc: bool,
77 ) -> GlfwWindow {
78 win.set_all_polling(true);
79 win.make_current();
80 let title = "<unknown window title, created from_pieces>";
81
82 let mut joysticks = Vec::new();
84 for &i in &JOYSTICKS {
85 joysticks.push(JoystickHelper::new(glfw.get_joystick(i)));
86 }
87
88 GlfwWindow {
89 joysticks,
90 window: win,
91 events,
92 glfw,
93 exit_on_esc,
94 event_queue: VecDeque::new(),
95 last_mouse_pos: None,
96 title: title.to_string(),
97 automatic_close: true,
98 joystick_deadzone: 0.0,
99 }
100 }
101
102 pub fn new(settings: &WindowSettings) -> Result<GlfwWindow, Box<dyn Error>> {
104 use glfw::SwapInterval;
105 use std::ptr::null;
106
107 let mut glfw = glfw::init_no_callbacks()?;
109
110 let api = settings
111 .get_maybe_graphics_api()
112 .unwrap_or(Api::opengl(3, 2));
113 if api.api != "OpenGL" {
114 return Err(UnsupportedGraphicsApiError {
115 found: api.api,
116 expected: vec!["OpenGL".into()],
117 }
118 .into());
119 };
120
121 glfw.window_hint(glfw::WindowHint::ContextVersion(api.major, api.minor));
123 glfw.window_hint(glfw::WindowHint::Resizable(settings.get_resizable()));
124 glfw.window_hint(glfw::WindowHint::Decorated(settings.get_decorated()));
125 glfw.window_hint(glfw::WindowHint::TransparentFramebuffer(
126 settings.get_transparent(),
127 ));
128 glfw.window_hint(glfw::WindowHint::SRgbCapable(settings.get_srgb()));
130 if api >= Api::opengl(3, 2) {
131 if cfg!(target_os = "macos") {
132 glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
133 }
134 glfw.window_hint(glfw::WindowHint::OpenGlProfile(
135 glfw::OpenGlProfileHint::Core,
136 ));
137 }
138 if settings.get_samples() != 0 {
139 glfw.window_hint(glfw::WindowHint::Samples(Some(
140 settings.get_samples() as u32
141 )));
142 }
143
144 let (mut window, events) = glfw
146 .create_window(
147 settings.get_size().width as u32,
148 settings.get_size().height as u32,
149 &settings.get_title(),
150 glfw::WindowMode::Windowed,
151 )
152 .ok_or("Failed to create GLFW window.")?;
153 window.set_all_polling(true);
154 window.make_current();
155
156 if settings.get_vsync() {
157 glfw.set_swap_interval(SwapInterval::Sync(1));
158 } else {
159 glfw.set_swap_interval(SwapInterval::None);
160 }
161
162 gl::load_with(|s| window.get_proc_address(s)
164 .map(|n| n as *const _)
165 .unwrap_or(null()));
166
167 let mut joysticks = Vec::new();
169 if settings.get_controllers() {
170 for &i in &JOYSTICKS {
171 joysticks.push(JoystickHelper::new(glfw.get_joystick(i)));
172 }
173 }
174
175 Ok(GlfwWindow {
176 joysticks,
177 window,
178 events,
179 glfw,
180 event_queue: VecDeque::new(),
181 last_mouse_pos: None,
182 title: settings.get_title(),
183 exit_on_esc: settings.get_exit_on_esc(),
184 automatic_close: settings.get_automatic_close(),
185 joystick_deadzone: 0.0,
186 })
187 }
188
189 fn flush_messages(&mut self) {
190 for (_, event) in glfw::flush_messages(&self.events) {
191 match event {
192 glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _)
193 if self.exit_on_esc =>
194 {
195 self.window.set_should_close(true);
196 }
197 glfw::WindowEvent::Close => {
198 if !self.automatic_close {
199 self.window.set_should_close(false);
200 }
201 self.event_queue.push_back(Input::Close(CloseArgs));
202 }
203 glfw::WindowEvent::Char(ch) => {
204 self.event_queue.push_back(Input::Text(ch.to_string()));
205 }
206 glfw::WindowEvent::Key(key, scancode, glfw::Action::Press, _) => {
207 self.event_queue.push_back(Input::Button(ButtonArgs {
208 state: ButtonState::Press,
209 button: Button::Keyboard(glfw_map_key(key)),
210 scancode: Some(scancode as i32),
211 }));
212 }
213 glfw::WindowEvent::Key(key, scancode, glfw::Action::Release, _) => {
214 self.event_queue.push_back(Input::Button(ButtonArgs {
215 state: ButtonState::Release,
216 button: Button::Keyboard(glfw_map_key(key)),
217 scancode: Some(scancode as i32),
218 }));
219 }
220 glfw::WindowEvent::MouseButton(button, glfw::Action::Press, _) => {
221 self.event_queue.push_back(Input::Button(ButtonArgs {
222 state: ButtonState::Press,
223 button: Button::Mouse(glfw_map_mouse(button)),
224 scancode: None,
225 }));
226 }
227 glfw::WindowEvent::MouseButton(button, glfw::Action::Release, _) => {
228 self.event_queue.push_back(Input::Button(ButtonArgs {
229 state: ButtonState::Release,
230 button: Button::Mouse(glfw_map_mouse(button)),
231 scancode: None,
232 }));
233 }
234 glfw::WindowEvent::CursorPos(x, y) => {
235 self.event_queue
236 .push_back(Input::Move(Motion::MouseCursor([x, y])));
237 match self.last_mouse_pos {
238 Some((lx, ly)) => self
239 .event_queue
240 .push_back(Input::Move(Motion::MouseRelative([x - lx, y - ly]))),
241 None => (),
242 }
243 self.last_mouse_pos = Some((x, y));
244 }
245 glfw::WindowEvent::Scroll(x, y) => {
246 self.event_queue
247 .push_back(Input::Move(Motion::MouseScroll([x, y])));
248 }
249 glfw::WindowEvent::Size(w, h) => {
250 let draw_size = self.draw_size();
251 self.event_queue.push_back(Input::Resize(ResizeArgs {
252 window_size: [w as f64, h as f64],
253 draw_size: draw_size.into(),
254 }));
255 }
256 glfw::WindowEvent::Focus(focus) => {
257 self.event_queue.push_back(Input::Focus(focus));
258 }
259 glfw::WindowEvent::CursorEnter(cursor) => {
260 self.event_queue.push_back(Input::Cursor(cursor));
261 }
262 glfw::WindowEvent::FileDrop(files) => {
263 for file in files {
264 self.event_queue
265 .push_back(Input::FileDrag(FileDrag::Drop(file)))
266 }
267 }
268 _ => (),
269 }
270 }
271
272 for j in self.joysticks.iter_mut() {
274 j.update(&mut self.event_queue, self.joystick_deadzone);
275 }
276 }
277
278 fn wait_event(&mut self) -> Event {
279 loop {
280 if self.event_queue.len() == 0 {
281 self.glfw.wait_events();
282 self.flush_messages();
283 }
284 if let Some(event) = self.event_queue.pop_front() {
285 return Event::Input(event, None);
286 }
287 }
288 }
289
290 fn wait_event_timeout(&mut self, timeout: Duration) -> Option<Event> {
291 if self.event_queue.len() == 0 {
292 let timeout_secs =
293 timeout.as_secs() as f64 + (timeout.subsec_nanos() as f64 / 1_000_000_000.0);
294 self.glfw.wait_events_timeout(timeout_secs);
295 self.flush_messages();
296 }
297 self.event_queue.pop_front().map(|x| Event::Input(x, None))
298 }
299
300 fn poll_event(&mut self) -> Option<Event> {
301 if self.event_queue.len() == 0 {
302 self.glfw.poll_events();
303 self.flush_messages();
304 }
305 self.event_queue.pop_front().map(|x| Event::Input(x, None))
306 }
307
308 fn capture_cursor(&mut self, enabled: bool) {
309 if enabled {
310 self.window.set_cursor_mode(glfw::CursorMode::Disabled);
311 } else {
312 self.window.set_cursor_mode(glfw::CursorMode::Normal);
313 self.last_mouse_pos = None;
314 }
315 }
316}
317
318impl BuildFromWindowSettings for GlfwWindow {
319 fn build_from_window_settings(settings: &WindowSettings) -> Result<GlfwWindow, Box<dyn Error>> {
320 GlfwWindow::new(settings)
321 }
322}
323
324impl Window for GlfwWindow {
325 fn size(&self) -> Size {
326 let (w, h) = self.window.get_size();
327 Size {
328 width: w as f64,
329 height: h as f64,
330 }
331 }
332
333 fn draw_size(&self) -> Size {
334 let (w, h) = self.window.get_framebuffer_size();
335 Size {
336 width: w as f64,
337 height: h as f64,
338 }
339 }
340
341 fn set_should_close(&mut self, value: bool) {
342 self.window.set_should_close(value);
343 }
344
345 fn should_close(&self) -> bool {
346 self.window.should_close()
347 }
348
349 fn swap_buffers(&mut self) {
350 self.window.swap_buffers()
351 }
352
353 fn wait_event(&mut self) -> Event {
354 self.wait_event()
355 }
356
357 fn wait_event_timeout(&mut self, timeout: Duration) -> Option<Event> {
358 self.wait_event_timeout(timeout)
359 }
360
361 fn poll_event(&mut self) -> Option<Event> {
362 self.poll_event()
363 }
364}
365
366impl AdvancedWindow for GlfwWindow {
367 fn get_title(&self) -> String {
368 self.title.clone()
369 }
370
371 fn set_title(&mut self, value: String) {
372 self.window.set_title(&value)
373 }
374
375 fn get_automatic_close(&self) -> bool {
376 self.automatic_close
377 }
378
379 fn set_automatic_close(&mut self, value: bool) {
380 self.automatic_close = value;
381 }
382
383 fn get_exit_on_esc(&self) -> bool {
384 self.exit_on_esc
385 }
386
387 fn set_exit_on_esc(&mut self, value: bool) {
388 self.exit_on_esc = value
389 }
390
391 fn set_capture_cursor(&mut self, value: bool) {
392 self.capture_cursor(value)
393 }
394
395 fn show(&mut self) {
396 self.window.show();
397 }
398
399 fn hide(&mut self) {
400 self.window.hide();
401 }
402
403 fn get_position(&self) -> Option<Position> {
404 let (x, y) = self.window.get_pos();
405 Some(Position { x: x, y: y })
406 }
407
408 fn set_position<P: Into<Position>>(&mut self, pos: P) {
409 let pos: Position = pos.into();
410 self.window.set_pos(pos.x, pos.y);
411 }
412
413 fn set_size<S: Into<Size>>(&mut self, size: S) {
414 let size: Size = size.into();
415 self.window.set_size(size.width as i32, size.height as i32);
416 }
417}
418
419impl OpenGLWindow for GlfwWindow {
420 fn get_proc_address(&mut self, proc_name: &str) -> ProcAddress {
421 use std::ptr::null;
422 self.window.get_proc_address(proc_name)
423 .map(|n| n as *const _)
424 .unwrap_or(null())
425 }
426
427 fn is_current(&self) -> bool {
428 self.window.is_current()
429 }
430
431 fn make_current(&mut self) {
432 self.window.make_current()
433 }
434}
435
436fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
437 use input::Key;
438
439 match keycode {
440 glfw::Key::Num0 => Key::D0,
441 glfw::Key::Num1 => Key::D1,
442 glfw::Key::Num2 => Key::D2,
443 glfw::Key::Num3 => Key::D3,
444 glfw::Key::Num4 => Key::D4,
445 glfw::Key::Num5 => Key::D5,
446 glfw::Key::Num6 => Key::D6,
447 glfw::Key::Num7 => Key::D7,
448 glfw::Key::Num8 => Key::D8,
449 glfw::Key::Num9 => Key::D9,
450 glfw::Key::A => Key::A,
451 glfw::Key::B => Key::B,
452 glfw::Key::C => Key::C,
453 glfw::Key::D => Key::D,
454 glfw::Key::E => Key::E,
455 glfw::Key::F => Key::F,
456 glfw::Key::G => Key::G,
457 glfw::Key::H => Key::H,
458 glfw::Key::I => Key::I,
459 glfw::Key::J => Key::J,
460 glfw::Key::K => Key::K,
461 glfw::Key::L => Key::L,
462 glfw::Key::M => Key::M,
463 glfw::Key::N => Key::N,
464 glfw::Key::O => Key::O,
465 glfw::Key::P => Key::P,
466 glfw::Key::Q => Key::Q,
467 glfw::Key::R => Key::R,
468 glfw::Key::S => Key::S,
469 glfw::Key::T => Key::T,
470 glfw::Key::U => Key::U,
471 glfw::Key::V => Key::V,
472 glfw::Key::W => Key::W,
473 glfw::Key::X => Key::X,
474 glfw::Key::Y => Key::Y,
475 glfw::Key::Z => Key::Z,
476 glfw::Key::Apostrophe => Key::Unknown,
477 glfw::Key::Backslash => Key::Backslash,
478 glfw::Key::Backspace => Key::Backspace,
479 glfw::Key::CapsLock => Key::CapsLock,
480 glfw::Key::Delete => Key::Delete,
481 glfw::Key::Comma => Key::Comma,
482 glfw::Key::Down => Key::Down,
483 glfw::Key::End => Key::End,
484 glfw::Key::Enter => Key::Return,
485 glfw::Key::Equal => Key::Equals,
486 glfw::Key::Escape => Key::Escape,
487 glfw::Key::F1 => Key::F1,
488 glfw::Key::F2 => Key::F2,
489 glfw::Key::F3 => Key::F3,
490 glfw::Key::F4 => Key::F4,
491 glfw::Key::F5 => Key::F5,
492 glfw::Key::F6 => Key::F6,
493 glfw::Key::F7 => Key::F7,
494 glfw::Key::F8 => Key::F8,
495 glfw::Key::F9 => Key::F9,
496 glfw::Key::F10 => Key::F10,
497 glfw::Key::F11 => Key::F11,
498 glfw::Key::F12 => Key::F12,
499 glfw::Key::F13 => Key::F13,
500 glfw::Key::F14 => Key::F14,
501 glfw::Key::F15 => Key::F15,
502 glfw::Key::F16 => Key::F16,
503 glfw::Key::F17 => Key::F17,
504 glfw::Key::F18 => Key::F18,
505 glfw::Key::F19 => Key::F19,
506 glfw::Key::F20 => Key::F20,
507 glfw::Key::F21 => Key::F21,
508 glfw::Key::F22 => Key::F22,
509 glfw::Key::F23 => Key::F23,
510 glfw::Key::F24 => Key::F24,
511 glfw::Key::F25 => Key::Unknown,
513 glfw::Key::Kp0 => Key::NumPad0,
514 glfw::Key::Kp1 => Key::NumPad1,
515 glfw::Key::Kp2 => Key::NumPad2,
516 glfw::Key::Kp3 => Key::NumPad3,
517 glfw::Key::Kp4 => Key::NumPad4,
518 glfw::Key::Kp5 => Key::NumPad5,
519 glfw::Key::Kp6 => Key::NumPad6,
520 glfw::Key::Kp7 => Key::NumPad7,
521 glfw::Key::Kp8 => Key::NumPad8,
522 glfw::Key::Kp9 => Key::NumPad9,
523 glfw::Key::KpDecimal => Key::NumPadDecimal,
524 glfw::Key::KpDivide => Key::NumPadDivide,
525 glfw::Key::KpMultiply => Key::NumPadMultiply,
526 glfw::Key::KpSubtract => Key::NumPadMinus,
527 glfw::Key::KpAdd => Key::NumPadPlus,
528 glfw::Key::KpEnter => Key::NumPadEnter,
529 glfw::Key::KpEqual => Key::NumPadEquals,
530 glfw::Key::LeftShift => Key::LShift,
531 glfw::Key::LeftControl => Key::LCtrl,
532 glfw::Key::LeftAlt => Key::LAlt,
533 glfw::Key::LeftSuper => Key::LGui,
534 glfw::Key::RightShift => Key::RShift,
535 glfw::Key::RightControl => Key::RCtrl,
536 glfw::Key::RightAlt => Key::RAlt,
537 glfw::Key::RightSuper => Key::RGui,
538 glfw::Key::GraveAccent => Key::Backquote,
540 glfw::Key::Home => Key::Home,
541 glfw::Key::Insert => Key::Insert,
542 glfw::Key::Left => Key::Left,
543 glfw::Key::LeftBracket => Key::LeftBracket,
544 glfw::Key::Menu => Key::Menu,
545 glfw::Key::Minus => Key::Minus,
546 glfw::Key::NumLock => Key::NumLockClear,
547 glfw::Key::PageDown => Key::PageDown,
548 glfw::Key::PageUp => Key::PageUp,
549 glfw::Key::Pause => Key::Pause,
550 glfw::Key::Period => Key::Period,
551 glfw::Key::PrintScreen => Key::PrintScreen,
552 glfw::Key::Right => Key::Right,
553 glfw::Key::RightBracket => Key::RightBracket,
554 glfw::Key::ScrollLock => Key::ScrollLock,
555 glfw::Key::Semicolon => Key::Semicolon,
556 glfw::Key::Slash => Key::Slash,
557 glfw::Key::Space => Key::Space,
558 glfw::Key::Tab => Key::Tab,
559 glfw::Key::Up => Key::Up,
560 glfw::Key::World1 => Key::Unknown,
561 glfw::Key::World2 => Key::Unknown,
562 glfw::Key::Unknown => Key::Unknown,
563 }
564}
565
566fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> MouseButton {
567 match mouse_button {
568 glfw::MouseButton::Button1 => MouseButton::Left,
569 glfw::MouseButton::Button2 => MouseButton::Right,
570 glfw::MouseButton::Button3 => MouseButton::Middle,
571 glfw::MouseButton::Button4 => MouseButton::X1,
572 glfw::MouseButton::Button5 => MouseButton::X2,
573 glfw::MouseButton::Button6 => MouseButton::Button6,
574 glfw::MouseButton::Button7 => MouseButton::Button7,
575 glfw::MouseButton::Button8 => MouseButton::Button8,
576 }
577}
578
579struct JoystickHelper {
581 joystick: Joystick,
583
584 buttons: HashMap<u8, bool>,
586 axes: HashMap<u8, f64>,
587 connected: bool,
589}
590impl JoystickHelper {
591 fn new(joystick: Joystick) -> Self {
592 Self {
593 joystick,
594 connected: false,
595 buttons: HashMap::new(),
596 axes: HashMap::new(),
597 }
598 }
599
600 fn update(&mut self, event_queue: &mut VecDeque<Input>, deadzone: f64) {
601 match (self.joystick.is_present(), self.connected) {
602 (false, false) => return,
604
605 (false, true) => {
607 self.connected = false;
608 self.buttons.clear();
610 self.axes.clear();
611 return;
612 }
613
614 (true, false) => {
616 self.connected = true;
618
619 for (axis, a) in self.joystick.get_axes().iter().enumerate() {
622 self.axes.insert(axis as u8, *a as f64);
623 }
624 for (button, a) in self.joystick.get_buttons().iter().enumerate() {
625 self.buttons.insert(button as u8, *a > 1);
626 }
627
628 return;
630 }
631
632 (true, true) => {}
634 }
635
636 for (axis, a) in self.joystick.get_axes().iter().enumerate() {
638 let previous = self.axes.get_mut(&(axis as u8)).unwrap();
639 let a = *a as f64;
640
641 if a == *previous || a.abs() < deadzone {
642 continue;
644 } else {
645 *previous = a
647 }
648
649 event_queue.push_back(Input::Move(Motion::ControllerAxis(
651 ControllerAxisArgs::new(self.joystick.id as u32, axis as u8, a),
652 )));
653 }
654
655 for (button, a) in self.joystick.get_buttons().iter().enumerate() {
657 let previous = self.buttons.get_mut(&(button as u8)).unwrap();
658 let pressed = *a > 0;
659
660 if pressed == *previous {
661 continue;
663 } else {
664 *previous = pressed
666 }
667
668 event_queue.push_back(Input::Button(ButtonArgs {
670 state: if pressed {
671 ButtonState::Press
672 } else {
673 ButtonState::Release
674 },
675 button: Button::Controller(ControllerButton::new(
676 self.joystick.id as u32,
677 button as u8,
678 )),
679 scancode: None,
680 }));
681 }
682 }
683}