Skip to main content

embedded_rgba/
canvas.rs

1pub use crate::*;
2
3use core::convert::Infallible;
4use embedded_graphics_core::Pixel;
5use embedded_graphics_core::{prelude::*, primitives::*};
6
7pub trait BufferStrategy: DrawTarget {
8    fn flush<T: DrawTarget<Color = Self::Color>>(&mut self, target: &mut T)
9    -> Result<(), T::Error>;
10}
11
12pub trait HasFramebuffer<C, const N: usize, const W: usize, const H: usize>
13where
14    C: RgbColor,
15{
16    fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H>;
17}
18
19/// Double buffering: draw into `current`, compare/prepare against `reference`, then swap on flush.
20pub struct DoubleBuffer<C, const N: usize, const W: usize, const H: usize>
21where
22    C: RgbColor,
23{
24    current: Framebuffer<C, N, W, H>,
25    reference: Framebuffer<C, N, W, H>,
26}
27
28impl<C, const N: usize, const W: usize, const H: usize> DoubleBuffer<C, N, W, H>
29where
30    C: RgbColor,
31{
32    pub fn new() -> Self {
33        Self {
34            current: Framebuffer::new(),
35            reference: Framebuffer::new(),
36        }
37    }
38}
39
40impl<C, const N: usize, const W: usize, const H: usize> DrawTarget for DoubleBuffer<C, N, W, H>
41where
42    C: RgbColor,
43{
44    type Color = C;
45    type Error = Infallible;
46
47    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
48    where
49        I: IntoIterator<Item = Pixel<Self::Color>>,
50    {
51        self.current.draw_iter(pixels)
52    }
53
54    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
55    where
56        I: IntoIterator<Item = Self::Color>,
57    {
58        self.current.fill_contiguous(area, colors)
59    }
60
61    fn fill_solid(&mut self, area: &Rectangle, color: C) -> Result<(), Self::Error> {
62        self.current.fill_solid(area, color)
63    }
64
65    fn clear(&mut self, color: C) -> Result<(), Self::Error> {
66        self.current.clear(color)
67    }
68}
69
70impl<C, const N: usize, const W: usize, const H: usize> OriginDimensions
71    for DoubleBuffer<C, N, W, H>
72where
73    C: RgbColor,
74{
75    fn size(&self) -> Size {
76        Size::new(W as u32, H as u32)
77    }
78}
79
80impl<C, const N: usize, const W: usize, const H: usize> BufferStrategy for DoubleBuffer<C, N, W, H>
81where
82    C: RgbColor,
83{
84    fn flush<T>(&mut self, target: &mut T) -> Result<(), T::Error>
85    where
86        T: DrawTarget<Color = Self::Color>,
87    {
88        let rect = Rectangle::new(Point::zero(), Size::new(W as u32, H as u32));
89        target.fill_contiguous(&rect, self.current.iter_colors())?;
90        core::mem::swap(&mut self.reference, &mut self.current);
91        Ok(())
92    }
93}
94
95impl<C, const N: usize, const W: usize, const H: usize> HasFramebuffer<C, N, W, H>
96    for DoubleBuffer<C, N, W, H>
97where
98    C: RgbColor,
99{
100    fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H> {
101        &mut self.current
102    }
103}
104
105/// Single buffering: only one framebuffer; flush pushes it to the target.
106pub struct SingleBuffer<C, const N: usize, const W: usize, const H: usize>
107where
108    C: RgbColor,
109{
110    current: Framebuffer<C, N, W, H>,
111}
112
113impl<C, const N: usize, const W: usize, const H: usize> SingleBuffer<C, N, W, H>
114where
115    C: RgbColor,
116{
117    pub fn new() -> Self {
118        Self {
119            current: Framebuffer::new(),
120        }
121    }
122}
123
124impl<C, const N: usize, const W: usize, const H: usize> BufferStrategy for SingleBuffer<C, N, W, H>
125where
126    C: RgbColor,
127{
128    fn flush<T>(&mut self, target: &mut T) -> Result<(), T::Error>
129    where
130        T: DrawTarget<Color = Self::Color>,
131    {
132        let rect = Rectangle::new(Point::zero(), Size::new(W as u32, H as u32));
133        target.fill_contiguous(&rect, self.current.iter_colors())
134    }
135}
136
137impl<C, const N: usize, const W: usize, const H: usize> DrawTarget for SingleBuffer<C, N, W, H>
138where
139    C: RgbColor,
140{
141    type Color = C;
142    type Error = Infallible;
143
144    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
145    where
146        I: IntoIterator<Item = Pixel<Self::Color>>,
147    {
148        self.current.draw_iter(pixels)
149    }
150
151    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
152    where
153        I: IntoIterator<Item = Self::Color>,
154    {
155        self.current.fill_contiguous(area, colors)
156    }
157
158    fn fill_solid(&mut self, area: &Rectangle, color: C) -> Result<(), Self::Error> {
159        self.current.fill_solid(area, color)
160    }
161
162    fn clear(&mut self, color: C) -> Result<(), Self::Error> {
163        self.current.clear(color)
164    }
165}
166
167impl<C, const N: usize, const W: usize, const H: usize> OriginDimensions
168    for SingleBuffer<C, N, W, H>
169where
170    C: RgbColor,
171{
172    fn size(&self) -> Size {
173        Size::new(W as u32, H as u32)
174    }
175}
176
177impl<C, const N: usize, const W: usize, const H: usize> HasFramebuffer<C, N, W, H>
178    for SingleBuffer<C, N, W, H>
179where
180    C: RgbColor,
181{
182    fn current_mut(&mut self) -> &mut Framebuffer<C, N, W, H> {
183        &mut self.current
184    }
185}
186
187pub struct Canvas<'a, T, S>
188where
189    T: DrawTarget,
190    S: BufferStrategy<Color = T::Color>,
191{
192    strategy: S,
193    target: &'a mut T,
194}
195
196impl<'a, T, S> Canvas<'a, T, S>
197where
198    T: DrawTarget,
199    S: BufferStrategy<Color = T::Color>,
200{
201    /// Construct a canvas from an explicit strategy.
202    pub fn with_strategy(target: &'a mut T, strategy: S) -> Self {
203        Self { strategy, target }
204    }
205
206    /// Flush via the strategy.
207    pub fn flush(&mut self) -> Result<(), T::Error> {
208        self.strategy.flush(self.target)
209    }
210}
211
212impl<'a, T, S> OriginDimensions for Canvas<'a, T, S>
213where
214    T: DrawTarget + OriginDimensions,
215    S: BufferStrategy<Color = T::Color>,
216{
217    fn size(&self) -> Size {
218        self.target.size()
219    }
220}
221
222impl<'a, T, C, const N: usize, const W: usize, const H: usize>
223    Canvas<'a, T, DoubleBuffer<C, N, W, H>>
224where
225    C: RgbColor,
226    T: DrawTarget<Color = C>,
227{
228    pub fn double_buffered(target: &'a mut T) -> Self {
229        Self::with_strategy(target, DoubleBuffer::new())
230    }
231}
232
233impl<'a, T, C, const N: usize, const W: usize, const H: usize>
234    Canvas<'a, T, SingleBuffer<C, N, W, H>>
235where
236    C: RgbColor,
237    T: DrawTarget<Color = C>,
238{
239    pub fn single_buffered(target: &'a mut T) -> Self {
240        Self::with_strategy(target, SingleBuffer::new())
241    }
242}
243
244impl<'a, T, S> Canvas<'a, T, S>
245where
246    T: DrawTarget,
247    S: BufferStrategy<Color = T::Color>,
248    T::Color: RgbColor,
249    Rgba<S::Color>: Blend<S::Color>,
250{
251    pub fn alpha<const N: usize, const W: usize, const H: usize>(
252        &mut self,
253    ) -> AlphaCanvas<'_, S::Color, N, W, H>
254    where
255        S: HasFramebuffer<S::Color, N, W, H>,
256    {
257        AlphaCanvas::new(self.strategy.current_mut())
258    }
259}
260
261impl<'a, T, S> DrawTarget for Canvas<'a, T, S>
262where
263    T: DrawTarget + OriginDimensions,
264    S: BufferStrategy<Color = T::Color>,
265{
266    type Error = S::Error;
267    type Color = S::Color;
268
269    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), S::Error>
270    where
271        I: IntoIterator<Item = Pixel<Self::Color>>,
272    {
273        self.strategy.draw_iter(pixels)
274    }
275
276    fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), S::Error>
277    where
278        I: IntoIterator<Item = Self::Color>,
279    {
280        self.strategy.fill_contiguous(area, colors)
281    }
282
283    fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), S::Error> {
284        self.strategy.fill_solid(area, color)
285    }
286
287    fn clear(&mut self, color: Self::Color) -> Result<(), S::Error> {
288        self.strategy.clear(color)
289    }
290}