multi_mono_font/
framebuf.rs1use core::ops::Sub;
2use embedded_graphics::Pixel;
3use embedded_graphics::prelude::*;
4use embedded_graphics::primitives::Rectangle;
5
6pub trait BulkFlushTarget: DrawTarget {
7 fn flush(&mut self, area: &Rectangle, data: &[Self::Color]) -> Result<(), Self::Error>;
9}
10
11pub struct Framebuffer<'a, COL: PixelColor, DRAW: BulkFlushTarget<Color = COL>> {
12 target: &'a mut DRAW,
13 fb: FramebufferInner<'a, COL>,
14}
15
16impl<'a, COL: PixelColor, DRAW: BulkFlushTarget<Color = COL>> Framebuffer<'a, COL, DRAW> {
17 pub fn new(target: &'a mut DRAW, buffer: &'a mut [COL]) -> Self {
19 Self {
20 target,
21 fb: FramebufferInner::new(buffer),
22 }
23 }
24}
25
26impl<'a, COL: PixelColor, DRAW: BulkFlushTarget<Color = COL>> Dimensions
27 for Framebuffer<'a, COL, DRAW>
28{
29 fn bounding_box(&self) -> Rectangle {
30 self.target.bounding_box()
31 }
32}
33
34impl<'a, COL: PixelColor, DRAW: BulkFlushTarget<Color = COL>> DrawTarget
35 for Framebuffer<'a, COL, DRAW>
36{
37 type Color = COL;
38 type Error = ();
39
40 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
41 where
42 I: IntoIterator<Item = Pixel<Self::Color>>,
43 {
44 self.target.draw_iter(pixels).map_err(|_| ())
45 }
46
47 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
48 where
49 I: IntoIterator<Item = Self::Color>,
50 {
51 if self.fb.start_drawing(area) {
52 self.fb.fill_contiguous(area, colors)?;
53 self.target
54 .flush(area, self.fb.get_buffer())
55 .map_err(|_| ())?;
56 self.fb.finalize();
57 Ok(())
58 } else {
59 self.target.fill_contiguous(area, colors).map_err(|_| ())
60 }
61 }
62}
63
64struct FramebufferInner<'a, C: PixelColor> {
65 buf: &'a mut [C],
66 size: Size,
67 position: Point,
68 len: usize,
69}
70
71impl<'a, C: PixelColor> FramebufferInner<'a, C> {
72 pub fn new(buf: &'a mut [C]) -> Self {
73 Self {
74 buf,
75 size: Size::zero(),
76 position: Point::zero(),
77 len: 0,
78 }
79 }
80
81 pub fn start_drawing(&mut self, area: &Rectangle) -> bool {
82 if self.len > 0 {
83 return false;
84 }
85
86 let size = area.size;
87 let position = area.top_left;
88 let len = size.width as usize * size.height as usize;
89
90 if len <= self.buf.len() {
91 self.size = size;
92 self.position = position;
93 self.len = len;
94 true
95 } else {
96 false
97 }
98 }
99
100 pub fn get_buffer(&mut self) -> &[C] {
101 &self.buf[0..self.len]
102 }
103
104 pub fn finalize(&mut self) {
105 self.len = 0;
106 }
107}
108
109impl<C: PixelColor> Dimensions for FramebufferInner<'_, C> {
110 fn bounding_box(&self) -> Rectangle {
111 Rectangle::new(self.position, self.size)
112 }
113}
114
115impl<C: PixelColor> DrawTarget for FramebufferInner<'_, C> {
116 type Color = C;
117 type Error = ();
118
119 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
120 where
121 I: IntoIterator<Item = Pixel<Self::Color>>,
122 {
123 for pixel in pixels {
124 let pt = pixel.0.sub(self.position);
125 let pos = pt.y * self.size.width as i32 + pt.x;
126 if pos < 0 || pos >= self.len as i32 {
127 continue;
128 }
129 self.buf[pos as usize] = pixel.1;
130 }
131
132 Ok(())
133 }
134
135 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
136 where
137 I: IntoIterator<Item = Self::Color>,
138 {
139 let drawable_area = area.intersection(&self.bounding_box());
140 if drawable_area.is_zero_sized() {
141 return Ok(());
142 }
143
144 let top_skip = drawable_area.top_left.y - area.top_left.y;
145 let left_skip = drawable_area.top_left.x - area.top_left.x;
146 let right_skip = area.size.width as i32 - (left_skip + drawable_area.size.width as i32);
147 let mut color_iter = colors.into_iter();
150
151 for _ in 0..top_skip {
153 for _ in 0..area.size.width as usize {
154 color_iter.next();
155 }
156 }
157 for y in drawable_area.top_left.y as usize
158 ..drawable_area.top_left.y as usize + drawable_area.size.height as usize
159 {
160 for _ in 0..left_skip {
161 color_iter.next();
162 }
164 for x in drawable_area.top_left.x as usize
165 ..drawable_area.top_left.x as usize + drawable_area.size.width as usize
166 {
167 let pos = (y as i32 - self.position.y) as usize * self.size.width as usize
168 + (x as i32 - self.position.x) as usize;
169 match color_iter.next() {
170 Some(color) => self.buf[pos] = color,
171 None => return Ok(()),
172 }
173 }
174 for _ in 0..right_skip {
175 color_iter.next();
176 }
178 }
179
180 Ok(())
181 }
182
183 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
184 let drawable_area = area.intersection(&self.bounding_box());
186
187 for y in drawable_area.top_left.y as usize
189 ..drawable_area.top_left.y as usize + drawable_area.size.height as usize
190 {
191 for x in drawable_area.top_left.x as usize
192 ..drawable_area.top_left.x as usize + drawable_area.size.width as usize
193 {
194 let pos = (y as i32 - self.position.y) as usize * self.size.width as usize
195 + (x as i32 - self.position.x) as usize;
196 self.buf[pos] = color;
197 }
198 }
199 Ok(())
200 }
201
202 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
203 self.buf[0..(self.size.width * self.size.height) as usize].fill(color);
204 Ok(())
205 }
206}
207
208impl<C: PixelColor> Drawable for FramebufferInner<'_, C> {
209 type Color = C;
210 type Output = ();
211
212 fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
213 where
214 D: DrawTarget<Color = Self::Color>,
215 {
216 target.fill_contiguous(
217 &Rectangle::new(self.position, self.size),
218 self.buf.iter().cloned(),
219 )
220 }
221}