scene.rs

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