raqote_display/
lib.rs

1use embedded_graphics::{
2    drawable::Pixel,
3    geometry::{Dimensions, Size},
4    image::{Image, ImageDimensions},
5    pixelcolor::{Rgb565, Rgb888, RgbColor},
6    prelude::*,
7    primitives,
8    style::{PrimitiveStyle, Styled},
9    DrawTarget,
10};
11
12use raqote;
13
14pub mod prelude;
15
16/// This display is based on raqote's `DrawTarget` and is used as draw target for the embedded graphics crate.
17///
18/// # Example
19///
20/// ```rust
21/// use RaqoteDisplay_display::prelude::*;
22/// use embedded_graphics::{
23///     image::{Image, ImageRaw, ImageRawLE},
24///     pixelcolor::Rgb565,
25///     prelude::*,
26///     primitives::rectangle::Rectangle,
27///     style::PrimitiveStyleBuilder,
28///     };
29///
30/// let mut display = RaqoteDisplay::new(160, 128).unwrap();
31///
32/// let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLACK).build();
33/// let black_backdrop = Rectangle::new(Point::new(0, 0), Point::new(160, 128)).into_styled(style);
34/// black_backdrop.draw(&mut display).unwrap();
35///
36/// // draw ferris
37/// let image_raw: ImageRawLE<Rgb565> = ImageRaw::new(include_bytes!("../../../assets/ferris.raw"), 86, 64);
38/// let image: Image<_, Rgb565> = Image::new(&image_raw, Point::new(34, 8));
39/// image.draw(&mut display).unwrap();
40/// ```
41pub struct RaqoteDisplay {
42    draw_target: raqote::DrawTarget,
43    size: Size,
44}
45
46impl RaqoteDisplay {
47    /// Creates a new display display with the given size.
48    pub fn new(width: u32, height: u32) -> Result<Self, String> {
49        Ok(RaqoteDisplay {
50            draw_target: raqote::DrawTarget::new(width as i32, height as i32),
51            size: Size::new(width, height),
52        })
53    }
54
55    fn fill(&mut self, path: &raqote::Path, color: Rgb565) {
56        self.draw_target.fill(
57            path,
58            &raqote::Source::from(convert_color(color)),
59            &raqote::DrawOptions::default(),
60        );
61    }
62
63    fn stroke(&mut self, path: &raqote::Path, color: Rgb565, stroke_width: u32) {
64        self.draw_target.stroke(
65            path,
66            &raqote::Source::from(convert_color(color)),
67            &raqote::StrokeStyle {
68                width: stroke_width as f32,
69                ..Default::default()
70            },
71            &raqote::DrawOptions::default(),
72        );
73    }
74
75    pub fn data(&self) -> &[u32] {
76        self.draw_target.get_data()
77    }
78
79    /// Pushes the frame buffer to the given surface and clears the frame buffer.
80    pub fn flip(&mut self, surface: &mut [u32]) {
81        surface.clone_from_slice(self.draw_target.get_data());
82        self.draw_target = raqote::DrawTarget::new(self.size.width as i32, self.size.height as i32);
83    }
84}
85
86impl DrawTarget<Rgb565> for RaqoteDisplay {
87    type Error = String;
88
89    fn draw_pixel(&mut self, pixel: Pixel<Rgb565>) -> Result<(), Self::Error> {
90        self.draw_target.fill_rect(
91            pixel.0.x as f32,
92            pixel.0.y as f32,
93            1.,
94            1.,
95            &raqote::Source::from(convert_color(pixel.1)),
96            &raqote::DrawOptions::default(),
97        );
98
99        Ok(())
100    }
101
102    fn draw_line(
103        &mut self,
104        item: &Styled<primitives::Line, PrimitiveStyle<Rgb565>>,
105    ) -> Result<(), Self::Error> {
106        let line = item.primitive;
107        let style = item.style;
108
109        let mut path_builder = raqote::PathBuilder::new();
110        path_builder.move_to(line.start.x as f32, line.start.y as f32);
111        path_builder.line_to(line.end.x as f32, line.end.y as f32);
112
113        let path = path_builder.finish();
114
115        if let Some(fill_color) = style.fill_color {
116            self.fill(&path, fill_color);
117        }
118
119        if let Some(stroke_color) = style.stroke_color {
120            self.stroke(&path, stroke_color, style.stroke_width);
121        }
122
123        Ok(())
124    }
125
126    fn draw_rectangle(
127        &mut self,
128        item: &Styled<primitives::Rectangle, PrimitiveStyle<Rgb565>>,
129    ) -> Result<(), Self::Error> {
130        let rectangle = item.primitive;
131        let style = item.style;
132
133        let width = (rectangle.bottom_right.x - rectangle.top_left.x) as f32;
134        let height = (rectangle.bottom_right.y - rectangle.top_left.y) as f32;
135
136        if let Some(fill_color) = style.fill_color {
137            self.draw_target.fill_rect(
138                rectangle.top_left().x as f32,
139                rectangle.top_left().y as f32,
140                width,
141                height,
142                &raqote::Source::from(convert_color(fill_color)),
143                &raqote::DrawOptions::default(),
144            );
145        }
146
147        if let Some(stroke_color) = style.stroke_color {
148            let mut path_builder = raqote::PathBuilder::new();
149            path_builder.rect(
150                rectangle.top_left().x as f32,
151                rectangle.top_left().y as f32,
152                width,
153                height,
154            );
155
156            self.stroke(&path_builder.finish(), stroke_color, style.stroke_width);
157        }
158
159        Ok(())
160    }
161
162    fn draw_circle(
163        &mut self,
164        item: &Styled<primitives::Circle, PrimitiveStyle<Rgb565>>,
165    ) -> Result<(), Self::Error> {
166        let circle = item.primitive;
167        let style = item.style;
168
169        let mut path_builder = raqote::PathBuilder::new();
170        path_builder.arc(
171            circle.center.x as f32,
172            circle.center.y as f32,
173            circle.radius as f32,
174            0.0,
175            2.0 * std::f32::consts::PI,
176        );
177
178        let path = path_builder.finish();
179
180        if let Some(fill_color) = style.fill_color {
181            self.fill(&path, fill_color);
182        }
183
184        if let Some(stroke_color) = style.stroke_color {
185            self.stroke(&path, stroke_color, style.stroke_width);
186        }
187
188        Ok(())
189    }
190
191    fn draw_image<'a, 'b, I>(&mut self, item: &'a Image<'b, I, Rgb565>) -> Result<(), Self::Error>
192    where
193        &'b I: IntoPixelIter<Rgb565>,
194        I: ImageDimensions,
195    {
196        let mut pixels = vec![];
197
198        for pixel in item {
199            let color = convert_color(pixel.1);
200
201            pixels.push(
202                0xFF00_0000
203                    | ((color.r() as u32) << 16)
204                    | ((color.g() as u32) << 8)
205                    | (color.b() as u32),
206            );
207        }
208
209        let image = raqote::Image {
210            width: item.size().width as i32,
211            height: item.size().height as i32,
212            data: &pixels,
213        };
214
215        self.draw_target.draw_image_at(
216            item.top_left().x as f32,
217            item.top_left().y as f32,
218            &image,
219            &raqote::DrawOptions::default(),
220        );
221
222        Ok(())
223    }
224
225    fn size(&self) -> Size {
226        self.size
227    }
228}
229
230fn convert_color(color: Rgb565) -> raqote::Color {
231    let color: Rgb888 = Rgb888::from(color);
232    raqote::Color::new(255, color.r(), color.g(), color.b())
233}