recastnavigation_rs/detour/
builder.rs1use cxx::{type_id, ExternType};
2use static_assertions::const_assert_eq;
3use std::fmt::{self, Debug, Formatter};
4use std::mem;
5
6use crate::base::XError;
7use crate::detour::base::{DtAABB, DtBuf};
8use crate::detour::mesh::DT_VERTS_PER_POLYGON;
9
10#[cxx::bridge]
11pub(crate) mod ffi {
12 unsafe extern "C++" {
13 include!("recastnavigation-rs/src/detour/detour-ffi.h");
14
15 type dtNavMeshCreateParams = crate::detour::builder::CxxDtNavMeshCreateParams;
16
17 unsafe fn dtCreateNavMeshData(
18 params: *mut dtNavMeshCreateParams,
19 outData: *mut *mut u8,
20 outDataSize: *mut i32,
21 ) -> bool;
22 unsafe fn dtNavMeshHeaderSwapEndian(data: *mut u8, dataSize: i32) -> bool;
23 unsafe fn dtNavMeshDataSwapEndian(data: *mut u8, dataSize: i32) -> bool;
24 }
25}
26
27#[derive(Default)]
29pub struct DtNavMeshCreateParams<'t> {
30 pub verts: Option<&'t [[u16; 3]]>,
31 pub polys: Option<&'t [u16]>,
32 pub poly_flags: Option<&'t [u16]>,
33 pub poly_areas: Option<&'t [u8]>,
34 pub nvp: usize,
35
36 pub detail_meshes: Option<&'t [[u32; 4]]>,
37 pub detail_verts: Option<&'t [[f32; 3]]>,
38 pub detail_tris: Option<&'t [[u8; 4]]>,
39
40 pub off_mesh_con_verts: Option<&'t [DtAABB]>,
41 pub off_mesh_con_rad: Option<&'t [f32]>,
42 pub off_mesh_con_flags: Option<&'t [u16]>,
43 pub off_mesh_con_areas: Option<&'t [u8]>,
44 pub off_mesh_con_dir: Option<&'t [u8]>,
45 pub off_mesh_con_user_id: Option<&'t [u32]>,
46
47 pub user_id: u32,
48 pub tile_x: i32,
49 pub tile_y: i32,
50 pub tile_layer: i32,
51 pub bmin: [f32; 3],
52 pub bmax: [f32; 3],
53
54 pub walkable_height: f32,
55 pub walkable_radius: f32,
56 pub walkable_climb: f32,
57 pub cs: f32,
58 pub ch: f32,
59
60 pub build_bv_tree: bool,
61}
62
63impl Debug for DtNavMeshCreateParams<'_> {
64 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
65 let cp = CxxDtNavMeshCreateParams::from(self);
66 return write!(f, "{:?}", cp);
67 }
68}
69
70fn unpack_ptr<T>(v: Option<&[T]>) -> *const T {
71 return v.map(|v| v.as_ptr()).unwrap_or(std::ptr::null());
72}
73
74fn unpack_len<T>(v: Option<&[T]>) -> i32 {
75 return v.map(|v| v.len() as i32).unwrap_or(0);
76}
77
78#[repr(C)]
79#[derive(Debug)]
80pub(crate) struct CxxDtNavMeshCreateParams {
81 verts: *const u16,
82 vert_count: i32,
83 polys: *const u16,
84 poly_flags: *const u16,
85 poly_areas: *const u8,
86 poly_count: i32,
87 nvp: i32,
88
89 detail_meshes: *const u32,
90 detail_verts: *const f32,
91 detail_verts_count: i32,
92 detail_tris: *const u8,
93 detail_tri_count: i32,
94
95 off_mesh_con_verts: *const f32,
96 off_mesh_con_rad: *const f32,
97 off_mesh_con_flags: *const u16,
98 off_mesh_con_areas: *const u8,
99 off_mesh_con_dir: *const u8,
100 off_mesh_con_user_id: *const u32,
101 off_mesh_con_count: i32,
102
103 user_id: u32,
104 tile_x: i32,
105 tile_y: i32,
106 tile_layer: i32,
107 bmin: [f32; 3],
108 bmax: [f32; 3],
109
110 walkable_height: f32,
111 walkable_radius: f32,
112 walkable_climb: f32,
113 cs: f32,
114 ch: f32,
115
116 build_bv_tree: bool,
117}
118
119#[cfg(target_pointer_width = "32")]
120const_assert_eq!(mem::size_of::<CxxDtNavMeshCreateParams>(), 140);
121
122#[cfg(target_pointer_width = "64")]
123const_assert_eq!(mem::size_of::<CxxDtNavMeshCreateParams>(), 208);
124
125unsafe impl ExternType for CxxDtNavMeshCreateParams {
126 type Id = type_id!("dtNavMeshCreateParams");
127 type Kind = cxx::kind::Trivial;
128}
129
130impl CxxDtNavMeshCreateParams {
131 fn from(params: &DtNavMeshCreateParams<'_>) -> CxxDtNavMeshCreateParams {
132 return CxxDtNavMeshCreateParams {
133 verts: unpack_ptr(params.verts) as *const _,
134 vert_count: unpack_len(params.verts),
135 polys: unpack_ptr(params.polys),
136 poly_flags: unpack_ptr(params.poly_flags),
137 poly_areas: unpack_ptr(params.poly_areas),
138 poly_count: unpack_len(params.poly_flags),
139 nvp: params.nvp as i32,
140
141 detail_meshes: unpack_ptr(params.detail_meshes) as *const _,
142 detail_verts: unpack_ptr(params.detail_verts) as *const _,
143 detail_verts_count: unpack_len(params.detail_verts),
144 detail_tris: unpack_ptr(params.detail_tris) as *const _,
145 detail_tri_count: unpack_len(params.detail_tris),
146
147 off_mesh_con_verts: unpack_ptr(params.off_mesh_con_verts) as *const _,
148 off_mesh_con_rad: unpack_ptr(params.off_mesh_con_rad),
149 off_mesh_con_flags: unpack_ptr(params.off_mesh_con_flags),
150 off_mesh_con_areas: unpack_ptr(params.off_mesh_con_areas),
151 off_mesh_con_dir: unpack_ptr(params.off_mesh_con_dir),
152 off_mesh_con_user_id: unpack_ptr(params.off_mesh_con_user_id),
153 off_mesh_con_count: unpack_len(params.off_mesh_con_verts),
154
155 user_id: params.user_id,
156 tile_x: params.tile_x,
157 tile_y: params.tile_y,
158 tile_layer: params.tile_layer,
159 bmin: params.bmin,
160 bmax: params.bmax,
161
162 walkable_height: params.walkable_height,
163 walkable_radius: params.walkable_radius,
164 walkable_climb: params.walkable_climb,
165 cs: params.cs,
166 ch: params.ch,
167
168 build_bv_tree: params.build_bv_tree,
169 };
170 }
171}
172
173pub fn dt_create_nav_mesh_data(params: &mut DtNavMeshCreateParams) -> Result<DtBuf, XError> {
174 let mut cp = CxxDtNavMeshCreateParams::from(params);
175
176 if cp.vert_count < 3 || cp.vert_count >= 0xFFFF {
177 return Err(XError::InvalidParam);
178 }
179
180 if cp.poly_count < 1 {
181 return Err(XError::InvalidParam);
182 }
183 if unpack_len(params.polys) != cp.poly_count * 2 * cp.nvp {
184 return Err(XError::InvalidParam);
185 }
186 if unpack_len(params.poly_flags) != cp.poly_count {
187 return Err(XError::InvalidParam);
188 }
189 if unpack_len(params.poly_areas) != cp.poly_count {
190 return Err(XError::InvalidParam);
191 }
192 if cp.nvp < 3 || cp.nvp > DT_VERTS_PER_POLYGON as i32 {
193 return Err(XError::InvalidParam);
194 }
195
196 if cp.detail_meshes.is_null() {
197 if unpack_len(params.detail_meshes) != cp.poly_count {
198 return Err(XError::InvalidParam);
199 }
200 }
201
202 if unpack_len(params.off_mesh_con_rad) != cp.off_mesh_con_count {
203 return Err(XError::InvalidParam);
204 }
205 if unpack_len(params.off_mesh_con_flags) != cp.off_mesh_con_count {
206 return Err(XError::InvalidParam);
207 }
208 if unpack_len(params.off_mesh_con_areas) != cp.off_mesh_con_count {
209 return Err(XError::InvalidParam);
210 }
211 if unpack_len(params.off_mesh_con_dir) != cp.off_mesh_con_count {
212 return Err(XError::InvalidParam);
213 }
214 if unpack_len(params.off_mesh_con_user_id) != cp.off_mesh_con_count {
215 return Err(XError::InvalidParam);
216 }
217
218 unsafe {
219 let mut buf = DtBuf::default();
220 let res = ffi::dtCreateNavMeshData((&mut cp) as *mut _, &mut buf.data, &mut buf.size);
221 if !res {
222 return Err(XError::Failed);
223 }
224 return Ok(buf);
225 }
226}
227
228pub fn dt_nav_mesh_header_swap_endian(buf: &mut DtBuf) -> Result<(), XError> {
229 let res = unsafe { ffi::dtNavMeshHeaderSwapEndian(buf.data, buf.size) };
230 if !res {
231 return Err(XError::Failed);
232 }
233 return Ok(());
234}
235
236pub fn dt_nav_mesh_data_swap_endian(buf: &mut DtBuf) -> Result<(), XError> {
237 let res = unsafe { ffi::dtNavMeshDataSwapEndian(buf.data, buf.size) };
238 if !res {
239 return Err(XError::Failed);
240 }
241 return Ok(());
242}