use std::time::Duration;
use std::time::Instant;
use pixels::Pixels;
use pixels::SurfaceTexture;
use winit::{
event::Event,
event_loop::{
EventLoop, ControlFlow
},
dpi::LogicalSize,
window::{WindowBuilder, Window, Fullscreen},
};
use crate::{
resources::Buffer,
commands::Commands,
color::YELLOW,
};
const MIN_WINDOW_SIZE: (u32, u32) = (10, 10);
fn create_pixels(window: &Window, width: u32, height: u32) -> Pixels {
let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(width, height, surface_texture).expect("Unable to initialize Pixels library")
}
#[derive(Clone, Copy)]
pub(crate) struct WindowSettings {
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) resizable: bool,
pub(crate) fullscreen: bool,
pub(crate) maximized: bool,
}
impl WindowSettings {
pub(crate) fn new(width: u32, height: u32, resizable: bool, fullscreen: bool, maximized: bool) -> Self {
Self {
width, height,
resizable,
fullscreen,
maximized,
}
}
}
fn create_window(title: &str, settings: WindowSettings, fullscreen: Option<Fullscreen>, event_loop: &EventLoop<()>) -> Window {
let size = LogicalSize::new(settings.width as f32, settings.height as f32);
let min_size = LogicalSize::new(MIN_WINDOW_SIZE.0 as f32, MIN_WINDOW_SIZE.1 as f32);
WindowBuilder::new()
.with_title(title)
.with_inner_size(size)
.with_min_inner_size(min_size)
.with_resizable(settings.resizable)
.with_fullscreen(fullscreen)
.with_maximized(settings.maximized)
.build(event_loop)
.expect("Cannot create window with winit")
}
pub trait System {
fn sys_loop(&mut self, cmd: &mut Commands) {
cmd.clear_buffer(YELLOW);
}
fn raw_sys(&mut self, _window: &mut Window, _event: &mut Event<'_, ()>, _pixels: &mut Pixels) { }
}
pub struct TearProgram {
window_settings: WindowSettings, buffer_size: (u32, u32),
}
impl TearProgram {
pub fn new() -> Self {
Self {
window_settings: WindowSettings::new(300, 300, true, false, false),
buffer_size: (300, 300),
}
}
pub fn window_size(&mut self, width: u32, height: u32) -> &mut Self { self.window_settings.width = width; self.window_settings.height = height; self }
pub fn buffer_size(&mut self, width: u32, height: u32) -> &mut Self { self.buffer_size = (width, height); self }
pub fn resizable(&mut self, value: bool) -> &mut Self { self.window_settings.resizable = value; self }
pub fn fullscreen(&mut self, value: bool) -> &mut Self { self.window_settings.fullscreen = value; self }
pub fn maximized(&mut self, value: bool) -> &mut Self { self.window_settings.maximized = value; self }
pub fn config_program(&mut self, win_size: (u32, u32), buf_size: (u32, u32), resizable: bool, fullscreen: bool, maximized: bool) -> &mut Self {
self.window_settings = WindowSettings::new(win_size.0, win_size.1, resizable, fullscreen, maximized);
self.buffer_size = buf_size; self
}
pub fn run<W: System + 'static>(&mut self, title: &str, mut world: W) {
let event_loop = EventLoop::new();
let mut window = if self.window_settings.fullscreen {
let monitor = event_loop
.available_monitors()
.next()
.expect("no monitor found!");
let mode = monitor.video_modes().next().expect("no monitor mode found!");
create_window(title, self.window_settings, Some(Fullscreen::Exclusive(mode)), &event_loop)
} else { create_window(title, self.window_settings, None, &event_loop) };
let mut pixels = create_pixels(&window, self.buffer_size.0, self.buffer_size.1);
let buffer = Buffer::new(self.buffer_size.0, self.buffer_size.1);
let fps = Fps::new();
let delta = DeltaTime::new();
let mut cmd = Commands::new(buffer, fps, delta);
event_loop.run(move |mut event, _, control_flow| {
if let Event::RedrawRequested(_) = event {
pixels.frame_mut().copy_from_slice(cmd.buffer.raw_buffer());
if let Err(err) = pixels.render() {
println!("Pixels render error: {}", err.to_string());
*control_flow = ControlFlow::Exit; return;
}
}
world.raw_sys(&mut window, &mut event, &mut pixels);
if cmd.winit_input.update(&event) {
if cmd.winit_input.close_requested() || cmd.quit {
*control_flow = ControlFlow::Exit; return;
}
if let Some(size) = cmd.winit_input.window_resized() {
if size.width != 0 && size.height != 0 {
if let Err(err) = pixels.resize_surface(size.width, size.height) {
println!("Pixels resize surface error: {}", err.to_string());
*control_flow = ControlFlow::Exit; return;
}
}
}
world.sys_loop(&mut cmd);
window.request_redraw();
}
});
}
}
pub(crate) struct DeltaTime {
last_frame_time: Instant
}
impl DeltaTime {
fn new() -> Self {
Self {
last_frame_time: Instant::now(),
}
}
pub(crate) fn get(&mut self) -> Duration {
let current_time = Instant::now();
let delta_time = current_time.duration_since(self.last_frame_time);
self.last_frame_time = current_time;
return delta_time;
}
}
pub(crate) struct Fps {
fps_counter: i32,
fps_timer: Instant,
}
impl Fps {
fn new() -> Self {
Self {
fps_counter: 0,
fps_timer: Instant::now(),
}
}
pub(crate) fn get(&mut self) -> f32 {
self.fps_counter += 1;
if self.fps_timer.elapsed().as_secs_f32() >= 1.0 {
self.fps_counter = 0;
self.fps_timer = Instant::now();
}
let fps = self.fps_counter as f32 / self.fps_timer.elapsed().as_secs_f32();
return fps;
}
}