lcd_async/
raw_framebuf.rs1use embedded_graphics::{
56 draw_target::DrawTarget,
57 geometry::{Dimensions, OriginDimensions},
58 pixelcolor::{raw::RawU16, PixelColor, RgbColor},
59 prelude::*,
60 primitives::Rectangle,
61 Pixel,
62};
63
64pub trait IntoRawBytes: PixelColor + Sized {
70 const BYTES_PER_PIXEL: usize;
72
73 type Raw: AsRef<[u8]> + AsMut<[u8]> + Copy + Default;
75
76 fn into_raw_bytes(self) -> <Self as IntoRawBytes>::Raw;
78}
79
80impl IntoRawBytes for embedded_graphics::pixelcolor::Rgb565 {
81 const BYTES_PER_PIXEL: usize = 2;
82 type Raw = [u8; 2];
83
84 fn into_raw_bytes(self) -> <Self as IntoRawBytes>::Raw {
85 RawU16::from(self).into_inner().to_be_bytes()
86 }
87}
88
89impl IntoRawBytes for embedded_graphics::pixelcolor::Rgb666 {
90 const BYTES_PER_PIXEL: usize = 3;
91 type Raw = [u8; 3];
92
93 fn into_raw_bytes(self) -> <Self as IntoRawBytes>::Raw {
95 [self.r() * 4, self.g() * 4, self.b() * 4]
96 }
97}
98
99impl IntoRawBytes for embedded_graphics::pixelcolor::Rgb888 {
100 const BYTES_PER_PIXEL: usize = 3;
101 type Raw = [u8; 3];
102
103 fn into_raw_bytes(self) -> <Self as IntoRawBytes>::Raw {
104 [self.r(), self.g(), self.b()]
105 }
106}
107
108pub trait RawBufferBackendMut {
114 fn as_mut_u8_slice(&mut self) -> &mut [u8];
116
117 fn as_u8_slice(&self) -> &[u8];
119
120 fn u8_len(&self) -> usize;
122}
123
124impl RawBufferBackendMut for &mut [u8] {
125 fn as_mut_u8_slice(&mut self) -> &mut [u8] {
126 self
127 }
128
129 fn as_u8_slice(&self) -> &[u8] {
130 self
131 }
132
133 fn u8_len(&self) -> usize {
134 self.len()
135 }
136}
137
138pub struct RawFrameBuf<C, BUF>
144where
145 C: IntoRawBytes,
146 BUF: RawBufferBackendMut,
147{
148 buffer: BUF,
149 width: usize,
150 height: usize,
151 _phantom_color: core::marker::PhantomData<C>,
152}
153
154impl<C, BUF> RawFrameBuf<C, BUF>
155where
156 C: IntoRawBytes,
157 BUF: RawBufferBackendMut,
158{
159 pub fn new(buffer: BUF, width: usize, height: usize) -> Self {
165 let expected_len = width * height * C::BYTES_PER_PIXEL;
166 assert!(
167 buffer.u8_len() >= expected_len,
168 "RawFrameBuf underlying buffer is too small. Expected at least {}, got {}.",
169 expected_len,
170 buffer.u8_len()
171 );
172 Self {
173 buffer,
174 width,
175 height,
176 _phantom_color: core::marker::PhantomData,
177 }
178 }
179
180 pub fn width(&self) -> usize {
182 self.width
183 }
184
185 pub fn height(&self) -> usize {
187 self.height
188 }
189
190 pub fn as_bytes(&self) -> &[u8] {
192 let expected_len = self.width * self.height * C::BYTES_PER_PIXEL;
193 &self.buffer.as_u8_slice()[0..expected_len]
194 }
195
196 pub fn as_mut_bytes(&mut self) -> &mut [u8] {
198 let expected_len = self.width * self.height * C::BYTES_PER_PIXEL;
199 &mut self.buffer.as_mut_u8_slice()[0..expected_len]
200 }
201}
202
203impl<C, BUF> OriginDimensions for RawFrameBuf<C, BUF>
204where
205 C: IntoRawBytes,
206 BUF: RawBufferBackendMut,
207{
208 fn size(&self) -> Size {
209 Size::new(self.width as u32, self.height as u32)
210 }
211}
212
213impl<C, BUF> DrawTarget for RawFrameBuf<C, BUF>
214where
215 C: IntoRawBytes,
216 BUF: RawBufferBackendMut,
217{
218 type Color = C;
219 type Error = core::convert::Infallible;
220
221 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
222 where
223 I: IntoIterator<Item = Pixel<Self::Color>>,
224 {
225 let bounding_box = self.bounding_box();
226 let current_width = self.width;
227
228 let buffer_slice = self.buffer.as_mut_u8_slice();
229 let active_buffer_len = self.width * self.height * C::BYTES_PER_PIXEL;
230
231 for Pixel(coord, color) in pixels.into_iter() {
232 if bounding_box.contains(coord) {
233 let byte_index =
234 (coord.y as usize * current_width + coord.x as usize) * C::BYTES_PER_PIXEL;
235
236 let color_bytes = color.into_raw_bytes();
237
238 if byte_index + C::BYTES_PER_PIXEL <= active_buffer_len {
239 buffer_slice[byte_index..byte_index + C::BYTES_PER_PIXEL]
240 .copy_from_slice(color_bytes.as_ref());
241 }
242 }
243 }
244 Ok(())
245 }
246
247 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
248 let color_bytes_array = color.into_raw_bytes();
249 let color_bytes = color_bytes_array.as_ref();
250
251 let buffer_slice = self.buffer.as_mut_u8_slice();
252 let active_buffer_len = self.width * self.height * C::BYTES_PER_PIXEL;
253 let active_slice = &mut buffer_slice[0..active_buffer_len];
254
255 let all_bytes_same = if let Some(first) = color_bytes.first() {
256 color_bytes.iter().all(|&b| b == *first)
257 } else {
258 true
259 };
260
261 if all_bytes_same && !color_bytes.is_empty() {
262 active_slice.fill(color_bytes[0]);
263 } else if C::BYTES_PER_PIXEL > 0 {
264 for chunk in active_slice.chunks_exact_mut(C::BYTES_PER_PIXEL) {
265 chunk.copy_from_slice(color_bytes);
266 }
267 }
268 Ok(())
269 }
270
271 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
272 let drawable_area = area.intersection(&self.bounding_box());
273 if drawable_area.is_zero_sized() {
274 return Ok(());
275 }
276
277 let color_bytes_array = color.into_raw_bytes();
278 let color_bytes = color_bytes_array.as_ref();
279
280 let current_width = self.width;
281 let buffer_slice = self.buffer.as_mut_u8_slice();
282
283 for p in drawable_area.points() {
284 let byte_index = (p.y as usize * current_width + p.x as usize) * C::BYTES_PER_PIXEL;
285
286 if byte_index + C::BYTES_PER_PIXEL <= buffer_slice.len() {
287 buffer_slice[byte_index..byte_index + C::BYTES_PER_PIXEL]
288 .copy_from_slice(color_bytes);
289 }
290 }
291 Ok(())
292 }
293}