rlvgl_core/
bitmap_font.rs1use crate::font::{FontLineMetrics, FontMetrics, GlyphInfo};
9use crate::renderer::Renderer;
10use crate::widget::{Color, Rect};
11
12pub struct BitmapFont {
18 pub glyph_width: u8,
20 pub glyph_height: u8,
22 pub scale: u8,
24 pub data: &'static [u8],
26}
27
28impl BitmapFont {
29 pub fn scaled_width(&self) -> i32 {
31 self.glyph_width as i32 * self.scale as i32
32 }
33
34 pub fn scaled_height(&self) -> i32 {
36 self.glyph_height as i32 * self.scale as i32
37 }
38
39 pub fn draw_char(&self, renderer: &mut dyn Renderer, x: i32, y: i32, ch: char, color: Color) {
41 let idx = if (0x20..=0x7E).contains(&(ch as u32)) {
42 (ch as u32 - 0x20) as usize
43 } else {
44 return; };
46 let bits_per_glyph = self.glyph_width as usize * self.glyph_height as usize;
47 let bit_offset = idx * bits_per_glyph;
48 let s = self.scale as i32;
49
50 for row in 0..self.glyph_height as usize {
51 for col in 0..self.glyph_width as usize {
52 let bit = bit_offset + row * self.glyph_width as usize + col;
53 let byte_idx = bit / 8;
54 let bit_idx = 7 - (bit % 8); if byte_idx < self.data.len() && (self.data[byte_idx] >> bit_idx) & 1 != 0 {
56 renderer.fill_rect(
57 Rect {
58 x: x + col as i32 * s,
59 y: y + row as i32 * s,
60 width: s,
61 height: s,
62 },
63 color,
64 );
65 }
66 }
67 }
68 }
69
70 pub fn draw_str(&self, renderer: &mut dyn Renderer, x: i32, y: i32, text: &str, color: Color) {
72 let advance = self.scaled_width() + self.scale as i32;
73 let mut cx = x;
74 for ch in text.chars() {
75 self.draw_char(renderer, cx, y, ch, color);
76 cx += advance;
77 }
78 }
79
80 pub fn draw_str_y(
85 &self,
86 renderer: &mut dyn Renderer,
87 x: i32,
88 y: i32,
89 text: &str,
90 color: Color,
91 ) {
92 let advance = self.scaled_width() + self.scale as i32;
93 let mut cy = y;
94 for ch in text.chars() {
95 self.draw_char(renderer, x, cy, ch, color);
96 cy += advance;
97 }
98 }
99}
100
101impl FontMetrics for BitmapFont {
102 fn glyph_metrics(&self, ch: char) -> Option<GlyphInfo> {
103 if !(0x20..=0x7e).contains(&(ch as u32)) {
104 return None;
105 }
106 let width = self.scaled_width().max(0) as u16;
107 let height = self.scaled_height().max(0) as u16;
108 let advance_px = self.scaled_width() + self.scale as i32;
109 Some(GlyphInfo {
110 advance_fp16: (advance_px.max(0) * 16).min(u16::MAX as i32) as u16,
111 bearing_x: 0,
112 bearing_y: height.min(i16::MAX as u16) as i16,
113 width,
114 height,
115 })
116 }
117
118 fn line_metrics(&self) -> FontLineMetrics {
119 let height = self.scaled_height().max(0).min(u16::MAX as i32) as u16;
120 FontLineMetrics {
121 line_height: height,
122 ascent: height.min(i16::MAX as u16) as i16,
123 descent: 0,
124 }
125 }
126
127 fn glyph_coverage_row(&self, ch: char, row: u16, x_offset: u16, coverage: &mut [u8]) -> bool {
128 if !(0x20..=0x7e).contains(&(ch as u32)) {
129 return false;
130 }
131
132 let scale = self.scale.max(1) as usize;
133 let source_row = row as usize / scale;
134 if source_row >= self.glyph_height as usize {
135 coverage.fill(0);
136 return true;
137 }
138
139 let glyph_idx = (ch as u32 - 0x20) as usize;
140 let bits_per_glyph = self.glyph_width as usize * self.glyph_height as usize;
141 let bit_offset = glyph_idx * bits_per_glyph;
142
143 for (offset, alpha) in coverage.iter_mut().enumerate() {
144 let source_col = (x_offset as usize + offset) / scale;
145 if source_col >= self.glyph_width as usize {
146 *alpha = 0;
147 continue;
148 }
149 let bit = bit_offset + source_row * self.glyph_width as usize + source_col;
150 let byte_idx = bit / 8;
151 let bit_idx = 7 - (bit % 8);
152 *alpha = if byte_idx < self.data.len() && (self.data[byte_idx] >> bit_idx) & 1 != 0 {
153 255
154 } else {
155 0
156 };
157 }
158 true
159 }
160}
161
162pub static FONT_6X10: BitmapFont = BitmapFont {
172 glyph_width: 6,
173 glyph_height: 10,
174 scale: 2,
175 data: &FONT_6X10_DATA,
176};
177
178static FONT_6X10_DATA: [u8; 713] = {
181 *include_bytes!("bitmap_font_6x10.bin")
189};