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}