min_timer
As things grow, this library grew a lot over the last two days. Now it consists
of three parts:
- Timer
- Profiler
- Main Loop
Each section depends on the previous one.
Timer
This is a small library that provides f64 based duration and timer. Standard
library's implementation uses integers. Thus, for a clock that gives time as
f64, this library should have higher performance.
Additionally, there are less checks. Although, there is strong type safety for
SI units (seconds), which is hopefully optimized away by the compiler.
fn count(upto: u32) {
use min_timer::{Std, Sec, Timer};
let dur = Sec::MINUTE; let now = Std::new(); let mut timer = Timer::new(&now);
let mut count = 0;
while count < upto {
if timer >= dur { timer -= dur; count += 1;
println!("Counting {}...", count);
}
}
}
Profiler
A small statistics and profiling functionality is also provided. These are all
intended to be used in a real-time application.
fn subroutine() {}
fn main_routine() {
use min_timer::{Std, Prf, Stat};
let mut stat = Stat::new();
let now = Std::new();
for _ in 0..10 {
let _ = Prf::new(&now, &mut stat); subroutine();
}
stat.refresh();
for _ in 0..15 {
let _ = Prf::new(&now, &mut stat);
subroutine();
}
println!(
"Subroutine called {} times, with {} average runtime and {} times per cycle.",
stat.get_count(), stat.find_average(),
stat.get_rate() );
}
Main Loop
This is the heart of a real-time application. The design is such that, you
provide a state class and a render that can draw it. The tick rate and the frame
rate are different; such that, smooth visuals can be achived without updating at
the same frequency.
This is done by interpolating the previous and current states of the program
before drawing using the remaning ticks to be done. Thus, states must implement
scaling and superposing; linearly combining.
use min_timer::{Hrt, Now, Render, Std, Stt, Timer};
use std::ops::{Add, Mul};
struct Bar {
len: u32,
pre: Option<u32>,
}
impl Default for Bar {
fn default() -> Self {
Self { len: 50, pre: None }
}
}
impl Bar {
fn print(&mut self, per: f64, len: u32) {
self.pre = Some(len);
print!("[");
for _ in 0..len {
print!("=");
}
if self.len != len {
print!(">");
for _ in 0..(self.len - len - 1) {
print!(" ");
}
}
println!("] {}%", per);
}
}
impl<T: Now> Render<T, Ex> for Bar {
fn render(&mut self, _: &Hrt<T>, stt: &Ex) {
let len = self.len as f64 * stt.0;
let len = len.floor() as u32;
let len = len.min(self.len);
let per = (stt.0 * 100.0).floor();
if let Some(pre) = self.pre {
if len != pre {
self.print(per, len);
}
} else {
self.print(per, len);
}
}
}
#[derive(Default, Clone, Copy)]
struct Ex(f64);
impl Mul<f64> for Ex {
type Output = Ex;
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl Add for Ex {
type Output = Ex;
fn add(self, rhs: Ex) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<T: Now> Stt<T> for Ex {
fn init(&mut self, _: &mut Hrt<T>, timer: Timer<T>) {
println!("Initialization done in {}!", timer);
}
fn update(&mut self, hrt: &mut Hrt<T>) {
self.0 += 1e-1;
if self.0 >= 1.0 {
hrt.stop();
}
}
fn sec(&mut self, hrt: &mut Hrt<T>) {
println!(
"Tick Rate: {} Frame Rate: {}",
hrt.ticks().avg_rate(),
hrt.frames().avg_rate()
);
}
}
fn main() {
let now = Std::new(); let mut hrt = Hrt::new(1e2, &now); hrt.start::<Ex, Bar>(); }
Motivation
Why write this when there is the standard library?
-
Education: I got to practice Rust, espacially newtype pattern with
Sec.
-
I didn't now much about std::time before writing this.
-
I will use this with GLFW timer, which returns the time as a double in
seconds. This way I will implement Now with GLFW and there will be no
conversions compared to:
fn time(glfw: &Glfw) -> Duration {
Duration::from_sec_f64(glfw.get_time()) }
let start = time(&glfw);
let elapsed = time(&glfw) - start;
let seconds = elapsed.as_sec_f64();
Check out my other crate, min_gl, for seeing the Now implementation for
the GLFW timer.
-
This crate provided a space where I could put more stuff about time, like
profiling.
-
Working with f64s is a lot more comfortable; I saw this as I worked on the
main loop.
Copyright (C) 2022 Cem Geçgel gecgelcem@outlook.com