Allow skipping frames

This commit is contained in:
Rico Riedel 2022-07-04 19:38:27 +02:00
parent 94888dcc7d
commit 7500e5af1b
No known key found for this signature in database
GPG Key ID: 75AC868575DE7B18
2 changed files with 31 additions and 15 deletions

View File

@ -5,8 +5,8 @@ use crate::timer::Timer;
/// Periodically calls [Renderer::render] and [Renderer::present].
pub struct Runner<TTimer, TRenderer> {
duration: Duration,
timer: TTimer,
ticks: u128,
renderer: TRenderer,
}
@ -14,19 +14,23 @@ impl<T1: Timer, T2: Renderer> Runner<T1, T2> {
pub fn new(duration: Duration,
timer: T1,
renderer: T2) -> Self {
let ticks = duration.as_nanos() / timer.delay().as_nanos();
Self { timer, ticks, renderer }
Self { duration, timer, renderer }
}
pub fn run(mut self) -> Result<(), Error> {
for i in 0..=self.ticks {
let step = i as f32 / self.ticks as f32;
self.timer.set();
while self.timer.elapsed() < self.duration {
let step = self.timer.elapsed().as_secs_f32() / self.duration.as_secs_f32();
self.renderer.render(step);
self.renderer.present()?;
self.timer.sleep();
}
self.renderer.render(1.0);
self.renderer.present()?;
Ok(())
}
}
@ -46,19 +50,21 @@ mod test {
let mut renderer = MockRenderer::new();
let seq = &mut Sequence::new();
timer.expect_delay().return_const(Duration::from_secs(2));
timer.expect_set().once().in_sequence(seq).return_const(());
timer.expect_elapsed().times(2).in_sequence(seq).return_const(Duration::from_secs(0));
renderer.expect_render().once().with(eq(0.0)).in_sequence(seq).return_const(());
renderer.expect_present().once().in_sequence(seq).returning(|| Ok(()));
timer.expect_sleep().once().in_sequence(seq).return_const(());
timer.expect_elapsed().times(2).in_sequence(seq).return_const(Duration::from_secs(2));
renderer.expect_render().once().with(eq(0.5)).in_sequence(seq).return_const(());
renderer.expect_present().once().in_sequence(seq).returning(|| Ok(()));
timer.expect_sleep().once().in_sequence(seq).return_const(());
timer.expect_elapsed().times(1).in_sequence(seq).return_const(Duration::from_secs(4));
renderer.expect_render().once().with(eq(1.0)).in_sequence(seq).return_const(());
renderer.expect_present().once().in_sequence(seq).returning(|| Ok(()));
timer.expect_sleep().once().in_sequence(seq).return_const(());
let runner = Runner::new(Duration::from_secs(4), timer, renderer);

View File

@ -7,29 +7,43 @@ use mockall::automock;
/// Allows for periodic execution of code.
#[cfg_attr(test, automock)]
pub trait Timer {
/// Set the start time of the timer.
fn set(&mut self);
/// Get the elapsed time since calling [Timer::set].
fn elapsed(&self) -> Duration;
/// Sleep until the next tick starts.
fn sleep(&mut self);
/// Get the delay between ticks.
fn delay(&self) -> Duration;
}
/// A simple [Timer] based on the system clock.
pub struct SimpleTimer {
delay: Duration,
start: Instant,
last: Instant
}
impl SimpleTimer {
pub fn new(delay: Duration) -> Self {
Self {
last: Instant::now(),
delay,
start: Instant::now(),
last: Instant::now(),
}
}
}
impl Timer for SimpleTimer {
fn set(&mut self) {
self.start = Instant::now();
self.last = self.start;
}
fn elapsed(&self) -> Duration {
Instant::now() - self.start
}
fn sleep(&mut self) {
let now = Instant::now();
@ -38,8 +52,4 @@ impl Timer for SimpleTimer {
}
self.last = Instant::now();
}
fn delay(&self) -> Duration {
self.delay
}
}