Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VGA palette loader #203

Merged
merged 2 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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