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