scene.rs

  1// todo("windows"): remove
  2#![cfg_attr(windows, allow(dead_code))]
  3
  4use schemars::JsonSchema;
  5use serde::{Deserialize, Serialize};
  6
  7use crate::{
  8    AtlasTextureId, AtlasTile, Background, Bounds, ContentMask, Corners, Edges, Hsla, Pixels,
  9    Point, Radians, ScaledPixels, Size, bounds_tree::BoundsTree, point,
 10};
 11use std::{fmt::Debug, iter::Peekable, ops::Range, slice};
 12
 13#[allow(non_camel_case_types, unused)]
 14pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
 15
 16pub(crate) type DrawOrder = u32;
 17
 18#[derive(Default)]
 19pub(crate) struct Scene {
 20    pub(crate) paint_operations: Vec<PaintOperation>,
 21    primitive_bounds: BoundsTree<ScaledPixels>,
 22    layer_stack: Vec<DrawOrder>,
 23    pub(crate) shadows: Vec<Shadow>,
 24    pub(crate) quads: Vec<Quad>,
 25    pub(crate) paths: Vec<Path<ScaledPixels>>,
 26    pub(crate) underlines: Vec<Underline>,
 27    pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
 28    pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
 29    pub(crate) surfaces: Vec<PaintSurface>,
 30}
 31
 32impl Scene {
 33    pub fn clear(&mut self) {
 34        self.paint_operations.clear();
 35        self.primitive_bounds.clear();
 36        self.layer_stack.clear();
 37        self.paths.clear();
 38        self.shadows.clear();
 39        self.quads.clear();
 40        self.underlines.clear();
 41        self.monochrome_sprites.clear();
 42        self.polychrome_sprites.clear();
 43        self.surfaces.clear();
 44    }
 45
 46    pub fn len(&self) -> usize {
 47        self.paint_operations.len()
 48    }
 49
 50    pub fn push_layer(&mut self, bounds: Bounds<ScaledPixels>) {
 51        let order = self.primitive_bounds.insert(bounds);
 52        self.layer_stack.push(order);
 53        self.paint_operations
 54            .push(PaintOperation::StartLayer(bounds));
 55    }
 56
 57    pub fn pop_layer(&mut self) {
 58        self.layer_stack.pop();
 59        self.paint_operations.push(PaintOperation::EndLayer);
 60    }
 61
 62    pub fn insert_primitive(&mut self, primitive: impl Into<Primitive>) {
 63        let mut primitive = primitive.into();
 64        let clipped_bounds = primitive
 65            .bounds()
 66            .intersect(&primitive.content_mask().bounds);
 67
 68        if clipped_bounds.is_empty() {
 69            return;
 70        }
 71
 72        let order = self
 73            .layer_stack
 74            .last()
 75            .copied()
 76            .unwrap_or_else(|| self.primitive_bounds.insert(clipped_bounds));
 77        match &mut primitive {
 78            Primitive::Shadow(shadow) => {
 79                shadow.order = order;
 80                self.shadows.push(shadow.clone());
 81            }
 82            Primitive::Quad(quad) => {
 83                quad.order = order;
 84                self.quads.push(quad.clone());
 85            }
 86            Primitive::Path(path) => {
 87                path.order = order;
 88                path.id = PathId(self.paths.len());
 89                self.paths.push(path.clone());
 90            }
 91            Primitive::Underline(underline) => {
 92                underline.order = order;
 93                self.underlines.push(underline.clone());
 94            }
 95            Primitive::MonochromeSprite(sprite) => {
 96                sprite.order = order;
 97                self.monochrome_sprites.push(sprite.clone());
 98            }
 99            Primitive::PolychromeSprite(sprite) => {
100                sprite.order = order;
101                self.polychrome_sprites.push(sprite.clone());
102            }
103            Primitive::Surface(surface) => {
104                surface.order = order;
105                self.surfaces.push(surface.clone());
106            }
107        }
108        self.paint_operations
109            .push(PaintOperation::Primitive(primitive));
110    }
111
112    pub fn replay(&mut self, range: Range<usize>, prev_scene: &Scene) {
113        for operation in &prev_scene.paint_operations[range] {
114            match operation {
115                PaintOperation::Primitive(primitive) => self.insert_primitive(primitive.clone()),
116                PaintOperation::StartLayer(bounds) => self.push_layer(*bounds),
117                PaintOperation::EndLayer => self.pop_layer(),
118            }
119        }
120    }
121
122    pub fn finish(&mut self) {
123        self.shadows.sort_by_key(|shadow| shadow.order);
124        self.quads.sort_by_key(|quad| quad.order);
125        self.paths.sort_by_key(|path| path.order);
126        self.underlines.sort_by_key(|underline| underline.order);
127        self.monochrome_sprites
128            .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
129        self.polychrome_sprites
130            .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
131        self.surfaces.sort_by_key(|surface| surface.order);
132    }
133
134    #[cfg_attr(
135        all(
136            any(target_os = "linux", target_os = "freebsd"),
137            not(any(feature = "x11", feature = "wayland"))
138        ),
139        allow(dead_code)
140    )]
141    pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch<'_>> {
142        BatchIterator {
143            shadows: &self.shadows,
144            shadows_start: 0,
145            shadows_iter: self.shadows.iter().peekable(),
146            quads: &self.quads,
147            quads_start: 0,
148            quads_iter: self.quads.iter().peekable(),
149            paths: &self.paths,
150            paths_start: 0,
151            paths_iter: self.paths.iter().peekable(),
152            underlines: &self.underlines,
153            underlines_start: 0,
154            underlines_iter: self.underlines.iter().peekable(),
155            monochrome_sprites: &self.monochrome_sprites,
156            monochrome_sprites_start: 0,
157            monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
158            polychrome_sprites: &self.polychrome_sprites,
159            polychrome_sprites_start: 0,
160            polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
161            surfaces: &self.surfaces,
162            surfaces_start: 0,
163            surfaces_iter: self.surfaces.iter().peekable(),
164        }
165    }
166}
167
168#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
169#[cfg_attr(
170    all(
171        any(target_os = "linux", target_os = "freebsd"),
172        not(any(feature = "x11", feature = "wayland"))
173    ),
174    allow(dead_code)
175)]
176pub(crate) enum PrimitiveKind {
177    Shadow,
178    #[default]
179    Quad,
180    Path,
181    Underline,
182    MonochromeSprite,
183    PolychromeSprite,
184    Surface,
185}
186
187pub(crate) enum PaintOperation {
188    Primitive(Primitive),
189    StartLayer(Bounds<ScaledPixels>),
190    EndLayer,
191}
192
193#[derive(Clone)]
194pub(crate) enum Primitive {
195    Shadow(Shadow),
196    Quad(Quad),
197    Path(Path<ScaledPixels>),
198    Underline(Underline),
199    MonochromeSprite(MonochromeSprite),
200    PolychromeSprite(PolychromeSprite),
201    Surface(PaintSurface),
202}
203
204impl Primitive {
205    pub fn bounds(&self) -> &Bounds<ScaledPixels> {
206        match self {
207            Primitive::Shadow(shadow) => &shadow.bounds,
208            Primitive::Quad(quad) => &quad.bounds,
209            Primitive::Path(path) => &path.bounds,
210            Primitive::Underline(underline) => &underline.bounds,
211            Primitive::MonochromeSprite(sprite) => &sprite.bounds,
212            Primitive::PolychromeSprite(sprite) => &sprite.bounds,
213            Primitive::Surface(surface) => &surface.bounds,
214        }
215    }
216
217    pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
218        match self {
219            Primitive::Shadow(shadow) => &shadow.content_mask,
220            Primitive::Quad(quad) => &quad.content_mask,
221            Primitive::Path(path) => &path.content_mask,
222            Primitive::Underline(underline) => &underline.content_mask,
223            Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
224            Primitive::PolychromeSprite(sprite) => &sprite.content_mask,
225            Primitive::Surface(surface) => &surface.content_mask,
226        }
227    }
228}
229
230#[cfg_attr(
231    all(
232        any(target_os = "linux", target_os = "freebsd"),
233        not(any(feature = "x11", feature = "wayland"))
234    ),
235    allow(dead_code)
236)]
237struct BatchIterator<'a> {
238    shadows: &'a [Shadow],
239    shadows_start: usize,
240    shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
241    quads: &'a [Quad],
242    quads_start: usize,
243    quads_iter: Peekable<slice::Iter<'a, Quad>>,
244    paths: &'a [Path<ScaledPixels>],
245    paths_start: usize,
246    paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
247    underlines: &'a [Underline],
248    underlines_start: usize,
249    underlines_iter: Peekable<slice::Iter<'a, Underline>>,
250    monochrome_sprites: &'a [MonochromeSprite],
251    monochrome_sprites_start: usize,
252    monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
253    polychrome_sprites: &'a [PolychromeSprite],
254    polychrome_sprites_start: usize,
255    polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
256    surfaces: &'a [PaintSurface],
257    surfaces_start: usize,
258    surfaces_iter: Peekable<slice::Iter<'a, PaintSurface>>,
259}
260
261impl<'a> Iterator for BatchIterator<'a> {
262    type Item = PrimitiveBatch<'a>;
263
264    fn next(&mut self) -> Option<Self::Item> {
265        let mut orders_and_kinds = [
266            (
267                self.shadows_iter.peek().map(|s| s.order),
268                PrimitiveKind::Shadow,
269            ),
270            (self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
271            (self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
272            (
273                self.underlines_iter.peek().map(|u| u.order),
274                PrimitiveKind::Underline,
275            ),
276            (
277                self.monochrome_sprites_iter.peek().map(|s| s.order),
278                PrimitiveKind::MonochromeSprite,
279            ),
280            (
281                self.polychrome_sprites_iter.peek().map(|s| s.order),
282                PrimitiveKind::PolychromeSprite,
283            ),
284            (
285                self.surfaces_iter.peek().map(|s| s.order),
286                PrimitiveKind::Surface,
287            ),
288        ];
289        orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
290
291        let first = orders_and_kinds[0];
292        let second = orders_and_kinds[1];
293        let (batch_kind, max_order_and_kind) = if first.0.is_some() {
294            (first.1, (second.0.unwrap_or(u32::MAX), second.1))
295        } else {
296            return None;
297        };
298
299        match batch_kind {
300            PrimitiveKind::Shadow => {
301                let shadows_start = self.shadows_start;
302                let mut shadows_end = shadows_start + 1;
303                self.shadows_iter.next();
304                while self
305                    .shadows_iter
306                    .next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
307                    .is_some()
308                {
309                    shadows_end += 1;
310                }
311                self.shadows_start = shadows_end;
312                Some(PrimitiveBatch::Shadows(
313                    &self.shadows[shadows_start..shadows_end],
314                ))
315            }
316            PrimitiveKind::Quad => {
317                let quads_start = self.quads_start;
318                let mut quads_end = quads_start + 1;
319                self.quads_iter.next();
320                while self
321                    .quads_iter
322                    .next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
323                    .is_some()
324                {
325                    quads_end += 1;
326                }
327                self.quads_start = quads_end;
328                Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
329            }
330            PrimitiveKind::Path => {
331                let paths_start = self.paths_start;
332                let mut paths_end = paths_start + 1;
333                self.paths_iter.next();
334                while self
335                    .paths_iter
336                    .next_if(|path| (path.order, batch_kind) < max_order_and_kind)
337                    .is_some()
338                {
339                    paths_end += 1;
340                }
341                self.paths_start = paths_end;
342                Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
343            }
344            PrimitiveKind::Underline => {
345                let underlines_start = self.underlines_start;
346                let mut underlines_end = underlines_start + 1;
347                self.underlines_iter.next();
348                while self
349                    .underlines_iter
350                    .next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
351                    .is_some()
352                {
353                    underlines_end += 1;
354                }
355                self.underlines_start = underlines_end;
356                Some(PrimitiveBatch::Underlines(
357                    &self.underlines[underlines_start..underlines_end],
358                ))
359            }
360            PrimitiveKind::MonochromeSprite => {
361                let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
362                let sprites_start = self.monochrome_sprites_start;
363                let mut sprites_end = sprites_start + 1;
364                self.monochrome_sprites_iter.next();
365                while self
366                    .monochrome_sprites_iter
367                    .next_if(|sprite| {
368                        (sprite.order, batch_kind) < max_order_and_kind
369                            && sprite.tile.texture_id == texture_id
370                    })
371                    .is_some()
372                {
373                    sprites_end += 1;
374                }
375                self.monochrome_sprites_start = sprites_end;
376                Some(PrimitiveBatch::MonochromeSprites {
377                    texture_id,
378                    sprites: &self.monochrome_sprites[sprites_start..sprites_end],
379                })
380            }
381            PrimitiveKind::PolychromeSprite => {
382                let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
383                let sprites_start = self.polychrome_sprites_start;
384                let mut sprites_end = self.polychrome_sprites_start + 1;
385                self.polychrome_sprites_iter.next();
386                while self
387                    .polychrome_sprites_iter
388                    .next_if(|sprite| {
389                        (sprite.order, batch_kind) < max_order_and_kind
390                            && sprite.tile.texture_id == texture_id
391                    })
392                    .is_some()
393                {
394                    sprites_end += 1;
395                }
396                self.polychrome_sprites_start = sprites_end;
397                Some(PrimitiveBatch::PolychromeSprites {
398                    texture_id,
399                    sprites: &self.polychrome_sprites[sprites_start..sprites_end],
400                })
401            }
402            PrimitiveKind::Surface => {
403                let surfaces_start = self.surfaces_start;
404                let mut surfaces_end = surfaces_start + 1;
405                self.surfaces_iter.next();
406                while self
407                    .surfaces_iter
408                    .next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
409                    .is_some()
410                {
411                    surfaces_end += 1;
412                }
413                self.surfaces_start = surfaces_end;
414                Some(PrimitiveBatch::Surfaces(
415                    &self.surfaces[surfaces_start..surfaces_end],
416                ))
417            }
418        }
419    }
420}
421
422#[derive(Debug)]
423#[cfg_attr(
424    all(
425        any(target_os = "linux", target_os = "freebsd"),
426        not(any(feature = "x11", feature = "wayland"))
427    ),
428    allow(dead_code)
429)]
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    Surfaces(&'a [PaintSurface]),
444}
445
446#[derive(Default, Debug, Clone)]
447#[repr(C)]
448pub(crate) struct Quad {
449    pub order: DrawOrder,
450    pub border_style: BorderStyle,
451    pub bounds: Bounds<ScaledPixels>,
452    pub content_mask: ContentMask<ScaledPixels>,
453    pub background: Background,
454    pub border_color: Hsla,
455    pub corner_radii: Corners<ScaledPixels>,
456    pub border_widths: Edges<ScaledPixels>,
457}
458
459impl From<Quad> for Primitive {
460    fn from(quad: Quad) -> Self {
461        Primitive::Quad(quad)
462    }
463}
464
465#[derive(Debug, Clone)]
466#[repr(C)]
467pub(crate) struct Underline {
468    pub order: DrawOrder,
469    pub pad: u32, // align to 8 bytes
470    pub bounds: Bounds<ScaledPixels>,
471    pub content_mask: ContentMask<ScaledPixels>,
472    pub color: Hsla,
473    pub thickness: ScaledPixels,
474    pub wavy: bool,
475}
476
477impl From<Underline> for Primitive {
478    fn from(underline: Underline) -> Self {
479        Primitive::Underline(underline)
480    }
481}
482
483#[derive(Debug, Clone)]
484#[repr(C)]
485pub(crate) struct Shadow {
486    pub order: DrawOrder,
487    pub blur_radius: ScaledPixels,
488    pub bounds: Bounds<ScaledPixels>,
489    pub corner_radii: Corners<ScaledPixels>,
490    pub content_mask: ContentMask<ScaledPixels>,
491    pub color: Hsla,
492}
493
494impl From<Shadow> for Primitive {
495    fn from(shadow: Shadow) -> Self {
496        Primitive::Shadow(shadow)
497    }
498}
499
500/// The style of a border.
501#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
502#[repr(C)]
503pub enum BorderStyle {
504    /// A solid border.
505    #[default]
506    Solid = 0,
507    /// A dashed border.
508    Dashed = 1,
509}
510
511/// A data type representing a 2 dimensional transformation that can be applied to an element.
512#[derive(Debug, Clone, Copy, PartialEq)]
513#[repr(C)]
514pub struct TransformationMatrix {
515    /// 2x2 matrix containing rotation and scale,
516    /// stored row-major
517    pub rotation_scale: [[f32; 2]; 2],
518    /// translation vector
519    pub translation: [f32; 2],
520}
521
522impl Eq for TransformationMatrix {}
523
524impl TransformationMatrix {
525    /// The unit matrix, has no effect.
526    pub fn unit() -> Self {
527        Self {
528            rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
529            translation: [0.0, 0.0],
530        }
531    }
532
533    /// Move the origin by a given point
534    pub fn translate(mut self, point: Point<ScaledPixels>) -> Self {
535        self.compose(Self {
536            rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
537            translation: [point.x.0, point.y.0],
538        })
539    }
540
541    /// Clockwise rotation in radians around the origin
542    pub fn rotate(self, angle: Radians) -> Self {
543        self.compose(Self {
544            rotation_scale: [
545                [angle.0.cos(), -angle.0.sin()],
546                [angle.0.sin(), angle.0.cos()],
547            ],
548            translation: [0.0, 0.0],
549        })
550    }
551
552    /// Scale around the origin
553    pub fn scale(self, size: Size<f32>) -> Self {
554        self.compose(Self {
555            rotation_scale: [[size.width, 0.0], [0.0, size.height]],
556            translation: [0.0, 0.0],
557        })
558    }
559
560    /// Perform matrix multiplication with another transformation
561    /// to produce a new transformation that is the result of
562    /// applying both transformations: first, `other`, then `self`.
563    #[inline]
564    pub fn compose(self, other: TransformationMatrix) -> TransformationMatrix {
565        if other == Self::unit() {
566            return self;
567        }
568        // Perform matrix multiplication
569        TransformationMatrix {
570            rotation_scale: [
571                [
572                    self.rotation_scale[0][0] * other.rotation_scale[0][0]
573                        + self.rotation_scale[0][1] * other.rotation_scale[1][0],
574                    self.rotation_scale[0][0] * other.rotation_scale[0][1]
575                        + self.rotation_scale[0][1] * other.rotation_scale[1][1],
576                ],
577                [
578                    self.rotation_scale[1][0] * other.rotation_scale[0][0]
579                        + self.rotation_scale[1][1] * other.rotation_scale[1][0],
580                    self.rotation_scale[1][0] * other.rotation_scale[0][1]
581                        + self.rotation_scale[1][1] * other.rotation_scale[1][1],
582                ],
583            ],
584            translation: [
585                self.translation[0]
586                    + self.rotation_scale[0][0] * other.translation[0]
587                    + self.rotation_scale[0][1] * other.translation[1],
588                self.translation[1]
589                    + self.rotation_scale[1][0] * other.translation[0]
590                    + self.rotation_scale[1][1] * other.translation[1],
591            ],
592        }
593    }
594
595    /// Apply transformation to a point, mainly useful for debugging
596    pub fn apply(&self, point: Point<Pixels>) -> Point<Pixels> {
597        let input = [point.x.0, point.y.0];
598        let mut output = self.translation;
599        for (i, output_cell) in output.iter_mut().enumerate() {
600            for (k, input_cell) in input.iter().enumerate() {
601                *output_cell += self.rotation_scale[i][k] * *input_cell;
602            }
603        }
604        Point::new(output[0].into(), output[1].into())
605    }
606}
607
608impl Default for TransformationMatrix {
609    fn default() -> Self {
610        Self::unit()
611    }
612}
613
614#[derive(Clone, Debug)]
615#[repr(C)]
616pub(crate) struct MonochromeSprite {
617    pub order: DrawOrder,
618    pub pad: u32, // align to 8 bytes
619    pub bounds: Bounds<ScaledPixels>,
620    pub content_mask: ContentMask<ScaledPixels>,
621    pub color: Hsla,
622    pub tile: AtlasTile,
623    pub transformation: TransformationMatrix,
624}
625
626impl From<MonochromeSprite> for Primitive {
627    fn from(sprite: MonochromeSprite) -> Self {
628        Primitive::MonochromeSprite(sprite)
629    }
630}
631
632#[derive(Clone, Debug)]
633#[repr(C)]
634pub(crate) struct PolychromeSprite {
635    pub order: DrawOrder,
636    pub pad: u32, // align to 8 bytes
637    pub grayscale: bool,
638    pub opacity: f32,
639    pub bounds: Bounds<ScaledPixels>,
640    pub content_mask: ContentMask<ScaledPixels>,
641    pub corner_radii: Corners<ScaledPixels>,
642    pub tile: AtlasTile,
643}
644
645impl From<PolychromeSprite> for Primitive {
646    fn from(sprite: PolychromeSprite) -> Self {
647        Primitive::PolychromeSprite(sprite)
648    }
649}
650
651#[derive(Clone, Debug)]
652pub(crate) struct PaintSurface {
653    pub order: DrawOrder,
654    pub bounds: Bounds<ScaledPixels>,
655    pub content_mask: ContentMask<ScaledPixels>,
656    #[cfg(target_os = "macos")]
657    pub image_buffer: core_video::pixel_buffer::CVPixelBuffer,
658}
659
660impl From<PaintSurface> for Primitive {
661    fn from(surface: PaintSurface) -> Self {
662        Primitive::Surface(surface)
663    }
664}
665
666#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
667pub(crate) struct PathId(pub(crate) usize);
668
669/// A line made up of a series of vertices and control points.
670#[derive(Clone, Debug)]
671pub struct Path<P: Clone + Debug + Default + PartialEq> {
672    pub(crate) id: PathId,
673    pub(crate) order: DrawOrder,
674    pub(crate) bounds: Bounds<P>,
675    pub(crate) content_mask: ContentMask<P>,
676    pub(crate) vertices: Vec<PathVertex<P>>,
677    pub(crate) color: Background,
678    start: Point<P>,
679    current: Point<P>,
680    contour_count: usize,
681}
682
683impl Path<Pixels> {
684    /// Create a new path with the given starting point.
685    pub fn new(start: Point<Pixels>) -> Self {
686        Self {
687            id: PathId(0),
688            order: DrawOrder::default(),
689            vertices: Vec::new(),
690            start,
691            current: start,
692            bounds: Bounds {
693                origin: start,
694                size: Default::default(),
695            },
696            content_mask: Default::default(),
697            color: Default::default(),
698            contour_count: 0,
699        }
700    }
701
702    /// Scale this path by the given factor.
703    pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
704        Path {
705            id: self.id,
706            order: self.order,
707            bounds: self.bounds.scale(factor),
708            content_mask: self.content_mask.scale(factor),
709            vertices: self
710                .vertices
711                .iter()
712                .map(|vertex| vertex.scale(factor))
713                .collect(),
714            start: self.start.map(|start| start.scale(factor)),
715            current: self.current.scale(factor),
716            contour_count: self.contour_count,
717            color: self.color,
718        }
719    }
720
721    /// Move the start, current point to the given point.
722    pub fn move_to(&mut self, to: Point<Pixels>) {
723        self.contour_count += 1;
724        self.start = to;
725        self.current = to;
726    }
727
728    /// Draw a straight line from the current point to the given point.
729    pub fn line_to(&mut self, to: Point<Pixels>) {
730        self.contour_count += 1;
731        if self.contour_count > 1 {
732            self.push_triangle(
733                (self.start, self.current, to),
734                (point(0., 1.), point(0., 1.), point(0., 1.)),
735            );
736        }
737        self.current = to;
738    }
739
740    /// Draw a curve from the current point to the given point, using the given control point.
741    pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
742        self.contour_count += 1;
743        if self.contour_count > 1 {
744            self.push_triangle(
745                (self.start, self.current, to),
746                (point(0., 1.), point(0., 1.), point(0., 1.)),
747            );
748        }
749
750        self.push_triangle(
751            (self.current, ctrl, to),
752            (point(0., 0.), point(0.5, 0.), point(1., 1.)),
753        );
754        self.current = to;
755    }
756
757    /// Push a triangle to the Path.
758    pub fn push_triangle(
759        &mut self,
760        xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
761        st: (Point<f32>, Point<f32>, Point<f32>),
762    ) {
763        self.bounds = self
764            .bounds
765            .union(&Bounds {
766                origin: xy.0,
767                size: Default::default(),
768            })
769            .union(&Bounds {
770                origin: xy.1,
771                size: Default::default(),
772            })
773            .union(&Bounds {
774                origin: xy.2,
775                size: Default::default(),
776            });
777
778        self.vertices.push(PathVertex {
779            xy_position: xy.0,
780            st_position: st.0,
781            content_mask: Default::default(),
782        });
783        self.vertices.push(PathVertex {
784            xy_position: xy.1,
785            st_position: st.1,
786            content_mask: Default::default(),
787        });
788        self.vertices.push(PathVertex {
789            xy_position: xy.2,
790            st_position: st.2,
791            content_mask: Default::default(),
792        });
793    }
794}
795
796impl From<Path<ScaledPixels>> for Primitive {
797    fn from(path: Path<ScaledPixels>) -> Self {
798        Primitive::Path(path)
799    }
800}
801
802#[derive(Clone, Debug)]
803#[repr(C)]
804pub(crate) struct PathVertex<P: Clone + Debug + Default + PartialEq> {
805    pub(crate) xy_position: Point<P>,
806    pub(crate) st_position: Point<f32>,
807    pub(crate) content_mask: ContentMask<P>,
808}
809
810impl PathVertex<Pixels> {
811    pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
812        PathVertex {
813            xy_position: self.xy_position.scale(factor),
814            st_position: self.st_position,
815            content_mask: self.content_mask.scale(factor),
816        }
817    }
818}