use embedded_graphics::{ prelude::*, pixelcolor::Rgb888 }; use ws2812_esp32_rmt_driver::lib_embedded_graphics::{Ws2812DrawTarget, LedPixelShape}; use std::rc::Rc; use std::cell::RefCell; use running_average::RealTimeRunningAverage; use crate::task; use crate::lib8::RGB8; use crate::power; use crate::time::Periodically; pub trait Shader: Send { fn draw(&self, coords: Point) -> RGB8; } pub trait Surfaces { fn new_surface(&mut self) -> Surface; } pub trait Display: Surfaces { fn start_frame(&mut self) {} fn end_frame(&mut self) {} fn render_frame(&mut self) {} } impl task::Task for T where T: Display { fn name(&self) -> &'static str { "Renderer" } fn tick(&mut self) { self.start_frame(); self.render_frame(); self.end_frame(); } } struct ShaderSlot { shader: Option> } pub struct Surface { slot: Rc> } impl Surface { fn new(slot: Rc>) -> Self { Self { slot: slot } } pub fn set_shader(&mut self, shader: Box) { self.slot.borrow_mut().shader = Some(shader); } } pub struct EmbeddedDisplay where T: DrawTarget { shaders : RefCell>>>, target: T, total_mw: u32, max_mw: u32, fps: RealTimeRunningAverage, frame: u32, fps_display: Periodically } impl EmbeddedDisplay where T: DrawTarget { pub fn new(target: T, max_mw: u32) -> Self { EmbeddedDisplay { shaders: RefCell::new(Vec::new()), target: target, max_mw: max_mw, total_mw: 0, fps: RealTimeRunningAverage::default(), frame: 0, fps_display: Periodically::new_every_n_seconds(5) } } } impl Surfaces for EmbeddedDisplay where T: DrawTarget { fn new_surface(&mut self) -> Surface { let slot = Rc::new(RefCell::new(ShaderSlot { shader: None })); let surface = Surface::new(slot.clone()); self.shaders.borrow_mut().push(slot); return surface; } } impl Display for EmbeddedDisplay> { fn start_frame(&mut self) { self.target.clear(Rgb888::BLACK).unwrap(); self.total_mw = 0; self.frame = self.frame.wrapping_add(1); } fn end_frame(&mut self) { let brightness = power::brightness_for_mw(self.total_mw, 255, self.max_mw); self.target.set_brightness(brightness); self.target.flush().unwrap(); self.fps.insert(1); self.fps_display.run(|| { log::info!("FPS: {} frame={} brightness={} mw={}", self.fps.measurement(), self.frame, brightness, self.total_mw); }); } fn render_frame(&mut self) { for slot in self.shaders.borrow().iter() { if let Some(ref shader) = slot.borrow().shader { for i in 0..T::size().width { let coords = Point::new(i as i32, 0); let color = shader.draw(coords); self.total_mw += power::color_to_mw(&color); Pixel(coords, Rgb888::new(color.red, color.green, color.blue)).draw(&mut self.target).unwrap(); } } } } }