use std::io; use rgb::Rgb; use crate::geometry::*; use crate::lib8::Rgb8Blend; use crate::lib8::interpolate::Fract8Ops; use crate::power::AsMilliwatts; use crate::task::Task; use crate::time::Periodically; use running_average::RealTimeRunningAverage; use std::fmt::Debug; pub trait HardwarePixel: Send + Sync + Rgb8Blend + Copy + AsMilliwatts + Default + From> + Fract8Ops {} impl HardwarePixel for T where T: Send + Sync + Rgb8Blend + Copy + AsMilliwatts + Default + From> + Fract8Ops {} pub trait PixelView { type Pixel: HardwarePixel; fn next(&mut self) -> Option<(Coordinates, &mut Self::Pixel)>; } pub trait Sample { type Pixel: HardwarePixel; fn sample(&mut self, rect: &Rectangle) -> impl PixelView; } pub trait Shader: Send + Debug { fn draw(&self, surface_coords: &VirtualCoordinates, frame: usize) -> Rgb; } pub trait Surfaces: Debug { type Surface: Surface; fn new_surface(&mut self, area: &Rectangle) -> Result; fn render_to(&self, output: &mut S, frame: usize); } pub trait Surface: Default + Clone + Debug { fn with_shader(&self, f: F); fn set_shader(&mut self, shader: Box); fn clear_shader(&mut self); fn rect(&self) -> Rectangle; fn set_rect(&mut self, rect: &Rectangle); fn opacity(&self) -> u8; fn set_opacity(&mut self, opacity: u8); } pub trait Output: Sample { fn blank(&mut self); fn commit(&mut self); } #[derive(Debug)] pub struct Renderer { output: T, surfaces: S, fps: RealTimeRunningAverage, fps_display: Periodically, frame: usize } impl Renderer { pub fn new(output: T, surfaces: S) -> Self { Self { output, surfaces: surfaces, fps: RealTimeRunningAverage::default(), fps_display: Periodically::new_every_n_seconds(5), frame: 0 } } } impl Task for Renderer { fn name(&self) -> &'static str { "Renderer" } fn tick(&mut self) { self.output.blank(); self.surfaces.render_to(&mut self.output, self.frame); self.output.commit(); self.fps.insert(1); self.frame += 1; self.fps_display.run(|| { log::info!("FPS: {}", self.fps.measurement()); }); } }