1use crate::*;
2use embedded_graphics_core::pixelcolor::*;
3use embedded_graphics_core::prelude::*;
4use embedded_graphics_core::primitives::*;
5
6pub struct AlphaCanvas<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> {
7 buffer: &'a mut Framebuffer<C, N, W, H>,
8}
9
10impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> AlphaCanvas<'a, C, N, W, H>
11where
12 Rgba<C>: Blend<C>,
13{
14 pub fn new(buffer: &'a mut Framebuffer<C, N, W, H>) -> Self {
15 Self { buffer }
16 }
17}
18
19impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> OriginDimensions
20 for AlphaCanvas<'a, C, N, W, H>
21where
22 Rgba<C>: Blend<C>,
23{
24 fn size(&self) -> Size {
25 self.buffer.size()
26 }
27}
28
29impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> DrawTarget
30 for AlphaCanvas<'a, C, N, W, H>
31where
32 Rgba<C>: Blend<C>,
33{
34 type Error = core::convert::Infallible;
35 type Color = Rgba<C>;
36
37 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
38 where
39 I: IntoIterator<Item = Pixel<Self::Color>>,
40 {
41 let buf = self.buffer.buf_mut();
43
44 for Pixel(point, fg) in pixels {
45 let x = point.x;
46 let y = point.y;
47
48 if x >= 0 && x < W as i32 && y >= 0 && y < H as i32 {
50 let xi = x as usize;
51 let yi = y as usize;
52 let idx = yi * W + xi;
53
54 let bg = buf[idx];
56 buf[idx] = fg.blend(bg);
57 }
58 }
59
60 Ok(())
61 }
62
63 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
64 where
65 I: IntoIterator<Item = Self::Color>,
66 {
67 use core::cmp::{max, min};
68
69 let mut it = colors.into_iter();
70
71 if area.size.width == 0 || area.size.height == 0 {
73 return Ok(());
74 }
75
76 let fb_left = 0i32;
78 let fb_top = 0i32;
79 let fb_right = W as i32; let fb_bottom = H as i32; let area_left = area.top_left.x;
83 let area_top = area.top_left.y;
84 let area_right = area_left + area.size.width as i32; let area_bottom = area_top + area.size.height as i32; let clip_left = max(fb_left, area_left);
89 let clip_top = max(fb_top, area_top);
90 let clip_right = min(fb_right, area_right);
91 let clip_bottom = min(fb_bottom, area_bottom);
92
93 if clip_left >= clip_right || clip_top >= clip_bottom {
95 let _ = it
97 .by_ref()
98 .take((area.size.width as usize) * (area.size.height as usize))
99 .for_each(drop);
100 return Ok(());
101 }
102
103 let buf = self.buffer.buf_mut();
104
105 for y in area_top..area_bottom {
108 let inside_y = y >= clip_top && y < clip_bottom;
109
110 let left_run = (clip_left - area_left).max(0) as usize;
112 let mid_run = if inside_y {
114 (clip_right - clip_left).max(0) as usize
115 } else {
116 0
118 };
119 let right_run = (area_right - clip_right).max(0) as usize;
121
122 for _ in 0..left_run {
124 let _ = it.next();
125 }
126
127 if inside_y {
128 let yi = y as usize;
129 let row_start = yi * W;
130 let x0 = clip_left as usize;
131 let idx0 = row_start + x0;
132
133 for i in 0..mid_run {
135 if let Some(fg) = it.next() {
136 let idx = idx0 + i;
137 let bg = buf[idx];
138 buf[idx] = fg.blend(bg);
139 } else {
140 break;
141 }
142 }
143 } else {
144 for _ in 0..((clip_right - clip_left).max(0) as usize) {
146 let _ = it.next();
147 }
148 }
149
150 for _ in 0..right_run {
152 let _ = it.next();
153 }
154 }
155
156 Ok(())
157 }
158
159 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
160 use core::cmp::{max, min};
161
162 let a = color.a();
164 if a == 0 {
165 return Ok(());
166 }
167
168 let fb_left = 0i32;
170 let fb_top = 0i32;
171 let fb_right = W as i32; let fb_bottom = H as i32; let area_left = area.top_left.x;
175 let area_top = area.top_left.y;
176 let area_right = area_left + area.size.width as i32; let area_bottom = area_top + area.size.height as i32; let clip_left = max(fb_left, area_left);
180 let clip_top = max(fb_top, area_top);
181 let clip_right = min(fb_right, area_right);
182 let clip_bottom = min(fb_bottom, area_bottom);
183
184 if clip_left >= clip_right || clip_top >= clip_bottom {
185 return Ok(());
186 }
187
188 let buf = self.buffer.buf_mut();
189
190 if a == 255 {
191 let oc: C = color.rgb();
193 for y in clip_top as usize..clip_bottom as usize {
194 let row_start = y * W;
195 let start = row_start + clip_left as usize;
196 let end = row_start + clip_right as usize;
197 for idx in start..end {
198 buf[idx] = oc;
199 }
200 }
201 return Ok(());
202 }
203
204 for y in clip_top as usize..clip_bottom as usize {
206 let row_start = y * W;
207 let start = row_start + clip_left as usize;
208 let end = row_start + clip_right as usize;
209 for idx in start..end {
210 let bg = buf[idx];
211 buf[idx] = color.blend(bg);
212 }
213 }
214
215 Ok(())
216 }
217
218 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
219 let a = color.a();
220 if a == 0 {
221 return Ok(());
222 }
223
224 let buf = self.buffer.buf_mut();
225
226 if a == 255 {
227 let oc: C = color.rgb();
228 for px in buf.iter_mut() {
229 *px = oc;
230 }
231 return Ok(());
232 }
233
234 for px in buf.iter_mut() {
235 let bg = *px;
236 *px = color.blend(bg);
237 }
238
239 Ok(())
240 }
241}