1
mod batch;
2
mod circle;
3
mod fill;
4
mod geometry;
5
mod path;
6
mod stroke;
7

            
8
use circle::Circle;
9
use easygpu_lyon::lyon_tessellation;
10
use figures::{Displayable, Figure, Points, Rectlike, Scale};
11
use geometry::ShapeGeometry;
12

            
13
pub use self::batch::*;
14
pub use self::fill::*;
15
pub use self::path::*;
16
pub use self::stroke::*;
17
use crate::math::{Pixels, Point, Rect, Scaled};
18
use crate::scene::{Element, Target};
19

            
20
/// A 2d shape.
21
3
#[derive(Debug, Clone)]
22
pub struct Shape<Unit> {
23
    geometry: ShapeGeometry<Unit>,
24
    stroke: Option<Stroke>,
25
    fill: Option<Fill>,
26
}
27

            
28
impl<Unit> Default for Shape<Unit> {
29
    fn default() -> Self {
30
        Self {
31
            geometry: ShapeGeometry::Empty,
32
            stroke: None,
33
            fill: None,
34
        }
35
    }
36
}
37

            
38
impl<Unit> Shape<Unit> {
39
    /// Returns a rectangle.
40
    pub fn rect(rect: impl Into<Rect<f32, Unit>>) -> Self {
41
        let rect = rect.into().as_extents();
42
        let path = PathBuilder::new(Point::from_figures(rect.origin.x(), rect.origin.y()))
43
            .line_to(Point::from_figures(rect.extent.x(), rect.origin.y()))
44
            .line_to(Point::from_figures(rect.extent.x(), rect.extent.y()))
45
            .line_to(Point::from_figures(rect.origin.x(), rect.extent.y()))
46
            .close()
47
            .build();
48

            
49
        Self {
50
            geometry: ShapeGeometry::Path(path),
51
            stroke: None,
52
            fill: None,
53
        }
54
    }
55

            
56
    /// Returns a circle with `center` and `radius`.
57
    #[must_use]
58
3
    pub const fn circle(center: Point<f32, Unit>, radius: Figure<f32, Unit>) -> Self {
59
3
        Self {
60
3
            geometry: ShapeGeometry::Circle(Circle { center, radius }),
61
3
            stroke: None,
62
3
            fill: None,
63
3
        }
64
3
    }
65

            
66
    /// Returns a closed polygon created with `points`.
67
    #[must_use]
68
    pub fn polygon(points: impl IntoIterator<Item = Point<f32, Unit>>) -> Self {
69
        let mut points = points.into_iter();
70
        if let Some(start) = points.next() {
71
            let mut builder = PathBuilder::new(start);
72
            for point in points {
73
                builder = builder.line_to(point);
74
            }
75

            
76
            Self {
77
                geometry: ShapeGeometry::Path(builder.close().build()),
78
                stroke: None,
79
                fill: None,
80
            }
81
        } else {
82
            Self::default()
83
        }
84
    }
85

            
86
    /// Builder-style function. Set `fill` and returns self.
87
    #[must_use]
88
3
    pub const fn fill(mut self, fill: Fill) -> Self {
89
3
        self.fill = Some(fill);
90
3
        self
91
3
    }
92

            
93
    /// Builder-style function. Set `stroke` and returns self.
94
    #[must_use]
95
    pub const fn stroke(mut self, stroke: Stroke) -> Self {
96
        self.stroke = Some(stroke);
97
        self
98
    }
99

            
100
    /// Returns the shape with the geometry casted to the unit provided. This
101
    /// does not change the underlying shape data at all.
102
    #[must_use]
103
    pub fn cast_unit<U>(self) -> Shape<U> {
104
        Shape {
105
            geometry: self.geometry.cast_unit(),
106
            fill: self.fill,
107
            stroke: self.stroke,
108
        }
109
    }
110
}
111

            
112
impl<Unit> Shape<Unit>
113
where
114
    Self: Displayable<f32, Pixels = Shape<Pixels>>,
