diff --git a/src/main.rs b/src/main.rs index 595a5fc..161da4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ extern crate sdl2; use std::thread::sleep; -use std::time::Duration; +use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH}; use bitvec::prelude::*; use sdl2::event::Event; @@ -28,6 +28,9 @@ const TOTAL_GLYPH_TEXTURES: usize = 256 * 16 * 8; // Total screen blocks = GLYPH_COLUMNS * GLYPH_ROWS 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, @@ -118,10 +121,10 @@ impl EgaColors { #[derive(Clone, Copy)] pub struct ScreenBlock { - blink: bool, - background: u8, - foreground: u8, - glyph: u8, + pub blink: bool, + pub background: u8, + pub foreground: u8, + pub glyph: u8, } impl ScreenBlock { @@ -147,7 +150,7 @@ impl ScreenBlock { pub fn as_texture_index(&self) -> usize { let num = ScreenBlock::attrs_to_index( - self.blink, + false, self.background, self.foreground, self.glyph @@ -166,9 +169,21 @@ pub fn block_to_canvas( textures: &Vec, x: u8, y: u8, - block: &ScreenBlock) { + block: &ScreenBlock, + blink: &bool +) { - let tex_idx = block.as_texture_index(); + 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, @@ -192,18 +207,30 @@ pub fn block_to_canvas( }; } -pub fn render(canvas: &mut WindowCanvas, textures: &Vec, screen: &[ScreenBlock]) { +pub fn update(elapsed: u128) { + //println!("Updated after {} nanoseconds.", elapsed); +} + +pub fn render(canvas: &mut WindowCanvas, textures: &Vec, screen: &[ScreenBlock], blink: &bool) { canvas.set_draw_color(EgaColors::from_enum(EgaColors::Black)); 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); + block_to_canvas(canvas, &textures, x, y, block, blink); } canvas.present(); } +pub fn get_timestamp_in_nanos() -> Result { + let current_systime = SystemTime::now(); + let since_epoch = current_systime.duration_since(UNIX_EPOCH)?; + let nanos = since_epoch.as_nanos(); + + Ok(nanos) +} + pub fn main() { let sdl_context = match sdl2::init() { Ok(sdl_context) => sdl_context, @@ -275,14 +302,30 @@ pub fn main() { dos_screen[idx] = ScreenBlock::new(false, EgaColors::as_u8(EgaColors::Black), EgaColors::as_u8(EgaColors::BrightYellow), 178); } - render(&mut canvas, &glyph_textures, &dos_screen); + dos_screen[1030] = ScreenBlock::new(true, EgaColors::as_u8(EgaColors::Blue), EgaColors::as_u8(EgaColors::LightGray), 178); + + let mut blink_tick: u128 = 0; + let mut blink_state: bool = false; + + render(&mut canvas, &glyph_textures, &dos_screen, &blink_state); 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), }; + let mut prev_tick = match get_timestamp_in_nanos() { + Ok(prev_tick) => prev_tick, + Err(err) => panic!("Could not get the current timestamp: {}", err), + }; + 'running: loop { + let curr_tick = match get_timestamp_in_nanos() { + Ok(curr_tick) => curr_tick, + Err(err) => panic!("Could not get the current timestamp: {}", err), + }; + let elapsed = curr_tick - prev_tick; + for event in event_pump.poll_iter() { match event { Event::Quit {..} | @@ -293,7 +336,18 @@ pub fn main() { } } - render(&mut canvas, &glyph_textures, &dos_screen); - sleep(Duration::new(0, 1_000_000_000u32 / 60)); + update(elapsed); + + if blink_tick >= BLINK_RATE { + blink_state = !blink_state; + blink_tick = 0; + } else { + blink_tick += elapsed; + } + + render(&mut canvas, &glyph_textures, &dos_screen, &blink_state); + //sleep(Duration::new(0, FPS_60_HERTZ)); + + prev_tick = curr_tick; } }