1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::error::Error;
use sdl2::event::Event;
use crate::{
input::{InputState, KeyboardState, MouseState},
Application,
};
pub struct Engine<'a> {
app: &'a mut dyn Application,
title: &'a str,
width: u32,
height: u32,
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>, Box<dyn Error>> {
Ok(Engine {
app,
title,
width,
height,
ctx: sdl2::init()?,
})
}
pub fn start(&mut self, present_vsync: bool) -> Result<(), Box<dyn Error>> {
let video = self.ctx.video()?;
let timer = 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 = 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();
}
let mut now = timer.performance_counter();
let mut time_acc = 0.0;
let mut fps_acc = 0.0;
let mut fps_counter = 0;
loop {
let last = now;
now = timer.performance_counter();
let elapsed_time = (now - last) as f64 / timer.performance_frequency() as f64;
time_acc += elapsed_time;
fps_acc += 1.0 / elapsed_time;
fps_counter += 1;
if time_acc >= 1.0 {
let fps = fps_acc / fps_counter as f64;
let title = format!("{} ({} FPS)", self.title, fps.round() as u32);
canvas.window_mut().set_title(title.as_str()).unwrap_or(());
time_acc -= 1.0;
fps_acc = 0.0;
fps_counter = 0;
}
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();
}
}
}