microbit_common/display/nonblocking/
image.rs

1//! Static 5×5 greyscale and black-and-white images.
2
3use tiny_led_matrix::{Render, MAX_BRIGHTNESS};
4
5/// A 5×5 image supporting the full range of brightnesses for each LED.
6///
7/// Uses 25 bytes of storage.
8#[derive(Copy, Clone, Debug)]
9pub struct GreyscaleImage([[u8; 5]; 5]);
10
11impl GreyscaleImage {
12    /// Constructs a GreyscaleImage from an array of brightnesses.
13    ///
14    /// The data should be an array of 5 rows (top first), each of which is an
15    /// array of 5 brightness values (left first).
16    ///
17    /// # Example
18    ///
19    /// ```no_run
20    /// # use microbit_common as microbit;
21    /// # use microbit::display::nonblocking::GreyscaleImage;
22    /// const GREY_HEART: GreyscaleImage = GreyscaleImage::new(&[
23    ///     [0, 9, 0, 9, 0],
24    ///     [9, 5, 9, 5, 9],
25    ///     [9, 5, 5, 5, 9],
26    ///     [0, 9, 5, 9, 0],
27    ///     [0, 0, 9, 0, 0],
28    /// ]);
29    /// ```
30    pub const fn new(data: &[[u8; 5]; 5]) -> GreyscaleImage {
31        GreyscaleImage(*data)
32    }
33
34    /// Construct a GreyscaleImage with all LEDs turned off.
35    pub const fn blank() -> GreyscaleImage {
36        GreyscaleImage([[0; 5]; 5])
37    }
38}
39
40impl Render for GreyscaleImage {
41    fn brightness_at(&self, x: usize, y: usize) -> u8 {
42        self.0[y][x]
43    }
44}
45
46impl Render for &GreyscaleImage {
47    fn brightness_at(&self, x: usize, y: usize) -> u8 {
48        GreyscaleImage::brightness_at(self, x, y)
49    }
50}
51
52/// A 5×5 image supporting only two levels of brightness (on and off).
53///
54/// Uses 5 bytes of storage.
55///
56/// For display, each pixel is treated as having brightness either 0 or
57/// MAX_BRIGHTNESS.
58#[derive(Copy, Clone, Debug)]
59pub struct BitImage([u8; 5]);
60
61impl BitImage {
62    /// Constructs a BitImage from an array of brightnesses.
63    ///
64    /// The data should be an array of 5 rows (top first), each of which is an
65    /// array of 5 values (left first). Each value should be either 0 or 1.
66    ///
67    /// # Example
68    ///
69    /// ```no_run
70    /// # use microbit_common as microbit;
71    /// # use microbit::display::nonblocking::BitImage;
72    /// const HEART: BitImage = BitImage::new(&[
73    ///     [0, 1, 0, 1, 0],
74    ///     [1, 0, 1, 0, 1],
75    ///     [1, 0, 0, 0, 1],
76    ///     [0, 1, 0, 1, 0],
77    ///     [0, 0, 1, 0, 0],
78    /// ]);
79    /// ```
80    pub const fn new(im: &[[u8; 5]; 5]) -> BitImage {
81        // FIXME: can we reject values other than 0 or 1?
82        const fn row_byte(row: [u8; 5]) -> u8 {
83            row[0] | (row[1] << 1) | (row[2] << 2) | (row[3] << 3) | (row[4] << 4)
84        }
85        BitImage([
86            row_byte(im[0]),
87            row_byte(im[1]),
88            row_byte(im[2]),
89            row_byte(im[3]),
90            row_byte(im[4]),
91        ])
92    }
93
94    /// Returns a new blank BitImage.
95    ///
96    /// All pixel values are 0.
97    pub const fn blank() -> BitImage {
98        BitImage([0; 5])
99    }
100}
101
102impl Render for BitImage {
103    fn brightness_at(&self, x: usize, y: usize) -> u8 {
104        let rowdata = self.0[y];
105        if rowdata & (1 << x) != 0 {
106            MAX_BRIGHTNESS
107        } else {
108            0
109        }
110    }
111}
112
113impl Render for &BitImage {
114    fn brightness_at(&self, x: usize, y: usize) -> u8 {
115        BitImage::brightness_at(self, x, y)
116    }
117}