1use embedded_graphics_core::draw_target::DrawTarget;
2use embedded_graphics_core::prelude::Point;
3
4use crate::DrawPrimitive;
5
6#[inline]
7pub fn draw<D: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>(
8 primitive: DrawPrimitive,
9 fb: &mut D,
10) where
11 <D as DrawTarget>::Error: std::fmt::Debug,
12{
13 match primitive {
14 DrawPrimitive::Line(p1, p2, color) => {
15 fb.draw_iter(
16 line_drawing::Bresenham::new((p1.x, p1.y), (p2.x, p2.y))
17 .map(|(x, y)| embedded_graphics_core::Pixel(Point::new(x, y), color)),
18 )
19 .unwrap();
20 }
21 DrawPrimitive::ColoredPoint(p, c) => {
22 let p = embedded_graphics_core::geometry::Point::new(p.x, p.y);
23
24 fb.draw_iter([embedded_graphics_core::Pixel(p, c)]).unwrap();
25 }
26 DrawPrimitive::ColoredTriangle(p1, p2, p3, color) => {
27 let mut vertices = [p1, p2, p3];
29 vertices.sort_by(|a, b| a.y.cmp(&b.y));
30
31 let [p1, p2, p3] = vertices
32 .iter()
33 .map(|p| embedded_graphics_core::geometry::Point::new(p.x, p.y))
34 .collect::<Vec<embedded_graphics_core::geometry::Point>>()
35 .try_into()
36 .unwrap();
37
38 if p2.y == p3.y {
39 fill_bottom_flat_triangle(p1, p2, p3, color, fb);
40 } else if p1.y == p2.y {
41 fill_top_flat_triangle(p1, p2, p3, color, fb);
42 } else {
43 let p4 = Point::new(
44 (p1.x as f32
45 + ((p2.y - p1.y) as f32 / (p3.y - p1.y) as f32) * (p3.x - p1.x) as f32)
46 as i32,
47 p2.y,
48 );
49
50 fill_bottom_flat_triangle(p1, p2, p4, color, fb);
51 fill_top_flat_triangle(p2, p4, p3, color, fb);
52 }
53 }
54 }
55}
56
57fn fill_bottom_flat_triangle<D: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>(
58 p1: Point,
59 p2: Point,
60 p3: Point,
61 color: embedded_graphics_core::pixelcolor::Rgb565,
62 fb: &mut D,
63) where
64 <D as DrawTarget>::Error: std::fmt::Debug,
65{
66 let invslope1 = (p2.x - p1.x) as f32 / (p2.y - p1.y) as f32;
67 let invslope2 = (p3.x - p1.x) as f32 / (p3.y - p1.y) as f32;
68
69 let mut curx1 = p1.x as f32;
70 let mut curx2 = p1.x as f32;
71
72 for scanline_y in p1.y..=p2.y {
73 draw_horizontal_line(
74 Point::new(curx1 as i32, scanline_y),
75 Point::new(curx2 as i32, scanline_y),
76 color,
77 fb,
78 );
79
80 curx1 += invslope1;
81 curx2 += invslope2;
82 }
83}
84
85fn fill_top_flat_triangle<D: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>(
86 p1: Point,
87 p2: Point,
88 p3: Point,
89 color: embedded_graphics_core::pixelcolor::Rgb565,
90 fb: &mut D,
91) where
92 <D as DrawTarget>::Error: std::fmt::Debug,
93{
94 let invslope1 = (p3.x - p1.x) as f32 / (p3.y - p1.y) as f32;
95 let invslope2 = (p3.x - p2.x) as f32 / (p3.y - p2.y) as f32;
96
97 let mut curx1 = p3.x as f32;
98 let mut curx2 = p3.x as f32;
99
100 for scanline_y in (p1.y..=p3.y).rev() {
101 draw_horizontal_line(
102 Point::new(curx1 as i32, scanline_y),
103 Point::new(curx2 as i32, scanline_y),
104 color,
105 fb,
106 );
107
108 curx1 -= invslope1;
109 curx2 -= invslope2;
110 }
111}
112
113fn draw_horizontal_line<D: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>(
114 p1: Point,
115 p2: Point,
116 color: embedded_graphics_core::pixelcolor::Rgb565,
117 fb: &mut D,
118) where
119 <D as DrawTarget>::Error: std::fmt::Debug,
120{
121 let start = p1.x.min(p2.x);
122 let end = p1.x.max(p2.x);
123
124 for x in start..=end {
125 fb.draw_iter([embedded_graphics_core::Pixel(Point::new(x, p1.y), color)])
126 .unwrap();
127 }
128}