summaryrefslogtreecommitdiff
path: root/src/common/overlay/terminal.rs
blob: a2382b14e36fc8f17cdeef64c180b12fe89c88d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use teleia::*;

pub const WIDTH: usize = 64;
pub const HEIGHT: usize = 64;

#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub struct Pos {
    pub x: i32, pub y: i32,
}
impl Pos {
    pub fn new(x: i32, y: i32) -> Self { Self { x, y } }
}
impl std::ops::Add for Pos {
    type Output = Pos;
    fn add(self, rhs: Self) -> Self { Self {x: self.x + rhs.x, y: self.y + rhs.y } }
}

#[derive(Debug, Clone)]
pub struct CharPair {
    pub first: char,
    pub second: Option<char>,
}
impl Default for CharPair {
    fn default() -> Self {
        Self {
            first: 'a',
            second: Some('b'),
        }
    }
}

pub struct Layer<T> {
    pub data: [T; WIDTH * HEIGHT],
}
impl<T> Layer<T> {
    pub fn new() -> Self where T: Default {
        Self {
            data: [(); WIDTH * HEIGHT].map(|_| T::default()),
        }
    }
    pub fn get(&self, p: Pos) -> Option<&T> {
        if p.x < 0 || p.x >= WIDTH as _ || p.y < 0 || p.y >= HEIGHT as _ { return None }
        let idx = p.x as usize + p.y as usize * WIDTH;
        Some(&self.data[idx])
    }
    pub fn set(&mut self, p: Pos, x: T) {
        if p.x < 0 || p.x >= WIDTH as _ || p.y < 0 || p.y >= HEIGHT as _ { return }
        let idx = p.x as usize + p.y as usize * WIDTH;
        self.data[idx] = x;
    }
}
impl Layer<CharPair> {
    pub fn from_str(&mut self, s: &str) {
        let chars: Vec<char> = s.chars().collect();
        if chars.is_empty() { return }
        let mut i: usize = 0;
        for row in 0..64 {
            for col in 0..64 {
                let first = chars[i]; i += 1; i %= chars.len();
                let second = Some(chars[i]); i += 1; i %= chars.len();
                self.set(Pos::new(col, row), CharPair { first, second });
            }
        }
    }
}
impl Layer<glam::Vec3> {
    pub fn from_framebuffer(&mut self, ctx: &context::Context, fb: &framebuffer::Framebuffer) {
        fb.get_pixels(ctx, &mut self.data);
    }
}

pub struct Terminal {
    pub font: font::Bitmap,
    pub base_color: Layer<glam::Vec3>,
    pub set_color: Layer<glam::Vec3>,
    pub set_char: Layer<CharPair>,
}
impl Terminal {
    pub fn new(ctx: &context::Context) -> Self {
        let mut set_char = Layer::new();
        set_char.from_str("lcolonq");
        Self {
            font: font::Bitmap::from_image(ctx, 6, 12, 96, 72, include_bytes!("assets/fonts/terminus.png")),
            base_color: Layer::new(),
            set_color: Layer::new(),
            set_char,
        }
    }
    pub fn get_color(&self, pos: Pos) -> glam::Vec3 {
        if let Some(c) = self.base_color.get(pos) {
            c.clone()
        } else {
            glam::Vec3::new(1.0, 1.0, 1.0)
        }
    }
    pub fn update(&mut self, ctx: &context::Context, fb: &framebuffer::Framebuffer) {
        self.base_color.from_framebuffer(ctx, fb);
    }
    pub fn fill_string(&mut self, s: &str) {
        self.set_char.from_str(s);
    }
    pub fn render(&self, ctx: &context::Context, pos: &glam::Vec2) {
        let mut s = String::new();
        let mut colors = Vec::new();
        for row in 0..64 {
            for col in 0..64 {
                let pos = Pos::new(col, row);
                let new = if let Some(p) = self.set_char.get(pos) {
                    format!("{}{}", p.first, if let Some(snd) = p.second { snd } else { ' ' })
                } else {
                    String::from("  ")
                };
                s += &new;
                let c = self.get_color(pos);
                colors.push(c); colors.push(c);
            }
            s += "\n";
            colors.push(glam::Vec3::new(1.0, 1.0, 1.0));
        }
        self.font.render_text_helper(ctx, pos, &s, &colors);
    }
}