add font.rs

This commit is contained in:
Sofia 2026-05-13 21:38:38 +03:00
parent 28d06825ce
commit 8d9f1ffbe9
2 changed files with 97 additions and 55 deletions

90
src/font.rs Normal file
View File

@ -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<f32>,
}
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<String>, 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::<Vec<_>>();
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::<Vec<_>>(),
));
}
}

View File

@ -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::<Vec<_>>();
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::<Vec<_>>(),
));
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);
}