1use super::scene::{Path, PathVertex};
2use crate::{color::Color, json::ToJson};
3pub use pathfinder_geometry::*;
4use rect::RectF;
5use serde::{Deserialize, Deserializer};
6use serde_json::json;
7use vector::{vec2f, Vector2F};
8
9pub struct PathBuilder {
10 vertices: Vec<PathVertex>,
11 start: Vector2F,
12 current: Vector2F,
13 contour_count: usize,
14 bounds: RectF,
15}
16
17enum PathVertexKind {
18 Solid,
19 Quadratic,
20}
21
22impl Default for PathBuilder {
23 fn default() -> Self {
24 PathBuilder::new()
25 }
26}
27
28impl PathBuilder {
29 pub fn new() -> Self {
30 Self {
31 vertices: Vec::new(),
32 start: vec2f(0., 0.),
33 current: vec2f(0., 0.),
34 contour_count: 0,
35 bounds: RectF::default(),
36 }
37 }
38
39 pub fn reset(&mut self, point: Vector2F) {
40 self.vertices.clear();
41 self.start = point;
42 self.current = point;
43 self.contour_count = 0;
44 }
45
46 pub fn line_to(&mut self, point: Vector2F) {
47 self.contour_count += 1;
48 if self.contour_count > 1 {
49 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
50 }
51
52 self.current = point;
53 }
54
55 pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
56 self.contour_count += 1;
57 if self.contour_count > 1 {
58 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
59 }
60
61 self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
62 self.current = point;
63 }
64
65 pub fn build(mut self, color: Color, clip_bounds: Option<RectF>) -> Path {
66 if let Some(clip_bounds) = clip_bounds {
67 self.bounds = self.bounds.intersection(clip_bounds).unwrap_or_default();
68 }
69 Path {
70 bounds: self.bounds,
71 color,
72 vertices: self.vertices,
73 }
74 }
75
76 fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
77 if self.vertices.is_empty() {
78 self.bounds = RectF::new(a, Vector2F::zero());
79 }
80 self.bounds = self.bounds.union_point(a).union_point(b).union_point(c);
81
82 match kind {
83 PathVertexKind::Solid => {
84 self.vertices.push(PathVertex {
85 xy_position: a,
86 st_position: vec2f(0., 1.),
87 });
88 self.vertices.push(PathVertex {
89 xy_position: b,
90 st_position: vec2f(0., 1.),
91 });
92 self.vertices.push(PathVertex {
93 xy_position: c,
94 st_position: vec2f(0., 1.),
95 });
96 }
97 PathVertexKind::Quadratic => {
98 self.vertices.push(PathVertex {
99 xy_position: a,
100 st_position: vec2f(0., 0.),
101 });
102 self.vertices.push(PathVertex {
103 xy_position: b,
104 st_position: vec2f(0.5, 0.),
105 });
106 self.vertices.push(PathVertex {
107 xy_position: c,
108 st_position: vec2f(1., 1.),
109 });
110 }
111 }
112 }
113}
114
115pub fn deserialize_vec2f<'de, D>(deserializer: D) -> Result<Vector2F, D::Error>
116where
117 D: Deserializer<'de>,
118{
119 let [x, y]: [f32; 2] = Deserialize::deserialize(deserializer)?;
120 Ok(vec2f(x, y))
121}
122
123impl ToJson for Vector2F {
124 fn to_json(&self) -> serde_json::Value {
125 json!([self.x(), self.y()])
126 }
127}
128
129impl ToJson for RectF {
130 fn to_json(&self) -> serde_json::Value {
131 json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
132 }
133}