Implemented character blinking.

This commit is contained in:
Josh W 2023-11-24 15:44:42 -05:00
parent 428079cf6b
commit 7802d55b5c

View file

@ -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<Texture>,
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<Texture>, screen: &[ScreenBlock]) {
pub fn update(elapsed: u128) {
//println!("Updated after {} nanoseconds.", elapsed);
}
pub fn render(canvas: &mut WindowCanvas, textures: &Vec<Texture>, 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<u128, SystemTimeError> {
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;
}
}