1use super::geometry::{Curve, Line, Rect};
2use super::texture::{TextureView, TextureViewAllocator};
3use std::f32;
4use std::iter::FromIterator;
5
6pub struct Shape {
7 segments: Vec<ShapeSegment>,
8}
9
10impl Shape {
11 pub fn new(segments: Vec<ShapeSegment>) -> Self {
12 Self { segments }
13 }
14
15 pub fn get_segments(&self) -> &[ShapeSegment] {
16 &self.segments
17 }
18}
19
20#[derive(Clone, Copy)]
21pub enum ShapeSegment {
22 Line { line: Line, mask: u8 },
23 Curve { curve: Curve, mask: u8 },
24 End { clock_wise: bool },
25}
26
27impl ShapeSegment {
28 pub fn bounding_box(&self) -> Option<Rect<f32>> {
29 match self {
30 ShapeSegment::Line { line, .. } => Some(line.bounding_box()),
31 ShapeSegment::Curve { curve, .. } => Some(curve.bounding_box()),
32 ShapeSegment::End { .. } => None,
33 }
34 }
35}
36
37pub struct AllocatedShape {
38 pub shape: Shape,
39 pub shape_bb: Rect<f32>,
40 pub texture_view: TextureView,
41 pub max_distance: f32,
42}
43
44impl AllocatedShape {
45 pub fn new(
46 shape: Shape,
47 texture_allocator: &mut TextureViewAllocator,
48 max_distance: f32,
49 ) -> Option<Self> {
50 let mut max_bb: Option<Rect<f32>> = None;
51 for segment in &shape.segments {
52 if let Some(bb) = segment.bounding_box() {
53 if let Some(ref mut max_bb) = max_bb {
54 max_bb.min.x = max_bb.min.x.min(bb.min.x);
55 max_bb.min.y = max_bb.min.y.min(bb.min.y);
56 max_bb.max.x = max_bb.max.x.max(bb.max.x);
57 max_bb.max.y = max_bb.max.y.max(bb.max.y);
58 } else {
59 max_bb = Some(bb);
60 }
61 }
62 }
63
64 let mut max_bb = max_bb?;
65 max_bb.min.x -= max_distance;
66 max_bb.min.y -= max_distance;
67 max_bb.max.x += max_distance;
68 max_bb.max.y += max_distance;
69
70 let texture_view = texture_allocator
71 .allocate(max_bb.width().ceil() as u32, max_bb.height().ceil() as u32)?;
72
73 Some(Self {
74 shape,
75 shape_bb: max_bb,
76 texture_view,
77 max_distance,
78 })
79 }
80}
81
82pub enum Segment {
83 Start { count: usize },
84 Line { line: Line },
85 Curve { curve: Curve },
86}
87
88impl<'a> FromIterator<Segment> for Shape {
89 fn from_iter<T: IntoIterator<Item = Segment>>(segments: T) -> Self {
90 let mut shape_segments = Vec::new();
91 let mut area = 0.0;
92 let mut mask = 0;
93 let mut remaining_segments = 0;
94
95 fn next_mask(mask: u8, remaining_segments: usize) -> u8 {
96 match mask {
97 0b110 => 0b011,
98 0b011 => 0b101,
99 _ => if remaining_segments == 0 {
100 0b011
101 } else {
102 0b110
103 },
104 }
105 };
106
107 let mut iter = segments.into_iter();
108 while let Some(segment) = iter.next() {
109 match segment {
110 Segment::Start { count } => {
111 remaining_segments = count;
112 mask = 0;
113 area = 0.0;
114 }
115 Segment::Line { line } => {
116 area += line.area();
117 remaining_segments -= 1;
118 mask = next_mask(mask, remaining_segments);
119 shape_segments.push(ShapeSegment::Line { line, mask });
120 }
121 Segment::Curve { curve } => {
122 area += curve.area();
123 remaining_segments -= 1;
124 mask = next_mask(mask, remaining_segments);
125 shape_segments.push(ShapeSegment::Curve { curve, mask });
126 }
127 }
128
129 if remaining_segments == 0 {
130 shape_segments.push(ShapeSegment::End {
131 clock_wise: area < 0.0,
132 });
133 }
134 }
135
136 Shape::new(shape_segments)
137 }
138}