1use crate::util::PoolManager;
38use crate::vertex::{CustomVertex, InstanceTransform};
39use crate::{Color, Stroke};
40use ahash::AHashMap;
41use lyon::lyon_tessellation::{
42 BuffersBuilder, FillOptions, FillTessellator, FillVertex, VertexBuffers,
43};
44use lyon::path::Winding;
45use lyon::tessellation::FillVertexConstructor;
46use smallvec::SmallVec;
47use std::sync::Arc;
48
49pub(crate) struct CachedShape {
50 pub vertex_buffers: Arc<VertexBuffers<CustomVertex, u16>>,
51 pub(crate) is_rect: bool,
53 pub(crate) rect_bounds: Option<[(f32, f32); 2]>,
55}
56
57pub(crate) enum TessellatedGeometry {
58 Owned(VertexBuffers<CustomVertex, u16>),
59 Shared(Arc<VertexBuffers<CustomVertex, u16>>),
60}
61
62impl TessellatedGeometry {
63 pub(crate) fn vertices(&self) -> &[CustomVertex] {
64 match self {
65 Self::Owned(vertex_buffers) => &vertex_buffers.vertices,
66 Self::Shared(vertex_buffers) => &vertex_buffers.vertices,
67 }
68 }
69
70 pub(crate) fn indices(&self) -> &[u16] {
71 match self {
72 Self::Owned(vertex_buffers) => &vertex_buffers.indices,
73 Self::Shared(vertex_buffers) => &vertex_buffers.indices,
74 }
75 }
76
77 pub(crate) fn into_owned(self) -> Option<VertexBuffers<CustomVertex, u16>> {
79 match self {
80 Self::Owned(vertex_buffers) => Some(vertex_buffers),
81 Self::Shared(_) => None,
82 }
83 }
84}
85
86impl CachedShape {
87 pub fn new(
92 shape: &Shape,
93 tessellator: &mut FillTessellator,
94 pool: &mut PoolManager,
95 tessellator_cache_key: Option<u64>,
96 ) -> Self {
97 let (is_rect, rect_bounds) = match shape {
98 Shape::Rect(r) => (true, Some(r.rect)),
99 _ => (false, None),
100 };
101 let vertices = match shape.tessellate(tessellator, pool, tessellator_cache_key) {
102 TessellatedGeometry::Owned(vertex_buffers) => Arc::new(vertex_buffers),
103 TessellatedGeometry::Shared(vertex_buffers) => vertex_buffers,
104 };
105 Self {
106 vertex_buffers: vertices,
107 is_rect,
108 rect_bounds,
109 }
110 }
111}
112#[derive(Debug, Clone)]
142pub enum Shape {
143 Path(PathShape),
145 Rect(RectShape),
147}
148
149impl Shape {
150 pub fn builder() -> ShapeBuilder {
160 ShapeBuilder::new()
161 }
162
163 pub fn rect(rect: [(f32, f32); 2], stroke: Stroke) -> Shape {
184 let rect_shape = RectShape::new(rect, stroke);
185 Shape::Rect(rect_shape)
186 }
187
188 pub fn rounded_rect(rect: [(f32, f32); 2], border_radii: BorderRadii, stroke: Stroke) -> Shape {
211 let mut path_builder = lyon::path::Path::builder();
212 let box2d = lyon::math::Box2D::new(rect[0].into(), rect[1].into());
213
214 path_builder.add_rounded_rectangle(&box2d, &border_radii.into(), Winding::Positive);
215 let path = path_builder.build();
216
217 let path_shape = PathShape { path, stroke };
218 Shape::Path(path_shape)
219 }
220
221 pub(crate) fn tessellate(
222 &self,
223 tessellator: &mut FillTessellator,
224 buffers_pool: &mut PoolManager,
225 tesselation_cache_key: Option<u64>,
226 ) -> TessellatedGeometry {
227 match &self {
228 Shape::Path(path_shape) => {
229 path_shape.tessellate(tessellator, buffers_pool, tesselation_cache_key)
230 }
231 Shape::Rect(rect_shape) => {
232 let min_width = rect_shape.rect[0].0;
233 let min_height = rect_shape.rect[0].1;
234 let max_width = rect_shape.rect[1].0;
235 let max_height = rect_shape.rect[1].1;
236
237 let w = (max_width - min_width).max(1e-6);
239 let h = (max_height - min_height).max(1e-6);
240 let uv =
241 |x: f32, y: f32| -> [f32; 2] { [(x - min_width) / w, (y - min_height) / h] };
242
243 let quad = [
244 CustomVertex {
245 position: [min_width, min_height],
246 tex_coords: uv(min_width, min_height),
247 normal: [0.0, 0.0],
248 coverage: 1.0,
249 },
250 CustomVertex {
251 position: [max_width, min_height],
252 tex_coords: uv(max_width, min_height),
253 normal: [0.0, 0.0],
254 coverage: 1.0,
255 },
256 CustomVertex {
257 position: [max_width, max_height],
258 tex_coords: uv(max_width, max_height),
259 normal: [0.0, 0.0],
260 coverage: 1.0,
261 },
262 CustomVertex {
263 position: [min_width, max_height],
264 tex_coords: uv(min_width, max_height),
265 normal: [0.0, 0.0],
266 coverage: 1.0,
267 },
268 ];
269 let indices = [0u16, 1, 2, 0, 2, 3];
270
271 let mut vertex_buffers = buffers_pool.lyon_vertex_buffers_pool.get_vertex_buffers();
272
273 vertex_buffers.vertices.extend(quad);
274 vertex_buffers.indices.extend(indices);
275
276 generate_aa_fringe(
278 &mut vertex_buffers.vertices,
279 &mut vertex_buffers.indices,
280 &mut buffers_pool.aa_fringe_scratch,
281 );
282
283 TessellatedGeometry::Owned(vertex_buffers)
284 }
285 }
286 }
287}
288
289impl From<PathShape> for Shape {
290 fn from(value: PathShape) -> Self {
291 Shape::Path(value)
292 }
293}
294
295impl From<RectShape> for Shape {
296 fn from(value: RectShape) -> Self {
297 Shape::Rect(value)
298 }
299}
300
301impl AsRef<Shape> for Shape {
302 fn as_ref(&self) -> &Shape {
303 self
304 }
305}
306
307#[derive(Debug, Clone)]
330pub struct RectShape {
331 pub(crate) rect: [(f32, f32); 2],
334 #[allow(unused)]
336 pub(crate) stroke: Stroke,
337}
338
339impl RectShape {
340 pub fn new(rect: [(f32, f32); 2], stroke: Stroke) -> Self {
361 Self { rect, stroke }
362 }
363}
364
365#[derive(Clone, Debug)]
393pub struct PathShape {
394 pub(crate) path: lyon::path::Path,
396 #[allow(unused)]
398 pub(crate) stroke: Stroke,
399}
400
401struct VertexConverter {}
402
403impl VertexConverter {
404 fn new() -> Self {
405 Self {}
406 }
407}
408
409impl FillVertexConstructor<CustomVertex> for VertexConverter {
410 fn new_vertex(&mut self, vertex: FillVertex) -> CustomVertex {
411 CustomVertex {
412 position: vertex.position().to_array(),
413 tex_coords: [0.0, 0.0],
414 normal: [0.0, 0.0],
415 coverage: 1.0,
416 }
417 }
418}
419
420#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
421struct BoundaryVertexKey {
422 x_bits: u32,
423 y_bits: u32,
424}
425
426impl BoundaryVertexKey {
427 fn from_position(position: [f32; 2]) -> Self {
428 Self {
429 x_bits: normalized_float_bits(position[0]),
430 y_bits: normalized_float_bits(position[1]),
431 }
432 }
433}
434
435#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
436struct BoundaryEdgeKey {
437 start: BoundaryVertexKey,
438 end: BoundaryVertexKey,
439}
440
441impl BoundaryEdgeKey {
442 fn new(start_position: [f32; 2], end_position: [f32; 2]) -> Self {
443 let start = BoundaryVertexKey::from_position(start_position);
444 let end = BoundaryVertexKey::from_position(end_position);
445 if start <= end {
446 Self { start, end }
447 } else {
448 Self {
449 start: end,
450 end: start,
451 }
452 }
453 }
454}
455
456#[derive(Clone, Copy, Debug, PartialEq)]
457struct BoundaryEdge {
458 start_vertex_index: u16,
459 end_vertex_index: u16,
460 opposite_vertex_index: u16,
461 triangle_index: usize,
462}
463
464#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
465struct BoundaryCornerKey {
466 vertex_key: BoundaryVertexKey,
467 component_index: usize,
468}
469
470#[derive(Clone, Copy, Debug, PartialEq)]
471struct BoundaryCornerNormalData {
472 accumulated_normal: [f32; 2],
473 source_vertex_index: u16,
474}
475
476pub(crate) struct AaFringeScratch {
477 edge_use_counts: AHashMap<BoundaryEdgeKey, (usize, BoundaryEdge)>,
478 edge_owners: AHashMap<BoundaryEdgeKey, SmallVec<[usize; 2]>>,
479 incident_triangles_by_vertex: AHashMap<BoundaryVertexKey, SmallVec<[usize; 4]>>,
480 triangle_adjacency: AHashMap<(BoundaryVertexKey, usize), SmallVec<[usize; 4]>>,
481 visited_triangles: AHashMap<usize, usize>,
482 triangle_component_map: AHashMap<(usize, BoundaryVertexKey), usize>,
483 boundary_corner_normals: AHashMap<BoundaryCornerKey, BoundaryCornerNormalData>,
484 outer_vertex_indices: AHashMap<BoundaryCornerKey, u16>,
485 boundary_edges: Vec<BoundaryEdge>,
486 triangle_stack: Vec<usize>,
487}
488
489impl AaFringeScratch {
490 pub(crate) fn new() -> Self {
491 Self {
492 edge_use_counts: AHashMap::new(),
493 edge_owners: AHashMap::new(),
494 incident_triangles_by_vertex: AHashMap::new(),
495 triangle_adjacency: AHashMap::new(),
496 visited_triangles: AHashMap::new(),
497 triangle_component_map: AHashMap::new(),
498 boundary_corner_normals: AHashMap::new(),
499 outer_vertex_indices: AHashMap::new(),
500 boundary_edges: Vec::new(),
501 triangle_stack: Vec::new(),
502 }
503 }
504
505 fn clear(&mut self) {
506 self.edge_use_counts.clear();
507 self.edge_owners.clear();
508 self.incident_triangles_by_vertex.clear();
509 self.triangle_adjacency.clear();
510 self.visited_triangles.clear();
511 self.triangle_component_map.clear();
512 self.boundary_corner_normals.clear();
513 self.outer_vertex_indices.clear();
514 self.boundary_edges.clear();
515 self.triangle_stack.clear();
516 }
517
518 pub(crate) fn trim(&mut self) {
519 self.edge_use_counts.shrink_to_fit();
520 self.edge_owners.shrink_to_fit();
521 self.incident_triangles_by_vertex.shrink_to_fit();
522 self.triangle_adjacency.shrink_to_fit();
523 self.visited_triangles.shrink_to_fit();
524 self.triangle_component_map.shrink_to_fit();
525 self.boundary_corner_normals.shrink_to_fit();
526 self.outer_vertex_indices.shrink_to_fit();
527 self.boundary_edges.shrink_to_fit();
528 self.triangle_stack.shrink_to_fit();
529 }
530}
531
532fn normalized_float_bits(value: f32) -> u32 {
533 if value == 0.0 {
534 0.0f32.to_bits()
535 } else {
536 value.to_bits()
537 }
538}
539
540fn build_boundary_data(vertices: &[CustomVertex], indices: &[u16], scratch: &mut AaFringeScratch) {
550 scratch.clear();
551
552 for (triangle_index, tri) in indices.chunks_exact(3).enumerate() {
553 let a = tri[0];
554 let b = tri[1];
555 let c = tri[2];
556 let vertex_keys = [a, b, c].map(|vertex_index| {
557 BoundaryVertexKey::from_position(vertices[vertex_index as usize].position)
558 });
559
560 for &vertex_key in &vertex_keys {
561 scratch
562 .incident_triangles_by_vertex
563 .entry(vertex_key)
564 .or_default()
565 .push(triangle_index);
566 }
567
568 for &(i, j, opp) in &[(a, b, c), (b, c, a), (c, a, b)] {
569 let key =
570 BoundaryEdgeKey::new(vertices[i as usize].position, vertices[j as usize].position);
571 scratch
572 .edge_use_counts
573 .entry(key)
574 .and_modify(|(count, _)| *count += 1)
575 .or_insert((
576 1,
577 BoundaryEdge {
578 start_vertex_index: i,
579 end_vertex_index: j,
580 opposite_vertex_index: opp,
581 triangle_index,
582 },
583 ));
584 scratch
585 .edge_owners
586 .entry(key)
587 .or_default()
588 .push(triangle_index);
589 }
590 }
591
592 scratch.boundary_edges.extend(
593 scratch
594 .edge_use_counts
595 .values()
596 .filter_map(|(count, boundary_edge)| (*count == 1).then_some(*boundary_edge)),
597 );
598}
599
600fn build_triangle_component_map(scratch: &mut AaFringeScratch) {
601 for (edge_key, owners) in &scratch.edge_owners {
602 if owners.len() < 2 {
603 continue;
604 }
605
606 for &vertex_key in &[edge_key.start, edge_key.end] {
607 for (owner_index, &owner_triangle_index) in owners.iter().enumerate() {
608 for &other_triangle_index in &owners[owner_index + 1..] {
609 scratch
610 .triangle_adjacency
611 .entry((vertex_key, owner_triangle_index))
612 .or_default()
613 .push(other_triangle_index);
614 scratch
615 .triangle_adjacency
616 .entry((vertex_key, other_triangle_index))
617 .or_default()
618 .push(owner_triangle_index);
619 }
620 }
621 }
622 }
623
624 for (&vertex_key, incident_triangles) in &scratch.incident_triangles_by_vertex {
625 scratch.visited_triangles.clear();
626 let mut component_index = 0usize;
627
628 for &triangle_index in incident_triangles {
629 if scratch.visited_triangles.contains_key(&triangle_index) {
630 continue;
631 }
632
633 scratch.triangle_stack.push(triangle_index);
634 while let Some(current_triangle_index) = scratch.triangle_stack.pop() {
635 if scratch
636 .visited_triangles
637 .insert(current_triangle_index, component_index)
638 .is_some()
639 {
640 continue;
641 }
642
643 if let Some(neighbors) = scratch
644 .triangle_adjacency
645 .get(&(vertex_key, current_triangle_index))
646 {
647 for &neighbor_triangle_index in neighbors {
648 if !scratch
649 .visited_triangles
650 .contains_key(&neighbor_triangle_index)
651 {
652 scratch.triangle_stack.push(neighbor_triangle_index);
653 }
654 }
655 }
656 }
657
658 component_index += 1;
659 }
660
661 for (&triangle_index, &component_index) in &scratch.visited_triangles {
662 scratch
663 .triangle_component_map
664 .insert((triangle_index, vertex_key), component_index);
665 }
666 }
667}
668
669#[cfg(test)]
677fn find_boundary_edges<'a>(
678 vertices: &[CustomVertex],
679 indices: &[u16],
680 scratch: &'a mut AaFringeScratch,
681) -> &'a [BoundaryEdge] {
682 build_boundary_data(vertices, indices, scratch);
683 &scratch.boundary_edges
684}
685
686fn generate_aa_fringe(
687 vertices: &mut Vec<CustomVertex>,
688 indices: &mut Vec<u16>,
689 scratch: &mut AaFringeScratch,
690) {
691 build_boundary_data(vertices, indices, scratch);
692
693 if scratch.boundary_edges.is_empty() {
694 return;
695 }
696
697 build_triangle_component_map(scratch);
698
699 for boundary_edge in &scratch.boundary_edges {
702 let pa = vertices[boundary_edge.start_vertex_index as usize].position;
703 let pb = vertices[boundary_edge.end_vertex_index as usize].position;
704 let po = vertices[boundary_edge.opposite_vertex_index as usize].position;
705
706 let dx = pb[0] - pa[0];
707 let dy = pb[1] - pa[1];
708 let edge_len = (dx * dx + dy * dy).sqrt();
709 if edge_len < 1e-10 {
710 continue;
711 }
712
713 let n1 = [-dy / edge_len, dx / edge_len];
714 let n2 = [dy / edge_len, -dx / edge_len];
715
716 let to_opp = [po[0] - pa[0], po[1] - pa[1]];
717 let dot1 = n1[0] * to_opp[0] + n1[1] * to_opp[1];
718 let outward = if dot1 < 0.0 { n1 } else { n2 };
719
720 for &vertex_index in &[
721 boundary_edge.start_vertex_index,
722 boundary_edge.end_vertex_index,
723 ] {
724 let vertex_key =
725 BoundaryVertexKey::from_position(vertices[vertex_index as usize].position);
726 let component_index = *scratch
727 .triangle_component_map
728 .get(&(boundary_edge.triangle_index, vertex_key))
729 .unwrap_or_else(|| {
730 panic!(
731 "missing triangle component mapping for triangle {} and boundary vertex {:?}",
732 boundary_edge.triangle_index,
733 vertex_key
734 )
735 });
736 let entry = scratch
737 .boundary_corner_normals
738 .entry(BoundaryCornerKey {
739 vertex_key,
740 component_index,
741 })
742 .or_insert(BoundaryCornerNormalData {
743 accumulated_normal: [0.0, 0.0],
744 source_vertex_index: vertex_index,
745 });
746 entry.accumulated_normal[0] += outward[0];
747 entry.accumulated_normal[1] += outward[1];
748 }
749 }
750
751 for boundary_corner_normal in scratch.boundary_corner_normals.values_mut() {
752 let len = (boundary_corner_normal.accumulated_normal[0]
753 * boundary_corner_normal.accumulated_normal[0]
754 + boundary_corner_normal.accumulated_normal[1]
755 * boundary_corner_normal.accumulated_normal[1])
756 .sqrt();
757 if len > 1e-10 {
758 boundary_corner_normal.accumulated_normal[0] /= len;
759 boundary_corner_normal.accumulated_normal[1] /= len;
760 }
761 }
762
763 vertices.reserve(scratch.boundary_corner_normals.len());
766 indices.reserve(scratch.boundary_edges.len() * 6);
767
768 for (&boundary_corner_key, boundary_corner_normal) in &scratch.boundary_corner_normals {
769 let source_vertex = &vertices[boundary_corner_normal.source_vertex_index as usize];
770 let outer_vertex = CustomVertex {
771 position: source_vertex.position,
772 tex_coords: source_vertex.tex_coords,
773 normal: boundary_corner_normal.accumulated_normal,
774 coverage: 0.0,
775 };
776 let new_idx = vertices.len() as u16;
777 vertices.push(outer_vertex);
778 scratch
779 .outer_vertex_indices
780 .insert(boundary_corner_key, new_idx);
781 }
782
783 for boundary_edge in &scratch.boundary_edges {
786 let start_vertex_key = BoundaryVertexKey::from_position(
787 vertices[boundary_edge.start_vertex_index as usize].position,
788 );
789 let end_vertex_key = BoundaryVertexKey::from_position(
790 vertices[boundary_edge.end_vertex_index as usize].position,
791 );
792 let pa = vertices[boundary_edge.start_vertex_index as usize].position;
793 let pb = vertices[boundary_edge.end_vertex_index as usize].position;
794 let po = vertices[boundary_edge.opposite_vertex_index as usize].position;
795
796 let dx = pb[0] - pa[0];
797 let dy = pb[1] - pa[1];
798 let edge_len = (dx * dx + dy * dy).sqrt();
799 if edge_len < 1e-10 {
800 continue;
801 }
802
803 let start_component_index = *scratch
804 .triangle_component_map
805 .get(&(boundary_edge.triangle_index, start_vertex_key))
806 .unwrap_or_else(|| {
807 panic!(
808 "missing triangle component mapping for triangle {} and boundary vertex {:?}",
809 boundary_edge.triangle_index, start_vertex_key
810 )
811 });
812 let end_component_index = *scratch
813 .triangle_component_map
814 .get(&(boundary_edge.triangle_index, end_vertex_key))
815 .unwrap_or_else(|| {
816 panic!(
817 "missing triangle component mapping for triangle {} and boundary vertex {:?}",
818 boundary_edge.triangle_index, end_vertex_key
819 )
820 });
821
822 let start_boundary_corner_key = BoundaryCornerKey {
823 vertex_key: start_vertex_key,
824 component_index: start_component_index,
825 };
826 let start_outer_vertex_index = match scratch
827 .outer_vertex_indices
828 .get(&start_boundary_corner_key)
829 {
830 Some(&idx) => idx,
831 None => {
832 debug_assert!(
833 false,
834 "missing outer vertex index for {:?} (start_vertex_key: {:?}, start_component_index: {})",
835 start_boundary_corner_key,
836 start_vertex_key,
837 start_component_index
838 );
839 continue;
840 }
841 };
842 let end_boundary_corner_key = BoundaryCornerKey {
843 vertex_key: end_vertex_key,
844 component_index: end_component_index,
845 };
846 let end_outer_vertex_index = match scratch
847 .outer_vertex_indices
848 .get(&end_boundary_corner_key)
849 {
850 Some(&idx) => idx,
851 None => {
852 debug_assert!(
853 false,
854 "missing outer vertex index for {:?} (end_vertex_key: {:?}, end_component_index: {})",
855 end_boundary_corner_key,
856 end_vertex_key,
857 end_component_index
858 );
859 continue;
860 }
861 };
862
863 let cross = (pb[0] - pa[0]) * (po[1] - pa[1]) - (pb[1] - pa[1]) * (po[0] - pa[0]);
864
865 if cross >= 0.0 {
866 indices.push(boundary_edge.start_vertex_index);
867 indices.push(boundary_edge.end_vertex_index);
868 indices.push(start_outer_vertex_index);
869
870 indices.push(boundary_edge.end_vertex_index);
871 indices.push(end_outer_vertex_index);
872 indices.push(start_outer_vertex_index);
873 } else {
874 indices.push(boundary_edge.start_vertex_index);
875 indices.push(start_outer_vertex_index);
876 indices.push(boundary_edge.end_vertex_index);
877
878 indices.push(boundary_edge.end_vertex_index);
879 indices.push(start_outer_vertex_index);
880 indices.push(end_outer_vertex_index);
881 }
882 }
883}
884
885impl PathShape {
886 pub fn new(path: lyon::path::Path, stroke: Stroke) -> Self {
904 Self { path, stroke }
905 }
906
907 pub(crate) fn tessellate(
918 &self,
919 tessellator: &mut FillTessellator,
920 buffers_pool: &mut PoolManager,
921 tesselation_cache_key: Option<u64>,
922 ) -> TessellatedGeometry {
923 if let Some(cache_key) = tesselation_cache_key {
924 if let Some(cached_vertex_buffers) = buffers_pool
925 .tessellation_cache
926 .get_vertex_buffers(&cache_key)
927 {
928 return TessellatedGeometry::Shared(cached_vertex_buffers);
929 }
930 }
931
932 let mut buffers: VertexBuffers<CustomVertex, u16> =
933 buffers_pool.lyon_vertex_buffers_pool.get_vertex_buffers();
934 self.tesselate_into_buffers(
935 &mut buffers,
936 tessellator,
937 &mut buffers_pool.aa_fringe_scratch,
938 );
939
940 #[allow(clippy::manual_is_multiple_of)]
941 let needs_index_padding = buffers.indices.len() % 2 != 0;
942 if needs_index_padding {
943 buffers.indices.push(0);
944 }
945
946 if let Some(cache_key) = tesselation_cache_key {
947 let shared_vertex_buffers = Arc::new(buffers);
948 buffers_pool
949 .tessellation_cache
950 .insert_vertex_buffers(cache_key, shared_vertex_buffers.clone());
951 TessellatedGeometry::Shared(shared_vertex_buffers)
952 } else {
953 TessellatedGeometry::Owned(buffers)
954 }
955 }
956
957 fn tesselate_into_buffers(
958 &self,
959 buffers: &mut VertexBuffers<CustomVertex, u16>,
960 tessellator: &mut FillTessellator,
961 aa_fringe_scratch: &mut AaFringeScratch,
962 ) {
963 let options = FillOptions::default();
964
965 let vertex_converter = VertexConverter::new();
966
967 tessellator
968 .tessellate_path(
969 &self.path,
970 &options,
971 &mut BuffersBuilder::new(buffers, vertex_converter),
972 )
973 .unwrap();
974
975 if !buffers.vertices.is_empty() {
977 let mut min_x = f32::INFINITY;
979 let mut min_y = f32::INFINITY;
980 let mut max_x = f32::NEG_INFINITY;
981 let mut max_y = f32::NEG_INFINITY;
982 for v in buffers.vertices.iter() {
983 let x = v.position[0];
984 let y = v.position[1];
985 if x < min_x {
986 min_x = x;
987 }
988 if y < min_y {
989 min_y = y;
990 }
991 if x > max_x {
992 max_x = x;
993 }
994 if y > max_y {
995 max_y = y;
996 }
997 }
998 let w = (max_x - min_x).max(1e-6);
999 let h = (max_y - min_y).max(1e-6);
1000 for v in buffers.vertices.iter_mut() {
1001 let u = (v.position[0] - min_x) / w;
1002 let vcoord = (v.position[1] - min_y) / h;
1003 v.tex_coords = [u, vcoord];
1004 }
1005 }
1006
1007 generate_aa_fringe(
1010 &mut buffers.vertices,
1011 &mut buffers.indices,
1012 aa_fringe_scratch,
1013 );
1014 }
1015}
1016
1017#[derive(Debug)]
1022pub(crate) struct ShapeDrawData {
1023 pub(crate) shape: Shape,
1025 pub(crate) cache_key: Option<u64>,
1027 pub(crate) index_buffer_range: Option<(usize, usize)>,
1029 pub(crate) is_empty: bool,
1031 pub(crate) stencil_ref: Option<u32>,
1033 pub(crate) instance_index: Option<usize>,
1035 pub(crate) transform: Option<InstanceTransform>,
1037 pub(crate) texture_ids: [Option<u64>; 2],
1041 pub(crate) color_override: Option<[f32; 4]>,
1043 pub(crate) is_leaf: bool,
1045 pub(crate) clips_children: bool,
1048 pub(crate) is_rect: bool,
1051}
1052
1053impl ShapeDrawData {
1054 pub fn new(shape: impl Into<Shape>, cache_key: Option<u64>) -> Self {
1055 let shape = shape.into();
1056 let is_rect = matches!(shape, Shape::Rect(_));
1057
1058 ShapeDrawData {
1059 shape,
1060 cache_key,
1061 index_buffer_range: None,
1062 is_empty: false,
1063 stencil_ref: None,
1064 instance_index: None,
1065 transform: None,
1066 texture_ids: [None, None],
1067 color_override: None,
1068 is_leaf: true,
1069 clips_children: true,
1070 is_rect,
1071 }
1072 }
1073
1074 #[inline(always)]
1076 pub(crate) fn tessellate(
1077 &mut self,
1078 tessellator: &mut FillTessellator,
1079 buffers_pool: &mut PoolManager,
1080 ) -> TessellatedGeometry {
1081 self.shape
1082 .tessellate(tessellator, buffers_pool, self.cache_key)
1083 }
1084}
1085
1086#[derive(Debug)]
1087pub(crate) struct CachedShapeDrawData {
1088 pub(crate) id: u64,
1089 pub(crate) index_buffer_range: Option<(usize, usize)>,
1090 pub(crate) is_empty: bool,
1091 pub(crate) stencil_ref: Option<u32>,
1093 pub(crate) instance_index: Option<usize>,
1095 pub(crate) transform: Option<InstanceTransform>,
1097 pub(crate) texture_ids: [Option<u64>; 2],
1099 pub(crate) color_override: Option<[f32; 4]>,
1101 pub(crate) is_leaf: bool,
1103 pub(crate) clips_children: bool,
1106 pub(crate) is_rect: bool,
1109 pub(crate) rect_bounds: Option<[(f32, f32); 2]>,
1111}
1112
1113impl CachedShapeDrawData {
1114 pub fn new(id: u64) -> Self {
1115 Self {
1116 id,
1117 index_buffer_range: None,
1118 is_empty: false,
1119 stencil_ref: None,
1120 instance_index: None,
1121 transform: None,
1122 texture_ids: [None, None],
1123 color_override: None,
1124 is_leaf: true,
1125 clips_children: true,
1126 is_rect: false,
1127 rect_bounds: None,
1128 }
1129 }
1130
1131 pub fn new_rect(id: u64, rect_bounds: [(f32, f32); 2]) -> Self {
1132 Self {
1133 is_rect: true,
1134 rect_bounds: Some(rect_bounds),
1135 ..Self::new(id)
1136 }
1137 }
1138}
1139
1140#[derive(Clone)]
1163pub struct ShapeBuilder {
1164 stroke: Stroke,
1166 path_builder: lyon::path::Builder,
1168}
1169
1170impl Default for ShapeBuilder {
1171 fn default() -> Self {
1180 Self::new()
1181 }
1182}
1183
1184impl ShapeBuilder {
1185 pub fn new() -> Self {
1195 Self {
1196 stroke: Stroke::new(1.0, Color::rgb(0, 0, 0)),
1197 path_builder: lyon::path::Path::builder(),
1198 }
1199 }
1200
1201 pub fn stroke(mut self, stroke: Stroke) -> Self {
1221 self.stroke = stroke;
1222 self
1223 }
1224
1225 pub fn begin(mut self, point: (f32, f32)) -> Self {
1243 self.path_builder.begin(point.into());
1244 self
1245 }
1246
1247 pub fn line_to(mut self, point: (f32, f32)) -> Self {
1265 self.path_builder.line_to(point.into());
1266 self
1267 }
1268
1269 pub fn cubic_bezier_to(mut self, ctrl: (f32, f32), ctrl2: (f32, f32), to: (f32, f32)) -> Self {
1291 self.path_builder
1292 .cubic_bezier_to(ctrl.into(), ctrl2.into(), to.into());
1293 self
1294 }
1295
1296 pub fn quadratic_bezier_to(mut self, ctrl: (f32, f32), to: (f32, f32)) -> Self {
1317 self.path_builder
1318 .quadratic_bezier_to(ctrl.into(), to.into());
1319 self
1320 }
1321
1322 pub fn close(mut self) -> Self {
1336 self.path_builder.close();
1337 self
1338 }
1339
1340 pub fn build(self) -> Shape {
1359 let path = self.path_builder.build();
1360 Shape::Path(PathShape {
1361 path,
1362 stroke: self.stroke,
1363 })
1364 }
1365}
1366
1367impl From<ShapeBuilder> for Shape {
1368 fn from(value: ShapeBuilder) -> Self {
1369 value.build()
1370 }
1371}
1372
1373#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default)]
1375pub struct BorderRadii {
1376 pub top_left: f32,
1377 pub top_right: f32,
1378 pub bottom_left: f32,
1379 pub bottom_right: f32,
1380}
1381
1382impl BorderRadii {
1410 pub fn new(radius: f32) -> Self {
1428 let r = radius.abs();
1429 BorderRadii {
1430 top_left: r,
1431 top_right: r,
1432 bottom_left: r,
1433 bottom_right: r,
1434 }
1435 }
1436}
1437
1438impl core::fmt::Display for BorderRadii {
1439 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1440 write!(
1442 f,
1443 "BorderRadii({}, {}, {}, {})",
1444 self.top_left, self.top_right, self.bottom_left, self.bottom_right
1445 )
1446 }
1447}
1448
1449impl From<BorderRadii> for lyon::path::builder::BorderRadii {
1450 fn from(val: BorderRadii) -> Self {
1451 lyon::path::builder::BorderRadii {
1452 top_left: val.top_left,
1453 top_right: val.top_right,
1454 bottom_left: val.bottom_left,
1455 bottom_right: val.bottom_right,
1456 }
1457 }
1458}
1459
1460pub(crate) trait DrawShapeCommand {
1461 fn index_buffer_range(&self) -> Option<(usize, usize)>; fn is_empty(&self) -> bool;
1463 fn stencil_ref_mut(&mut self) -> &mut Option<u32>;
1464 fn instance_index_mut(&mut self) -> &mut Option<usize>;
1465 fn instance_index(&self) -> Option<usize>;
1466 fn transform(&self) -> Option<InstanceTransform>;
1467 fn set_transform(&mut self, t: InstanceTransform);
1468 fn texture_id(&self, layer: usize) -> Option<u64>;
1469 fn set_texture_id(&mut self, layer: usize, id: Option<u64>);
1470 fn instance_color_override(&self) -> Option<[f32; 4]>;
1471 fn set_instance_color_override(&mut self, color: Option<[f32; 4]>);
1472 fn clips_children(&self) -> bool;
1473 fn is_rect(&self) -> bool;
1474 fn rect_bounds(&self) -> Option<[(f32, f32); 2]>;
1475}
1476
1477impl DrawShapeCommand for ShapeDrawData {
1478 #[inline]
1479 fn index_buffer_range(&self) -> Option<(usize, usize)> {
1480 self.index_buffer_range
1481 }
1482
1483 #[inline]
1484 fn is_empty(&self) -> bool {
1485 self.is_empty
1486 }
1487
1488 #[inline]
1489 fn stencil_ref_mut(&mut self) -> &mut Option<u32> {
1490 &mut self.stencil_ref
1491 }
1492
1493 #[inline]
1494 fn instance_index_mut(&mut self) -> &mut Option<usize> {
1495 &mut self.instance_index
1496 }
1497
1498 #[inline]
1499 fn instance_index(&self) -> Option<usize> {
1500 self.instance_index
1501 }
1502
1503 #[inline]
1504 fn transform(&self) -> Option<InstanceTransform> {
1505 self.transform
1506 }
1507
1508 #[inline]
1509 fn set_transform(&mut self, t: InstanceTransform) {
1510 self.transform = Some(t);
1511 }
1512
1513 #[inline]
1514 fn texture_id(&self, layer: usize) -> Option<u64> {
1515 self.texture_ids.get(layer).copied().unwrap_or(None)
1516 }
1517
1518 #[inline]
1519 fn set_texture_id(&mut self, layer: usize, id: Option<u64>) {
1520 if let Some(slot) = self.texture_ids.get_mut(layer) {
1521 *slot = id;
1522 }
1523 }
1524
1525 #[inline]
1526 fn instance_color_override(&self) -> Option<[f32; 4]> {
1527 self.color_override
1528 }
1529
1530 #[inline]
1531 fn set_instance_color_override(&mut self, color: Option<[f32; 4]>) {
1532 self.color_override = color;
1533 }
1534
1535 #[inline]
1536 fn clips_children(&self) -> bool {
1537 self.clips_children
1538 }
1539
1540 #[inline]
1541 fn is_rect(&self) -> bool {
1542 self.is_rect
1543 }
1544
1545 #[inline]
1546 fn rect_bounds(&self) -> Option<[(f32, f32); 2]> {
1547 match &self.shape {
1548 Shape::Rect(r) => Some(r.rect),
1549 _ => None,
1550 }
1551 }
1552}
1553
1554impl DrawShapeCommand for CachedShapeDrawData {
1555 #[inline]
1556 fn index_buffer_range(&self) -> Option<(usize, usize)> {
1557 self.index_buffer_range
1558 }
1559
1560 #[inline]
1561 fn is_empty(&self) -> bool {
1562 self.is_empty
1563 }
1564
1565 #[inline]
1566 fn stencil_ref_mut(&mut self) -> &mut Option<u32> {
1567 &mut self.stencil_ref
1568 }
1569
1570 #[inline]
1571 fn instance_index_mut(&mut self) -> &mut Option<usize> {
1572 &mut self.instance_index
1573 }
1574
1575 #[inline]
1576 fn instance_index(&self) -> Option<usize> {
1577 self.instance_index
1578 }
1579
1580 #[inline]
1581 fn transform(&self) -> Option<InstanceTransform> {
1582 self.transform
1583 }
1584
1585 #[inline]
1586 fn set_transform(&mut self, t: InstanceTransform) {
1587 self.transform = Some(t);
1588 }
1589
1590 #[inline]
1591 fn texture_id(&self, layer: usize) -> Option<u64> {
1592 self.texture_ids.get(layer).copied().unwrap_or(None)
1593 }
1594
1595 #[inline]
1596 fn set_texture_id(&mut self, layer: usize, id: Option<u64>) {
1597 if let Some(slot) = self.texture_ids.get_mut(layer) {
1598 *slot = id;
1599 }
1600 }
1601
1602 #[inline]
1603 fn instance_color_override(&self) -> Option<[f32; 4]> {
1604 self.color_override
1605 }
1606
1607 #[inline]
1608 fn set_instance_color_override(&mut self, color: Option<[f32; 4]>) {
1609 self.color_override = color;
1610 }
1611
1612 #[inline]
1613 fn clips_children(&self) -> bool {
1614 self.clips_children
1615 }
1616
1617 #[inline]
1618 fn is_rect(&self) -> bool {
1619 self.is_rect
1620 }
1621
1622 #[inline]
1623 fn rect_bounds(&self) -> Option<[(f32, f32); 2]> {
1624 self.rect_bounds
1625 }
1626}
1627
1628#[cfg(test)]
1629mod tests {
1630 use super::{
1631 find_boundary_edges, generate_aa_fringe, AaFringeScratch, BoundaryVertexKey, CustomVertex,
1632 RectShape, Shape,
1633 };
1634 use crate::{util::PoolManager, Stroke};
1635 use lyon::lyon_tessellation::FillTessellator;
1636 use std::num::NonZeroUsize;
1637
1638 fn test_vertex(position: [f32; 2]) -> CustomVertex {
1639 CustomVertex {
1640 position,
1641 tex_coords: [0.0, 0.0],
1642 normal: [0.0, 0.0],
1643 coverage: 1.0,
1644 }
1645 }
1646
1647 #[test]
1648 fn aa_fringe_ignores_internal_seams_with_duplicate_vertices() {
1649 let mut vertices = vec![
1650 test_vertex([0.0, 0.0]),
1651 test_vertex([1.0, 0.0]),
1652 test_vertex([1.0, 1.0]),
1653 test_vertex([0.0, 0.0]),
1654 test_vertex([1.0, 1.0]),
1655 test_vertex([0.0, 1.0]),
1656 ];
1657 let mut indices = vec![0, 1, 2, 3, 4, 5];
1658 let mut aa_fringe_scratch = AaFringeScratch::new();
1659
1660 let boundary_edges = find_boundary_edges(&vertices, &indices, &mut aa_fringe_scratch);
1661 assert_eq!(boundary_edges.len(), 4);
1662
1663 generate_aa_fringe(&mut vertices, &mut indices, &mut aa_fringe_scratch);
1664
1665 assert_eq!(vertices.len(), 10);
1666 assert_eq!(indices.len(), 30);
1667
1668 let outer_vertex_count = vertices
1669 .iter()
1670 .filter(|vertex| vertex.coverage == 0.0)
1671 .count();
1672 assert_eq!(outer_vertex_count, 4);
1673
1674 let unique_outer_vertex_positions = vertices
1675 .iter()
1676 .filter(|vertex| vertex.coverage == 0.0)
1677 .map(|vertex| BoundaryVertexKey::from_position(vertex.position))
1678 .collect::<std::collections::BTreeSet<_>>();
1679 assert_eq!(unique_outer_vertex_positions.len(), 4);
1680 }
1681
1682 #[test]
1683 fn rect_tessellation_uses_shared_quad_corners() {
1684 let rect_shape = RectShape::new([(10.0, 20.0), (30.0, 50.0)], Stroke::default());
1685 let mut tessellator = FillTessellator::new();
1686 let mut pool_manager = PoolManager::new(NonZeroUsize::new(1).unwrap());
1687
1688 let tessellated_geometry =
1689 Shape::Rect(rect_shape).tessellate(&mut tessellator, &mut pool_manager, None);
1690
1691 assert_eq!(tessellated_geometry.vertices().len(), 8);
1692 assert_eq!(tessellated_geometry.indices().len(), 30);
1693
1694 let fill_vertex_count = tessellated_geometry
1695 .vertices()
1696 .iter()
1697 .filter(|vertex| vertex.coverage == 1.0)
1698 .count();
1699 assert_eq!(fill_vertex_count, 4);
1700 }
1701
1702 #[test]
1703 fn aa_fringe_keeps_distinct_corners_for_point_touching_triangles() {
1704 let mut vertices = vec![
1705 test_vertex([0.0, 0.0]),
1706 test_vertex([1.0, 0.0]),
1707 test_vertex([0.0, 1.0]),
1708 test_vertex([0.0, 0.0]),
1709 test_vertex([-1.0, 0.0]),
1710 test_vertex([0.0, -1.0]),
1711 ];
1712 let mut indices = vec![0, 1, 2, 3, 4, 5];
1713 let mut aa_fringe_scratch = AaFringeScratch::new();
1714
1715 generate_aa_fringe(&mut vertices, &mut indices, &mut aa_fringe_scratch);
1716
1717 let outer_vertices = vertices
1718 .iter()
1719 .filter(|vertex| vertex.coverage == 0.0)
1720 .collect::<Vec<_>>();
1721 assert_eq!(outer_vertices.len(), 6);
1722
1723 let shared_point_outer_vertices = outer_vertices
1724 .iter()
1725 .filter(|vertex| {
1726 BoundaryVertexKey::from_position(vertex.position)
1727 == BoundaryVertexKey::from_position([0.0, 0.0])
1728 })
1729 .count();
1730 assert_eq!(shared_point_outer_vertices, 2);
1731 }
1732
1733 #[test]
1734 fn aa_fringe_skips_zero_length_boundary_edges() {
1735 let mut vertices = vec![
1736 test_vertex([5.0, 5.0]),
1737 test_vertex([5.0, 5.0]),
1738 test_vertex([6.0, 5.0]),
1739 ];
1740 let mut indices = vec![0, 1, 2];
1741 let mut aa_fringe_scratch = AaFringeScratch::new();
1742
1743 generate_aa_fringe(&mut vertices, &mut indices, &mut aa_fringe_scratch);
1744
1745 assert_eq!(vertices.len(), 3);
1746 assert_eq!(indices.len(), 3);
1747 }
1748}