scene.rs

  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}