summaryrefslogtreecommitdiff
path: root/src/common/overlay/terminal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/overlay/terminal.rs')
-rw-r--r--src/common/overlay/terminal.rs122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/common/overlay/terminal.rs b/src/common/overlay/terminal.rs
new file mode 100644
index 0000000..a2382b1
--- /dev/null
+++ b/src/common/overlay/terminal.rs
@@ -0,0 +1,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);
+ }
+}