libtess2_rs/
lib.rs

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}