rustscii/rendering/
terminal.rs1use image::DynamicImage;
2use image::GenericImageView;
3use image::ImageBuffer;
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::path::Path;
7use std::rc::Rc;
8
9pub struct Terminal {
11 char_width: usize,
12 char_height: usize,
13 font: DynamicImage,
14 characters: HashMap<char, DynamicImage>,
15 grid: Vec<Vec<char>>,
16}
17
18impl Terminal {
19 pub fn new(font_path: &str, char_width: usize, char_height: usize) -> Self {
21 let font = image::open(Path::new(font_path)).expect("Failed to load font image");
22 let characters = HashMap::new();
23 let grid = vec![vec![' '; 80]; 25]; Terminal {
26 char_width,
27 char_height,
28 font,
29 characters,
30 grid,
31 }
32 }
33
34 pub fn load_characters(&mut self) {
36 for ascii_code in 32..=127 {
37 let character = char::from(ascii_code);
38 let char_x = (ascii_code - 32) % 16 * self.char_width as u8;
39 let char_y = (ascii_code - 32) / 16 * self.char_height as u8;
40
41 let char_img = self
42 .font
43 .crop_imm(char_x as u32, char_y as u32, self.char_width as u32, self.char_height as u32);
44 self.characters.insert(character, char_img);
45 }
46 }
47
48 pub fn set_char(&mut self, x: usize, y: usize, character: char) {
50 if x < self.grid[0].len() && y < self.grid.len() {
51 self.grid[y][x] = character;
52 }
53 }
54
55 pub fn render(&self) -> DynamicImage {
57 let mut img = ImageBuffer::new(
58 self.char_width as u32 * self.grid[0].len() as u32,
59 self.char_height as u32 * self.grid.len() as u32,
60 );
61
62 for (row, line) in self.grid.iter().enumerate() {
63 for (col, character) in line.iter().enumerate() {
64 if let Some(char_img) = self.characters.get(character) {
65 for (x, y, pixel) in char_img.pixels() {
66 img.put_pixel(
67 (col as u32 * self.char_width as u32 + x) as u32,
68 (row as u32 * self.char_height as u32 + y) as u32,
69 pixel,
70 );
71 }
72 }
73 }
74 }
75
76 DynamicImage::ImageRgba8(img)
77 }
78
79 pub fn get_raw_grid(&self) -> impl Iterator<Item = &Vec<char>> {
81 self.grid.iter()
82 }
83
84 pub fn get_rc(self) -> Rc<RefCell<Terminal>> {
86 Rc::new(RefCell::new(self))
87 }
88}