use bootloader_api::info::FrameBuffer; use embedded_graphics::{ draw_target::DrawTarget, geometry::{Dimensions, OriginDimensions, Point, Size}, mono_font::{ascii::FONT_6X10, MonoTextStyle}, pixelcolor::{Rgb888, RgbColor}, primitives::{ Circle, Primitive, PrimitiveStyle, PrimitiveStyleBuilder, Rectangle, StrokeAlignment, Triangle, }, text::{Alignment, Text}, Drawable, Pixel, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Position { pub x: usize, pub y: usize, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Color { pub red: u8, pub green: u8, pub blue: u8, } pub fn set_pixel_in(framebuffer: &mut FrameBuffer, position: Position, color: Color) { let info = framebuffer.info(); let byte_offset = { let line_offset = position.y * info.stride; let pixel_offset = line_offset + position.x; pixel_offset * info.bytes_per_pixel }; let pixel_buffer = &mut framebuffer.buffer_mut()[byte_offset..]; match info.pixel_format { bootloader_api::info::PixelFormat::Rgb => { pixel_buffer[0] = color.red; pixel_buffer[1] = color.green; pixel_buffer[2] = color.blue; } bootloader_api::info::PixelFormat::Bgr => { pixel_buffer[0] = color.blue; pixel_buffer[1] = color.green; pixel_buffer[2] = color.red; } bootloader_api::info::PixelFormat::U8 => { let gray = color.red / 3 + color.green / 3 + color.blue / 3; pixel_buffer[0] = gray; } other => panic!("unknown pixel format {other:?}"), } } pub struct Display<'a> { framebuffer: &'a mut FrameBuffer, } impl<'a> Display<'a> { pub fn new(framebuffer: &'a mut FrameBuffer) -> Self { Self { framebuffer } } fn draw_pixel(&mut self, pos: Position, color: Color) { let (width, height) = { let info = self.framebuffer.info(); (info.width, info.height) }; if pos.x >= width || pos.y >= height { return; } set_pixel_in(&mut self.framebuffer, pos, color); } } impl OriginDimensions for Display<'_> { fn size(&self) -> embedded_graphics::prelude::Size { let info = self.framebuffer.info(); Size { width: info.width as u32, height: info.height as u32, } } } impl DrawTarget for Display<'_> { type Color = Rgb888; type Error = core::convert::Infallible; fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> where I: IntoIterator>, { for Pixel(coordinates, color) in pixels.into_iter() { self.draw_pixel( Position { x: coordinates.x as usize, y: coordinates.y as usize, }, Color { red: color.r(), green: color.g(), blue: color.b(), }, ); } Ok(()) } } pub fn draw_test(framebuffer: &mut FrameBuffer) { for b in framebuffer.buffer_mut() { *b = 0; } let mut display = Display::new(framebuffer); // Create styles used by the drawing operations. let thin_stroke = PrimitiveStyle::with_stroke(Rgb888::new(0, 255, 255), 1); let thick_stroke = PrimitiveStyle::with_stroke(Rgb888::new(0, 255, 255), 3); let border_stroke = PrimitiveStyleBuilder::new() .stroke_color(Rgb888::new(0, 255, 255)) .stroke_width(3) .stroke_alignment(StrokeAlignment::Inside) .build(); let fill = PrimitiveStyle::with_fill(Rgb888::new(0, 255, 255)); let character_style = MonoTextStyle::new(&FONT_6X10, Rgb888::new(0, 255, 255)); let yoffset = 10; // Draw a 3px wide outline around the display. display .bounding_box() .into_styled(border_stroke) .draw(&mut display) .unwrap(); Rectangle::new(Point::new(52, yoffset), Size::new(16, 16)) .into_styled(fill) .draw(&mut display) .unwrap(); // Draw a triangle. Triangle::new( Point::new(16, 16 + yoffset), Point::new(16 + 16, 16 + yoffset), Point::new(16 + 8, yoffset), ) .into_styled(thin_stroke) .draw(&mut display) .unwrap(); // Draw a filled square Rectangle::new(Point::new(52, yoffset), Size::new(16, 16)) .into_styled(fill) .draw(&mut display) .unwrap(); // Draw a circle with a 3px wide stroke. Circle::new(Point::new(88, yoffset), 17) .into_styled(thick_stroke) .draw(&mut display) .unwrap(); // Draw centered text. let text = "jugando"; Text::with_alignment( text, display.bounding_box().center() + Point::new(0, 15), character_style, Alignment::Center, ) .draw(&mut display) .unwrap(); }