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