diff --git a/src/font.rs b/src/font.rs new file mode 100644 index 0000000..9d86d5e --- /dev/null +++ b/src/font.rs @@ -0,0 +1,90 @@ +use embedded_hal::delay::DelayNs; +use esp_hal::DriverMode; +use rusttype::{Font, Point, Scale}; + +use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; + +use crate::display::{self, Display, Position, Rgb565}; + +static OPEN_SANS: &'static [u8] = include_bytes!("./OpenSans_Condensed-Regular.ttf"); + +pub struct FontRenderer<'a> { + font: Font<'a>, + height: u32, + scale: Scale, + offset: Point, +} + +impl<'a> FontRenderer<'a> { + pub fn create(size: u32) -> FontRenderer<'a> { + let font = Font::try_from_bytes(OPEN_SANS).unwrap(); + let scale = Scale { + x: size as f32 * 2., + y: size as f32, + }; + + let v_metrics = font.v_metrics(scale); + let offset = rusttype::Point { + x: 0.0, + y: v_metrics.ascent, + }; + FontRenderer { + font, + height: size, + scale, + offset, + } + } + + pub fn render<'d, T: Into, DM: DriverMode, Delay: DelayNs>( + &self, + display: &mut Display<'d, DM, Delay>, + text: T, + pos: Position, + ) { + let glyphs = self + .font + .layout(&text.into(), self.scale, self.offset) + .collect::>(); + + let width = libm::ceil( + glyphs + .iter() + .rev() + .map(|g| g.position().x as f32 + g.unpositioned().h_metrics().advance_width) + .next() + .unwrap_or(0.0) as f64, + ) as usize; + + let mut pixel_data = vec![Rgb565::white(); self.height as usize * width]; + + for g in glyphs { + if let Some(bb) = g.pixel_bounding_box() { + g.draw(|x, y, cov| { + let x = bb.min.x + x as i32; + let y = bb.min.y + y as i32; + if x >= 0 && y >= 0 && x < width as i32 && y < self.height as i32 { + let col = 255 - (255. * cov) as u8; + pixel_data[(x + y * width as i32) as usize] = Rgb565(col, col, col); + } + }); + } + } + + display.set_window( + pos, + Position { + x: pos.x + width as u16 - 1, + y: pos.y + self.height as u16 - 1, + }, + ); + display.write(display::Writeable::Data( + &pixel_data + .iter() + .flat_map(|p| p.as_color().bytes) + .collect::>(), + )); + } +} diff --git a/src/main.rs b/src/main.rs index 2635b36..7e4deaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,10 @@ use esp_hal::{ use esp_backtrace as _; use rusttype::Font; -use crate::display::{Color, Display, Position, Rgb565, SetAddressMode}; +use crate::{ + display::{Color, Display, Position, Rgb565, SetAddressMode}, + font::FontRenderer, +}; use esp_alloc::HEAP; use alloc::vec; @@ -30,6 +33,7 @@ use alloc::vec; extern crate alloc; mod display; +mod font; static OPEN_SANS: &'static [u8] = include_bytes!("./OpenSans_Condensed-Regular.ttf"); @@ -106,65 +110,13 @@ fn main() -> ! { Rgb565::yellow().as_color(), ); - let font = Font::try_from_bytes(OPEN_SANS).unwrap(); - let glyph = font.glyph('a'); - const SCALE: u16 = 30; - let scale = rusttype::Scale { - x: SCALE as f32 * 2., - y: SCALE as f32, - }; - let v_metrics = font.v_metrics(scale); - let offset = rusttype::Point { - x: 0.0, - y: v_metrics.ascent, - }; - let glyphs = font - .layout("Hello world", scale, offset) - .collect::>(); + let font_renderer = FontRenderer::create(30); - let width = libm::ceil( - glyphs - .iter() - .rev() - .map(|g| g.position().x as f32 + g.unpositioned().h_metrics().advance_width) - .next() - .unwrap_or(0.0) as f64, - ) as usize; - - let mut pixel_data = vec![Rgb565::white(); SCALE as usize * width]; - - for g in glyphs { - if let Some(bb) = g.pixel_bounding_box() { - g.draw(|x, y, cov| { - let x = bb.min.x + x as i32; - let y = bb.min.y + y as i32; - if x >= 0 && y >= 0 && x < width as i32 && y < SCALE as i32 { - let col = 255 - (255. * cov) as u8; - pixel_data[(x + y * width as i32) as usize] = Rgb565(col, col, col); - } - }); - } - } - - display.set_window( - Position { x: 0, y: 0 }, - Position { - x: width as u16 - 1, - y: SCALE as u16 - 1, - }, - ); - display.write(display::Writeable::Data( - &pixel_data - .iter() - .flat_map(|p| p.as_color().bytes) - .collect::>(), - )); + font_renderer.render(&mut display, "Hello World!", Position::new(0, 0)); loop { let delay_start = Instant::now(); - log::info!("Hello world"); - while delay_start.elapsed() < Duration::from_millis(100) {} // test_delay.delay_millis(1); }