115
{
116
    /// Renders the shape within `scene`. Uses the coordinates in the shape
117
    /// without translation.
118
3
    pub fn render(&self, scene: &Target) {
119
3
        self.render_at(&Point::<f32, Pixels>::default(), scene);
120
3
    }
121

            
122
    /// Renders the shape at `location` within `scene`.
123
3
    pub fn render_at(
124
3
        &self,
125
3
        location: &impl Displayable<f32, Pixels = Point<f32, Pixels>>,
126
3
        scene: &Target,
127
3
    ) {
128
3
        let location = location.to_pixels(scene.scale());
129
3
        let pixel_shape = self.to_pixels(scene.scale());
130
3
        let translated = pixel_shape.convert_from_user_to_device(location, scene);
131
3
        scene.push_element(Element::Shape(translated));
132
3
    }
133
}
134

            
135
impl Shape<Pixels> {
136
3
    fn convert_from_user_to_device(&self, location: Point<f32, Pixels>, scene: &Target) -> Self {
137
3
        Self {
138
3
            geometry: self
139
3
                .geometry
140
3
                .translate_and_convert_to_device(location, scene),
141
3
            fill: self.fill.clone(),
142
3
            stroke: self.stroke.clone(),
143
3
        }
144
3
    }
145
}
146

            
147
impl Shape<Pixels> {
148
3
    pub(crate) fn build(&self, builder: &mut easygpu_lyon::ShapeBuilder) -> crate::Result<()> {
149
3
        self.geometry.build(builder, &self.stroke, &self.fill)
150
3
    }
151
}
152

            
153
impl<Src, Dst> std::ops::Mul<Scale<f32, Src, Dst>> for Shape<Src> {
154
    type Output = Shape<Dst>;
155

            
156
    fn mul(self, scale: Scale<f32, Src, Dst>) -> Self::Output {
157
        Self::Output {
158
            geometry: self.geometry * scale,
159
            fill: self.fill,
160
            stroke: self.stroke,
161
        }
162
    }
163
}
164

            
165
impl Displayable<f32> for Shape<Pixels> {
166
    type Pixels = Self;
167
    type Points = Shape<Points>;
168
    type Scaled = Shape<Scaled>;
169

            
170
    fn to_pixels(&self, _scale: &figures::DisplayScale<f32>) -> Self::Pixels {
171
        self.clone()
172
    }
173

            
174
    fn to_points(&self, scale: &figures::DisplayScale<f32>) -> Self::Points {
175
        Shape {
176
            geometry: self.geometry.to_points(scale),
177
            stroke: self.stroke.clone(),
178
            fill: self.fill.clone(),
179
        }
180
    }
181

            
182
    fn to_scaled(&self, scale: &figures::DisplayScale<f32>) -> Self::Scaled {
183
        Shape {
184
            geometry: self.geometry.to_scaled(scale),
185
            stroke: self.stroke.clone(),
186
            fill: self.fill.clone(),
187
        }
188
    }
189
}
190

            
191
impl Displayable<f32> for Shape<Points> {
192
    type Pixels = Shape<Pixels>;
193
    type Points = Self;
194
    type Scaled = Shape<Scaled>;
195

            
196
    fn to_pixels(&self, scale: &figures::DisplayScale<f32>) -> Self::Pixels {
197
        Shape {
198
            geometry: self.geometry.to_pixels(scale),
199
            stroke: self.stroke.clone(),
200
            fill: self.fill.clone(),
201
        }
202
    }
203

            
204
    fn to_points(&self, _scale: &figures::DisplayScale<f32>) -> Self::Points {
205
        self.clone()
206
    }
207

            
208
    fn to_scaled(&self, scale: &figures::DisplayScale<f32>) -> Self::Scaled {
209
        Shape {
210
            geometry: self.geometry.to_scaled(scale),
211
            stroke: self.stroke.clone(),
212
            fill: self.fill.clone(),
213
        }
214
    }
215
}
216

            
217
impl Displayable<f32> for Shape<Scaled> {
218
    type Pixels = Shape<Pixels>;
219
    type Points = Shape<Points>;
220
    type Scaled = Self;
221

            
222
3
    fn to_pixels(&self, scale: &figures::DisplayScale<f32>) -> Self::Pixels {
223
3
        Shape {
224
3
            geometry: self.geometry.to_pixels(scale),
225
3
            stroke: self.stroke.clone(),
226
3
            fill: self.fill.clone(),
227
3
        }
228
3
    }
229

            
230
    fn to_points(&self, scale: &figures::DisplayScale<f32>) -> Self::Points {
231
        Shape {
232
            geometry: self.geometry.to_points(scale),
233
            stroke: self.stroke.clone(),
234
            fill: self.fill.clone(),
235
        }
236
    }
237

            
238
    fn to_scaled(&self, _scale: &figures::DisplayScale<f32>) -> Self::Scaled {
239
        self.clone()
240
    }
241
}
242

            
243
3
const fn lyon_point<T>(pt: Point<f32, T>) -> lyon_tessellation::math::Point {
244
3
    lyon_tessellation::math::Point::new(pt.x, pt.y)
245
3
}