Refactored/cleaned up display code.

master
James T. Martin 2020-07-16 17:04:19 -07:00
parent dffee5652c
commit 42af83395b
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
8 changed files with 123 additions and 82 deletions

View File

@ -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' {

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}