Skip to content

Commit

Permalink
Add VGA palette loader (#203)
Browse files Browse the repository at this point in the history
* Add VGA palette loader

* Update screenshot
  • Loading branch information
vinc authored Jul 13, 2021
1 parent 9ca1429 commit 46de848
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 32 deletions.
1 change: 1 addition & 0 deletions dsk/ini/boot.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vga set palette /ini/palette.csv
vga set font /ini/fonts/zap-light-8x16.psf
read /ini/banner.txt
user login
Expand Down
18 changes: 18 additions & 0 deletions dsk/ini/palette.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# VGA Palette File (Index, Red, Green, Blue)
# Dark Gruvbox color palette
0x00, 0x28, 0x28, 0x28 # Black
0x01, 0x45, 0x85, 0x88 # Blue
0x02, 0x98, 0x97, 0x1A # Green
0x03, 0x68, 0x9D, 0x6A # Cyan
0x04, 0xCC, 0x24, 0x1D # Red
0x05, 0xB1, 0x62, 0x86 # Magenta
0x06, 0xD7, 0x99, 0x21 # Brown (Dark Yellow)
0x07, 0xEB, 0xDB, 0xB2 # Light Gray
0x08, 0xA8, 0x99, 0x84 # Dark Gray (Gray)
0x09, 0x83, 0xa5, 0x98 # Light Blue
0x0A, 0xB8, 0xBB, 0x26 # Light Green
0x0B, 0x8E, 0xC0, 0x7C # Light Cyan
0x0C, 0xFB, 0x49, 0x34 # Light Red
0x0D, 0xD3, 0x86, 0x9B # Pink (Light Magenta)
0x0E, 0xFA, 0xBD, 0x2F # Yellow (Light Yellow)
0x0F, 0xFB, 0xF1, 0xF7 # White
Binary file modified moros.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 48 additions & 32 deletions src/kernel/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,29 @@ fn color_from_ansi(code: u8) -> Color {
}
}

impl Color {
fn to_palette_code(&self) -> u8 {
match self {
Color::Black => 0x00,
Color::Blue => 0x01,
Color::Green => 0x02,
Color::Cyan => 0x03,
Color::Red => 0x04,
Color::Magenta => 0x05,
Color::LightGray => 0x07,
Color::Brown => 0x14,
Color::DarkGray => 0x38,
Color::LightBlue => 0x39,
Color::LightGreen => 0x3A,
Color::LightCyan => 0x3B,
Color::LightRed => 0x3C,
Color::Pink => 0x3D,
Color::Yellow => 0x3E,
Color::White => 0x3F,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
struct ColorCode(u8);
Expand Down Expand Up @@ -278,6 +301,22 @@ impl Writer {
}
}

pub fn set_palette(&mut self, palette: Palette) {
let mut addr: Port<u8> = Port::new(0x03C8); // Address Write Mode Register
let mut data: Port<u8> = Port::new(0x03C9); // Data Register
for (i, r, g, b) in palette.colors {
if i < 16 {
let code = COLORS[i as usize].to_palette_code();
unsafe {
addr.write(code);
data.write(r >> 2); // Convert 8-bit color to 6-bit color
data.write(g >> 2);
data.write(b >> 2);
}
}
}
}

}

/// See https://vt100.net/emu/dec_ansi_parser
Expand Down Expand Up @@ -413,25 +452,15 @@ pub fn set_font(font: &Font) {
})
}

// Dark Gruvbox color palette
const PALETTE: [(u8, u8, u8, u8); 16] = [
(0x00, 0x28, 0x28, 0x28), // Black
(0x01, 0x45, 0x85, 0x88), // Blue
(0x02, 0x98, 0x97, 0x1A), // Green
(0x03, 0x68, 0x9D, 0x6A), // Cyan
(0x04, 0xCC, 0x24, 0x1D), // Red
(0x05, 0xB1, 0x62, 0x86), // Magenta
(0x07, 0xEB, 0xDB, 0xB2), // Light Gray
(0x14, 0xD7, 0x99, 0x21), // Brown (Dark Yellow)
(0x38, 0xA8, 0x99, 0x84), // Gray (Dark Gray)
(0x39, 0x83, 0xa5, 0x98), // Light Blue
(0x3A, 0xB8, 0xBB, 0x26), // Light Green
(0x3B, 0x8E, 0xC0, 0x7C), // Light Cyan
(0x3C, 0xFB, 0x49, 0x34), // Light Red
(0x3D, 0xD3, 0x86, 0x9B), // Pink (Light Magenta)
(0x3E, 0xFA, 0xBD, 0x2F), // Yellow (Light Yellow)
(0x3F, 0xFB, 0xF1, 0xF7), // White
];
pub fn set_palette(palette: Palette) {
interrupts::without_interrupts(|| {
WRITER.lock().set_palette(palette)
})
}

pub struct Palette {
pub colors: [(u8, u8, u8, u8); 16]
}

pub fn init() {
let mut isr: Port<u8> = Port::new(0x03DA); // Input Status Register
Expand All @@ -445,17 +474,4 @@ pub fn init() {
let value = adrr.read(); // Read attribute mode control register
aadr.write(value & !0x08); // Use `value | 0x08` to enable and `value ^ 0x08` to toggle
}


// Load color palette
let mut addr: Port<u8> = Port::new(0x03C8); // Address Write Mode Register
let mut data: Port<u8> = Port::new(0x03C9); // Data Register
for (i, r, g, b) in &PALETTE {
unsafe {
addr.write(*i);
data.write(*r >> 2); // Convert 8-bit color to 6-bit color
data.write(*g >> 2);
data.write(*b >> 2);
}
}
}
1 change: 1 addition & 0 deletions src/user/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
copy_file("/ini/boot.sh", include_bytes!("../../dsk/ini/boot.sh"));
copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt"));
copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt"));
copy_file("/ini/palette.csv", include_bytes!("../../dsk/ini/palette.csv"));
copy_file("/tmp/alice.txt", include_bytes!("../../dsk/tmp/alice.txt"));

create_dir("/ini/fonts");
Expand Down
25 changes: 25 additions & 0 deletions src/user/vga.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{kernel, print, user};
use crate::kernel::vga::Palette;
use alloc::vec::Vec;
use core::convert::TryInto;

pub fn main(args: &[&str]) -> user::shell::ExitCode {
if args.len() == 1 {
Expand All @@ -21,6 +23,29 @@ pub fn main(args: &[&str]) -> user::shell::ExitCode {
return user::shell::ExitCode::CommandError;
}
}
} else if args.len() == 4 && args[2] == "palette" {
if let Some(file) = kernel::fs::File::open(args[3]) {
let mut colors = Vec::with_capacity(16);
for line in file.read_to_string().split("\n") {
let line = line.split("#").next().unwrap();
let color: Vec<u8> = line.split(",").filter_map(|value| {
let radix = if value.contains("0x") { 16 } else { 10 };
let value = value.trim().trim_start_matches("0x");
u8::from_str_radix(value, radix).ok()
}).collect();
if color.len() == 4 {
colors.push((color[0], color[1], color[2], color[3]));
}
}
if let Ok(colors) = colors.try_into() {
let palette = Palette { colors };
kernel::vga::set_palette(palette);
} else {
print!("Could not parse palette file\n");
return user::shell::ExitCode::CommandError;
}
}

} else {
print!("Invalid command\n");
return user::shell::ExitCode::CommandError;
Expand Down

0 comments on commit 46de848

Please sign in to comment.