bracket_terminal/hal/gl_common/
font.rs1use super::{gl_error, TextureId};
2use crate::BResult;
3use bracket_color::prelude::RGB;
4use bracket_embedding::prelude::EMBED;
5use glow::HasContext;
6
7#[derive(PartialEq, Clone)]
8pub struct Font {
10 pub bitmap_file: String,
11 pub width: u32,
12 pub height: u32,
13
14 pub gl_id: Option<TextureId>,
15
16 pub tile_size: (u32, u32),
17 pub explicit_background: Option<RGB>,
18 pub font_dimensions_glyphs: (u32, u32),
19 pub font_dimensions_texture: (f32, f32),
20}
21
22#[allow(non_snake_case)]
23impl Font {
24 pub fn new<S: ToString>(filename: S, width: u32, height: u32, tile_size: (u32, u32)) -> Font {
26 Font {
27 bitmap_file: filename.to_string(),
28 width,
29 height,
30 gl_id: None,
31 tile_size,
32 explicit_background: None,
33 font_dimensions_glyphs: (tile_size.0 / width, tile_size.1 / height),
34 font_dimensions_texture: (
35 tile_size.0 as f32 / width as f32,
36 tile_size.1 as f32 / height as f32,
37 ),
38 }
39 }
40
41 fn load_image(filename: &str) -> image::DynamicImage {
42 let resource = EMBED.lock().get_resource(filename.to_string());
43 match resource {
44 None => image::open(std::path::Path::new(&filename.to_string()))
45 .expect("Failed to load texture"),
46 Some(res) => image::load_from_memory(res).expect("Failed to load texture from memory"),
47 }
48 }
49
50 pub fn load<S: ToString>(
52 filename: S,
53 tile_size: (u32, u32),
54 explicit_background: Option<RGB>,
55 ) -> Font {
56 let img = Font::load_image(&filename.to_string());
57 Font {
58 bitmap_file: filename.to_string(),
59 width: img.width(),
60 height: img.height(),
61 gl_id: None,
62 tile_size,
63 explicit_background,
64 font_dimensions_glyphs: (img.width() / tile_size.0, img.height() / tile_size.1),
65 font_dimensions_texture: (
66 tile_size.0 as f32 / img.width() as f32,
67 tile_size.1 as f32 / img.height() as f32,
68 ),
69 }
70 }
71
72 pub fn setup_gl_texture(&mut self, gl: &glow::Context) -> BResult<TextureId> {
74 let texture;
75
76 unsafe {
77 texture = gl.create_texture().unwrap();
78 gl.bind_texture(glow::TEXTURE_2D, Some(texture));
79 gl.tex_parameter_i32(
80 glow::TEXTURE_2D,
81 glow::TEXTURE_WRAP_S,
82 glow::CLAMP_TO_EDGE as i32,
83 ); gl.tex_parameter_i32(
85 glow::TEXTURE_2D,
86 glow::TEXTURE_WRAP_T,
87 glow::CLAMP_TO_EDGE as i32,
88 );
89 gl.tex_parameter_i32(
91 glow::TEXTURE_2D,
92 glow::TEXTURE_MIN_FILTER,
93 glow::NEAREST as i32,
94 );
95 gl.tex_parameter_i32(
96 glow::TEXTURE_2D,
97 glow::TEXTURE_MAG_FILTER,
98 glow::NEAREST as i32,
99 );
100
101 let img_orig = Font::load_image(&self.bitmap_file);
102 let w = img_orig.width() as i32;
103 let h = img_orig.height() as i32;
104 self.width = w as u32;
105 self.height = h as u32;
106 let img_flip = img_orig.flipv();
107 let img = img_flip.to_rgba8();
108 let mut data = img.into_raw();
109 if let Some(bg_rgb) = self.explicit_background {
110 let bg_r = (bg_rgb.r * 255.0) as u8;
111 let bg_g = (bg_rgb.g * 255.0) as u8;
112 let bg_b = (bg_rgb.b * 255.0) as u8;
113 let len = data.len() / 4;
114 for i in 0..len {
115 let idx = i * 4;
116 if data[idx] == bg_r && data[idx + 1] == bg_g && data[idx + 2] == bg_b {
117 data[idx] = 0;
118 data[idx + 1] = 0;
119 data[idx + 2] = 0;
120 data[idx + 3] = 0;
121 }
122 }
123 }
124 let format = glow::RGBA;
125 gl.tex_image_2d(
126 glow::TEXTURE_2D,
127 0,
128 format as i32,
129 w,
130 h,
131 0,
132 format,
133 glow::UNSIGNED_BYTE,
134 Some(&data),
135 );
136 }
137
138 self.gl_id = Some(texture);
139 gl_error(gl);
140
141 Ok(texture)
142 }
143
144 pub fn bind_texture(&self, gl: &glow::Context) {
146 unsafe {
147 gl.bind_texture(glow::TEXTURE_2D, self.gl_id);
148 gl_error(gl);
149 }
150 }
151}
152
153#[cfg(test)]
156mod tests {
157 use super::Font;
158
159 #[test]
160 fn make_font_minimal() {
162 let f = Font::new("test.png", 1, 2, (8, 8));
163 assert_eq!(f.bitmap_file, "test.png");
164 assert_eq!(f.width, 1);
165 assert_eq!(f.height, 2);
166 }
167
168 #[test]
169 fn make_font_from_file() {
171 let f = Font::load("resources/terminal8x8.png", (8, 8), None);
172 assert_eq!(f.width, 128);
173 assert_eq!(f.height, 128);
174 }
175}