init
This commit is contained in:
30
src/utility/constants.rs
Normal file
30
src/utility/constants.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::utility::debug::ValidationInfo;
|
||||
use crate::utility::structures::DeviceExtension;
|
||||
use ash::vk_make_version;
|
||||
|
||||
use std::os::raw::c_char;
|
||||
|
||||
pub const APPLICATION_VERSION: u32 = vk_make_version!(1, 0, 0);
|
||||
pub const ENGINE_VERSION: u32 = vk_make_version!(1, 0, 0);
|
||||
pub const API_VERSION: u32 = vk_make_version!(1, 0, 92);
|
||||
|
||||
pub const WINDOW_WIDTH: u32 = 800;
|
||||
pub const WINDOW_HEIGHT: u32 = 600;
|
||||
pub const VALIDATION: ValidationInfo = ValidationInfo {
|
||||
is_enable: true,
|
||||
required_validation_layers: ["VK_LAYER_KHRONOS_validation"],
|
||||
};
|
||||
pub const DEVICE_EXTENSIONS: DeviceExtension = DeviceExtension {
|
||||
names: ["VK_KHR_swapchain"],
|
||||
};
|
||||
pub const MAX_FRAMES_IN_FLIGHT: usize = 2;
|
||||
pub const IS_PAINT_FPS_COUNTER: bool = false;
|
||||
|
||||
impl DeviceExtension {
|
||||
pub fn get_extensions_raw_names(&self) -> [*const c_char; 1] {
|
||||
[
|
||||
// currently just enable the Swapchain extension.
|
||||
ash::extensions::khr::Swapchain::name().as_ptr(),
|
||||
]
|
||||
}
|
||||
}
|
109
src/utility/debug.rs
Normal file
109
src/utility/debug.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use ash::version::EntryV1_0;
|
||||
use ash::vk;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
|
||||
unsafe extern "system" fn vulkan_debug_utils_callback(
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
|
||||
_p_user_data: *mut c_void,
|
||||
) -> vk::Bool32 {
|
||||
let severity = match message_severity {
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => "[Verbose]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => "[Warning]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => "[Error]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => "[Info]",
|
||||
_ => "[Unknown]",
|
||||
};
|
||||
let types = match message_type {
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL => "[General]",
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE => "[Performance]",
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION => "[Validation]",
|
||||
_ => "[Unknown]",
|
||||
};
|
||||
let message = CStr::from_ptr((*p_callback_data).p_message);
|
||||
println!("[Debug]{}{}{:?}", severity, types, message);
|
||||
|
||||
vk::FALSE
|
||||
}
|
||||
|
||||
pub struct ValidationInfo {
|
||||
pub is_enable: bool,
|
||||
pub required_validation_layers: [&'static str; 1],
|
||||
}
|
||||
|
||||
pub fn check_validation_layer_support(
|
||||
entry: &ash::Entry,
|
||||
required_validation_layers: &Vec<&str>,
|
||||
) -> bool {
|
||||
// if support validation layer, then return true
|
||||
|
||||
let layer_properties = entry
|
||||
.enumerate_instance_layer_properties()
|
||||
.expect("Failed to enumerate Instance Layers Properties");
|
||||
|
||||
if layer_properties.len() <= 0 {
|
||||
eprintln!("No available layers.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for required_layer_name in required_validation_layers.iter() {
|
||||
let mut is_layer_found = false;
|
||||
|
||||
for layer_property in layer_properties.iter() {
|
||||
let test_layer_name = super::tools::vk_to_string(&layer_property.layer_name);
|
||||
if (*required_layer_name) == test_layer_name {
|
||||
is_layer_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if is_layer_found == false {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn setup_debug_utils(
|
||||
is_enable_debug: bool,
|
||||
entry: &ash::Entry,
|
||||
instance: &ash::Instance,
|
||||
) -> (ash::extensions::ext::DebugUtils, vk::DebugUtilsMessengerEXT) {
|
||||
let debug_utils_loader = ash::extensions::ext::DebugUtils::new(entry, instance);
|
||||
|
||||
if is_enable_debug == false {
|
||||
(debug_utils_loader, ash::vk::DebugUtilsMessengerEXT::null())
|
||||
} else {
|
||||
let messenger_ci = populate_debug_messenger_create_info();
|
||||
|
||||
let utils_messenger = unsafe {
|
||||
debug_utils_loader
|
||||
.create_debug_utils_messenger(&messenger_ci, None)
|
||||
.expect("Debug Utils Callback")
|
||||
};
|
||||
|
||||
(debug_utils_loader, utils_messenger)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate_debug_messenger_create_info() -> vk::DebugUtilsMessengerCreateInfoEXT {
|
||||
vk::DebugUtilsMessengerCreateInfoEXT {
|
||||
s_type: vk::StructureType::DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
p_next: ptr::null(),
|
||||
flags: vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING |
|
||||
// vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE |
|
||||
// vk::DebugUtilsMessageSeverityFlagsEXT::INFO |
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
|
||||
message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
|
||||
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE
|
||||
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION,
|
||||
pfn_user_callback: Some(vulkan_debug_utils_callback),
|
||||
p_user_data: ptr::null_mut(),
|
||||
}
|
||||
}
|
67
src/utility/fps_limiter.rs
Normal file
67
src/utility/fps_limiter.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
const SAMPLE_COUNT: usize = 5;
|
||||
const SAMPLE_COUNT_FLOAT: f32 = SAMPLE_COUNT as f32;
|
||||
|
||||
pub struct FPSLimiter {
|
||||
counter: Instant,
|
||||
frame_time_prefer: u32, // unit microseconds
|
||||
samples: [u32; SAMPLE_COUNT],
|
||||
current_frame: usize,
|
||||
delta_frame: u32,
|
||||
}
|
||||
|
||||
impl FPSLimiter {
|
||||
pub fn new() -> FPSLimiter {
|
||||
const DEFAULT_PREFER_FPS: f32 = 60.0;
|
||||
|
||||
FPSLimiter {
|
||||
counter: Instant::now(),
|
||||
frame_time_prefer: (1000_000.0_f32 / DEFAULT_PREFER_FPS) as u32,
|
||||
samples: [0; SAMPLE_COUNT],
|
||||
current_frame: 0,
|
||||
delta_frame: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_prefer_fps(&mut self, prefer_fps: f32) {
|
||||
self.frame_time_prefer = (1000_000.0_f32 / prefer_fps) as u32;
|
||||
}
|
||||
|
||||
/// Call this function in game loop to update its inner status.
|
||||
pub fn tick_frame(&mut self) {
|
||||
let time_elapsed = self.counter.elapsed();
|
||||
self.counter = Instant::now();
|
||||
|
||||
self.delta_frame = time_elapsed.subsec_micros();
|
||||
self.samples[self.current_frame] = self.delta_frame;
|
||||
self.current_frame = (self.current_frame + 1) % SAMPLE_COUNT;
|
||||
}
|
||||
|
||||
// TODO: this function seems not work.
|
||||
pub fn keep_fps(&self) {
|
||||
if self.frame_time_prefer > self.delta_frame {
|
||||
let delay = Duration::from_micros((self.frame_time_prefer - self.delta_frame) as u64);
|
||||
|
||||
thread::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the current FPS.
|
||||
pub fn fps(&self) -> f32 {
|
||||
let mut sum = 0_u32;
|
||||
self.samples.iter().for_each(|val| {
|
||||
sum += val;
|
||||
});
|
||||
|
||||
1000_000.0_f32 / (sum as f32 / SAMPLE_COUNT_FLOAT)
|
||||
}
|
||||
|
||||
/// Return current delta time in seconds
|
||||
/// this function ignore its second part, since the second is mostly zero.
|
||||
pub fn delta_time(&self) -> f32 {
|
||||
self.delta_frame as f32 / 1000_000.0_f32 // time in second
|
||||
}
|
||||
}
|
134
src/utility/platforms.rs
Normal file
134
src/utility/platforms.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use ash::version::{EntryV1_0, InstanceV1_0};
|
||||
use ash::vk;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use ash::extensions::khr::Win32Surface;
|
||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
|
||||
use ash::extensions::khr::XlibSurface;
|
||||
#[cfg(target_os = "macos")]
|
||||
use ash::extensions::mvk::MacOSSurface;
|
||||
|
||||
use ash::extensions::ext::DebugUtils;
|
||||
use ash::extensions::khr::Surface;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use cocoa::appkit::{NSView, NSWindow};
|
||||
#[cfg(target_os = "macos")]
|
||||
use cocoa::base::id as cocoa_id;
|
||||
#[cfg(target_os = "macos")]
|
||||
use metal::CoreAnimationLayer;
|
||||
#[cfg(target_os = "macos")]
|
||||
use objc::runtime::YES;
|
||||
|
||||
// required extension ------------------------------------------------------
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn required_extension_names() -> Vec<*const i8> {
|
||||
vec![
|
||||
Surface::name().as_ptr(),
|
||||
MacOSSurface::name().as_ptr(),
|
||||
DebugUtils::name().as_ptr(),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(all(windows))]
|
||||
pub fn required_extension_names() -> Vec<*const i8> {
|
||||
vec![
|
||||
Surface::name().as_ptr(),
|
||||
Win32Surface::name().as_ptr(),
|
||||
DebugUtils::name().as_ptr(),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
|
||||
pub fn required_extension_names() -> Vec<*const i8> {
|
||||
vec![
|
||||
Surface::name().as_ptr(),
|
||||
XlibSurface::name().as_ptr(),
|
||||
DebugUtils::name().as_ptr(),
|
||||
]
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// create surface ---------------------------------------------------------
|
||||
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
|
||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
|
||||
entry: &E,
|
||||
instance: &I,
|
||||
window: &winit::window::Window,
|
||||
) -> Result<vk::SurfaceKHR, vk::Result> {
|
||||
use std::ptr;
|
||||
use winit::platform::unix::WindowExtUnix;
|
||||
|
||||
let x11_display = window.xlib_display().unwrap();
|
||||
let x11_window = window.xlib_window().unwrap();
|
||||
let x11_create_info = vk::XlibSurfaceCreateInfoKHR {
|
||||
s_type: vk::StructureType::XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
p_next: ptr::null(),
|
||||
flags: Default::default(),
|
||||
window: x11_window as vk::Window,
|
||||
dpy: x11_display as *mut vk::Display,
|
||||
};
|
||||
let xlib_surface_loader = XlibSurface::new(entry, instance);
|
||||
xlib_surface_loader.create_xlib_surface(&x11_create_info, None)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
|
||||
entry: &E,
|
||||
instance: &I,
|
||||
window: &winit::window::Window,
|
||||
) -> Result<vk::SurfaceKHR, vk::Result> {
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use winit::platform::macos::WindowExtMacOS;
|
||||
|
||||
let wnd: cocoa_id = mem::transmute(window.ns_window());
|
||||
|
||||
let layer = CoreAnimationLayer::new();
|
||||
|
||||
layer.set_edge_antialiasing_mask(0);
|
||||
layer.set_presents_with_transaction(false);
|
||||
layer.remove_all_animations();
|
||||
|
||||
let view = wnd.contentView();
|
||||
|
||||
layer.set_contents_scale(view.backingScaleFactor());
|
||||
view.setLayer(mem::transmute(layer.as_ref()));
|
||||
view.setWantsLayer(YES);
|
||||
|
||||
let create_info = vk::MacOSSurfaceCreateInfoMVK {
|
||||
s_type: vk::StructureType::MACOS_SURFACE_CREATE_INFO_M,
|
||||
p_next: ptr::null(),
|
||||
flags: Default::default(),
|
||||
p_view: window.ns_view() as *const c_void,
|
||||
};
|
||||
|
||||
let macos_surface_loader = MacOSSurface::new(entry, instance);
|
||||
macos_surface_loader.create_mac_os_surface_mvk(&create_info, None)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub unsafe fn create_surface<E: EntryV1_0, I: InstanceV1_0>(
|
||||
entry: &E,
|
||||
instance: &I,
|
||||
window: &winit::window::Window,
|
||||
) -> Result<vk::SurfaceKHR, vk::Result> {
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
use winapi::shared::windef::HWND;
|
||||
use winapi::um::libloaderapi::GetModuleHandleW;
|
||||
use winit::platform::windows::WindowExtWindows;
|
||||
|
||||
let hwnd = window.hwnd() as HWND;
|
||||
let hinstance = GetModuleHandleW(ptr::null()) as *const c_void;
|
||||
let win32_create_info = vk::Win32SurfaceCreateInfoKHR {
|
||||
s_type: vk::StructureType::WIN32_SURFACE_CREATE_INFO_KHR,
|
||||
p_next: ptr::null(),
|
||||
flags: Default::default(),
|
||||
hinstance,
|
||||
hwnd: hwnd as *const c_void,
|
||||
};
|
||||
let win32_surface_loader = Win32Surface::new(entry, instance);
|
||||
win32_surface_loader.create_win32_surface(&win32_create_info, None)
|
||||
}
|
2169
src/utility/share.rs
Normal file
2169
src/utility/share.rs
Normal file
File diff suppressed because it is too large
Load Diff
155
src/utility/structures.rs
Normal file
155
src/utility/structures.rs
Normal file
@ -0,0 +1,155 @@
|
||||
use ash::vk;
|
||||
use cgmath::Matrix4;
|
||||
|
||||
use memoffset::offset_of;
|
||||
|
||||
pub struct DeviceExtension {
|
||||
pub names: [&'static str; 1],
|
||||
// pub raw_names: [*const i8; 1],
|
||||
}
|
||||
|
||||
pub struct SurfaceStuff {
|
||||
pub surface_loader: ash::extensions::khr::Surface,
|
||||
pub surface: vk::SurfaceKHR,
|
||||
|
||||
pub screen_width: u32,
|
||||
pub screen_height: u32,
|
||||
}
|
||||
pub struct SwapChainStuff {
|
||||
pub swapchain_loader: ash::extensions::khr::Swapchain,
|
||||
pub swapchain: vk::SwapchainKHR,
|
||||
pub swapchain_images: Vec<vk::Image>,
|
||||
pub swapchain_format: vk::Format,
|
||||
pub swapchain_extent: vk::Extent2D,
|
||||
}
|
||||
|
||||
pub struct SwapChainSupportDetail {
|
||||
pub capabilities: vk::SurfaceCapabilitiesKHR,
|
||||
pub formats: Vec<vk::SurfaceFormatKHR>,
|
||||
pub present_modes: Vec<vk::PresentModeKHR>,
|
||||
}
|
||||
|
||||
pub struct QueueFamilyIndices {
|
||||
pub graphics_family: Option<u32>,
|
||||
pub present_family: Option<u32>,
|
||||
}
|
||||
|
||||
impl QueueFamilyIndices {
|
||||
pub fn new() -> QueueFamilyIndices {
|
||||
QueueFamilyIndices {
|
||||
graphics_family: None,
|
||||
present_family: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_complete(&self) -> bool {
|
||||
self.graphics_family.is_some() && self.present_family.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SyncObjects {
|
||||
pub image_available_semaphores: Vec<vk::Semaphore>,
|
||||
pub render_finished_semaphores: Vec<vk::Semaphore>,
|
||||
pub inflight_fences: Vec<vk::Fence>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub struct UniformBufferObject {
|
||||
pub model: Matrix4<f32>,
|
||||
pub view: Matrix4<f32>,
|
||||
pub proj: Matrix4<f32>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub struct VertexV1 {
|
||||
pub pos: [f32; 2],
|
||||
pub color: [f32; 3],
|
||||
}
|
||||
impl VertexV1 {
|
||||
pub fn get_binding_description() -> [vk::VertexInputBindingDescription; 1] {
|
||||
[vk::VertexInputBindingDescription {
|
||||
binding: 0,
|
||||
stride: ::std::mem::size_of::<VertexV1>() as u32,
|
||||
input_rate: vk::VertexInputRate::VERTEX,
|
||||
}]
|
||||
}
|
||||
|
||||
pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
|
||||
[
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 0,
|
||||
format: vk::Format::R32G32_SFLOAT,
|
||||
offset: offset_of!(VertexV1, pos) as u32,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 1,
|
||||
format: vk::Format::R32G32B32_SFLOAT,
|
||||
offset: offset_of!(VertexV1, color) as u32,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct VertexV3 {
|
||||
pub pos: [f32; 4],
|
||||
pub color: [f32; 4],
|
||||
pub tex_coord: [f32; 2],
|
||||
}
|
||||
impl VertexV3 {
|
||||
pub fn get_binding_descriptions() -> [vk::VertexInputBindingDescription; 1] {
|
||||
[vk::VertexInputBindingDescription {
|
||||
binding: 0,
|
||||
stride: ::std::mem::size_of::<Self>() as u32,
|
||||
input_rate: vk::VertexInputRate::VERTEX,
|
||||
}]
|
||||
}
|
||||
|
||||
pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] {
|
||||
[
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 0,
|
||||
format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
offset: offset_of!(Self, pos) as u32,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 1,
|
||||
format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
offset: offset_of!(Self, color) as u32,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
binding: 0,
|
||||
location: 2,
|
||||
format: vk::Format::R32G32_SFLOAT,
|
||||
offset: offset_of!(Self, tex_coord) as u32,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub const RECT_VERTICES_DATA: [VertexV1; 4] = [
|
||||
VertexV1 {
|
||||
pos: [-0.5, -0.5],
|
||||
color: [1.0, 0.0, 0.0],
|
||||
},
|
||||
VertexV1 {
|
||||
pos: [0.5, -0.5],
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
VertexV1 {
|
||||
pos: [0.5, 0.5],
|
||||
color: [0.0, 0.0, 1.0],
|
||||
},
|
||||
VertexV1 {
|
||||
pos: [-0.5, 0.5],
|
||||
color: [1.0, 1.0, 1.0],
|
||||
},
|
||||
];
|
||||
pub const RECT_INDICES_DATA: [u32; 6] = [0, 1, 2, 2, 3, 0];
|
46
src/utility/tools.rs
Normal file
46
src/utility/tools.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use std::path::Path;
|
||||
|
||||
/// Helper function to convert [c_char; SIZE] to string
|
||||
pub fn vk_to_string(raw_string_array: &[c_char]) -> String {
|
||||
// Implementation 1
|
||||
// let end = '\0' as u8;
|
||||
//
|
||||
// let mut content: Vec<u8> = vec![];
|
||||
//
|
||||
// for ch in raw_string_array.iter() {
|
||||
// let ch = (*ch) as u8;
|
||||
//
|
||||
// if ch != end {
|
||||
// content.push(ch);
|
||||
// } else {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// String::from_utf8(content)
|
||||
// .expect("Failed to convert vulkan raw string")
|
||||
|
||||
// Implementation 2
|
||||
let raw_string = unsafe {
|
||||
let pointer = raw_string_array.as_ptr();
|
||||
CStr::from_ptr(pointer)
|
||||
};
|
||||
|
||||
raw_string
|
||||
.to_str()
|
||||
.expect("Failed to convert vulkan raw string.")
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub fn read_shader_code(shader_path: &Path) -> Vec<u8> {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
let spv_file =
|
||||
File::open(shader_path).expect(&format!("Failed to find spv file at {:?}", shader_path));
|
||||
let bytes_code: Vec<u8> = spv_file.bytes().filter_map(|byte| byte.ok()).collect();
|
||||
|
||||
bytes_code
|
||||
}
|
97
src/utility/window.rs
Normal file
97
src/utility/window.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use winit::event::{Event, VirtualKeyCode, ElementState, KeyboardInput, WindowEvent};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
|
||||
|
||||
const IS_PAINT_FPS_COUNTER: bool = true;
|
||||
|
||||
pub fn init_window(
|
||||
event_loop: &EventLoop<()>,
|
||||
title: &str,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> winit::window::Window {
|
||||
winit::window::WindowBuilder::new()
|
||||
.with_title(title)
|
||||
.with_inner_size(winit::dpi::LogicalSize::new(width, height))
|
||||
.build(event_loop)
|
||||
.expect("Failed to create window.")
|
||||
}
|
||||
|
||||
pub trait VulkanApp {
|
||||
fn draw_frame(&mut self, delta_time: f32);
|
||||
fn recreate_swapchain(&mut self);
|
||||
fn cleanup_swapchain(&self);
|
||||
fn wait_device_idle(&self);
|
||||
fn resize_framebuffer(&mut self);
|
||||
fn window_ref(&self) -> &winit::window::Window;
|
||||
}
|
||||
|
||||
pub struct ProgramProc {
|
||||
pub event_loop: EventLoop<()>,
|
||||
}
|
||||
|
||||
impl ProgramProc {
|
||||
|
||||
pub fn new() -> ProgramProc {
|
||||
// init window stuff
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
ProgramProc { event_loop }
|
||||
}
|
||||
|
||||
pub fn main_loop<A: 'static + VulkanApp>(self, mut vulkan_app: A) {
|
||||
|
||||
let mut tick_counter = super::fps_limiter::FPSLimiter::new();
|
||||
|
||||
self.event_loop.run(move |event, _, control_flow| {
|
||||
|
||||
match event {
|
||||
| Event::WindowEvent { event, .. } => {
|
||||
match event {
|
||||
| WindowEvent::CloseRequested => {
|
||||
vulkan_app.wait_device_idle();
|
||||
*control_flow = ControlFlow::Exit
|
||||
},
|
||||
| WindowEvent::KeyboardInput { input, .. } => {
|
||||
match input {
|
||||
| KeyboardInput { virtual_keycode, state, .. } => {
|
||||
match (virtual_keycode, state) {
|
||||
| (Some(VirtualKeyCode::Escape), ElementState::Pressed) => {
|
||||
vulkan_app.wait_device_idle();
|
||||
*control_flow = ControlFlow::Exit
|
||||
},
|
||||
| _ => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
| WindowEvent::Resized(_new_size) => {
|
||||
vulkan_app.wait_device_idle();
|
||||
vulkan_app.resize_framebuffer();
|
||||
},
|
||||
| _ => {},
|
||||
}
|
||||
},
|
||||
| Event::MainEventsCleared => {
|
||||
vulkan_app.window_ref().request_redraw();
|
||||
},
|
||||
| Event::RedrawRequested(_window_id) => {
|
||||
let delta_time = tick_counter.delta_time();
|
||||
vulkan_app.draw_frame(delta_time);
|
||||
|
||||
if IS_PAINT_FPS_COUNTER {
|
||||
print!("FPS: {}\r", tick_counter.fps());
|
||||
}
|
||||
|
||||
tick_counter.tick_frame();
|
||||
},
|
||||
| Event::LoopDestroyed => {
|
||||
vulkan_app.wait_device_idle();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user