1use crate::style::{FillStyle, StrokeStyle, Style};
2
3use data_stream::{
4 default_settings::PortableSettings, from_stream, numbers::EndianSettings, to_stream,
5 FromStream, ToStream,
6};
7use femtovg::{Canvas, Path, Renderer};
8use ga2::Vector;
9
10use std::io::{Error, ErrorKind, Read, Result, Write};
11
12#[derive(Copy, Clone, Debug)]
13enum IndexedVerb {
14 MoveTo(usize),
15 LineTo(usize),
16 QuadTo(usize, usize),
17 BezierTo(usize, usize, usize),
18 Close,
19}
20
21impl ToStream<PortableSettings> for IndexedVerb {
22 fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
23 use IndexedVerb::*;
24 match self {
25 MoveTo(index) => {
26 to_stream::<PortableSettings, _, _>(&0u8, stream)?;
27 to_stream::<PortableSettings, _, _>(index, stream)
28 }
29 LineTo(index) => {
30 to_stream::<PortableSettings, _, _>(&1u8, stream)?;
31 to_stream::<PortableSettings, _, _>(index, stream)
32 }
33 QuadTo(index1, index2) => {
34 to_stream::<PortableSettings, _, _>(&2u8, stream)?;
35 to_stream::<PortableSettings, _, _>(index1, stream)?;
36 to_stream::<PortableSettings, _, _>(index2, stream)
37 }
38 BezierTo(index1, index2, index3) => {
39 to_stream::<PortableSettings, _, _>(&3u8, stream)?;
40 to_stream::<PortableSettings, _, _>(index1, stream)?;
41 to_stream::<PortableSettings, _, _>(index2, stream)?;
42 to_stream::<PortableSettings, _, _>(index3, stream)
43 }
44 Close => to_stream::<PortableSettings, _, _>(&4u8, stream),
45 }
46 }
47}
48
49impl FromStream<PortableSettings> for IndexedVerb {
50 fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
51 let verb_kind: u8 = from_stream::<PortableSettings, _, _>(stream)?;
52
53 use IndexedVerb::*;
54 Ok(match verb_kind {
55 0 => MoveTo(from_stream::<PortableSettings, _, _>(stream)?),
56 1 => LineTo(from_stream::<PortableSettings, _, _>(stream)?),
57 2 => QuadTo(
58 from_stream::<PortableSettings, _, _>(stream)?,
59 from_stream::<PortableSettings, _, _>(stream)?,
60 ),
61 3 => BezierTo(
62 from_stream::<PortableSettings, _, _>(stream)?,
63 from_stream::<PortableSettings, _, _>(stream)?,
64 from_stream::<PortableSettings, _, _>(stream)?,
65 ),
66 4 => Close,
67 _ => {
68 return Err(Error::new(
69 ErrorKind::InvalidData,
70 "Trying to read invalid enum variant",
71 ))
72 }
73 })
74 }
75}
76
77#[derive(Clone)]
82pub struct IndexedPath {
83 verbs: Vec<IndexedVerb>,
84 style: Style,
85}
86
87impl IndexedPath {
88 pub fn stroke(style: StrokeStyle) -> Self {
90 Self {
91 verbs: Vec::new(),
92 style: Style::Stroke(style),
93 }
94 }
95
96 pub fn fill(style: FillStyle) -> Self {
98 Self {
99 verbs: Vec::new(),
100 style: Style::Fill(style),
101 }
102 }
103
104 pub fn new(fill: FillStyle, stroke: StrokeStyle) -> Self {
106 Self {
107 verbs: Vec::new(),
108 style: Style::Colored { fill, stroke },
109 }
110 }
111
112 pub fn move_to(&mut self, index: usize) {
114 self.verbs.push(IndexedVerb::MoveTo(index));
115 }
116
117 pub fn line_to(&mut self, index: usize) {
119 self.verbs.push(IndexedVerb::LineTo(index));
120 }
121
122 pub fn quad_to(&mut self, index1: usize, index2: usize) {
124 self.verbs.push(IndexedVerb::QuadTo(index1, index2));
125 }
126
127 pub fn bezier_to(&mut self, index1: usize, index2: usize, index3: usize) {
129 self.verbs
130 .push(IndexedVerb::BezierTo(index1, index2, index3));
131 }
132
133 pub fn close(&mut self) {
135 self.verbs.push(IndexedVerb::Close);
136 }
137
138 pub fn render<R: Renderer>(&self, canvas: &mut Canvas<R>, points: &[Vector<f32>]) {
140 let mut path = Path::new();
141 for verb in &self.verbs {
142 use IndexedVerb::*;
143 match *verb {
144 MoveTo(index) => {
145 let point = points[index];
146 path.move_to(point.x, point.y);
147 }
148 LineTo(index) => {
149 let point = points[index];
150 path.line_to(point.x, point.y);
151 }
152 QuadTo(index1, index2) => {
153 let point1 = points[index1];
154 let point2 = points[index2];
155 path.quad_to(point1.x, point1.y, point2.x, point2.y);
156 }
157 BezierTo(index1, index2, index3) => {
158 let point1 = points[index1];
159 let point2 = points[index2];
160 let point3 = points[index3];
161 path.bezier_to(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y);
162 }
163 Close => path.close(),
164 }
165 }
166
167 use Style::*;
168 match &self.style {
169 Stroke(style) => canvas.stroke_path(&path, &style.to_paint()),
170 Fill(style) => canvas.fill_path(&path, &style.to_paint()),
171 Colored { fill, stroke } => {
172 canvas.fill_path(&path, &fill.to_paint());
173 canvas.stroke_path(&path, &stroke.to_paint());
174 }
175 }
176 }
177}
178
179impl<S: EndianSettings> ToStream<S> for IndexedPath {
180 fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
181 to_stream(&self.verbs, stream)?;
182 to_stream::<S, _, _>(&self.style, stream)
183 }
184}
185
186impl<S: EndianSettings> FromStream<S> for IndexedPath {
187 fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
188 Ok(Self {
189 verbs: from_stream(stream)?,
190 style: from_stream::<S, _, _>(stream)?,
191 })
192 }
193}