Refactored/cleaned up display code.
parent
dffee5652c
commit
42af83395b
|
@ -12,9 +12,9 @@ use crate::graphics::tty::Tty;
|
|||
use crate::graphics::tty::terminal::TerminalTty;
|
||||
|
||||
pub fn do_graphics(st: &uefi::prelude::SystemTable<uefi::prelude::Boot>) {
|
||||
let display = GopDisplay::init(st.boot_services());
|
||||
let terminal = DisplayTerminal::create(display, font(), COLOR_BLACK, COLOR_WHITE);
|
||||
let mut tty = TerminalTty::create(terminal);
|
||||
let mut display = GopDisplay::init(st.boot_services());
|
||||
let mut terminal = DisplayTerminal::new(&mut display, font(), COLOR_BLACK, COLOR_WHITE);
|
||||
let mut tty = TerminalTty::new(&mut terminal);
|
||||
|
||||
for _ in 0..30 {
|
||||
for c in 'a'..'z' {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::graphics::color::Color;
|
||||
use crate::graphics::color::RGB;
|
||||
use crate::graphics::font::psf::PSFGlyph;
|
||||
|
||||
pub mod gop;
|
||||
|
@ -8,8 +8,8 @@ pub trait Display {
|
|||
fn width(&self) -> usize { self.resolution().0 }
|
||||
fn height(&self) -> usize { self.resolution().1 }
|
||||
|
||||
unsafe fn set_pixel(&mut self, color: impl Color, x: usize, y: usize);
|
||||
fn set_pixel_ignore_oob(&mut self, color: impl Color, x: usize, y: usize) {
|
||||
unsafe fn set_pixel(&mut self, color: RGB, x: usize, y: usize);
|
||||
fn set_pixel_ignore_oob(&mut self, color: RGB, x: usize, y: usize) {
|
||||
if x > self.width() || y > self.height() {
|
||||
return;
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ pub trait Display {
|
|||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: impl Color);
|
||||
fn clear(&mut self, color: RGB);
|
||||
|
||||
unsafe fn draw_glyph(&mut self, color: impl Color, x: usize, y: usize, glyph: PSFGlyph) {
|
||||
unsafe fn draw_glyph(&mut self, color: RGB, x: usize, y: usize, glyph: PSFGlyph) {
|
||||
// Glyphs may actually be larger than their nominal bounding box.
|
||||
// In fact, the Cozette font is like this: the heart symbol is 7 pixels wide,
|
||||
// despite nominally being a 6x13 font.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::graphics::color::Color;
|
||||
use crate::graphics::color::{Color, RGB};
|
||||
use crate::graphics::display::Display;
|
||||
use uefi::proto::console::gop::{FrameBuffer, GraphicsOutput, ModeInfo, PixelFormat};
|
||||
|
||||
|
@ -47,11 +47,11 @@ impl GopDisplay<'_> {
|
|||
impl Display for GopDisplay<'_> {
|
||||
fn resolution(&self) -> (usize, usize) { self.mode.resolution() }
|
||||
|
||||
unsafe fn set_pixel(&mut self, color: impl Color, x: usize, y: usize) {
|
||||
unsafe fn set_pixel(&mut self, color: RGB, x: usize, y: usize) {
|
||||
self.fb.write_value(self.pixel_index(x, y), self.make_pixel(color));
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: impl Color) {
|
||||
fn clear(&mut self, color: RGB) {
|
||||
let (width, height) = self.resolution();
|
||||
let px = self.make_pixel(color);
|
||||
for x in 0..width {
|
||||
|
|
|
@ -21,6 +21,18 @@ pub struct PSFGlyph<'a> {
|
|||
}
|
||||
|
||||
impl PSF {
|
||||
pub fn resolution(&self) -> (u32, u32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn index_of(&self, c: char) -> Option<usize> {
|
||||
for entry in &self.unicode {
|
||||
if entry.c == c {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
pub mod display;
|
||||
pub mod frame;
|
||||
|
||||
use crate::graphics::terminal::frame::TerminalFrame;
|
||||
|
||||
pub trait Terminal {
|
||||
fn resolution(&self) -> (usize, usize);
|
||||
fn width(&self) -> usize { self.resolution().0 }
|
||||
fn height(&self) -> usize { self.resolution().1 }
|
||||
|
||||
fn set_char(&mut self, x: usize, y: usize, c: char);
|
||||
fn clear(&mut self);
|
||||
|
||||
fn get_frame<'a>(&'a self) -> &'a TerminalFrame;
|
||||
fn borrow_frame<'a>(&'a mut self) -> &'a mut TerminalFrame;
|
||||
fn refresh(&mut self);
|
||||
}
|
||||
|
|
|
@ -1,76 +1,54 @@
|
|||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use crate::graphics::color::{Color, RGB};
|
||||
use crate::graphics::color::RGB;
|
||||
use crate::graphics::display::Display;
|
||||
use crate::graphics::display::gop::GopDisplay;
|
||||
use crate::graphics::font::psf::PSF;
|
||||
use crate::graphics::terminal::Terminal;
|
||||
use crate::graphics::terminal::frame::TerminalFrame;
|
||||
|
||||
pub struct DisplayTerminal<'a> {
|
||||
dp: GopDisplay<'a>,
|
||||
pub struct DisplayTerminal<'display> {
|
||||
display: &'display mut dyn Display,
|
||||
frame: TerminalFrame,
|
||||
font: Arc<PSF>,
|
||||
buf: Vec<char>,
|
||||
bg: RGB,
|
||||
fg: RGB,
|
||||
}
|
||||
|
||||
impl DisplayTerminal<'_> {
|
||||
pub fn create<'a>(dp: GopDisplay<'a>, font: Arc<PSF>, bg: impl Color, fg: impl Color) -> DisplayTerminal<'a> {
|
||||
let (dp_width, dp_height) = dp.resolution();
|
||||
let (font_width, font_height) = (font.width, font.height);
|
||||
pub fn new<'display>(display: &'display mut dyn Display, font: Arc<PSF>, bg: RGB, fg: RGB) -> DisplayTerminal<'display> {
|
||||
let (dp_width, dp_height) = display.resolution();
|
||||
let (ft_width, ft_height) = font.resolution();
|
||||
let ch_width = dp_width / ft_width as usize;
|
||||
let ch_height = dp_height / ft_height as usize;
|
||||
|
||||
DisplayTerminal {
|
||||
dp: dp,
|
||||
display: display,
|
||||
frame: TerminalFrame::new((ch_width, ch_height)),
|
||||
font: font,
|
||||
buf: {
|
||||
let char_count = (dp_width / font_width as usize) * (dp_height / font_height as usize);
|
||||
let mut buf = Vec::with_capacity(char_count);
|
||||
for _ in 0..char_count {
|
||||
buf.push(' ');
|
||||
}
|
||||
buf
|
||||
},
|
||||
bg: bg.into_rgb(),
|
||||
fg: fg.into_rgb(),
|
||||
bg: bg,
|
||||
fg: fg,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_index(&self, x: usize, y: usize) -> usize {
|
||||
self.width() * y + x
|
||||
}
|
||||
|
||||
fn get_char(&self, x: usize, y: usize) -> char {
|
||||
let i = self.get_index(x, y);
|
||||
self.buf[i]
|
||||
}
|
||||
}
|
||||
|
||||
impl Terminal for DisplayTerminal<'_> {
|
||||
fn resolution(&self) -> (usize, usize) {
|
||||
let width = self.dp.width() / self.font.width as usize;
|
||||
let height = self.dp.height() / self.font.height as usize;
|
||||
(width, height)
|
||||
fn get_frame<'a>(&'a self) -> &'a TerminalFrame {
|
||||
&self.frame
|
||||
}
|
||||
|
||||
fn set_char(&mut self, x: usize, y: usize, c: char) {
|
||||
let i = self.get_index(x, y);
|
||||
self.buf.as_mut_slice()[i] = c;
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
for x in 0..self.width() {
|
||||
for y in 0..self.height() {
|
||||
self.set_char(x, y, ' ');
|
||||
}
|
||||
}
|
||||
fn borrow_frame<'a>(&'a mut self) -> &'a mut TerminalFrame {
|
||||
&mut self.frame
|
||||
}
|
||||
|
||||
fn refresh(&mut self) {
|
||||
self.dp.clear(self.bg);
|
||||
for x in 0..self.width() {
|
||||
for y in 0..self.height() {
|
||||
let glyph = self.font.lookup(self.get_char(x, y)).expect("Character missing from font.");
|
||||
self.display.clear(self.bg);
|
||||
for x in 0..self.frame.width() {
|
||||
for y in 0..self.frame.height() {
|
||||
let c = self.frame.get(x, y);
|
||||
if c == '\u{0}' { continue; }
|
||||
|
||||
let glyph = self.font.lookup(c).expect("Character missing from font.");
|
||||
unsafe {
|
||||
self.dp.draw_glyph(self.fg, self.font.width as usize * x, self.font.height as usize * y, glyph);
|
||||
self.display.draw_glyph(self.fg, self.font.width() as usize * x, self.font.height() as usize * y, glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
use alloc::vec::Vec;
|
||||
|
||||
pub struct TerminalFrame {
|
||||
resolution: (usize, usize),
|
||||
buf: Vec<char>,
|
||||
}
|
||||
|
||||
impl TerminalFrame {
|
||||
pub fn new(resolution: (usize, usize)) -> TerminalFrame {
|
||||
let (width, height) = resolution;
|
||||
let buf_length = width * height;
|
||||
let mut buf = Vec::with_capacity(buf_length);
|
||||
for _ in 0..buf_length {
|
||||
buf.push('\u{0}');
|
||||
}
|
||||
|
||||
TerminalFrame {
|
||||
resolution: resolution,
|
||||
buf: buf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolution(&self) -> (usize, usize) {
|
||||
self.resolution
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.resolution.0
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
self.resolution.1
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
for i in 0..self.buf.len() {
|
||||
self.buf[i] = '\u{0}';
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&self, x: usize, y: usize) -> usize {
|
||||
self.width() * y + x
|
||||
}
|
||||
|
||||
pub fn get(&self, x: usize, y: usize) -> char {
|
||||
self.buf[self.index(x, y)]
|
||||
}
|
||||
|
||||
pub fn set(&mut self, x: usize, y: usize, c: char) {
|
||||
let i = self.index(x, y);
|
||||
self.buf[i] = c;
|
||||
}
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use crate::graphics::terminal::Terminal;
|
||||
use crate::graphics::terminal::display::DisplayTerminal;
|
||||
use crate::graphics::tty::Tty;
|
||||
|
||||
pub struct TerminalTty<'a> {
|
||||
term: DisplayTerminal<'a>,
|
||||
lines: Vec<String>,
|
||||
pub struct TerminalTty<'terminal> {
|
||||
term: &'terminal mut dyn Terminal,
|
||||
history: Vec<String>,
|
||||
}
|
||||
|
||||
impl TerminalTty<'_> {
|
||||
pub fn create<'a>(term: DisplayTerminal<'a>) -> TerminalTty<'a> {
|
||||
pub fn new<'a>(term: &'a mut dyn Terminal) -> TerminalTty<'a> {
|
||||
TerminalTty {
|
||||
term: term,
|
||||
lines: {
|
||||
history: {
|
||||
let mut vec = Vec::new();
|
||||
vec.push("".to_string());
|
||||
vec
|
||||
|
@ -25,11 +24,11 @@ impl TerminalTty<'_> {
|
|||
impl Tty for TerminalTty<'_> {
|
||||
fn putc(&mut self, c: char) {
|
||||
if c == '\n' {
|
||||
self.lines.push("".to_string());
|
||||
self.history.push("".to_string());
|
||||
return;
|
||||
}
|
||||
let i = self.lines.len() - 1;
|
||||
self.lines[i].push(c);
|
||||
let i = self.history.len() - 1;
|
||||
self.history[i].push(c);
|
||||
}
|
||||
|
||||
fn puts(&mut self, s: &str) {
|
||||
|
@ -39,17 +38,17 @@ impl Tty for TerminalTty<'_> {
|
|||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.lines.clear();
|
||||
self.lines.push("".to_string());
|
||||
self.history.clear();
|
||||
self.history.push("".to_string());
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
let mut physical_lines = Vec::new();
|
||||
for line in &self.lines {
|
||||
for line in &self.history {
|
||||
let mut chars = line.chars().collect::<Vec<_>>().into_iter();
|
||||
while chars.len() > 0 {
|
||||
let mut physical_line = String::new();
|
||||
let width = chars.len().min(self.term.width());
|
||||
let width = chars.len().min(self.term.get_frame().width());
|
||||
for _ in 0..width {
|
||||
physical_line.push(chars.next().unwrap());
|
||||
}
|
||||
|
@ -57,11 +56,12 @@ impl Tty for TerminalTty<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut y = physical_lines.len().min(self.term.height() - 1);
|
||||
let mut y = physical_lines.len().min(self.term.get_frame().height() - 1);
|
||||
let frame = self.term.borrow_frame();
|
||||
for line in physical_lines.into_iter().rev() {
|
||||
let mut x = 0;
|
||||
for c in line.chars() {
|
||||
self.term.set_char(x, y, c);
|
||||
frame.set(x, y, c);
|
||||
x += 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue