1use std::{
2 ffi::{c_int, c_void},
3 mem,
4};
5
6use libtess2_sys::{
7 tessAddContour, tessDeleteTess, tessGetElementCount, tessGetElements, tessGetVertexCount,
8 tessGetVertices, tessNewTess, tessSetOption, tessTesselate, TESSreal,
9 TESStesselator, TessElementType, TessElementType_TESS_BOUNDARY_CONTOURS,
10 TessElementType_TESS_CONNECTED_POLYGONS, TessElementType_TESS_POLYGONS, TessOption,
11 TessOption_TESS_CONSTRAINED_DELAUNAY_TRIANGULATION, TessOption_TESS_REVERSE_CONTOURS,
12 TessWindingRule, TessWindingRule_TESS_WINDING_ABS_GEQ_TWO,
13 TessWindingRule_TESS_WINDING_NEGATIVE, TessWindingRule_TESS_WINDING_NONZERO,
14 TessWindingRule_TESS_WINDING_ODD, TessWindingRule_TESS_WINDING_POSITIVE,
15};
16
17#[derive(Clone, Copy)]
18pub enum WindingRule {
19 EvenOdd,
20 NonZero,
21 Positive,
22 Negative,
23 AbsGeqTwo,
24}
25
26impl From<WindingRule> for TessWindingRule {
27 fn from(value: WindingRule) -> Self {
28 match value {
29 WindingRule::EvenOdd => TessWindingRule_TESS_WINDING_ODD,
30 WindingRule::NonZero => TessWindingRule_TESS_WINDING_NONZERO,
31 WindingRule::Positive => TessWindingRule_TESS_WINDING_POSITIVE,
32 WindingRule::Negative => TessWindingRule_TESS_WINDING_NEGATIVE,
33 WindingRule::AbsGeqTwo => TessWindingRule_TESS_WINDING_ABS_GEQ_TWO,
34 }
35 }
36}
37
38#[derive(Clone, Copy)]
39pub enum ElementType {
40 Polygons,
41 ConnectedPolygons,
42 BoundaryPolygons,
43}
44
45impl From<ElementType> for TessElementType {
46 fn from(value: ElementType) -> Self {
47 match value {
48 ElementType::Polygons => TessElementType_TESS_POLYGONS,
49 ElementType::ConnectedPolygons => TessElementType_TESS_CONNECTED_POLYGONS,
50 ElementType::BoundaryPolygons => TessElementType_TESS_BOUNDARY_CONTOURS,
51 }
52 }
53}
54
55#[derive(Clone, Copy)]
56pub enum TesselatorOption {
57 ConstrainedDelaunayTriangulation,
58 ReverseContour,
59}
60
61impl From<TesselatorOption> for TessOption {
62 fn from(value: TesselatorOption) -> Self {
63 match value {
64 TesselatorOption::ConstrainedDelaunayTriangulation => {
65 TessOption_TESS_CONSTRAINED_DELAUNAY_TRIANGULATION
66 }
67 TesselatorOption::ReverseContour => TessOption_TESS_REVERSE_CONTOURS,
68 }
69 }
70}
71
72pub type Float = TESSreal;
73pub struct Tesselator {
74 _tess: *mut TESStesselator,
75}
76
77impl Tesselator {
78 pub fn new() -> Self {
79 let _tess = unsafe { tessNewTess(std::ptr::null_mut()) };
80 Self { _tess: _tess }
81 }
82
83 pub fn set_option(&self, option: TesselatorOption, value: i32) {
84 let tess_option: TessOption = option.into();
85 unsafe { tessSetOption(self._tess, tess_option.try_into().unwrap(), value) }
86 }
87
88 pub fn add_contour(&self, points: Vec<[Float; 2]>) {
89 let stride: c_int = mem::size_of::<Float>().try_into().unwrap();
90 let pointer = points.as_ptr();
91 let ptr_to_void: *const c_void = pointer as *const c_void;
92 let size: c_int = 2;
93 let count: c_int = points.len().try_into().unwrap();
94 unsafe { tessAddContour(self._tess, size, ptr_to_void, stride * size, count) }
95 }
96
97 pub fn tesselate(&self, winding_rule: WindingRule) -> Option<(Vec<[Float; 2]>, Vec<u32>)> {
98 let element_type: ElementType = ElementType::Polygons;
99 let tess_winding_rule: TessWindingRule = winding_rule.into();
100 let tess_element_type: TessElementType = element_type.into();
101 let poly_size: c_int = 3;
102 let vertex_size: c_int = 2;
103 let result = unsafe {
104 tessTesselate(
105 self._tess,
106 tess_winding_rule.try_into().unwrap(),
107 tess_element_type.try_into().unwrap(),
108 poly_size,
109 vertex_size,
110 std::ptr::null(),
111 )
112 };
113
114 if result == 0 {
115 return None;
116 }
117 let vertices: *const f32;
118 let vertex_count: i32;
119 let elements: *const i32;
120 let element_count: i32;
121 unsafe {
122 vertices = tessGetVertices(self._tess);
123 vertex_count = tessGetVertexCount(self._tess);
124 elements = tessGetElements(self._tess);
125 element_count = tessGetElementCount(self._tess);
126 }
127
128 let mut indices_out: Vec<u32> = Vec::new();
129 let tess_undef = -1;
130 let poly_size = 3;
131 for i in 0..element_count {
132 let p = unsafe { elements.offset((i * poly_size).try_into().unwrap()) };
133 for j in 0..poly_size {
134 let idx = unsafe { *p.offset(j as isize) };
135 if idx != tess_undef {
136 indices_out.push(idx as u32);
137 }
138 }
139 }
140
141 let vertex_size = 2;
142 let mut vertices_out: Vec<[Float; 2]> = Vec::new();
143 for i in 0..vertex_count {
144 unsafe {
145 let x = vertices.offset(i as isize * vertex_size);
146 let y = vertices.offset(i as isize * vertex_size + 1);
147 vertices_out.push([*x, *y]);
148 }
149 }
150
151 return Some((vertices_out, indices_out));
152 }
153}
154
155impl Drop for Tesselator {
156 fn drop(&mut self) {
157 unsafe { tessDeleteTess(self._tess) }
158 }
159}