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