You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.9 KiB

  1. use glutin::{
  2. dpi::{PhysicalPosition, PhysicalSize},
  3. event_loop::EventLoop,
  4. monitor::VideoMode,
  5. window::{Fullscreen, Window as GlutinWindow, WindowBuilder},
  6. Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent,
  7. };
  8. use log::{error, info};
  9. use crate::{resources::Config, Error};
  10. pub struct Window {
  11. context: ContextWrapper<PossiblyCurrent, GlutinWindow>,
  12. }
  13. impl Window {
  14. pub fn new<T>(event_loop: &EventLoop<T>, config: &Config) -> Result<Self, Error> {
  15. let monitor = event_loop
  16. .primary_monitor()
  17. .or_else(|| event_loop.available_monitors().next());
  18. let (fullscreen, border) = match (config.video.windowed, config.video.fullscreen) {
  19. (false, true) => {
  20. let mut video_mode: Option<VideoMode> = None;
  21. if let Some(monitor) = monitor {
  22. for mode in monitor.video_modes() {
  23. video_mode = Some(match video_mode {
  24. Some(current) => {
  25. if mode.size().width <= config.video.resolution.0
  26. && mode.size().height <= config.video.resolution.1
  27. && mode.size().width >= current.size().width
  28. && mode.size().height >= current.size().height
  29. && mode.bit_depth() >= current.bit_depth()
  30. && mode.refresh_rate() >= current.refresh_rate()
  31. {
  32. mode
  33. } else {
  34. current
  35. }
  36. }
  37. None => mode,
  38. });
  39. }
  40. }
  41. match video_mode {
  42. Some(video_mode) => (Some(Fullscreen::Exclusive(video_mode)), false),
  43. None => {
  44. error!("Unable to find video mode for exclusive fullscreen!");
  45. (Some(Fullscreen::Borderless(None)), false)
  46. }
  47. }
  48. }
  49. (true, true) => (Some(Fullscreen::Borderless(None)), false),
  50. (false, false) => (None, false),
  51. (true, false) => (None, true),
  52. };
  53. let mut multisampling = [16u16, 8, 4, 2, 1, 0].iter();
  54. let context = loop {
  55. let multisampling = match multisampling.next() {
  56. Some(multisampling) => *multisampling,
  57. None => return Err(Error::CreateContext),
  58. };
  59. if config.video.multisampling < multisampling {
  60. continue;
  61. }
  62. info!("Create OpenGL context (multisampling={})", multisampling);
  63. let window_builder = WindowBuilder::new()
  64. .with_title("space-crush")
  65. .with_visible(true)
  66. .with_decorations(border)
  67. .with_fullscreen(fullscreen.clone())
  68. .with_inner_size::<PhysicalSize<u32>>(config.video.resolution.into());
  69. let ret = ContextBuilder::new()
  70. .with_double_buffer(Some(true))
  71. .with_hardware_acceleration(Some(true))
  72. .with_pixel_format(24, 8)
  73. .with_multisampling(multisampling)
  74. .with_vsync(false)
  75. .with_gl(GlRequest::Specific(Api::OpenGl, (4, 5)))
  76. .with_gl_profile(GlProfile::Core)
  77. .build_windowed(window_builder, event_loop);
  78. if let Ok(context) = ret {
  79. break context;
  80. }
  81. };
  82. let window = context.window();
  83. let window_size = window.outer_size();
  84. let monitor_size = window.current_monitor().unwrap().size();
  85. window.set_outer_position(PhysicalPosition::new(
  86. (monitor_size.width - window_size.width) / 2,
  87. (monitor_size.height - window_size.height) / 2,
  88. ));
  89. let context = unsafe { context.make_current().unwrap() };
  90. gl::load_with(|s| context.get_proc_address(s));
  91. gl::disable(gl::CULL_FACE);
  92. gl::disable(gl::DEPTH_TEST);
  93. gl::clear_color(0.1, 0.1, 0.1, 1.0);
  94. gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
  95. Ok(Self { context })
  96. }
  97. pub fn swap_buffers(&self) -> Result<(), Error> {
  98. self.context.swap_buffers()?;
  99. Ok(())
  100. }
  101. pub fn set_mouse_locked(&self, value: bool) -> Result<(), Error> {
  102. let window = self.context.window();
  103. window.set_cursor_grab(value)?;
  104. if !value {
  105. window.set_cursor_visible(true);
  106. }
  107. Ok(())
  108. }
  109. pub fn set_mouse_pos(&self, x: f64, y: f64) -> Result<(), Error> {
  110. let window = self.context.window();
  111. window.set_cursor_visible(false);
  112. window.set_cursor_position(PhysicalPosition { x, y })?;
  113. Ok(())
  114. }
  115. }