Skip to main content

embedded_3dgfx/
primitive.rs

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    #[cfg(feature = "lighting")]
21    GouraudTriangle {
22        points: [Point2<i32>; 3],
23        colors: [Rgb565; 3],
24    },
25    #[cfg(feature = "lighting")]
26    GouraudTriangleWithDepth {
27        points: [Point2<i32>; 3],
28        depths: [f32; 3],
29        colors: [Rgb565; 3],
30    },
31    #[cfg(feature = "textured")]
32    TexturedTriangle {
33        points: [Point2<i32>; 3],
34        uvs: [[f32; 2]; 3],
35        texture_id: u32,
36    },
37    #[cfg(feature = "textured")]
38    TexturedTriangleWithDepth {
39        points: [Point2<i32>; 3],
40        depths: [f32; 3],
41        ws: [f32; 3],
42        uvs: [[f32; 2]; 3],
43        texture_id: u32,
44    },
45    #[cfg(feature = "textured")]
46    TexturedGouraudTriangleWithDepth {
47        points: [Point2<i32>; 3],
48        depths: [f32; 3],
49        ws: [f32; 3],
50        uvs: [[f32; 2]; 3],
51        colors: [Rgb565; 3],
52        texture_id: u32,
53    },
54    /// Perspective-correct textured triangle with baked lightmap.
55    ///
56    /// The final pixel colour is:
57    /// `clamp(surface.sample(su,sv) × lightmap.sample(lu,lv) + dynamic_tint)`
58    /// where `×` is per-channel normalised multiply.
59    /// Set `lightmap_id = u32::MAX` to fall back to full-bright surface colour.
60    /// Set `dynamic_tint = Rgb565::new(0,0,0)` for no dynamic lighting.
61    #[cfg(feature = "textured")]
62    LightmappedTriangle {
63        points: [Point2<i32>; 3],
64        depths: [f32; 3],
65        ws: [f32; 3],
66        surface_uvs: [[f32; 2]; 3],
67        lm_uvs: [[f32; 2]; 3],
68        texture_id: u32,
69        lightmap_id: u32,
70        /// Per-face brightness multiplier in 0..=255 (255 = no darkening).
71        brightness: u8,
72        /// Additive RGB565 tint from runtime point lights.
73        dynamic_tint: Rgb565,
74    },
75}
76
77impl DrawPrimitive {
78    /// Calculate screen-space axis-aligned bounding box (min_x, min_y, max_x, max_y)
79    pub fn bounds(&self) -> (i32, i32, i32, i32) {
80        match self {
81            DrawPrimitive::ColoredPoint(p, _) => (p.x, p.y, p.x, p.y),
82            DrawPrimitive::Line([a, b], _) => {
83                (a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y))
84            }
85            DrawPrimitive::ColoredTriangle(points, _)
86            | DrawPrimitive::ColoredTriangleWithDepth { points, .. }
87            | DrawPrimitive::TranslucentTriangleWithDepth { points, .. } => {
88                let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
89                let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
90                let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
91                let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
92                (min_x, min_y, max_x, max_y)
93            }
94            #[cfg(feature = "lighting")]
95            DrawPrimitive::GouraudTriangle { points, .. }
96            | DrawPrimitive::GouraudTriangleWithDepth { points, .. } => {
97                let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
98                let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
99                let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
100                let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
101                (min_x, min_y, max_x, max_y)
102            }
103            #[cfg(feature = "textured")]
104            DrawPrimitive::TexturedTriangle { points, .. }
105            | DrawPrimitive::TexturedTriangleWithDepth { points, .. }
106            | DrawPrimitive::TexturedGouraudTriangleWithDepth { points, .. }
107            | DrawPrimitive::LightmappedTriangle { points, .. } => {
108                let min_x = points.iter().map(|p| p.x).min().unwrap_or(0);
109                let min_y = points.iter().map(|p| p.y).min().unwrap_or(0);
110                let max_x = points.iter().map(|p| p.x).max().unwrap_or(0);
111                let max_y = points.iter().map(|p| p.y).max().unwrap_or(0);
112                (min_x, min_y, max_x, max_y)
113            }
114        }
115    }
116}