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// }