Code cleanup.

This commit is contained in:
Josh W 2023-11-25 20:07:16 -05:00
parent 76650ac828
commit cac8c85fcb
3 changed files with 205 additions and 146 deletions

View file

@ -35,7 +35,7 @@ pub const GLYPHS: [[u8; 14]; 256] = [
[0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00], // [↔] (29)
[0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00], // [▲] (30)
[0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00], // [▼] (31)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [ ] (32)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [SP] (32)
[0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00], // [!] (33)
[0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // ["] (34)
[0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00], // [#] (35)
@ -258,12 +258,12 @@ pub const GLYPHS: [[u8; 14]; 256] = [
[0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [ⁿ] (252)
[0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [²] (253)
[0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00], // [■] (254)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [ ] (255)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // [NBSP] (255)
];
/// Prints a specific glyph to StdOut for easier viewing.
#[allow(dead_code)]
fn debug_print_glyph(glyph: [u8; 14]) {
pub fn debug_print_glyph(glyph: [u8; 14]) {
for line in glyph.iter() {
let bits = line.view_bits::<Lsb0>();
for pixel in bits.iter() {

145
src/ega.rs Normal file
View file

@ -0,0 +1,145 @@
extern crate sdl2;
use sdl2::pixels::Color;
pub enum EgaColors {
Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
LightGray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
BrightYellow,
White,
}
impl TryFrom<u8> for EgaColors {
type Error = &'static str;
fn try_from(num: u8) -> Result<Self, Self::Error> {
match num {
0 => Ok(EgaColors::Black),
1 => Ok(EgaColors::Blue),
2 => Ok(EgaColors::Green),
3 => Ok(EgaColors::Cyan),
4 => Ok(EgaColors::Red),
5 => Ok(EgaColors::Magenta),
6 => Ok(EgaColors::Brown),
7 => Ok(EgaColors::LightGray),
8 => Ok(EgaColors::DarkGray),
9 => Ok(EgaColors::BrightBlue),
10 => Ok(EgaColors::BrightGreen),
11 => Ok(EgaColors::BrightCyan),
12 => Ok(EgaColors::BrightRed),
13 => Ok(EgaColors::BrightMagenta),
14 => Ok(EgaColors::BrightYellow),
15 => Ok(EgaColors::White),
_ => Err("EgaColors must be between 0 and 15 inclusive."),
}
}
}
impl Into<u8> for EgaColors {
fn into(self) -> u8 {
match self {
EgaColors::Black => 0,
EgaColors::Blue => 1,
EgaColors::Green => 2,
EgaColors::Cyan => 3,
EgaColors::Red => 4,
EgaColors::Magenta => 5,
EgaColors::Brown => 6,
EgaColors::LightGray => 7,
EgaColors::DarkGray => 8,
EgaColors::BrightBlue => 9,
EgaColors::BrightGreen => 10,
EgaColors::BrightCyan => 11,
EgaColors::BrightRed => 12,
EgaColors::BrightMagenta => 13,
EgaColors::BrightYellow => 14,
EgaColors::White => 15,
}
}
}
impl TryFrom<Color> for EgaColors {
type Error = &'static str;
fn try_from(color: Color) -> Result<Self, Self::Error> {
match color {
Color { r: 0x00, g: 0x00, b: 0x00, a: 0xff } => Ok(EgaColors::Black),
Color { r: 0x00, g: 0x00, b: 0xaa, a: 0xff } => Ok(EgaColors::Blue),
Color { r: 0x00, g: 0xaa, b: 0x00, a: 0xff } => Ok(EgaColors::Green),
Color { r: 0x00, g: 0xaa, b: 0xaa, a: 0xff } => Ok(EgaColors::Cyan),
Color { r: 0xaa, g: 0x00, b: 0x00, a: 0xff } => Ok(EgaColors::Red),
Color { r: 0xaa, g: 0x00, b: 0xaa, a: 0xff } => Ok(EgaColors::Magenta),
Color { r: 0xaa, g: 0x55, b: 0x00, a: 0xff } => Ok(EgaColors::Brown),
Color { r: 0xaa, g: 0xaa, b: 0xaa, a: 0xff } => Ok(EgaColors::LightGray),
Color { r: 0x55, g: 0x55, b: 0x55, a: 0xff } => Ok(EgaColors::DarkGray),
Color { r: 0x55, g: 0x55, b: 0xff, a: 0xff } => Ok(EgaColors::BrightBlue),
Color { r: 0x55, g: 0xff, b: 0x55, a: 0xff } => Ok(EgaColors::BrightGreen),
Color { r: 0x55, g: 0xff, b: 0xff, a: 0xff } => Ok(EgaColors::BrightCyan),
Color { r: 0xff, g: 0x55, b: 0x55, a: 0xff } => Ok(EgaColors::BrightRed),
Color { r: 0xff, g: 0x55, b: 0xff, a: 0xff } => Ok(EgaColors::BrightMagenta),
Color { r: 0xff, g: 0xff, b: 0x55, a: 0xff } => Ok(EgaColors::BrightYellow),
Color { r: 0xff, g: 0xff, b: 0xff, a: 0xff } => Ok(EgaColors::White),
_ => Err("The RGB color provided does not match an EgaColor."),
}
}
}
impl Into<Color> for EgaColors {
fn into(self) -> Color {
match self {
EgaColors::Black => Color { r: 0x00, g: 0x00, b: 0x00, a: 0xff },
EgaColors::Blue => Color { r: 0x00, g: 0x00, b: 0xaa, a: 0xff },
EgaColors::Green => Color { r: 0x00, g: 0xaa, b: 0x00, a: 0xff },
EgaColors::Cyan => Color { r: 0x00, g: 0xaa, b: 0xaa, a: 0xff },
EgaColors::Red => Color { r: 0xaa, g: 0x00, b: 0x00, a: 0xff },
EgaColors::Magenta => Color { r: 0xaa, g: 0x00, b: 0xaa, a: 0xff },
EgaColors::Brown => Color { r: 0xaa, g: 0x55, b: 0x00, a: 0xff },
EgaColors::LightGray => Color { r: 0xaa, g: 0xaa, b: 0xaa, a: 0xff },
EgaColors::DarkGray => Color { r: 0x55, g: 0x55, b: 0x55, a: 0xff },
EgaColors::BrightBlue => Color { r: 0x55, g: 0x55, b: 0xff, a: 0xff },
EgaColors::BrightGreen => Color { r: 0x55, g: 0xff, b: 0x55, a: 0xff },
EgaColors::BrightCyan => Color { r: 0x55, g: 0xff, b: 0xff, a: 0xff },
EgaColors::BrightRed => Color { r: 0xff, g: 0x55, b: 0x55, a: 0xff },
EgaColors::BrightMagenta => Color { r: 0xff, g: 0x55, b: 0xff, a: 0xff },
EgaColors::BrightYellow => Color { r: 0xff, g: 0xff, b: 0x55, a: 0xff },
EgaColors::White => Color { r: 0xff, g: 0xff, b: 0xff, a: 0xff },
}
}
}
impl EgaColors {
pub fn u8_to_rgb(num: u8) -> Color {
let col = match num {
0 => Color::RGB(0x00, 0x00, 0x00),
1 => Color::RGB(0x00, 0x00, 0xaa),
2 => Color::RGB(0x00, 0xaa, 0x00),
3 => Color::RGB(0x00, 0xaa, 0xaa),
4 => Color::RGB(0xaa, 0x00, 0x00),
5 => Color::RGB(0xaa, 0x00, 0xaa),
6 => Color::RGB(0xaa, 0x55, 0x00),
7 => Color::RGB(0xaa, 0xaa, 0xaa),
8 => Color::RGB(0x55, 0x55, 0x55),
9 => Color::RGB(0x55, 0x55, 0xff),
10 => Color::RGB(0x55, 0xff, 0x55),
11 => Color::RGB(0x55, 0xff, 0xff),
12 => Color::RGB(0xff, 0x55, 0x55),
13 => Color::RGB(0xff, 0x55, 0xff),
14 => Color::RGB(0xff, 0xff, 0x55),
15 => Color::RGB(0xff, 0xff, 0xff),
_ => panic!("Unknown value for EgaColors: {}", num),
};
col
}
}

View file

@ -11,7 +11,9 @@ use sdl2::rect::Rect;
use sdl2::render::{WindowCanvas, Texture};
pub mod cp437;
pub mod ega;
use cp437::GLYPHS;
use ega::EgaColors;
const SCREEN_HEIGHT: u32 = 350;
const SCREEN_WIDTH: u32 = 640;
@ -31,94 +33,6 @@ const TOTAL_SCREEN_BLOCKS: usize = 2000;
const FPS_60_HERTZ: u32 = 1_000_000_000u32 / 60;
const BLINK_RATE: u128 = 266666666;
pub enum EgaColors {
Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
LightGray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
BrightYellow,
White,
}
impl EgaColors {
pub fn as_u8(color: EgaColors) -> u8 {
let num = match color {
EgaColors::Black => 0,
EgaColors::Blue => 1,
EgaColors::Green => 2,
EgaColors::Cyan => 3,
EgaColors::Red => 4,
EgaColors::Magenta => 5,
EgaColors::Brown => 6,
EgaColors::LightGray => 7,
EgaColors::DarkGray => 8,
EgaColors::BrightBlue => 9,
EgaColors::BrightGreen => 10,
EgaColors::BrightCyan => 11,
EgaColors::BrightRed => 12,
EgaColors::BrightMagenta => 13,
EgaColors::BrightYellow => 14,
EgaColors::White => 15,
};
num
}
pub fn from_enum(color: EgaColors) -> Color {
let col = match color {
EgaColors::Black => Color::RGB(0x00, 0x00, 0x00),
EgaColors::Blue => Color::RGB(0x00, 0x00, 0xaa),
EgaColors::Green => Color::RGB(0x00, 0xaa, 0x00),
EgaColors::Cyan => Color::RGB(0x00, 0xaa, 0xaa),
EgaColors::Red => Color::RGB(0xaa, 0x00, 0x00),
EgaColors::Magenta => Color::RGB(0xaa, 0x00, 0xaa),
EgaColors::Brown => Color::RGB(0xaa, 0x55, 0x00),
EgaColors::LightGray => Color::RGB(0xaa, 0xaa, 0xaa),
EgaColors::DarkGray => Color::RGB(0x55, 0x55, 0x55),
EgaColors::BrightBlue => Color::RGB(0x55, 0x55, 0xff),
EgaColors::BrightGreen => Color::RGB(0x55, 0xff, 0x55),
EgaColors::BrightCyan => Color::RGB(0x55, 0xff, 0xff),
EgaColors::BrightRed => Color::RGB(0xff, 0x55, 0x55),
EgaColors::BrightMagenta => Color::RGB(0xff, 0x55, 0xff),
EgaColors::BrightYellow => Color::RGB(0xff, 0xff, 0x55),
EgaColors::White => Color::RGB(0xff, 0xff, 0xff),
};
col
}
pub fn from_u8(num: u8) -> Color {
let col = match num {
0 => Color::RGB(0x00, 0x00, 0x00),
1 => Color::RGB(0x00, 0x00, 0xaa),
2 => Color::RGB(0x00, 0xaa, 0x00),
3 => Color::RGB(0x00, 0xaa, 0xaa),
4 => Color::RGB(0xaa, 0x00, 0x00),
5 => Color::RGB(0xaa, 0x00, 0xaa),
6 => Color::RGB(0xaa, 0x55, 0x00),
7 => Color::RGB(0xaa, 0xaa, 0xaa),
8 => Color::RGB(0x55, 0x55, 0x55),
9 => Color::RGB(0x55, 0x55, 0xff),
10 => Color::RGB(0x55, 0xff, 0x55),
11 => Color::RGB(0x55, 0xff, 0xff),
12 => Color::RGB(0xff, 0x55, 0x55),
13 => Color::RGB(0xff, 0x55, 0xff),
14 => Color::RGB(0xff, 0xff, 0x55),
15 => Color::RGB(0xff, 0xff, 0xff),
_ => panic!("Unknown value for EgaColors: {}", num),
};
col
}
}
#[derive(Clone, Copy)]
pub struct ScreenBlock {
pub blink: bool,
@ -162,49 +76,49 @@ impl ScreenBlock {
let (blink, background, foreground, glyph) = ScreenBlock::index_to_attrs(num);
ScreenBlock { blink, background, foreground, glyph }
}
}
pub fn block_to_canvas(
canvas: &mut WindowCanvas,
textures: &Vec<Texture>,
x: u8,
y: u8,
block: &ScreenBlock,
blink: &bool
) {
let tex_idx = match blink {
false => block.as_texture_index(),
true => match block.blink {
false => block.as_texture_index(),
true => ScreenBlock::new(block.blink, block.background, block.background, block.glyph).as_texture_index(),
},
};
// These next two assignments look odd mainly because of Rust's current
// issue with exclusive range patterns. See here:
// https://github.com/rust-lang/rust/issues/37854
let dest_x = match x {
n if (0..=GLYPH_COLUMNS - 1).contains(&n) => GLYPH_WIDTH as i32 * x as i32,
//0..=79 => GLYPH_WIDTH as i32 * x as i32,
_ => panic!("x is out of range! Must be 0..79 inclusive."),
};
let dest_y = match y {
n if (0..=GLYPH_ROWS - 1).contains(&n) => GLYPH_HEIGHT as i32 * y as i32,
//0..=24 => GLYPH_HEIGHT as i32 * y as i32,
_ => panic!("y is out of range! Must be 0..24 inclusive."),
};
match canvas.copy(
&textures[tex_idx],
Rect::new(0, 0, u32::from(GLYPH_WIDTH), u32::from(GLYPH_HEIGHT)),
Rect::new(dest_x, dest_y, u32::from(GLYPH_WIDTH), u32::from(GLYPH_HEIGHT)),
pub fn to_canvas(
&self,
canvas: &mut WindowCanvas,
textures: &Vec<Texture>,
x: u8,
y: u8,
blink: &bool
) {
Ok(()) => (),
Err(err) => panic!("Unable to copy texture to canvas! SDL Error: {}", err),
};
let tex_idx = match blink {
false => self.as_texture_index(),
true => match self.blink {
false => self.as_texture_index(),
true => ScreenBlock::new(self.blink, self.background, self.background, self.glyph).as_texture_index(),
},
};
// These next two assignments look odd mainly because of Rust's current
// issue with exclusive range patterns. See here:
// https://github.com/rust-lang/rust/issues/37854
let dest_x = match x {
n if (0..=GLYPH_COLUMNS - 1).contains(&n) => GLYPH_WIDTH as i32 * x as i32,
//0..=79 => GLYPH_WIDTH as i32 * x as i32,
_ => panic!("x is out of range! Must be 0..79 inclusive."),
};
let dest_y = match y {
n if (0..=GLYPH_ROWS - 1).contains(&n) => GLYPH_HEIGHT as i32 * y as i32,
//0..=24 => GLYPH_HEIGHT as i32 * y as i32,
_ => panic!("y is out of range! Must be 0..24 inclusive."),
};
match canvas.copy(
&textures[tex_idx],
Rect::new(0, 0, u32::from(GLYPH_WIDTH), u32::from(GLYPH_HEIGHT)),
Rect::new(dest_x, dest_y, u32::from(GLYPH_WIDTH), u32::from(GLYPH_HEIGHT)),
) {
Ok(()) => (),
Err(err) => panic!("Unable to copy texture to canvas! SDL Error: {}", err),
};
}
}
pub fn update(elapsed: u128) {
@ -212,13 +126,13 @@ pub fn update(elapsed: u128) {
}
pub fn render(canvas: &mut WindowCanvas, textures: &Vec<Texture>, screen: &[ScreenBlock], blink: &bool) {
canvas.set_draw_color(EgaColors::from_enum(EgaColors::Black));
canvas.set_draw_color::<Color>(EgaColors::Black.into());
canvas.clear();
for (idx, block) in screen.iter().enumerate() {
let x = (idx % GLYPH_COLUMNS as usize) as u8;
let y = (idx / GLYPH_COLUMNS as usize) as u8;
block_to_canvas(canvas, &textures, x, y, block, blink);
block.to_canvas(canvas, &textures, x, y, blink);
}
canvas.present();
}
@ -270,13 +184,13 @@ pub fn main() {
for (x, pixel) in bits.iter().enumerate() {
let offset = y * pitch + x * 3;
if pixel == false {
buffer[offset] = EgaColors::from_u8(back).r;
buffer[offset + 1] = EgaColors::from_u8(back).g;
buffer[offset + 2] = EgaColors::from_u8(back).b;
buffer[offset] = EgaColors::u8_to_rgb(back).r;
buffer[offset + 1] = EgaColors::u8_to_rgb(back).g;
buffer[offset + 2] = EgaColors::u8_to_rgb(back).b;
} else {
buffer[offset] = EgaColors::from_u8(fore).r;
buffer[offset + 1] = EgaColors::from_u8(fore).g;
buffer[offset + 2] = EgaColors::from_u8(fore).b;
buffer[offset] = EgaColors::u8_to_rgb(fore).r;
buffer[offset + 1] = EgaColors::u8_to_rgb(fore).g;
buffer[offset + 2] = EgaColors::u8_to_rgb(fore).b;
}
}
}
@ -287,22 +201,22 @@ pub fn main() {
glyph_textures.push(texture);
}
let mut dos_screen: [ScreenBlock; TOTAL_SCREEN_BLOCKS] = [ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::Black), 0); TOTAL_SCREEN_BLOCKS];
let mut dos_screen: [ScreenBlock; TOTAL_SCREEN_BLOCKS] = [ScreenBlock::new(false, EgaColors::Black.into(), EgaColors::Black.into(), 0); TOTAL_SCREEN_BLOCKS];
for col in 0..60 {
dos_screen[col as usize] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 178);
dos_screen[col as usize] = ScreenBlock::new(false, EgaColors::Black.into(), EgaColors::BrightYellow.into(), 178);
}
for row in 1..GLYPH_ROWS-1 {
let idx = row as usize * GLYPH_COLUMNS as usize;
dos_screen[idx] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 178);
dos_screen[idx + 59] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 178);
dos_screen[idx] = ScreenBlock::new(false, EgaColors::Black.into(), EgaColors::BrightYellow.into(), 178);
dos_screen[idx + 59] = ScreenBlock::new(false, EgaColors::Black.into(), EgaColors::BrightYellow.into(), 178);
}
for col in 0..60 {
let idx = (GLYPH_ROWS - 1) as usize * GLYPH_COLUMNS as usize + col as usize;
dos_screen[idx] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 178);
dos_screen[idx] = ScreenBlock::new(false, EgaColors::Black.into(), EgaColors::BrightYellow.into(), 178);
}
dos_screen[1030] = ScreenBlock::new(true, EgaColors::as_u8(EgaColors::Blue), EgaColors::as_u8(EgaColors::LightGray), 178);
dos_screen[1030] = ScreenBlock::new(true, EgaColors::Blue.into(), EgaColors::LightGray.into(), 178);
let mut blink_tick: u128 = 0;
let mut blink_state: bool = false;