vexide_graphics/
embedded_graphics.rs

1//! Embedded-graphics driver for the V5 Brain display.
2
3use embedded_graphics_core::{pixelcolor::Rgb888, prelude::*, primitives::Rectangle};
4use vexide_devices::{display::Display, rgb::Rgb};
5
6fn rgb_into_raw(rgb: Rgb<u8>) -> u32 {
7    (u32::from(rgb.r) << 16) + (u32::from(rgb.g) << 8) + u32::from(rgb.b)
8}
9
10/// An embedded-graphics draw target for the V5 Brain display
11/// Currently, this does not support touch detection like the regular [`Display`] API.
12pub struct BrainDisplay {
13    display: Display,
14    triple_buffer:
15        [u32; Display::HORIZONTAL_RESOLUTION as usize * Display::VERTICAL_RESOLUTION as usize],
16}
17impl BrainDisplay {
18    /// Create a new [`BrainDisplay`] from a [`Display`].
19    /// The display must be moved into this struct,
20    /// as it is used to render the display and having multiple mutable references to it is unsafe.
21    #[must_use]
22    pub fn new(mut display: Display) -> Self {
23        display.set_render_mode(vexide_devices::display::RenderMode::DoubleBuffered);
24        Self {
25            display,
26            #[allow(clippy::large_stack_arrays)] // we got plenty
27            triple_buffer: [0; Display::HORIZONTAL_RESOLUTION as usize
28                * Display::VERTICAL_RESOLUTION as usize],
29        }
30    }
31}
32impl Dimensions for BrainDisplay {
33    fn bounding_box(&self) -> Rectangle {
34        Rectangle::new(
35            Point::new(0, 0),
36            Size::new(
37                Display::HORIZONTAL_RESOLUTION as _,
38                Display::VERTICAL_RESOLUTION as _,
39            ),
40        )
41    }
42}
43impl DrawTarget for BrainDisplay {
44    type Color = Rgb888;
45
46    type Error = !;
47
48    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
49    where
50        I: IntoIterator<Item = Pixel<Self::Color>>,
51    {
52        pixels
53            .into_iter()
54            .map(|p| (p.0, rgb_into_raw(Rgb::new(p.1.r(), p.1.g(), p.1.b()))))
55            .for_each(|(pos, col)| {
56                self.triple_buffer
57                    [pos.y as usize * Display::HORIZONTAL_RESOLUTION as usize + pos.x as usize] =
58                    col;
59            });
60
61        unsafe {
62            vex_sdk::vexDisplayCopyRect(
63                0,
64                0x20,
65                Display::HORIZONTAL_RESOLUTION.into(),
66                Display::VERTICAL_RESOLUTION.into(),
67                self.triple_buffer.as_mut_ptr(),
68                Display::HORIZONTAL_RESOLUTION.into(),
69            );
70        };
71        self.display.render();
72
73        Ok(())
74    }
75}