1use crate::{
2 d2::{SimpleConvexGeometry, Vertex2D},
3 Geometry,
4};
5
6#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default)]
8pub struct Rad(pub f32);
9
10#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default)]
12pub struct Deg(pub f32);
13
14impl From<Rad> for Deg {
15 #[inline]
16 fn from(rad: Rad) -> Deg {
17 Deg(rad.0 * 180.0 / std::f32::consts::PI)
18 }
19}
20
21impl From<Deg> for Rad {
22 #[inline]
23 fn from(deg: Deg) -> Rad {
24 Rad(deg.0 * std::f32::consts::PI / 180.0)
25 }
26}
27
28#[derive(Debug, Copy, Clone, PartialEq)]
29pub enum ArcType {
30 Pie,
31 Open,
32 Closed,
33}
34
35impl Default for ArcType {
36 fn default() -> Self {
37 ArcType::Pie
38 }
39}
40
41#[derive(Debug, Copy, Clone, Default, PartialEq)]
42pub struct Arc {
43 pub arc_type: ArcType,
44 pub x: f32,
45 pub y: f32,
46 pub radius: f32,
47 pub angle1: Rad,
48 pub angle2: Rad,
49 pub segments: u32,
50}
51
52impl SimpleConvexGeometry for Arc {
53 type Vertices = std::vec::IntoIter<Vertex2D>;
54
55 fn vertices(&self) -> Self::Vertices {
56 let Arc {
57 arc_type,
58 x,
59 y,
60 radius,
61 angle1,
62 angle2,
63 segments,
64 } = *self;
65 let (angle1, angle2) = (angle1.0, angle2.0);
66
67 if segments == 0 || (angle1 - angle2).abs() < f32::EPSILON {
68 return Vec::<Vertex2D>::new().into_iter();
69 }
70
71 const TWO_PI: f32 = std::f32::consts::PI * 2.;
72 if (angle1 - angle2).abs() >= TWO_PI {
73 return SimpleConvexGeometry::vertices(&Circle {
74 x,
75 y,
76 radius,
77 segments,
78 })
79 .collect::<Vec<_>>() .into_iter();
81 }
82
83 let angle_shift = (angle2 - angle1) / segments as f32;
84 if angle_shift == 0. {
85 return Vec::<Vertex2D>::new().into_iter(); }
87
88 let mut create_points = {
89 let mut phi = angle1;
90 move |coordinates: &mut [Vertex2D]| {
91 for coordinate in coordinates.iter_mut() {
92 let (s, c) = phi.sin_cos();
93 let x = x + radius * c;
94 let y = y + radius * s;
95 coordinate.position[0] = x;
96 coordinate.position[1] = y;
97 coordinate.uv[0] = (c + 1.) / 2.;
98 coordinate.uv[1] = (s + 1.) / 2.;
99 phi += angle_shift;
100 }
101 }
102 };
103
104 let vertices = match arc_type {
105 ArcType::Pie => {
106 let num_coords = segments as usize + 3;
107 let mut coords = vec![Vertex2D::default(); num_coords];
108 let anchor = Vertex2D {
109 position: [x, y],
110 ..Vertex2D::default()
111 };
112 coords[0] = anchor;
113 coords[num_coords - 1] = anchor;
114 create_points(&mut coords[1..num_coords - 1]);
115 coords
116 }
117 ArcType::Open => {
118 let num_coords = segments as usize + 1;
119 let mut coords = vec![Vertex2D::default(); num_coords];
120 create_points(&mut coords);
121 coords
122 }
123 ArcType::Closed => {
124 let num_coords = segments as usize + 2;
125 let mut coords = vec![Vertex2D::default(); num_coords];
126 create_points(&mut coords);
127 coords[num_coords - 1] = coords[0];
128 coords
129 }
130 };
131
132 vertices.into_iter()
133 }
134
135 fn vertex_count(&self) -> usize {
136 match self.arc_type {
137 ArcType::Pie => self.segments as usize + 3,
138 ArcType::Open => self.segments as usize + 1,
139 ArcType::Closed => self.segments as usize + 2,
140 }
141 }
142}
143
144#[derive(Debug, Copy, Clone, Default, PartialEq)]
145pub struct Circle {
146 pub x: f32,
147 pub y: f32,
148 pub radius: f32,
149 pub segments: u32,
150}
151
152impl SimpleConvexGeometry for Circle {
153 type Vertices = <SimpleConvexPolygon as SimpleConvexGeometry>::Vertices;
154
155 fn vertices(&self) -> Self::Vertices {
156 let ellipse: Ellipse = (*self).into();
157 let polygon: SimpleConvexPolygon = ellipse.into();
158 SimpleConvexGeometry::vertices(&polygon)
159 }
160
161 fn vertex_count(&self) -> usize {
162 self.segments as usize
163 }
164}
165
166impl From<Circle> for Ellipse {
167 fn from(c: Circle) -> Self {
168 Self {
169 x: c.x,
170 y: c.y,
171 radius_x: c.radius,
172 radius_y: c.radius,
173 segments: c.segments,
174 }
175 }
176}
177
178#[derive(Copy, Clone, Default, Debug, PartialEq)]
179pub struct Ellipse {
180 pub x: f32,
181 pub y: f32,
182 pub radius_x: f32,
183 pub radius_y: f32,
184 pub segments: u32,
185}
186
187impl From<Ellipse> for SimpleConvexPolygon {
188 fn from(e: Ellipse) -> Self {
189 Self {
190 x: e.x,
191 y: e.y,
192 vertex_count: e.segments,
193 radius_x: e.radius_x,
194 radius_y: e.radius_y,
195 }
196 }
197}
198
199impl SimpleConvexGeometry for Ellipse {
200 type Vertices = <SimpleConvexPolygon as SimpleConvexGeometry>::Vertices;
201
202 fn vertices(&self) -> Self::Vertices {
203 let polygon: SimpleConvexPolygon = (*self).into();
204 SimpleConvexGeometry::vertices(&polygon)
205 }
206
207 fn vertex_count(&self) -> usize {
208 self.segments as usize
209 }
210}
211
212#[derive(Copy, Clone, Default, Debug, PartialEq)]
213pub struct Rectangle {
214 pub x: f32,
215 pub y: f32,
216 pub width: f32,
217 pub height: f32,
218}
219
220impl Rectangle {
221 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
222 Self {
223 x,
224 y,
225 width,
226 height,
227 }
228 }
229
230 pub fn vertices(&self) -> Vec<Vertex2D> {
231 vec![
232 Vertex2D {
233 position: [self.x, self.y],
234 uv: [0., 0.],
235 ..Default::default()
236 },
237 Vertex2D {
238 position: [self.x, self.y + self.height],
239 uv: [0., 1.],
240 ..Default::default()
241 },
242 Vertex2D {
243 position: [self.x + self.width, self.y + self.height],
244 uv: [1., 1.],
245 ..Default::default()
246 },
247 Vertex2D {
248 position: [self.x + self.width, self.y],
249 uv: [1., 0.],
250 ..Default::default()
251 },
252 ]
253 }
254}
255
256impl From<Rectangle> for solstice::quad_batch::Quad<Vertex2D> {
257 fn from(r: Rectangle) -> Self {
258 use solstice::{quad_batch::Quad, viewport::Viewport};
259 let positions = Quad::from(Viewport::new(r.x, r.y, r.width, r.height));
260 let uvs = Quad::from(Viewport::new(0., 0., 1., 1.));
261 positions.zip(uvs).map(|((x, y), (s, t))| Vertex2D {
262 position: [x, y],
263 uv: [s, t],
264 ..Default::default()
265 })
266 }
267}
268
269impl From<Rectangle> for solstice::quad_batch::Quad<(f32, f32)> {
270 fn from(r: Rectangle) -> Self {
271 use solstice::{quad_batch::Quad, viewport::Viewport};
272 Quad::from(Viewport::new(r.x, r.y, r.width, r.height))
273 }
274}
275
276impl From<&Rectangle> for Geometry<'_, Vertex2D> {
277 fn from(r: &Rectangle) -> Self {
278 Geometry::new(r.vertices(), Some(&[0u32, 1, 2, 0, 3, 2][..]))
279 }
280}
281
282impl From<Rectangle> for Geometry<'_, Vertex2D> {
283 fn from(r: Rectangle) -> Self {
284 (&r).into()
285 }
286}
287
288impl From<solstice::quad_batch::Quad<Vertex2D>> for Geometry<'_, Vertex2D> {
289 fn from(quad: solstice::quad_batch::Quad<Vertex2D>) -> Self {
290 Geometry::new(
291 quad.vertices.to_vec(),
292 Some(
293 solstice::quad_batch::INDICES[..]
294 .iter()
295 .copied()
296 .map(|i| i as u32)
297 .collect::<Vec<_>>(),
298 ),
299 )
300 }
301}
302
303#[derive(Copy, Clone, Default, Debug, PartialEq)]
304pub struct RegularPolygon {
305 pub x: f32,
306 pub y: f32,
307 pub vertex_count: u32,
308 pub radius: f32,
309}
310
311impl RegularPolygon {
312 pub fn new(x: f32, y: f32, vertex_count: u32, radius: f32) -> Self {
313 Self {
314 x,
315 y,
316 vertex_count,
317 radius,
318 }
319 }
320}
321
322impl SimpleConvexGeometry for RegularPolygon {
323 type Vertices = std::iter::Map<std::ops::Range<u32>, Box<dyn Fn(u32) -> Vertex2D>>;
324
325 fn vertices(&self) -> Self::Vertices {
326 const TWO_PI: f32 = std::f32::consts::PI * 2.;
327 let RegularPolygon {
328 x,
329 y,
330 vertex_count,
331 radius,
332 } = *self;
333 let angle_shift = TWO_PI / vertex_count as f32;
334
335 (0..vertex_count).map(Box::new(move |i| {
337 let phi = angle_shift * i as f32;
338 let (s, c) = phi.sin_cos();
339 let (x, y) = (x + radius * c, y + radius * s);
340 Vertex2D::new([x, y], [1., 1., 1., 1.], [(c + 1.) / 2., (s + 1.) / 2.])
341 }))
342 }
343
344 fn vertex_count(&self) -> usize {
345 self.vertex_count as _
346 }
347}
348
349#[derive(Copy, Clone, Default, Debug, PartialEq)]
350pub struct SimpleConvexPolygon {
351 pub x: f32,
352 pub y: f32,
353 pub vertex_count: u32,
354 pub radius_x: f32,
355 pub radius_y: f32,
356}
357
358impl SimpleConvexGeometry for SimpleConvexPolygon {
359 type Vertices = std::iter::Map<std::ops::Range<u32>, Box<dyn Fn(u32) -> Vertex2D>>;
360
361 fn vertices(&self) -> Self::Vertices {
362 const TWO_PI: f32 = std::f32::consts::PI * 2.;
363 let SimpleConvexPolygon {
364 x,
365 y,
366 vertex_count,
367 radius_x,
368 radius_y,
369 } = *self;
370 let angle_shift = TWO_PI / vertex_count as f32;
371
372 (0..vertex_count).map(Box::new(move |i| {
374 let phi = angle_shift * i as f32;
375 let (x, y) = (x + radius_x * phi.cos(), y + radius_y * phi.sin());
376 Vertex2D::new([x, y], [1., 1., 1., 1.], [0.5, 0.5])
377 }))
378 }
379
380 fn vertex_count(&self) -> usize {
381 self.vertex_count as usize
382 }
383}
384
385impl<T> From<T> for Geometry<'_, Vertex2D>
386where
387 T: SimpleConvexGeometry,
388{
389 fn from(s: T) -> Self {
390 let vertices = s.vertices().collect::<Vec<_>>();
391 let indices = (1..(vertices.len() as u32).saturating_sub(1))
392 .flat_map(|i| [0, i, i + 1])
393 .collect::<Vec<_>>();
394 Geometry::new(vertices, Some(indices))
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401
402 #[test]
403 fn geometry() {
404 use crate::Geometry;
405 let geometry = SimpleConvexPolygon {
406 x: 0.0,
407 y: 0.0,
408 vertex_count: 3,
409 radius_x: 100.,
410 radius_y: 100.,
411 };
412
413 let data = Geometry::<'_, Vertex2D>::from(geometry);
414 assert_eq!(data.vertices.len(), 3);
415 assert_eq!(data.indices.unwrap().len(), 3);
416
417 let geometry = SimpleConvexPolygon {
418 vertex_count: 4,
419 ..geometry
420 };
421 let data = Geometry::<'_, Vertex2D>::from(geometry);
422 assert_eq!(data.vertices.len(), 4);
423 assert_eq!(data.indices.unwrap().len(), 6);
424
425 let geometry = SimpleConvexPolygon {
426 vertex_count: 5,
427 ..geometry
428 };
429 let data = Geometry::<'_, Vertex2D>::from(geometry);
430 assert_eq!(data.vertices.len(), 5);
431 assert_eq!(data.indices.unwrap().len(), (5 - 2) * 3);
432 }
433}