mikktspace_sys/
lib.rs

1use std::os::raw::{c_float, c_int, c_void};
2
3#[allow(unused_variables, clippy::too_many_arguments)]
4pub trait MikkTSpaceInterface {
5    fn get_num_faces(&self) -> usize;
6    fn get_num_vertices_of_face(&self, face: usize) -> usize;
7    fn get_position(&self, face: usize, vert: usize) -> [f32; 3];
8    fn get_normal(&self, face: usize, vert: usize) -> [f32; 3];
9    fn get_tex_coord(&self, face: usize, vert: usize) -> [f32; 2];
10    fn set_tspace_basic(&mut self, tangent: [f32; 3], sign: f32, face: usize, vert: usize) {}
11    fn set_tspace(
12        &mut self,
13        tangent: [f32; 3],
14        bi_tangent: [f32; 3],
15        mag_s: f32,
16        mag_t: f32,
17        is_orientation_preserving: bool,
18        face: usize,
19        vert: usize,
20    ) {
21    }
22}
23
24#[repr(C)]
25struct SMikkTSpaceContext {
26    interface: *const SMikkTSpaceInterface,
27    user_data: *mut c_void,
28}
29
30#[repr(C)]
31struct SMikkTSpaceInterface {
32    get_num_faces: extern "C" fn(context: *const SMikkTSpaceContext) -> c_int,
33    get_num_vertices_of_face:
34        extern "C" fn(context: *const SMikkTSpaceContext, face: c_int) -> c_int,
35    get_position: extern "C" fn(
36        context: *const SMikkTSpaceContext,
37        pos_out: *mut c_float,
38        face: c_int,
39        vert: c_int,
40    ),
41    get_normal: extern "C" fn(
42        context: *const SMikkTSpaceContext,
43        norm_out: *mut c_float,
44        face: c_int,
45        vert: c_int,
46    ),
47    get_tex_coord: extern "C" fn(
48        context: *const SMikkTSpaceContext,
49        texc_out: *mut c_float,
50        face: c_int,
51        vert: c_int,
52    ),
53    set_tspace_basic: extern "C" fn(
54        context: *const SMikkTSpaceContext,
55        tangent: *const c_float,
56        sign: c_float,
57        face: c_int,
58        vert: c_int,
59    ),
60    set_tspace: extern "C" fn(
61        context: *const SMikkTSpaceContext,
62        tangent: *const c_float,
63        bi_tangent: *const c_float,
64        mag_s: c_float,
65        mag_t: c_float,
66        is_orientation_preserving: c_int,
67        face: c_int,
68        vert: c_int,
69    ),
70}
71
72#[link(name = "mikktspace")]
73extern "C" {
74    fn genTangSpaceDefault(context: *const SMikkTSpaceContext) -> c_int;
75    fn genTangSpace(context: *const SMikkTSpaceContext, angular_threshold: c_float) -> c_int;
76}
77
78extern "C" fn get_num_faces_callback(context: *const SMikkTSpaceContext) -> c_int {
79    unsafe {
80        let interface = &(*((*context).user_data as *const InterfaceWrapper)).interface;
81        interface.get_num_faces() as c_int
82    }
83}
84
85extern "C" fn get_num_vertices_of_face_callback(
86    context: *const SMikkTSpaceContext,
87    face: c_int,
88) -> c_int {
89    unsafe {
90        let interface = &(*((*context).user_data as *const InterfaceWrapper)).interface;
91        interface.get_num_vertices_of_face(face as usize) as c_int
92    }
93}
94
95extern "C" fn get_position_callback(
96    context: *const SMikkTSpaceContext,
97    pos_out: *mut c_float,
98    face: c_int,
99    vert: c_int,
100) {
101    unsafe {
102        let interface = &(*((*context).user_data as *const InterfaceWrapper)).interface;
103        let pos = interface.get_position(face as usize, vert as usize);
104        *pos_out.offset(0) = pos[0];
105        *pos_out.offset(1) = pos[1];
106        *pos_out.offset(2) = pos[2];
107    }
108}
109
110extern "C" fn get_normal_callback(
111    context: *const SMikkTSpaceContext,
112    norm_out: *mut c_float,
113    face: c_int,
114    vert: c_int,
115) {
116    unsafe {
117        let interface = &(*((*context).user_data as *const InterfaceWrapper)).interface;
118        let normal = interface.get_normal(face as usize, vert as usize);
119        *norm_out.offset(0) = normal[0];
120        *norm_out.offset(1) = normal[1];
121        *norm_out.offset(2) = normal[2];
122    }
123}
124
125extern "C" fn get_tex_coord_callback(
126    context: *const SMikkTSpaceContext,
127    texc_out: *mut c_float,
128    face: c_int,
129    vert: c_int,
130) {
131    unsafe {
132        let interface = &(*((*context).user_data as *const InterfaceWrapper)).interface;
133        let tex_coord = interface.get_tex_coord(face as usize, vert as usize);
134        *texc_out.offset(0) = tex_coord[0];
135        *texc_out.offset(1) = tex_coord[1];
136    }
137}
138
139extern "C" fn set_tspace_basic_callback(
140    context: *const SMikkTSpaceContext,
141    tangent: *const c_float,
142    sign: c_float,
143    face: c_int,
144    vert: c_int,
145) {
146    unsafe {
147        let interface = &mut (*((*context).user_data as *mut InterfaceWrapper)).interface;
148        let tangent_arr = [*tangent.offset(0), *tangent.offset(1), *tangent.offset(2)];
149        interface.set_tspace_basic(tangent_arr, sign, face as usize, vert as usize);
150    }
151}
152
153extern "C" fn set_tspace_callback(
154    context: *const SMikkTSpaceContext,
155    tangent: *const c_float,
156    bi_tangent: *const c_float,
157    mag_s: c_float,
158    mag_t: c_float,
159    is_orientation_preserving: c_int,
160    face: c_int,
161    vert: c_int,
162) {
163    unsafe {
164        let interface = &mut (*((*context).user_data as *mut InterfaceWrapper)).interface;
165        let tangent_arr = [*tangent.offset(0), *tangent.offset(1), *tangent.offset(2)];
166        let bi_tangent_arr = [
167            *bi_tangent.offset(0),
168            *bi_tangent.offset(1),
169            *bi_tangent.offset(2),
170        ];
171        interface.set_tspace(
172            tangent_arr,
173            bi_tangent_arr,
174            mag_s,
175            mag_t,
176            is_orientation_preserving != 0,
177            face as usize,
178            vert as usize,
179        );
180    }
181}
182
183const MIKK_INTERFACE: SMikkTSpaceInterface = SMikkTSpaceInterface {
184    get_num_faces: get_num_faces_callback,
185    get_num_vertices_of_face: get_num_vertices_of_face_callback,
186    get_position: get_position_callback,
187    get_normal: get_normal_callback,
188    get_tex_coord: get_tex_coord_callback,
189    set_tspace_basic: set_tspace_basic_callback,
190    set_tspace: set_tspace_callback,
191};
192
193struct InterfaceWrapper<'a> {
194    interface: &'a mut dyn MikkTSpaceInterface,
195}
196
197fn create_context(interface_wrapper: &InterfaceWrapper) -> SMikkTSpaceContext {
198    SMikkTSpaceContext {
199        interface: &MIKK_INTERFACE as *const _,
200        user_data: interface_wrapper as *const _ as *mut _,
201    }
202}
203
204pub fn gen_tang_space_default<I>(interface: &mut I) -> bool
205where
206    I: MikkTSpaceInterface,
207{
208    let interface_wrapper = InterfaceWrapper { interface };
209    let context = create_context(&interface_wrapper);
210    unsafe { genTangSpaceDefault(&context) != 0 }
211}
212
213pub fn gen_tang_space<I>(interface: &mut I, angular_threshold: f32) -> bool
214where
215    I: MikkTSpaceInterface,
216{
217    let interface_wrapper = InterfaceWrapper { interface };
218    let context = create_context(&interface_wrapper);
219    unsafe { genTangSpace(&context, angular_threshold) != 0 }
220}