1use embedded_graphics_core::pixelcolor::Rgb565;
2use nalgebra::Point2;
3
4#[derive(Debug, Clone)]
5pub enum DrawPrimitive {
6 ColoredPoint(Point2<i32>, Rgb565),
7 Line([Point2<i32>; 2], Rgb565),
8 ColoredTriangle([Point2<i32>; 3], Rgb565),
9 ColoredTriangleWithDepth {
10 points: [Point2<i32>; 3],
11 depths: [f32; 3],
12 color: Rgb565,
13 },
14 TranslucentTriangleWithDepth {
15 points: [Point2<i32>; 3],
16 depths: [f32; 3],
17 color: Rgb565,
18 alpha: u8,
19 },
20 ScreenDoorTriangleWithDepth {
22 points: [Point2<i32>; 3],
23 depths: [f32; 3],
24 color: Rgb565,
25 alpha: u8,
26 },
27 #[cfg(feature = "lighting")]
28 GouraudTriangle {
29 points: [Point2<i32>; 3],
30 colors: [Rgb565; 3],
31 },
32 #[cfg(feature = "lighting")]
33 GouraudTriangleWithDepth {
34 points: [Point2<i32>; 3],
35 depths: [f32; 3],
36 colors: [Rgb565; 3],
37 },
38 #[cfg(feature = "textured")]
39 TexturedTriangle {
40 points: [Point2<i32>; 3],
41 uvs: [[f32; 2]; 3],
42 texture_id: u32,
43 },
44 #[cfg(feature = "textured")]
45 TexturedTriangleWithDepth {
46 points: [Point2<i32>; 3],
47 depths: [f32; 3],
48 ws: [f32; 3],
49 uvs: [[f32; 2]; 3],
50 texture_id: u32,
51 },
52 #[cfg(feature = "textured")]
53 TexturedGouraudTriangleWithDepth {
54 points: [Point2<i32>; 3],
55 depths: [f32; 3],
56 ws: [f32; 3],
57 uvs: [[f32; 2]; 3],
58 colors: [Rgb565; 3],
59 texture_id: u32,
60 },
61 #[cfg(feature = "textured")]
69 LightmappedTriangle {
70 points: [Point2<i32>; 3],
71 depths: [f32; 3],
72 ws: [f32; 3],
73 surface_uvs: [[f32; 2]; 3],
74 lm_uvs: [[f32; 2]; 3],
75 texture_id: u32,
76 lightmap_id: u32,
77 brightness: u8,
79 dynamic_tint: Rgb565,
81 },
82}
83
84impl DrawPrimitive {
85 pub fn bounds(&self) -> (i32, i32, i32, i32) {
87 match self {
88 DrawPrimitive::ColoredPoint(p, _) => (p.x, p.y, p.x, p.y),
89 DrawPrimitive::Line([a, b], _) => {
90 (a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y))
91 }
92 DrawPrimitive::ColoredTriangle(points, _)
93 | DrawPrimitive::ColoredTriangleWithDepth { points, .. }
94 | DrawPrimitive::TranslucentTriangleWithDepth { points, .. }
95 | DrawPrimitive::ScreenDoorTriangleWithDepth { points, .. } => {
96 let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
97 let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
98 let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
99 let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
100 (min_x, min_y, max_x, max_y)
101 }
102 #[cfg(feature = "lighting")]
103 DrawPrimitive::GouraudTriangle { points, .. }
104 | DrawPrimitive::GouraudTriangleWithDepth { points, .. } => {
105 let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
106 let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
107 let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
108 let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
109 (min_x, min_y, max_x, max_y)
110 }
111 #[cfg(feature = "textured")]
112 DrawPrimitive::TexturedTriangle { points, .. }
113 | DrawPrimitive::TexturedTriangleWithDepth { points, .. }
114 | DrawPrimitive::TexturedGouraudTriangleWithDepth { points, .. }
115 | DrawPrimitive::LightmappedTriangle { points, .. } => {
116 let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
117 let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
118 let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
119 let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
120 (min_x, min_y, max_x, max_y)
121 }
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use embedded_graphics_core::pixelcolor::RgbColor;
130
131 fn pts() -> [Point2<i32>; 3] {
132 [Point2::new(-2, 0), Point2::new(3, -4), Point2::new(1, 5)]
133 }
134
135 #[test]
136 fn primitive_bounds_cover_every_family() {
137 let p = pts();
138 assert_eq!(
139 DrawPrimitive::ColoredPoint(p[0], Rgb565::RED).bounds(),
140 (-2, 0, -2, 0)
141 );
142 assert_eq!(
143 DrawPrimitive::Line([p[0], p[2]], Rgb565::RED).bounds(),
144 (-2, 0, 1, 5)
145 );
146 assert_eq!(
147 DrawPrimitive::ColoredTriangle(p, Rgb565::RED).bounds(),
148 (-2, -4, 3, 5)
149 );
150 assert_eq!(
151 DrawPrimitive::ColoredTriangleWithDepth {
152 points: p,
153 depths: [1.0; 3],
154 color: Rgb565::RED,
155 }
156 .bounds(),
157 (-2, -4, 3, 5)
158 );
159 assert_eq!(
160 DrawPrimitive::TranslucentTriangleWithDepth {
161 points: p,
162 depths: [1.0; 3],
163 color: Rgb565::RED,
164 alpha: 128,
165 }
166 .bounds(),
167 (-2, -4, 3, 5)
168 );
169 assert_eq!(
170 DrawPrimitive::ScreenDoorTriangleWithDepth {
171 points: p,
172 depths: [1.0; 3],
173 color: Rgb565::RED,
174 alpha: 128,
175 }
176 .bounds(),
177 (-2, -4, 3, 5)
178 );
179
180 #[cfg(feature = "lighting")]
181 {
182 assert_eq!(
183 DrawPrimitive::GouraudTriangle {
184 points: p,
185 colors: [Rgb565::RED; 3],
186 }
187 .bounds(),
188 (-2, -4, 3, 5)
189 );
190 assert_eq!(
191 DrawPrimitive::GouraudTriangleWithDepth {
192 points: p,
193 depths: [1.0; 3],
194 colors: [Rgb565::RED; 3],
195 }
196 .bounds(),
197 (-2, -4, 3, 5)
198 );
199 }
200
201 #[cfg(feature = "textured")]
202 {
203 let uvs = [[0.0; 2]; 3];
204 assert_eq!(
205 DrawPrimitive::TexturedTriangle {
206 points: p,
207 uvs,
208 texture_id: 0,
209 }
210 .bounds(),
211 (-2, -4, 3, 5)
212 );
213 assert_eq!(
214 DrawPrimitive::TexturedTriangleWithDepth {
215 points: p,
216 depths: [1.0; 3],
217 ws: [1.0; 3],
218 uvs,
219 texture_id: 0,
220 }
221 .bounds(),
222 (-2, -4, 3, 5)
223 );
224 assert_eq!(
225 DrawPrimitive::TexturedGouraudTriangleWithDepth {
226 points: p,
227 depths: [1.0; 3],
228 ws: [1.0; 3],
229 uvs,
230 colors: [Rgb565::RED; 3],
231 texture_id: 0,
232 }
233 .bounds(),
234 (-2, -4, 3, 5)
235 );
236 assert_eq!(
237 DrawPrimitive::LightmappedTriangle {
238 points: p,
239 depths: [1.0; 3],
240 ws: [1.0; 3],
241 surface_uvs: uvs,
242 lm_uvs: uvs,
243 texture_id: 0,
244 lightmap_id: 0,
245 brightness: 255,
246 dynamic_tint: Rgb565::BLACK,
247 }
248 .bounds(),
249 (-2, -4, 3, 5)
250 );
251 }
252 }
253}