mod fps;
use fps::FpsCounter;
use std::error::Error;
use sdl2::event::Event;
use crate::{
input::{InputState, KeyboardState, MouseState},
Application, WindowCanvas,
};
pub struct Engine<'a> {
app: &'a mut dyn Application<WindowCanvas>,
title: &'a str,
width: u32,
height: u32,
pub show_fps: bool,
ctx: sdl2::Sdl,
}
impl<'a> Engine<'a> {
pub fn new(
app: &'a mut dyn Application,
title: &'a str,
width: u32,
height: u32,
) -> Result<Engine<'a>, String> {
Ok(Engine {
app,
title,
width,
height,
show_fps: true,
ctx: sdl2::init()?,
})
}
pub fn start(&mut self, present_vsync: bool) -> Result<(), Box<dyn Error>> {
let video = self.ctx.video()?;
let mut fps_counter = FpsCounter::new(self.ctx.timer()?);
let mut canvas = video
.window(self.title, self.width, self.height)
.position_centered()
.build()?
.into_canvas()
.accelerated();
if present_vsync {
canvas = canvas.present_vsync();
}
let mut canvas = WindowCanvas::new(canvas.build()?);
let mut event_pump = self.ctx.event_pump()?;
let mut input = InputState {
keyboard: KeyboardState::new(event_pump.keyboard_state().scancodes()),
mouse: MouseState::new(event_pump.mouse_state()),
};
if !self.app.on_create(&mut canvas, &input)? {
return self.app.on_quit();
}
loop {
let elapsed_time = fps_counter.update(self.show_fps);
if self.show_fps && fps_counter.time_acc() >= 1.0 {
let fps = fps_counter.fps();
let title = format!("{} ({} FPS)", self.title, fps.round() as u32);
canvas.window_mut().set_title(title.as_str()).ok();
fps_counter.reset_average();
}
if !self.app.on_update(&mut canvas, &input, elapsed_time)? {
return self.app.on_quit();
}
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. } => {
return self.app.on_quit();
}
_ => {}
}
}
input
.keyboard
.update(event_pump.keyboard_state().scancodes());
input.mouse.update(event_pump.mouse_state());
canvas.present();
}
}
}