poppin/kernel/src/std/vga/video/mod.rs
2024-09-11 02:30:48 +03:00

121 lines
3.5 KiB
Rust

mod util;
use embedded_graphics::{pixelcolor::Rgb888, prelude::{DrawTarget, OriginDimensions, PixelColor, RgbColor, Size}};
use multiboot2::{BootInformation, BootInformationHeader, FramebufferTag, FramebufferType, TagTrait};
pub use util::is_video_mode_enabled;
#[derive(Clone, Copy)]
pub struct Color {
r: u8,
g: u8,
b: u8,
}
impl Color {
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self {r, g, b}
}
}
#[derive(Clone, Copy)]
pub struct VideoControler{
component_size: u8,
r_ofs: u8,
g_ofs: u8,
b_ofs: u8,
buf_addr: u64,
pitch: usize,
size: [usize; 2],
bpp: u8
}
impl VideoControler {
pub fn new(mb2p: *const BootInformationHeader) -> Self {
let boot_info = unsafe { BootInformation::load(mb2p).unwrap() };
let fbt = boot_info.framebuffer_tag().unwrap().unwrap();
let FramebufferType::RGB { red, green, blue } = fbt.buffer_type().unwrap() else {
panic!();
};
assert!(red.size == green.size && green.size == blue.size);
log::info!("VGA VIDEO addr: {:x}", fbt.address());
log::info!("{fbt:#?}");
Self {
component_size: red.size,
r_ofs: red.position,
g_ofs: green.position,
b_ofs: blue.position,
buf_addr: fbt.address(),
size: [fbt.width() as usize, fbt.height() as usize],
pitch: fbt.pitch() as usize,
bpp: fbt.bpp(),
}
}
pub fn set_px(&self, x: usize, y: usize, c: Color) {
assert!(x <= self.size[0] && y <= self.size[1]);
let ptr = self.buf_addr as *mut () as *mut u8;
let px = ptr.wrapping_add((self.bpp / 8) as usize * x + self.pitch * y);
unsafe {
*px.wrapping_add((self.r_ofs / 8) as usize) = c.r;
*px.wrapping_add((self.g_ofs / 8) as usize) = c.g;
*px.wrapping_add((self.b_ofs / 8) as usize) = c.b;
}
}
pub fn fill_screen(&self, c: Color) {
for x in 0..self.size[0] {
for y in 0..self.size[1] {
self.set_px(x, y, c);
}
}
}
pub fn fill_screen_grad(&self, start: Color, end: Color) {
let diag = libm::sqrt((self.size[0].pow(2) + self.size[1].pow(2)) as f64);
for x in 0..self.size[0] {
for y in 0..self.size[1] {
let dist = libm::sqrt((x.pow(2) + y.pow(2)) as f64);
let fact = dist / diag;
let color = Color::new(
start.r + (fact * (end.r - start.r) as f64) as u8,
start.g + (fact * (end.g - start.g) as f64) as u8,
start.b + (fact * (end.b - start.b) as f64) as u8,
);
self.set_px(x, y, color);
}
}
}
}
impl DrawTarget for VideoControler {
type Color = Rgb888;
type Error = &'static str;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>> {
for px in pixels {
self.set_px(
px.0.x as usize,
px.0.y as usize,
px.1.into()
)
}
Ok(())
}
}
impl OriginDimensions for VideoControler {
fn size(&self) -> embedded_graphics::prelude::Size {
Size::new(self.size[0] as u32, self.size[1] as u32)
}
}
impl From<Rgb888> for Color {
fn from(c: Rgb888) -> Self {
Color::new(c.r(), c.g(), c.b())
}
}