use std::fs::OpenOptions;
use std::io;
use std::os::unix::io::AsRawFd;
use memmap::{MmapMut, MmapOptions};
pub mod sys;
use sys::fb_var_screeninfo;
use sys::get_var_screeninfo;
mod error;
pub use error::{Error, Result};
pub mod shape;
use shape::{Shape, Color};
mod compositor;
pub use compositor::{Compositor, CompositorBuilder};
#[cfg(feature = "text")]
mod text;
#[cfg(feature = "images")]
mod image;
pub struct Framebuffer {
screen: Vec<u8>,
pub screen_info: fb_var_screeninfo,
framebuffer: MmapMut,
}
impl Framebuffer {
pub fn open() -> io::Result<Self> {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(false)
.open("/dev/fb0")?;
let mut screen_info: fb_var_screeninfo = Default::default();
unsafe {
get_var_screeninfo(file.as_raw_fd(), &mut screen_info)
.expect("Failed to get var_screeninfo")
};
if screen_info.bits_per_pixel != 32 {
panic!("Size of one pixel must be 32 bits for linfb to work");
}
let framebuffer = unsafe {
MmapOptions::new()
.len(screen_info.overall_size())
.map_mut(&file)?
};
let screen = vec![0u8; framebuffer.len()];
Ok(Self {
screen,
framebuffer,
screen_info,
})
}
pub fn flush(&mut self) {
self.framebuffer.copy_from_slice(self.screen.as_slice());
}
pub fn set_pixel<C: Into<Color>>(&mut self, x: u32, y: u32, color: C) {
let color: Color = color.into();
let pixel_pos = ((y * self.screen_info.xres + x) * 4) as usize;
let mut pixel = 0u32;
pixel |= (color.red as u32) >> (8 - self.screen_info.red.length) << self.screen_info.red.offset;
pixel |= (color.green as u32) >> (8 - self.screen_info.green.length) << self.screen_info.green.offset;
pixel |= (color.blue as u32) >> (8 - self.screen_info.blue.length) << self.screen_info.blue.offset;
pixel |= (color.alpha as u32) >> (8 - self.screen_info.transp.length) << self.screen_info.transp.offset;
self.screen[pixel_pos..pixel_pos + 4].copy_from_slice(&pixel.to_ne_bytes());
}
pub fn draw<T: Shape>(&mut self, x: u32, y: u32, shape: &T) {
for (inner_y, row) in shape.render().iter().enumerate() {
for (inner_x, color) in row.iter().enumerate() {
if let Some(color) = color {
self.set_pixel(x + (inner_x as u32), y + (inner_y as u32), *color);
}
}
}
}
pub fn compositor(&self, background: Color) -> Compositor {
Compositor::new(self.screen_info.xres as usize, self.screen_info.yres as usize, background)
}
}