1use core::{convert::Infallible, marker::PhantomData};
4
5use crate::{
6 draw_target::DrawTarget,
7 geometry::{OriginDimensions, Point, Size},
8 image::{GetPixel, ImageRaw},
9 iterator::raw::RawDataSlice,
10 pixelcolor::{
11 raw::{
12 BigEndian, ByteOrder, LittleEndian, RawData, RawU1, RawU16, RawU2, RawU24, RawU32,
13 RawU4, RawU8, ToBytes,
14 },
15 PixelColor,
16 },
17 Pixel,
18};
19
20pub const fn buffer_size<C: PixelColor>(width: usize, height: usize) -> usize {
25 buffer_size_bpp(width, height, C::Raw::BITS_PER_PIXEL)
26}
27
28pub const fn buffer_size_bpp(width: usize, height: usize, bpp: usize) -> usize {
33 (width * bpp + 7) / 8 * height
34}
35
36#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
57pub struct Framebuffer<C, R, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> {
58 data: [u8; N],
59 color_type: PhantomData<C>,
60 raw_type: PhantomData<R>,
61 byte_order: PhantomData<BO>,
62 n_assert: (),
63}
64
65impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
66 Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
67where
68 C: PixelColor,
69{
70 const BUFFER_SIZE: usize = buffer_size::<C>(WIDTH, HEIGHT);
71
72 const CHECK_N: () = assert!(
75 N >= Self::BUFFER_SIZE,
76 "Invalid N: see Framebuffer documentation for more information"
77 );
78
79 pub const fn new() -> Self {
81 Self {
82 data: [0; N],
83 color_type: PhantomData,
84 raw_type: PhantomData,
85 byte_order: PhantomData,
86 n_assert: Self::CHECK_N,
87 }
88 }
89
90 pub const fn data(&self) -> &[u8; N] {
92 &self.data
93 }
94
95 pub fn data_mut(&mut self) -> &mut [u8; N] {
97 &mut self.data
98 }
99}
100
101impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
102 Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
103where
104 C: PixelColor + From<C::Raw>,
105 BO: ByteOrder,
106 for<'a> RawDataSlice<'a, C::Raw, BO>: IntoIterator<Item = C::Raw>,
107{
108 pub fn as_image(&self) -> ImageRaw<'_, C, BO> {
110 ImageRaw::new(&self.data[0..Self::BUFFER_SIZE], WIDTH as u32)
111 }
112}
113
114impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> GetPixel
115 for Framebuffer<C, C::Raw, BO, WIDTH, HEIGHT, N>
116where
117 C: PixelColor + From<C::Raw>,
118 BO: ByteOrder,
119 for<'a> RawDataSlice<'a, C::Raw, BO>: IntoIterator<Item = C::Raw>,
120{
121 type Color = C;
122
123 fn pixel(&self, p: Point) -> Option<C> {
124 self.as_image().pixel(p)
125 }
126}
127
128macro_rules! impl_bit {
129 ($raw_type:ident) => {
130 impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
131 Framebuffer<C, $raw_type, BO, WIDTH, HEIGHT, N>
132 where
133 C: PixelColor + Into<$raw_type>,
134 {
135 pub fn set_pixel(&mut self, p: Point, c: C) {
139 if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
140 if x < WIDTH && y < HEIGHT {
141 let pixels_per_bit = 8 / C::Raw::BITS_PER_PIXEL;
142 let bits_per_row = WIDTH * C::Raw::BITS_PER_PIXEL;
143 let bytes_per_row = (bits_per_row + 7) / 8;
144 let byte_index = bytes_per_row * y + (x / pixels_per_bit);
145 let bit_index = 8 - (x % pixels_per_bit + 1) * C::Raw::BITS_PER_PIXEL;
146
147 let mask = !((2u8.pow(C::Raw::BITS_PER_PIXEL as u32) - 1) << bit_index);
148 let bits = c.into().into_inner() << bit_index;
149
150 self.data[byte_index] = self.data[byte_index] & mask | bits;
151 }
152 }
153 }
154 }
155
156 impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
157 for Framebuffer<C, $raw_type, BO, WIDTH, HEIGHT, N>
158 where
159 C: PixelColor<Raw = $raw_type> + Into<$raw_type>,
160 {
161 type Color = C;
162 type Error = Infallible;
163
164 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
165 where
166 I: IntoIterator<Item = Pixel<Self::Color>>,
167 {
168 for Pixel(p, c) in pixels {
169 self.set_pixel(p, c);
170 }
171
172 Ok(())
173 }
174 }
175 };
176}
177
178impl_bit!(RawU1);
179impl_bit!(RawU2);
180impl_bit!(RawU4);
181
182impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize>
183 Framebuffer<C, RawU8, BO, WIDTH, HEIGHT, N>
184where
185 C: PixelColor + Into<RawU8>,
186{
187 pub fn set_pixel(&mut self, p: Point, c: C) {
191 if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
192 if x < WIDTH && y < HEIGHT {
193 let x = p.x as usize;
194 let y = p.y as usize;
195
196 self.data[y * WIDTH + x] = c.into().into_inner();
197 }
198 }
199 }
200}
201
202impl<C, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
203 for Framebuffer<C, RawU8, BO, WIDTH, HEIGHT, N>
204where
205 C: PixelColor<Raw = RawU8> + Into<RawU8>,
206{
207 type Color = C;
208 type Error = Infallible;
209
210 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
211 where
212 I: IntoIterator<Item = Pixel<Self::Color>>,
213 {
214 for Pixel(p, c) in pixels {
215 self.set_pixel(p, c);
216 }
217
218 Ok(())
219 }
220}
221
222macro_rules! impl_bytes {
223 ($raw_type:ty, $bo_type:ty, $to_bytes_fn:ident) => {
224 impl<C, const WIDTH: usize, const HEIGHT: usize, const N: usize>
225 Framebuffer<C, $raw_type, $bo_type, WIDTH, HEIGHT, N>
226 where
227 C: PixelColor + Into<$raw_type>,
228 {
229 pub fn set_pixel(&mut self, p: Point, c: C) {
233 const BYTES_PER_PIXEL: usize = <$raw_type>::BITS_PER_PIXEL / 8;
234
235 if let (Ok(x), Ok(y)) = (usize::try_from(p.x), usize::try_from(p.y)) {
236 if x < WIDTH && y < HEIGHT {
237 let x = p.x as usize;
238 let y = p.y as usize;
239
240 let index = (y * WIDTH + x) * BYTES_PER_PIXEL;
241
242 self.data[index..index + BYTES_PER_PIXEL]
243 .copy_from_slice(&c.into().$to_bytes_fn());
244 }
245 }
246 }
247 }
248
249 impl<C, const WIDTH: usize, const HEIGHT: usize, const N: usize> DrawTarget
250 for Framebuffer<C, $raw_type, $bo_type, WIDTH, HEIGHT, N>
251 where
252 C: PixelColor<Raw = $raw_type> + Into<$raw_type>,
253 {
254 type Color = C;
255 type Error = Infallible;
256
257 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
258 where
259 I: IntoIterator<Item = Pixel<Self::Color>>,
260 {
261 for Pixel(p, c) in pixels {
262 self.set_pixel(p, c);
263 }
264
265 Ok(())
266 }
267 }
268 };
269
270 ($raw_type:ty) => {
271 impl_bytes!($raw_type, LittleEndian, to_le_bytes);
272 impl_bytes!($raw_type, BigEndian, to_be_bytes);
273 };
274}
275
276impl_bytes!(RawU16);
277impl_bytes!(RawU24);
278impl_bytes!(RawU32);
279
280impl<C, R, BO, const WIDTH: usize, const HEIGHT: usize, const N: usize> OriginDimensions
281 for Framebuffer<C, R, BO, WIDTH, HEIGHT, N>
282{
283 fn size(&self) -> Size {
284 Size::new(WIDTH as u32, HEIGHT as u32)
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use embedded_graphics_core::prelude::GrayColor;
291
292 use super::*;
293
294 use crate::{
295 geometry::Dimensions,
296 geometry::Point,
297 image::Image,
298 mock_display::MockDisplay,
299 pixelcolor::{BinaryColor, Gray2, Gray4, Gray8, Rgb565, Rgb888, RgbColor},
300 primitives::{Primitive, PrimitiveStyle},
301 Drawable,
302 };
303
304 macro_rules! framebuffer {
306 ($color_type:ty, $byte_order:ty, $width:expr, $height:expr) => {
307 $crate::framebuffer::Framebuffer::<
308 $color_type,
309 <$color_type as $crate::pixelcolor::PixelColor>::Raw,
310 $byte_order,
311 $width,
312 $height,
313 { $crate::framebuffer::buffer_size::<$color_type>($width, $height) },
314 >
315 };
316
317 ($color_type:ty, $width:expr, $height:expr) => {
318 $crate::framebuffer::Framebuffer::<
319 $color_type,
320 <$color_type as $crate::pixelcolor::PixelColor>::Raw,
321 $crate::pixelcolor::raw::LittleEndian,
322 $width,
323 $height,
324 { $crate::framebuffer::buffer_size::<$color_type>($width, $height) },
325 >
326 };
327 }
328
329 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
330 struct U32Color(u32);
331
332 impl PixelColor for U32Color {
333 type Raw = RawU32;
334 }
335
336 impl From<RawU32> for U32Color {
337 fn from(raw: RawU32) -> Self {
338 Self(raw.into_inner())
339 }
340 }
341
342 impl From<U32Color> for RawU32 {
343 fn from(color: U32Color) -> Self {
344 Self::new(color.0)
345 }
346 }
347
348 #[test]
349 fn raw_u1() {
350 let mut fb = <framebuffer!(BinaryColor, 9, 2)>::new();
351
352 use BinaryColor::{Off, On};
353 fb.draw_iter(
354 [
355 ((0, 0), On), ((8, 1), On), ((1, 1), On), ((1, 1), Off), ((-1, 0), On), ((0, -1), On), ((9, 0), On), ((0, 2), On), ]
364 .iter()
365 .map(|(p, c)| Pixel(Point::from(*p), *c)),
366 )
367 .unwrap();
368
369 assert_eq!(
370 fb.data(),
371 &[
372 0b10000000, 0b00000000, 0b00000000, 0b10000000, ]
375 );
376 }
377
378 #[test]
379 fn raw_u2() {
380 type FB = framebuffer!(Gray2, 6, 4);
381 let mut fb = FB::new();
382
383 fb.draw_iter(
384 [
385 ((0, 0), 1), ((5, 3), 2), ((1, 1), 3), ((1, 2), 0), ((-1, 0), 3), ((0, -1), 3), ((6, 0), 3), ((0, 4), 3), ]
394 .iter()
395 .map(|(p, c)| Pixel(Point::from(*p), Gray2::new(*c))),
396 )
397 .unwrap();
398
399 assert_eq!(
400 fb.data(),
401 &[
402 0b01000000, 0b00000000, 0b00110000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00100000, ]
407 );
408 }
409
410 #[test]
411 fn raw_u4() {
412 let mut fb = <framebuffer!(Gray4, 3, 2)>::new();
413
414 fb.draw_iter(
415 [
416 ((0, 0), 0x1), ((2, 1), 0xF), ((1, 0), 0xA), ((1, 1), 0xB), ((-1, 0), 0xF), ((0, -1), 0xF), ((3, 0), 0xF), ((0, 2), 0xF), ]
425 .iter()
426 .map(|(p, c)| Pixel(Point::from(*p), Gray4::new(*c))),
427 )
428 .unwrap();
429
430 assert_eq!(
431 fb.data(),
432 &[
433 0x1A, 0x00, 0x0B, 0xF0, ]
436 );
437 }
438
439 #[test]
440 fn raw_u8() {
441 let mut fb = <framebuffer!(Gray8, 3, 2)>::new();
442
443 fb.draw_iter(
444 [
445 ((0, 0), 0x10), ((2, 1), 0x22), ((1, 0), 0x3F), ((1, 1), 0xF0), ((-1, 0), 0xFF), ((0, -1), 0xFF), ((3, 0), 0xFF), ((0, 2), 0xFF), ]
454 .iter()
455 .map(|(p, c)| Pixel(Point::from(*p), Gray8::new(*c))),
456 )
457 .unwrap();
458
459 assert_eq!(
460 fb.data(),
461 &[
462 0x10, 0x3F, 0x00, 0x00, 0xF0, 0x22, ]
465 );
466 }
467
468 #[test]
469 fn raw_u16_le() {
470 let mut fb = <framebuffer!(Rgb565, 3, 2)>::new();
471
472 fb.draw_iter(
473 [
474 ((0, 0), 0x1000), ((2, 1), 0x0001), ((1, 0), 0x1234), ((1, 1), 0x8765), ((-1, 0), 0xFFFF), ((0, -1), 0xFFFF), ((3, 0), 0xFFFF), ((0, 2), 0xFFFF), ]
483 .iter()
484 .map(|(p, c)| Pixel(Point::from(*p), Rgb565::from(RawU16::new(*c)))),
485 )
486 .unwrap();
487
488 assert_eq!(
489 fb.data(),
490 &[
491 0x00, 0x10, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x65, 0x87, 0x01, 0x00, ]
494 );
495 }
496
497 #[test]
498 fn raw_u16_be() {
499 let mut fb = <framebuffer!(Rgb565, BigEndian, 3, 2)>::new();
500
501 fb.draw_iter(
502 [
503 ((0, 0), 0x1000), ((2, 1), 0x0001), ((1, 0), 0x1234), ((1, 1), 0x8765), ((-1, 0), 0xFFFF), ((0, -1), 0xFFFF), ((3, 0), 0xFFFF), ((0, 2), 0xFFFF), ]
512 .iter()
513 .map(|(p, c)| Pixel(Point::from(*p), Rgb565::from(RawU16::new(*c)))),
514 )
515 .unwrap();
516
517 assert_eq!(
518 fb.data(),
519 &[
520 0x10, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x87, 0x65, 0x00, 0x01, ]
523 );
524 }
525
526 #[test]
527 fn raw_u24_le() {
528 let mut fb = <framebuffer!(Rgb888, 3, 2)>::new();
529
530 fb.draw_iter(
531 [
532 ((0, 0), 0x100000), ((2, 1), 0x000001), ((1, 0), 0x123456), ((1, 1), 0x876543), ((-1, 0), 0xFFFFFF), ((0, -1), 0xFFFFFF), ((3, 0), 0xFFFFFF), ((0, 2), 0xFFFFFF), ]
541 .iter()
542 .map(|(p, c)| Pixel(Point::from(*p), Rgb888::from(RawU24::new(*c)))),
543 )
544 .unwrap();
545
546 assert_eq!(
547 fb.data(),
548 &[
549 0x00, 0x00, 0x10, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x65, 0x87, 0x01, 0x00, 0x00, ]
552 );
553 }
554
555 #[test]
556 fn raw_u24_be() {
557 let mut fb = <framebuffer!(Rgb888, BigEndian, 3, 2)>::new();
558
559 fb.draw_iter(
560 [
561 ((0, 0), 0x100000), ((2, 1), 0x000001), ((1, 0), 0x123456), ((1, 1), 0x876543), ((-1, 0), 0xFFFFFF), ((0, -1), 0xFFFFFF), ((3, 0), 0xFFFFFF), ((0, 2), 0xFFFFFF), ]
570 .iter()
571 .map(|(p, c)| Pixel(Point::from(*p), Rgb888::from(RawU24::new(*c)))),
572 )
573 .unwrap();
574
575 assert_eq!(
576 fb.data(),
577 &[
578 0x10, 0x00, 0x00, 0x12, 0x34, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x65, 0x43, 0x00, 0x00, 0x01, ]
581 );
582 }
583
584 #[test]
585 fn raw_u32_le() {
586 let mut fb = <framebuffer!(U32Color, 3, 2)>::new();
587
588 fb.draw_iter(
589 [
590 ((0, 0), 0x10000000), ((2, 1), 0x00000001), ((1, 0), 0x12345678), ((1, 1), 0x87654321), ((-1, 0), 0xFFFFFFFF), ((0, -1), 0xFFFFFFFF), ((3, 0), 0xFFFFFFFF), ((0, 2), 0xFFFFFFFF), ]
599 .iter()
600 .map(|(p, c)| Pixel(Point::from(*p), U32Color::from(RawU32::new(*c)))),
601 )
602 .unwrap();
603
604 assert_eq!(
605 fb.data(),
606 &[
607 0x00, 0x00, 0x00, 0x10, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x01, 0x00, 0x00, 0x00, ]
610 );
611 }
612
613 #[test]
614 fn raw_u32_be() {
615 let mut fb = <framebuffer!(U32Color, BigEndian, 3, 2)>::new();
616
617 fb.draw_iter(
618 [
619 ((0, 0), 0x10000000), ((2, 1), 0x00000001), ((1, 0), 0x12345678), ((1, 1), 0x87654321), ((-1, 0), 0xFFFFFFFF), ((0, -1), 0xFFFFFFFF), ((3, 0), 0xFFFFFFFF), ((0, 2), 0xFFFFFFFF), ]
628 .iter()
629 .map(|(p, c)| Pixel(Point::from(*p), U32Color::from(RawU32::new(*c)))),
630 )
631 .unwrap();
632
633 assert_eq!(
634 fb.data(),
635 &[
636 0x10, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x65, 0x43, 0x21, 0x00, 0x00, 0x00, 0x01, ]
639 );
640 }
641
642 #[test]
643 fn as_image() {
644 let mut fb = <framebuffer!(BinaryColor, 10, 10)>::new();
645
646 fb.bounding_box()
647 .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
648 .draw(&mut fb)
649 .unwrap();
650
651 fb.draw_iter(
652 [(7, 2), (8, 8)]
653 .into_iter()
654 .map(|p| Pixel(Point::from(p), BinaryColor::On)),
655 )
656 .unwrap();
657
658 let mut display = MockDisplay::<BinaryColor>::new();
659 Image::new(&fb.as_image(), Point::new(2, 1))
660 .draw(&mut display)
661 .unwrap();
662
663 display.assert_pattern(&[
664 " ",
665 " ##########",
666 " #........#",
667 " #......#.#",
668 " #........#",
669 " #........#",
670 " #........#",
671 " #........#",
672 " #........#",
673 " #.......##",
674 " ##########",
675 ]);
676 }
677
678 #[test]
679 fn pixel() {
680 let mut fb = <framebuffer!(BinaryColor, 10, 10)>::new();
681
682 fb.draw_iter(
683 [(7, 2), (8, 8)]
684 .into_iter()
685 .map(|p| Pixel(Point::from(p), BinaryColor::On)),
686 )
687 .unwrap();
688
689 let expected = [
690 ((0, 0), Some(BinaryColor::Off)),
691 ((1, 0), Some(BinaryColor::Off)),
692 ((1, 1), Some(BinaryColor::Off)),
693 ((7, 2), Some(BinaryColor::On)),
694 ((8, 8), Some(BinaryColor::On)),
695 ((-1, 0), None),
696 ((0, -1), None),
697 ((10, 0), None),
698 ((0, 10), None),
699 ];
700 for (p, c) in expected {
701 assert_eq!(fb.pixel(p.into()), c, "{p:?}");
702 }
703 }
704
705 #[test]
706 fn set_pixel() {
707 <framebuffer!(BinaryColor, 10, 10)>::new().set_pixel(Point::zero(), BinaryColor::On);
711 <framebuffer!(Gray2, 10, 10)>::new().set_pixel(Point::zero(), Gray2::WHITE);
712 <framebuffer!(Gray4, 10, 10)>::new().set_pixel(Point::zero(), Gray4::WHITE);
713 <framebuffer!(Gray8, 10, 10)>::new().set_pixel(Point::zero(), Gray8::WHITE);
714 <framebuffer!(Rgb565, 10, 10)>::new().set_pixel(Point::zero(), Rgb565::WHITE);
715 <framebuffer!(Rgb888, 10, 10)>::new().set_pixel(Point::zero(), Rgb888::WHITE);
716 <framebuffer!(U32Color, 10, 10)>::new().set_pixel(Point::zero(), U32Color(0));
717 }
718
719 #[test]
720 fn oversized_buffer() {
721 let fb = Framebuffer::<
722 BinaryColor,
723 _,
724 LittleEndian,
725 10,
726 5,
727 { buffer_size::<BinaryColor>(10, 5) * 3 / 2 },
728 >::new();
729
730 assert_eq!(fb.size(), Size::new(10, 5));
731 assert_eq!(fb.as_image().size(), Size::new(10, 5));
732
733 let outside_x = Point::zero() + fb.size().x_axis();
734 let outside_y = Point::zero() + fb.size().y_axis();
735
736 assert_eq!(fb.pixel(outside_x), None);
737 assert_eq!(fb.pixel(outside_y), None);
738
739 let mut fb2 = fb.clone();
740 fb2.set_pixel(outside_x, BinaryColor::On);
741 fb2.set_pixel(outside_y, BinaryColor::On);
742
743 assert_eq!(fb, fb2);
744 }
745}