Add font rendering

This commit is contained in:
Sofia 2026-05-13 21:24:03 +03:00
parent 99d33fdcab
commit 28d06825ce
4 changed files with 111 additions and 19 deletions

43
Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
dependencies = [
"libm",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.3.1" version = "0.3.1"
@ -594,7 +603,9 @@ dependencies = [
"esp-bootloader-esp-idf", "esp-bootloader-esp-idf",
"esp-hal", "esp-hal",
"esp-println", "esp-println",
"libm",
"log", "log",
"rusttype",
] ]
[[package]] [[package]]
@ -826,6 +837,12 @@ version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libm"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]] [[package]]
name = "linked_list_allocator" name = "linked_list_allocator"
version = "0.10.6" version = "0.10.6"
@ -874,6 +891,15 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "owned_ttf_parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb"
dependencies = [
"ttf-parser",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.15" version = "1.0.15"
@ -1018,6 +1044,17 @@ dependencies = [
"svgbobdoc", "svgbobdoc",
] ]
[[package]]
name = "rusttype"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967"
dependencies = [
"ab_glyph_rasterizer",
"libm",
"owned_ttf_parser",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.22" version = "1.0.22"
@ -1223,6 +1260,12 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "ttf-parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.20.0" version = "1.20.0"

View File

@ -12,7 +12,7 @@ esp-bootloader-esp-idf = { version = "0.5.0", features = ["esp32", "log-04"] }
log = "0.4.27" log = "0.4.27"
critical-section = "1.2.0" critical-section = "1.2.0"
esp-alloc = "0.10.0" esp-alloc = { version = "0.10.0", features = ["esp32"] }
esp-backtrace = { version = "0.19.0", features = [ esp-backtrace = { version = "0.19.0", features = [
"esp32", "esp32",
"panic-handler", "panic-handler",
@ -20,6 +20,11 @@ esp-backtrace = { version = "0.19.0", features = [
] } ] }
esp-println = { version = "0.17.0", features = ["esp32", "log-04"] } esp-println = { version = "0.17.0", features = ["esp32", "log-04"] }
# ttf-parser = {version = "^0.25.0", features = ["no-std-float"], default-features = false }
rusttype = {version = "^0.9.0", features = ["libm-math"], default-features = false }
libm = "*"
# For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html # For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html
[profile.dev] [profile.dev]

Binary file not shown.

View File

@ -7,8 +7,9 @@
)] )]
#![deny(clippy::large_stack_frames)] #![deny(clippy::large_stack_frames)]
// use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget}; use core::{hint::black_box, mem::MaybeUninit};
// use embedded_hal_bus::spi::ExclusiveDevice;
use alloc::vec::Vec;
use esp_hal::{ use esp_hal::{
clock::CpuClock, clock::CpuClock,
delay::Delay, delay::Delay,
@ -19,16 +20,19 @@ use esp_hal::{
}; };
use esp_backtrace as _; use esp_backtrace as _;
// use mipidsi::{Builder, interface::SpiInterface, models::ST7789}; use rusttype::Font;
use crate::display::{Color, Display, Position, Rgb565, SetAddressMode}; use crate::display::{Color, Display, Position, Rgb565, SetAddressMode};
use esp_alloc::HEAP;
// use crate::display::{Color, Display, Position, Rgb565, Rotation}; use alloc::vec;
extern crate alloc; extern crate alloc;
mod display; mod display;
static OPEN_SANS: &'static [u8] = include_bytes!("./OpenSans_Condensed-Regular.ttf");
// This creates a default app-descriptor required by the esp-idf bootloader. // This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> // For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!(); esp_bootloader_esp_idf::esp_app_desc!();
@ -91,7 +95,7 @@ fn main() -> ! {
}; };
display.init(SetAddressMode { display.init(SetAddressMode {
color_order: display::ColorOrder::Bgr, color_order: display::ColorOrder::Rgb,
..Default::default() ..Default::default()
}); });
display.set_tearing(display::TearingMode::Off); display.set_tearing(display::TearingMode::Off);
@ -102,24 +106,64 @@ fn main() -> ! {
Rgb565::yellow().as_color(), Rgb565::yellow().as_color(),
); );
let test_delay = Delay::new(); 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 mut color = 0; 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<_>>(),
));
loop { loop {
let delay_start = Instant::now(); let delay_start = Instant::now();
log::info!("Hello world: {}", color); log::info!("Hello world");
color = (color + 50) % 200;
display.draw_rect(
Position::new(0, 0),
Position::new(240, 240),
Color {
bytes: [color, color],
},
);
while delay_start.elapsed() < Duration::from_millis(100) {} while delay_start.elapsed() < Duration::from_millis(100) {}
// test_delay.delay_millis(1); // test_delay.delay_millis(1);