117 lines
2.3 KiB
Rust
117 lines
2.3 KiB
Rust
use core::slice;
|
|
use rand::seq::IndexedRandom;
|
|
|
|
use crate::RNG;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum VgaColor {
|
|
Black,
|
|
Gray,
|
|
Blue,
|
|
Cyan,
|
|
Orange,
|
|
Red,
|
|
Green,
|
|
Purple,
|
|
Yellow,
|
|
}
|
|
|
|
impl VgaColor {
|
|
pub fn as_u8(self) -> u8 {
|
|
match self {
|
|
Self::Black => 0b0000_0000,
|
|
Self::Gray => 0b1110_0000,
|
|
Self::Blue => 0b0000_0001,
|
|
Self::Cyan => 0b0000_0011,
|
|
Self::Orange => 0b0000_0110,
|
|
Self::Red => 0b0000_0100,
|
|
Self::Green => 0b0000_0010,
|
|
Self::Purple => 0b0000_0101,
|
|
Self::Yellow => 0b1100_0000,
|
|
}
|
|
}
|
|
|
|
/// Pick a random non-utility color
|
|
pub fn choose_rand() -> Self {
|
|
let colors = [
|
|
VgaColor::Blue,
|
|
VgaColor::Cyan,
|
|
VgaColor::Orange,
|
|
VgaColor::Red,
|
|
VgaColor::Green,
|
|
VgaColor::Purple,
|
|
VgaColor::Yellow,
|
|
];
|
|
|
|
let mut rng = RNG.lock();
|
|
*(colors.choose(&mut rng).unwrap())
|
|
}
|
|
}
|
|
|
|
/// VGA driver for mode 0x13:
|
|
///
|
|
/// - mode: graphics
|
|
/// - text res: 40x25
|
|
/// - pixel box: 8x8
|
|
/// - pixel res: 320x200
|
|
/// - colors: 256/256k
|
|
/// - addr: A000
|
|
/// - pixel format: RRRGGGBB
|
|
pub struct Vga13h {
|
|
// Double frame buffers
|
|
fb_a: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
|
|
fb_b: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
|
|
|
|
/// If true, show fb_a (and write to fb_b).
|
|
/// if false, show fb_b.
|
|
show_fb_a: bool,
|
|
}
|
|
|
|
impl Vga13h {
|
|
pub const WIDTH: usize = 320;
|
|
pub const HEIGHT: usize = 200;
|
|
pub const ADDR: usize = 0xA0000;
|
|
|
|
/// Initialize a new VGA driver.
|
|
///
|
|
/// Only one of these should exist.
|
|
pub const unsafe fn new() -> Self {
|
|
Self {
|
|
fb_a: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
|
|
fb_b: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
|
|
show_fb_a: true,
|
|
}
|
|
}
|
|
|
|
unsafe fn segment(&mut self) -> &'static mut [u8] {
|
|
slice::from_raw_parts_mut(Vga13h::ADDR as *mut u8, Vga13h::WIDTH * Vga13h::HEIGHT)
|
|
}
|
|
|
|
pub fn swap(&mut self) {
|
|
let seg = unsafe { self.segment() };
|
|
if self.show_fb_a {
|
|
seg.copy_from_slice(&self.fb_b);
|
|
self.show_fb_a = false;
|
|
self.fb_a.fill(0);
|
|
} else {
|
|
seg.copy_from_slice(&self.fb_a);
|
|
self.show_fb_a = true;
|
|
self.fb_b.fill(0);
|
|
}
|
|
}
|
|
|
|
pub fn get_fb(&mut self) -> &mut [u8; Vga13h::WIDTH * Vga13h::HEIGHT] {
|
|
if self.show_fb_a {
|
|
&mut self.fb_b
|
|
} else {
|
|
&mut self.fb_a
|
|
}
|
|
}
|
|
|
|
pub fn pix_idx(x: usize, y: usize) -> usize {
|
|
debug_assert!(x < Vga13h::WIDTH);
|
|
debug_assert!(y < Vga13h::HEIGHT);
|
|
return y * Vga13h::WIDTH + x;
|
|
}
|
|
}
|