From 428079cf6b71b57710800fe782e642235f49c132 Mon Sep 17 00:00:00 2001 From: jodhus Date: Thu, 16 Nov 2023 01:23:22 -0500 Subject: [PATCH] Created screen array --- src/main.rs | 265 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 206 insertions(+), 59 deletions(-) diff --git a/src/main.rs b/src/main.rs index e0bc5bc..595a5fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,60 +16,191 @@ use cp437::GLYPHS; const SCREEN_HEIGHT: u32 = 350; const SCREEN_WIDTH: u32 = 640; -const EGA_COLORS: [Color; 16] = [ - Color::RGB(0x00, 0x00, 0x00), // Black - Color::RGB(0x00, 0x00, 0xaa), // Blue - Color::RGB(0x00, 0xaa, 0x00), // Green - Color::RGB(0x00, 0xaa, 0xaa), // Cyan - Color::RGB(0xaa, 0x00, 0x00), // Red - Color::RGB(0xaa, 0x00, 0xaa), // Magenta - Color::RGB(0xaa, 0x55, 0x00), // Brown - Color::RGB(0xaa, 0xaa, 0xaa), // White / Light Gray - Color::RGB(0x55, 0x55, 0x55), // Dark Gray / Bright Black - Color::RGB(0x55, 0x55, 0xff), // Bright Blue - Color::RGB(0x55, 0xff, 0x55), // Bright Green - Color::RGB(0x55, 0xff, 0xff), // Bright Cyan - Color::RGB(0xff, 0x55, 0x55), // Bright Red - Color::RGB(0xff, 0x55, 0xff), // Bright Magenta - Color::RGB(0xff, 0xff, 0x55), // Bright Yellow - Color::RGB(0xff, 0xff, 0xff), // Bright White -]; +const GLYPH_COLUMNS: u8 = 80; +const GLYPH_ROWS: u8 = 25; -pub fn textattr_to_int(back: u8, fore: u8, codepoint: u8, blink: bool) -> usize { - let num = (usize::from(blink) << 15) + - (usize::from(back) << 12) + - (usize::from(fore) << 8) + - usize::from(codepoint); - num +const GLYPH_HEIGHT: u8 = 14; +const GLYPH_WIDTH: u8 = 8; + +// Total glyph textures = 256 glyphs * 16 foreground colors * 8 background colors +const TOTAL_GLYPH_TEXTURES: usize = 256 * 16 * 8; + +// Total screen blocks = GLYPH_COLUMNS * GLYPH_ROWS +const TOTAL_SCREEN_BLOCKS: usize = 2000; + +pub enum EgaColors { + Black, + Blue, + Green, + Cyan, + Red, + Magenta, + Brown, + LightGray, + DarkGray, + BrightBlue, + BrightGreen, + BrightCyan, + BrightRed, + BrightMagenta, + BrightYellow, + White, } -pub fn int_to_textattr(num: usize) -> (u8, u8, u8, bool) { - let blink = (num >> 15) != 0; - let back = (num >> 12) as u8; - let fore = ((num >> 8) & 15) as u8; - let codepoint = (num & 255) as u8; - (back, fore, codepoint, blink) +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 + } } -pub fn render(canvas: &mut WindowCanvas, color: Color, texture: &Texture) { - canvas.set_draw_color(color); +#[derive(Clone, Copy)] +pub struct ScreenBlock { + blink: bool, + background: u8, + foreground: u8, + glyph: u8, +} + +impl ScreenBlock { + pub fn new(blink: bool, background: u8, foreground: u8, glyph: u8) -> Self { + ScreenBlock { blink, background, foreground, glyph } + } + + pub fn attrs_to_index(blink: bool, background: u8, foreground: u8, glyph: u8) -> usize { + let num = (usize::from(blink) << 15) + + (usize::from(background) << 12) + + (usize::from(foreground) << 8) + + usize::from(glyph); + num + } + + pub fn index_to_attrs(num: usize) -> (bool, u8, u8, u8) { + let blink = (num >> 15) != 0; + let back = (num >> 12) as u8; + let fore = ((num >> 8) & 15) as u8; + let glyph = (num & 255) as u8; + (blink, back, fore, glyph) + } + + pub fn as_texture_index(&self) -> usize { + let num = ScreenBlock::attrs_to_index( + self.blink, + self.background, + self.foreground, + self.glyph + ); + num + } + + pub fn from_texture_index(num: usize) -> Self { + 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, + x: u8, + y: u8, + block: &ScreenBlock) { + + let tex_idx = block.as_texture_index(); + + 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 render(canvas: &mut WindowCanvas, textures: &Vec, screen: &[ScreenBlock]) { + canvas.set_draw_color(EgaColors::from_enum(EgaColors::Black)); canvas.clear(); - match canvas.copy(texture, Rect::new(0, 0, 8, 14), Rect::new(0, 0, 8, 14)) { - Ok(()) => (), - Err(err) => panic!("Unable to copy texture to canvas! SDL Error: {}", err), - }; - - match canvas.copy(texture, Rect::new(0, 0, 8, 14), Rect::new(8, 0, 8, 14)) { - Ok(()) => (), - Err(err) => panic!("Unable to copy texture to canvas! SDL Error: {}", err), - }; - - match canvas.copy(texture, Rect::new(0, 0, 8, 14), Rect::new(16, 0, 8, 14)) { - Ok(()) => (), - Err(err) => panic!("Unable to copy texture to canvas! SDL Error: {}", err), - }; - + 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); + } canvas.present(); } @@ -100,9 +231,9 @@ pub fn main() { let texture_creator = canvas.texture_creator(); let mut glyph_textures: Vec = Vec::new(); - for tex_idx in 0..=32767 { - let (back, fore, cp, _) = int_to_textattr(tex_idx); - let mut texture = match texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, 8, 14) { + for tex_idx in 0..TOTAL_GLYPH_TEXTURES { + let (_, back, fore, cp) = ScreenBlock::index_to_attrs(tex_idx); + let mut texture = match texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, u32::from(GLYPH_WIDTH), u32::from(GLYPH_HEIGHT)) { Ok(texture) => texture, Err(err) => panic!("SDL could not create texture. SDL Error: {}", err), }; @@ -112,13 +243,13 @@ pub fn main() { for (x, pixel) in bits.iter().enumerate() { let offset = y * pitch + x * 3; if pixel == false { - buffer[offset] = EGA_COLORS[back as usize].r; - buffer[offset + 1] = EGA_COLORS[back as usize].g; - buffer[offset + 2] = EGA_COLORS[back as usize].b; + buffer[offset] = EgaColors::from_u8(back).r; + buffer[offset + 1] = EgaColors::from_u8(back).g; + buffer[offset + 2] = EgaColors::from_u8(back).b; } else { - buffer[offset] = EGA_COLORS[fore as usize].r; - buffer[offset + 1] = EGA_COLORS[fore as usize].g; - buffer[offset + 2] = EGA_COLORS[fore as usize].b; + buffer[offset] = EgaColors::from_u8(fore).r; + buffer[offset + 1] = EgaColors::from_u8(fore).g; + buffer[offset + 2] = EgaColors::from_u8(fore).b; } } } @@ -128,13 +259,29 @@ pub fn main() { }; glyph_textures.push(texture); } - - render(&mut canvas, Color::RGB(0, 0, 0), &glyph_textures[3762]); + + 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]; + + for col in 0..60 { + dos_screen[col as usize] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 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); + } + 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); + } + + render(&mut canvas, &glyph_textures, &dos_screen); let mut event_pump = match sdl_context.event_pump() { Ok(event_pump) => event_pump, Err(err) => panic!("Could not obtain SDL2 Event Pump! SDL_Error: {}", err), }; + 'running: loop { for event in event_pump.poll_iter() { match event { @@ -146,7 +293,7 @@ pub fn main() { } } - render(&mut canvas, Color::RGB(0, 0, 0), &glyph_textures[3762]); + render(&mut canvas, &glyph_textures, &dos_screen); sleep(Duration::new(0, 1_000_000_000u32 / 60)); } }