use std::time::Instant;
use crate::types::Rect;
pub const UNCAPPED_FPS: u32 = u32::MAX;
#[derive(Debug, Clone)]
pub struct RenderRegion {
pub id: &'static str,
pub rect: Rect,
pub target_fps: u32,
pub dirty: bool,
}
impl RenderRegion {
pub fn dirty_driven(id: &'static str, rect: Rect) -> Self {
Self { id, rect, target_fps: 0, dirty: true }
}
pub fn capped(id: &'static str, rect: Rect, fps: u32) -> Self {
Self { id, rect, target_fps: fps, dirty: true }
}
pub fn uncapped(id: &'static str, rect: Rect) -> Self {
Self { id, rect, target_fps: UNCAPPED_FPS, dirty: true }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TickRate {
Dirty,
Capped(u32),
Uncapped,
}
impl TickRate {
pub fn target_fps(self) -> u32 {
match self {
TickRate::Dirty => 0,
TickRate::Uncapped => UNCAPPED_FPS,
TickRate::Capped(fps) => fps,
}
}
pub fn label(self) -> String {
match self {
TickRate::Dirty => "dirty".into(),
TickRate::Uncapped => "uncapped".into(),
TickRate::Capped(fps) => fps.to_string(),
}
}
}
impl Default for TickRate {
fn default() -> Self {
TickRate::Capped(60)
}
}
#[derive(Debug, Clone)]
pub struct RegionScheduleState {
pub last_painted: Option<Instant>,
}
impl Default for RegionScheduleState {
fn default() -> Self {
Self { last_painted: None }
}
}
impl RegionScheduleState {
pub fn due(&self, region: &RenderRegion, now: Instant) -> bool {
match region.target_fps {
0 => region.dirty,
UNCAPPED_FPS => true,
fps => match self.last_painted {
None => true,
Some(t) => {
let target = std::time::Duration::from_secs_f64(1.0 / fps as f64);
now.duration_since(t) >= target
}
},
}
}
pub fn next_due(&self, region: &RenderRegion, now: Instant) -> Option<Instant> {
match region.target_fps {
0 => if region.dirty { Some(now) } else { None },
UNCAPPED_FPS => Some(now),
fps => match self.last_painted {
None => Some(now),
Some(t) => {
let target = std::time::Duration::from_secs_f64(1.0 / fps as f64);
Some(t + target)
}
},
}
}
}