endbasic_std/gfx/lcd/
mod.rs1use crate::console::{RGB, SizeInPixels};
19use std::convert::TryFrom;
20use std::io;
21
22mod buffered;
23pub mod fonts;
24
25pub use buffered::BufferedLcd;
26
27pub trait AsByteSlice {
29 fn as_slice(&self) -> &[u8];
31}
32
33#[derive(Clone, Copy)]
35pub struct RGB565Pixel(pub [u8; 2]);
36
37impl AsByteSlice for RGB565Pixel {
38 fn as_slice(&self) -> &[u8] {
39 &self.0
40 }
41}
42
43pub trait Lcd {
45 type Pixel: AsByteSlice + Copy;
47
48 fn info(&self) -> (LcdSize, usize);
50
51 fn decode(&self, pixel: &[u8]) -> RGB;
53
54 fn encode(&self, rgb: RGB) -> Self::Pixel;
56
57 fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()>;
60}
61
62#[derive(Clone, Copy)]
64#[cfg_attr(test, derive(Debug, PartialEq))]
65pub struct LcdXY {
66 pub x: usize,
68
69 pub y: usize,
71}
72
73#[derive(Clone, Copy)]
75#[cfg_attr(test, derive(Debug, PartialEq))]
76pub struct LcdSize {
77 pub width: usize,
79
80 pub height: usize,
82}
83
84impl LcdSize {
85 fn between(x1y1: LcdXY, x2y2: LcdXY) -> Self {
87 debug_assert!(x2y2.x >= x1y1.x);
88 debug_assert!(x2y2.y >= x1y1.y);
89 Self { width: x2y2.x - x1y1.x + 1, height: x2y2.y - x1y1.y + 1 }
90 }
91
92 fn new_buffer(&self, stride: usize) -> Vec<u8> {
95 Vec::with_capacity(self.width * self.height * stride)
96 }
97}
98
99impl From<LcdSize> for SizeInPixels {
100 fn from(value: LcdSize) -> Self {
101 Self::new(
102 u16::try_from(value.width).expect("Must fit"),
103 u16::try_from(value.height).expect("Must fit"),
104 )
105 }
106}
107
108pub fn to_xy_size(x1y1: LcdXY, x2y2: LcdXY) -> (LcdXY, LcdSize) {
110 let x1 = std::cmp::min(x1y1.x, x2y2.x);
111 let y1 = std::cmp::min(x1y1.y, x2y2.y);
112
113 let x2 = std::cmp::max(x1y1.x, x2y2.x);
114 let y2 = std::cmp::max(x1y1.y, x2y2.y);
115
116 (LcdXY { x: x1, y: y1 }, LcdSize { width: x2 + 1 - x1, height: y2 + 1 - y1 })
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 fn xy(x: usize, y: usize) -> LcdXY {
125 LcdXY { x, y }
126 }
127
128 fn size(width: usize, height: usize) -> LcdSize {
130 LcdSize { width, height }
131 }
132
133 #[test]
134 fn test_lcdsize_between_one_pixel() {
135 assert_eq!(size(1, 1), LcdSize::between(xy(15, 16), xy(15, 16)));
136 }
137
138 #[test]
139 fn test_lcdsize_between_rect() {
140 assert_eq!(size(4, 5), LcdSize::between(xy(10, 25), xy(13, 29)));
141 }
142
143 #[test]
144 fn test_lcdsize_new_buffer() {
145 let buffer = size(10, 20).new_buffer(3);
146 assert_eq!(10 * 20 * 3, buffer.capacity());
147 }
148
149 #[test]
150 fn test_to_xy_size_one_pixel() {
151 assert_eq!(
152 (LcdXY { x: 10, y: 20 }, LcdSize { width: 1, height: 1 }),
153 to_xy_size(xy(10, 20), xy(10, 20))
154 );
155 }
156
157 #[test]
158 fn test_to_xy_size_rect() {
159 assert_eq!(
160 (LcdXY { x: 10, y: 20 }, LcdSize { width: 5, height: 7 }),
161 to_xy_size(xy(10, 20), xy(14, 26))
162 );
163 }
164}