1use crate::{
2 point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point,
3 ScaledPixels, StackingOrder,
4};
5use collections::BTreeMap;
6use etagere::euclid::{Point3D, Vector3D};
7use plane_split::{BspSplitter, Polygon as BspPolygon};
8use std::{fmt::Debug, iter::Peekable, mem, slice};
9
10// Exported to metal
11pub(crate) type PointF = Point<f32>;
12#[allow(non_camel_case_types, unused)]
13pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
14
15pub type LayerId = u32;
16
17pub type DrawOrder = u32;
18
19pub(crate) struct SceneBuilder {
20 last_order: Option<(StackingOrder, LayerId)>,
21 layers_by_order: BTreeMap<StackingOrder, LayerId>,
22 splitter: BspSplitter<(PrimitiveKind, usize)>,
23 shadows: Vec<Shadow>,
24 quads: Vec<Quad>,
25 paths: Vec<Path<ScaledPixels>>,
26 underlines: Vec<Underline>,
27 monochrome_sprites: Vec<MonochromeSprite>,
28 polychrome_sprites: Vec<PolychromeSprite>,
29 surfaces: Vec<Surface>,
30}
31
32impl Default for SceneBuilder {
33 fn default() -> Self {
34 SceneBuilder {
35 last_order: None,
36 layers_by_order: BTreeMap::new(),
37 splitter: BspSplitter::new(),
38 shadows: Vec::new(),
39 quads: Vec::new(),
40 paths: Vec::new(),
41 underlines: Vec::new(),
42 monochrome_sprites: Vec::new(),
43 polychrome_sprites: Vec::new(),
44 surfaces: Vec::new(),
45 }
46 }
47}
48
49impl SceneBuilder {
50 pub fn build(&mut self) -> Scene {
51 // Map each layer id to a float between 0. and 1., with 1. closer to the viewer.
52 let mut layer_z_values = vec![0.; self.layers_by_order.len()];
53 for (ix, layer_id) in self.layers_by_order.values().enumerate() {
54 layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32;
55 }
56 self.layers_by_order.clear();
57 self.last_order = None;
58
59 // Add all primitives to the BSP splitter to determine draw order
60 self.splitter.reset();
61
62 for (ix, shadow) in self.shadows.iter().enumerate() {
63 let z = layer_z_values[shadow.order as LayerId as usize];
64 self.splitter
65 .add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix)));
66 }
67
68 for (ix, quad) in self.quads.iter().enumerate() {
69 let z = layer_z_values[quad.order as LayerId as usize];
70 self.splitter
71 .add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix)));
72 }
73
74 for (ix, path) in self.paths.iter().enumerate() {
75 let z = layer_z_values[path.order as LayerId as usize];
76 self.splitter
77 .add(path.bounds.to_bsp_polygon(z, (PrimitiveKind::Path, ix)));
78 }
79
80 for (ix, underline) in self.underlines.iter().enumerate() {
81 let z = layer_z_values[underline.order as LayerId as usize];
82 self.splitter.add(
83 underline
84 .bounds
85 .to_bsp_polygon(z, (PrimitiveKind::Underline, ix)),
86 );
87 }
88
89 for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() {
90 let z = layer_z_values[monochrome_sprite.order as LayerId as usize];
91 self.splitter.add(
92 monochrome_sprite
93 .bounds
94 .to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)),
95 );
96 }
97
98 for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() {
99 let z = layer_z_values[polychrome_sprite.order as LayerId as usize];
100 self.splitter.add(
101 polychrome_sprite
102 .bounds
103 .to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)),
104 );
105 }
106
107 for (ix, surface) in self.surfaces.iter().enumerate() {
108 let z = layer_z_values[surface.order as LayerId as usize];
109 self.splitter.add(
110 surface
111 .bounds
112 .to_bsp_polygon(z, (PrimitiveKind::Surface, ix)),
113 );
114 }
115
116 // Sort all polygons, then reassign the order field of each primitive to `draw_order`
117 // We need primitives to be repr(C), hence the weird reuse of the order field for two different types.
118 for (draw_order, polygon) in self
119 .splitter
120 .sort(Vector3D::new(0., 0., 1.))
121 .iter()
122 .enumerate()
123 {
124 match polygon.anchor {
125 (PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder,
126 (PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder,
127 (PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder,
128 (PrimitiveKind::Underline, ix) => {
129 self.underlines[ix].order = draw_order as DrawOrder
130 }
131 (PrimitiveKind::MonochromeSprite, ix) => {
132 self.monochrome_sprites[ix].order = draw_order as DrawOrder
133 }
134 (PrimitiveKind::PolychromeSprite, ix) => {
135 self.polychrome_sprites[ix].order = draw_order as DrawOrder
136 }
137 (PrimitiveKind::Surface, ix) => self.surfaces[ix].order = draw_order as DrawOrder,
138 }
139 }
140
141 self.shadows.sort_unstable();
142 self.quads.sort_unstable();
143 self.paths.sort_unstable();
144 self.underlines.sort_unstable();
145 self.monochrome_sprites.sort_unstable();
146 self.polychrome_sprites.sort_unstable();
147 self.surfaces.sort_unstable();
148
149 Scene {
150 shadows: mem::take(&mut self.shadows),
151 quads: mem::take(&mut self.quads),
152 paths: mem::take(&mut self.paths),
153 underlines: mem::take(&mut self.underlines),
154 monochrome_sprites: mem::take(&mut self.monochrome_sprites),
155 polychrome_sprites: mem::take(&mut self.polychrome_sprites),
156 surfaces: mem::take(&mut self.surfaces),
157 }
158 }
159
160 pub fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) {
161 let primitive = primitive.into();
162 let clipped_bounds = primitive
163 .bounds()
164 .intersect(&primitive.content_mask().bounds);
165 if clipped_bounds.size.width <= ScaledPixels(0.)
166 || clipped_bounds.size.height <= ScaledPixels(0.)
167 {
168 return;
169 }
170
171 let layer_id = self.layer_id_for_order(order);
172 match primitive {
173 Primitive::Shadow(mut shadow) => {
174 shadow.order = layer_id;
175 self.shadows.push(shadow);
176 }
177 Primitive::Quad(mut quad) => {
178 quad.order = layer_id;
179 self.quads.push(quad);
180 }
181 Primitive::Path(mut path) => {
182 path.order = layer_id;
183 path.id = PathId(self.paths.len());
184 self.paths.push(path);
185 }
186 Primitive::Underline(mut underline) => {
187 underline.order = layer_id;
188 self.underlines.push(underline);
189 }
190 Primitive::MonochromeSprite(mut sprite) => {
191 sprite.order = layer_id;
192 self.monochrome_sprites.push(sprite);
193 }
194 Primitive::PolychromeSprite(mut sprite) => {
195 sprite.order = layer_id;
196 self.polychrome_sprites.push(sprite);
197 }
198 Primitive::Surface(mut surface) => {
199 surface.order = layer_id;
200 self.surfaces.push(surface);
201 }
202 }
203 }
204
205 fn layer_id_for_order(&mut self, order: &StackingOrder) -> u32 {
206 if let Some((last_order, last_layer_id)) = self.last_order.as_ref() {
207 if last_order == order {
208 return *last_layer_id;
209 }
210 };
211
212 let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) {
213 *layer_id
214 } else {
215 let next_id = self.layers_by_order.len() as LayerId;
216 self.layers_by_order.insert(order.clone(), next_id);
217 next_id
218 };
219 self.last_order = Some((order.clone(), layer_id));
220 layer_id
221 }
222}
223
224pub struct Scene {
225 pub shadows: Vec<Shadow>,
226 pub quads: Vec<Quad>,
227 pub paths: Vec<Path<ScaledPixels>>,
228 pub underlines: Vec<Underline>,
229 pub monochrome_sprites: Vec<MonochromeSprite>,
230 pub polychrome_sprites: Vec<PolychromeSprite>,
231 pub surfaces: Vec<Surface>,
232}
233
234impl Scene {
235 #[allow(dead_code)]
236 pub fn paths(&self) -> &[Path<ScaledPixels>] {
237 &self.paths
238 }
239
240 pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
241 BatchIterator {
242 shadows: &self.shadows,
243 shadows_start: 0,
244 shadows_iter: self.shadows.iter().peekable(),
245 quads: &self.quads,
246 quads_start: 0,
247 quads_iter: self.quads.iter().peekable(),
248 paths: &self.paths,
249 paths_start: 0,
250 paths_iter: self.paths.iter().peekable(),
251 underlines: &self.underlines,
252 underlines_start: 0,
253 underlines_iter: self.underlines.iter().peekable(),
254 monochrome_sprites: &self.monochrome_sprites,
255 monochrome_sprites_start: 0,
256 monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
257 polychrome_sprites: &self.polychrome_sprites,
258 polychrome_sprites_start: 0,
259 polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
260 surfaces: &self.surfaces,
261 surfaces_start: 0,
262 surfaces_iter: self.surfaces.iter().peekable(),
263 }
264 }
265}
266
267struct BatchIterator<'a> {
268 shadows: &'a [Shadow],
269 shadows_start: usize,
270 shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
271 quads: &'a [Quad],
272 quads_start: usize,
273 quads_iter: Peekable<slice::Iter<'a, Quad>>,
274 paths: &'a [Path<ScaledPixels>],
275 paths_start: usize,
276 paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
277 underlines: &'a [Underline],
278 underlines_start: usize,
279 underlines_iter: Peekable<slice::Iter<'a, Underline>>,
280 monochrome_sprites: &'a [MonochromeSprite],
281 monochrome_sprites_start: usize,
282 monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
283 polychrome_sprites: &'a [PolychromeSprite],
284 polychrome_sprites_start: usize,
285 polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
286 surfaces: &'a [Surface],
287 surfaces_start: usize,
288 surfaces_iter: Peekable<slice::Iter<'a, Surface>>,
289}
290
291impl<'a> Iterator for BatchIterator<'a> {
292 type Item = PrimitiveBatch<'a>;
293
294 fn next(&mut self) -> Option<Self::Item> {
295 let mut orders_and_kinds = [
296 (
297 self.shadows_iter.peek().map(|s| s.order),
298 PrimitiveKind::Shadow,
299 ),
300 (self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
301 (self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
302 (
303 self.underlines_iter.peek().map(|u| u.order),
304 PrimitiveKind::Underline,
305 ),
306 (
307 self.monochrome_sprites_iter.peek().map(|s| s.order),
308 PrimitiveKind::MonochromeSprite,
309 ),
310 (
311 self.polychrome_sprites_iter.peek().map(|s| s.order),
312 PrimitiveKind::PolychromeSprite,
313 ),
314 (
315 self.surfaces_iter.peek().map(|s| s.order),
316 PrimitiveKind::Surface,
317 ),
318 ];
319 orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
320
321 let first = orders_and_kinds[0];
322 let second = orders_and_kinds[1];
323 let (batch_kind, max_order) = if first.0.is_some() {
324 (first.1, second.0.unwrap_or(u32::MAX))
325 } else {
326 return None;
327 };
328
329 match batch_kind {
330 PrimitiveKind::Shadow => {
331 let shadows_start = self.shadows_start;
332 let mut shadows_end = shadows_start;
333 while self
334 .shadows_iter
335 .next_if(|shadow| shadow.order <= max_order)
336 .is_some()
337 {
338 shadows_end += 1;
339 }
340 self.shadows_start = shadows_end;
341 Some(PrimitiveBatch::Shadows(
342 &self.shadows[shadows_start..shadows_end],
343 ))
344 }
345 PrimitiveKind::Quad => {
346 let quads_start = self.quads_start;
347 let mut quads_end = quads_start;
348 while self
349 .quads_iter
350 .next_if(|quad| quad.order <= max_order)
351 .is_some()
352 {
353 quads_end += 1;
354 }
355 self.quads_start = quads_end;
356 Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
357 }
358 PrimitiveKind::Path => {
359 let paths_start = self.paths_start;
360 let mut paths_end = paths_start;
361 while self
362 .paths_iter
363 .next_if(|path| path.order <= max_order)
364 .is_some()
365 {
366 paths_end += 1;
367 }
368 self.paths_start = paths_end;
369 Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
370 }
371 PrimitiveKind::Underline => {
372 let underlines_start = self.underlines_start;
373 let mut underlines_end = underlines_start;
374 while self
375 .underlines_iter
376 .next_if(|underline| underline.order <= max_order)
377 .is_some()
378 {
379 underlines_end += 1;
380 }
381 self.underlines_start = underlines_end;
382 Some(PrimitiveBatch::Underlines(
383 &self.underlines[underlines_start..underlines_end],
384 ))
385 }
386 PrimitiveKind::MonochromeSprite => {
387 let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
388 let sprites_start = self.monochrome_sprites_start;
389 let mut sprites_end = sprites_start;
390 while self
391 .monochrome_sprites_iter
392 .next_if(|sprite| {
393 sprite.order <= max_order && sprite.tile.texture_id == texture_id
394 })
395 .is_some()
396 {
397 sprites_end += 1;
398 }
399 self.monochrome_sprites_start = sprites_end;
400 Some(PrimitiveBatch::MonochromeSprites {
401 texture_id,
402 sprites: &self.monochrome_sprites[sprites_start..sprites_end],
403 })
404 }
405 PrimitiveKind::PolychromeSprite => {
406 let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
407 let sprites_start = self.polychrome_sprites_start;
408 let mut sprites_end = self.polychrome_sprites_start;
409 while self
410 .polychrome_sprites_iter
411 .next_if(|sprite| {
412 sprite.order <= max_order && sprite.tile.texture_id == texture_id
413 })
414 .is_some()
415 {
416 sprites_end += 1;
417 }
418 self.polychrome_sprites_start = sprites_end;
419 Some(PrimitiveBatch::PolychromeSprites {
420 texture_id,
421 sprites: &self.polychrome_sprites[sprites_start..sprites_end],
422 })
423 }
424 PrimitiveKind::Surface => {
425 let surfaces_start = self.surfaces_start;
426 let mut surfaces_end = surfaces_start;
427 while self
428 .surfaces_iter
429 .next_if(|surface| surface.order <= max_order)
430 .is_some()
431 {
432 surfaces_end += 1;
433 }
434 self.surfaces_start = surfaces_end;
435 Some(PrimitiveBatch::Surfaces(
436 &self.surfaces[surfaces_start..surfaces_end],
437 ))
438 }
439 }
440 }
441}
442
443#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
444pub enum PrimitiveKind {
445 Shadow,
446 #[default]
447 Quad,
448 Path,
449 Underline,
450 MonochromeSprite,
451 PolychromeSprite,
452 Surface,
453}
454
455pub enum Primitive {
456 Shadow(Shadow),
457 Quad(Quad),
458 Path(Path<ScaledPixels>),
459 Underline(Underline),
460 MonochromeSprite(MonochromeSprite),
461 PolychromeSprite(PolychromeSprite),
462 Surface(Surface),
463}
464
465impl Primitive {
466 pub fn bounds(&self) -> &Bounds<ScaledPixels> {
467 match self {
468 Primitive::Shadow(shadow) => &shadow.bounds,
469 Primitive::Quad(quad) => &quad.bounds,
470 Primitive::Path(path) => &path.bounds,
471 Primitive::Underline(underline) => &underline.bounds,
472 Primitive::MonochromeSprite(sprite) => &sprite.bounds,
473 Primitive::PolychromeSprite(sprite) => &sprite.bounds,
474 Primitive::Surface(surface) => &surface.bounds,
475 }
476 }
477
478 pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
479 match self {
480 Primitive::Shadow(shadow) => &shadow.content_mask,
481 Primitive::Quad(quad) => &quad.content_mask,
482 Primitive::Path(path) => &path.content_mask,
483 Primitive::Underline(underline) => &underline.content_mask,
484 Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
485 Primitive::PolychromeSprite(sprite) => &sprite.content_mask,
486 Primitive::Surface(surface) => &surface.content_mask,
487 }
488 }
489}
490
491#[derive(Debug)]
492pub(crate) enum PrimitiveBatch<'a> {
493 Shadows(&'a [Shadow]),
494 Quads(&'a [Quad]),
495 Paths(&'a [Path<ScaledPixels>]),
496 Underlines(&'a [Underline]),
497 MonochromeSprites {
498 texture_id: AtlasTextureId,
499 sprites: &'a [MonochromeSprite],
500 },
501 PolychromeSprites {
502 texture_id: AtlasTextureId,
503 sprites: &'a [PolychromeSprite],
504 },
505 Surfaces(&'a [Surface]),
506}
507
508#[derive(Default, Debug, Clone, Eq, PartialEq)]
509#[repr(C)]
510pub struct Quad {
511 pub order: u32, // Initially a LayerId, then a DrawOrder.
512 pub bounds: Bounds<ScaledPixels>,
513 pub content_mask: ContentMask<ScaledPixels>,
514 pub background: Hsla,
515 pub border_color: Hsla,
516 pub corner_radii: Corners<ScaledPixels>,
517 pub border_widths: Edges<ScaledPixels>,
518}
519
520impl Ord for Quad {
521 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
522 self.order.cmp(&other.order)
523 }
524}
525
526impl PartialOrd for Quad {
527 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
528 Some(self.cmp(other))
529 }
530}
531
532impl From<Quad> for Primitive {
533 fn from(quad: Quad) -> Self {
534 Primitive::Quad(quad)
535 }
536}
537
538#[derive(Debug, Clone, Eq, PartialEq)]
539#[repr(C)]
540pub struct Underline {
541 pub order: u32,
542 pub bounds: Bounds<ScaledPixels>,
543 pub content_mask: ContentMask<ScaledPixels>,
544 pub thickness: ScaledPixels,
545 pub color: Hsla,
546 pub wavy: bool,
547}
548
549impl Ord for Underline {
550 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
551 self.order.cmp(&other.order)
552 }
553}
554
555impl PartialOrd for Underline {
556 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
557 Some(self.cmp(other))
558 }
559}
560
561impl From<Underline> for Primitive {
562 fn from(underline: Underline) -> Self {
563 Primitive::Underline(underline)
564 }
565}
566
567#[derive(Debug, Clone, Eq, PartialEq)]
568#[repr(C)]
569pub struct Shadow {
570 pub order: u32,
571 pub bounds: Bounds<ScaledPixels>,
572 pub corner_radii: Corners<ScaledPixels>,
573 pub content_mask: ContentMask<ScaledPixels>,
574 pub color: Hsla,
575 pub blur_radius: ScaledPixels,
576}
577
578impl Ord for Shadow {
579 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
580 self.order.cmp(&other.order)
581 }
582}
583
584impl PartialOrd for Shadow {
585 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
586 Some(self.cmp(other))
587 }
588}
589
590impl From<Shadow> for Primitive {
591 fn from(shadow: Shadow) -> Self {
592 Primitive::Shadow(shadow)
593 }
594}
595
596#[derive(Clone, Debug, Eq, PartialEq)]
597#[repr(C)]
598pub struct MonochromeSprite {
599 pub order: u32,
600 pub bounds: Bounds<ScaledPixels>,
601 pub content_mask: ContentMask<ScaledPixels>,
602 pub color: Hsla,
603 pub tile: AtlasTile,
604}
605
606impl Ord for MonochromeSprite {
607 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
608 match self.order.cmp(&other.order) {
609 std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
610 order => order,
611 }
612 }
613}
614
615impl PartialOrd for MonochromeSprite {
616 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
617 Some(self.cmp(other))
618 }
619}
620
621impl From<MonochromeSprite> for Primitive {
622 fn from(sprite: MonochromeSprite) -> Self {
623 Primitive::MonochromeSprite(sprite)
624 }
625}
626
627#[derive(Clone, Debug, Eq, PartialEq)]
628#[repr(C)]
629pub struct PolychromeSprite {
630 pub order: u32,
631 pub bounds: Bounds<ScaledPixels>,
632 pub content_mask: ContentMask<ScaledPixels>,
633 pub corner_radii: Corners<ScaledPixels>,
634 pub tile: AtlasTile,
635 pub grayscale: bool,
636}
637
638impl Ord for PolychromeSprite {
639 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
640 match self.order.cmp(&other.order) {
641 std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
642 order => order,
643 }
644 }
645}
646
647impl PartialOrd for PolychromeSprite {
648 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
649 Some(self.cmp(other))
650 }
651}
652
653impl From<PolychromeSprite> for Primitive {
654 fn from(sprite: PolychromeSprite) -> Self {
655 Primitive::PolychromeSprite(sprite)
656 }
657}
658
659#[derive(Clone, Debug, Eq, PartialEq)]
660pub struct Surface {
661 pub order: u32,
662 pub bounds: Bounds<ScaledPixels>,
663 pub content_mask: ContentMask<ScaledPixels>,
664 pub image_buffer: media::core_video::CVImageBuffer,
665}
666
667impl Ord for Surface {
668 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
669 self.order.cmp(&other.order)
670 }
671}
672
673impl PartialOrd for Surface {
674 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
675 Some(self.cmp(other))
676 }
677}
678
679impl From<Surface> for Primitive {
680 fn from(surface: Surface) -> Self {
681 Primitive::Surface(surface)
682 }
683}
684
685#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
686pub(crate) struct PathId(pub(crate) usize);
687
688#[derive(Debug)]
689pub struct Path<P: Clone + Default + Debug> {
690 pub(crate) id: PathId,
691 order: u32,
692 pub(crate) bounds: Bounds<P>,
693 pub(crate) content_mask: ContentMask<P>,
694 pub(crate) vertices: Vec<PathVertex<P>>,
695 pub(crate) color: Hsla,
696 start: Point<P>,
697 current: Point<P>,
698 contour_count: usize,
699}
700
701impl Path<Pixels> {
702 pub fn new(start: Point<Pixels>) -> Self {
703 Self {
704 id: PathId(0),
705 order: 0,
706 vertices: Vec::new(),
707 start,
708 current: start,
709 bounds: Bounds {
710 origin: start,
711 size: Default::default(),
712 },
713 content_mask: Default::default(),
714 color: Default::default(),
715 contour_count: 0,
716 }
717 }
718
719 pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
720 Path {
721 id: self.id,
722 order: self.order,
723 bounds: self.bounds.scale(factor),
724 content_mask: self.content_mask.scale(factor),
725 vertices: self
726 .vertices
727 .iter()
728 .map(|vertex| vertex.scale(factor))
729 .collect(),
730 start: self.start.map(|start| start.scale(factor)),
731 current: self.current.scale(factor),
732 contour_count: self.contour_count,
733 color: self.color,
734 }
735 }
736
737 pub fn line_to(&mut self, to: Point<Pixels>) {
738 self.contour_count += 1;
739 if self.contour_count > 1 {
740 self.push_triangle(
741 (self.start, self.current, to),
742 (point(0., 1.), point(0., 1.), point(0., 1.)),
743 );
744 }
745 self.current = to;
746 }
747
748 pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
749 self.contour_count += 1;
750 if self.contour_count > 1 {
751 self.push_triangle(
752 (self.start, self.current, to),
753 (point(0., 1.), point(0., 1.), point(0., 1.)),
754 );
755 }
756
757 self.push_triangle(
758 (self.current, ctrl, to),
759 (point(0., 0.), point(0.5, 0.), point(1., 1.)),
760 );
761 self.current = to;
762 }
763
764 fn push_triangle(
765 &mut self,
766 xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
767 st: (Point<f32>, Point<f32>, Point<f32>),
768 ) {
769 self.bounds = self
770 .bounds
771 .union(&Bounds {
772 origin: xy.0,
773 size: Default::default(),
774 })
775 .union(&Bounds {
776 origin: xy.1,
777 size: Default::default(),
778 })
779 .union(&Bounds {
780 origin: xy.2,
781 size: Default::default(),
782 });
783
784 self.vertices.push(PathVertex {
785 xy_position: xy.0,
786 st_position: st.0,
787 content_mask: Default::default(),
788 });
789 self.vertices.push(PathVertex {
790 xy_position: xy.1,
791 st_position: st.1,
792 content_mask: Default::default(),
793 });
794 self.vertices.push(PathVertex {
795 xy_position: xy.2,
796 st_position: st.2,
797 content_mask: Default::default(),
798 });
799 }
800}
801
802impl Eq for Path<ScaledPixels> {}
803
804impl PartialEq for Path<ScaledPixels> {
805 fn eq(&self, other: &Self) -> bool {
806 self.order == other.order
807 }
808}
809
810impl Ord for Path<ScaledPixels> {
811 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
812 self.order.cmp(&other.order)
813 }
814}
815
816impl PartialOrd for Path<ScaledPixels> {
817 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
818 Some(self.cmp(other))
819 }
820}
821
822impl From<Path<ScaledPixels>> for Primitive {
823 fn from(path: Path<ScaledPixels>) -> Self {
824 Primitive::Path(path)
825 }
826}
827
828#[derive(Clone, Debug)]
829#[repr(C)]
830pub struct PathVertex<P: Clone + Default + Debug> {
831 pub(crate) xy_position: Point<P>,
832 pub(crate) st_position: Point<f32>,
833 pub(crate) content_mask: ContentMask<P>,
834}
835
836impl PathVertex<Pixels> {
837 pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
838 PathVertex {
839 xy_position: self.xy_position.scale(factor),
840 st_position: self.st_position,
841 content_mask: self.content_mask.scale(factor),
842 }
843 }
844}
845
846#[derive(Copy, Clone, Debug)]
847pub struct AtlasId(pub(crate) usize);
848
849impl Bounds<ScaledPixels> {
850 fn to_bsp_polygon<A: Copy>(&self, z: f32, anchor: A) -> BspPolygon<A> {
851 let upper_left = self.origin;
852 let upper_right = self.upper_right();
853 let lower_right = self.lower_right();
854 let lower_left = self.lower_left();
855
856 BspPolygon::from_points(
857 [
858 Point3D::new(upper_left.x.into(), upper_left.y.into(), z as f64),
859 Point3D::new(upper_right.x.into(), upper_right.y.into(), z as f64),
860 Point3D::new(lower_right.x.into(), lower_right.y.into(), z as f64),
861 Point3D::new(lower_left.x.into(), lower_left.y.into(), z as f64),
862 ],
863 anchor,
864 )
865 .expect("Polygon should not be empty")
866 }
867}