use ash::vk;
use concinnity_core::components::WindowMode;
use concinnity_core::input::keymap::KeyMap;
use concinnity_core::input::snapshot::InputSnapshot;
use concinnity_core::render::error::{RenderError, RenderResult};
use concinnity_core::window::clipboard::Clipboard;
use concinnity_core::window::display_mode::DisplayMode;
use crate::win32::display_mode::{self, FullscreenDisplayMode};
use crate::win32::window;
use crate::win32::window::{WindowState, create_window, frame_tick, take_input_snapshot};
pub(crate) struct Win32Window {
win_state: Box<WindowState>,
fullscreen_display: FullscreenDisplayMode,
}
impl Win32Window {
pub(crate) fn new(
title: &str,
width: u32,
height: u32,
mode: &WindowMode,
_resizable: bool,
title_bar: bool,
) -> RenderResult<Self> {
let (_hwnd, win_state) =
create_window(title, width, height, title_bar).map_err(RenderError::Other)?;
let mut this = Self {
win_state,
fullscreen_display: FullscreenDisplayMode::new(),
};
if !matches!(mode, WindowMode::Windowed) {
this.set_window_mode(*mode);
}
Ok(this)
}
pub(crate) fn poll(&mut self) -> bool {
frame_tick(&mut self.win_state, &mut self.fullscreen_display)
}
pub(crate) fn take_input(&mut self) -> InputSnapshot {
take_input_snapshot(&mut self.win_state)
}
pub(crate) fn clipboard(&mut self) -> Option<&mut dyn Clipboard> {
Some(&mut *self.win_state)
}
pub(crate) fn request_cursor_capture(&mut self) {
self.win_state.recapture_on_click = true;
}
pub(crate) fn set_ui_cursor_hidden(&mut self, hidden: bool) {
window::set_ui_cursor_hidden(&mut self.win_state, hidden);
}
pub(crate) fn set_menu_mode(&mut self, on: bool) {
self.win_state.menu_mode = on;
}
pub(crate) fn set_camera_capture(&mut self, capture: bool) {
if capture == self.win_state.cursor_captured {
return;
}
if capture {
let hwnd = self.win_state.hwnd;
window::capture_cursor(hwnd, &mut self.win_state);
} else {
window::release_cursor(&mut self.win_state);
}
}
pub(crate) fn cursor_outside_window(&self) -> bool {
self.win_state.cursor_outside_window
}
pub(crate) fn set_keymap(&mut self, keymap: &KeyMap) {
self.win_state.key.set_keymap(keymap);
}
pub(crate) fn set_window_mode(&mut self, mode: WindowMode) {
window::set_window_mode(&mut self.win_state, mode);
}
pub(crate) fn set_window_size(&mut self, width: u32, height: u32) {
window::set_window_size(&mut self.win_state, width, height);
}
pub(crate) fn display_modes(&self) -> Vec<DisplayMode> {
display_mode::enumerate(self.win_state.hwnd)
}
pub(crate) fn current_display_mode(&self) -> Option<DisplayMode> {
display_mode::current(self.win_state.hwnd)
}
pub(crate) fn set_display_mode(&mut self, mode: DisplayMode) {
self.fullscreen_display.set_desired(mode);
}
pub(crate) fn framebuffer_size(&self) -> (i32, i32) {
(self.win_state.width, self.win_state.height)
}
pub(crate) fn logical_size(&self) -> (f32, f32) {
(self.win_state.width as f32, self.win_state.height as f32)
}
pub(crate) fn top_content_inset(&self) -> f32 {
0.0
}
pub(crate) fn create_surface(
&mut self,
entry: &ash::Entry,
instance: &ash::Instance,
) -> RenderResult<vk::SurfaceKHR> {
let hinstance = unsafe { windows::Win32::System::LibraryLoader::GetModuleHandleW(None) }
.map_err(|e| RenderError::Other(format!("GetModuleHandleW: {e}")))?;
let info = vk::Win32SurfaceCreateInfoKHR::default()
.hinstance(hinstance.0 as isize)
.hwnd(self.win_state.hwnd.0 as isize);
let loader = ash::khr::win32_surface::Instance::new(entry, instance);
unsafe { loader.create_win32_surface(&info, None) }
.map_err(|e| crate::vulkan::error::map_vk_result(e, "vkCreateWin32SurfaceKHR"))
}
pub(crate) fn required_instance_extensions(&self) -> Vec<String> {
[ash::khr::surface::NAME, ash::khr::win32_surface::NAME]
.into_iter()
.map(|n| n.to_str().unwrap_or_default().to_string())
.collect()
}
}