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