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