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