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