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