recastnavigation_rs/demo/
demo.rs1use cxx::{let_cxx_string, type_id, ExternType, UniquePtr};
2use static_assertions::const_assert_eq;
3use std::mem;
4use std::pin::Pin;
5use std::slice;
6
7use crate::base::XError;
8use crate::detour::DtNavMesh;
9
10#[allow(dead_code)]
11#[cxx::bridge]
12pub(crate) mod ffi {
13 unsafe extern "C++" {
14 include!("recastnavigation-rs/src/demo/demo-ffi.h");
15
16 type dtNavMesh = crate::detour::mesh::ffi::dtNavMesh;
17
18 type rcMeshLoaderObj;
19 fn load(self: Pin<&mut rcMeshLoaderObj>, fileName: &CxxString) -> bool;
20 fn rcNewMeshLoaderObj() -> UniquePtr<rcMeshLoaderObj>;
21 fn getVerts(self: &rcMeshLoaderObj) -> *const f32;
22 fn getNormals(self: &rcMeshLoaderObj) -> *const f32;
23 fn getTris(self: &rcMeshLoaderObj) -> *const i32;
24 fn getVertCount(self: &rcMeshLoaderObj) -> i32;
25 fn getTriCount(self: &rcMeshLoaderObj) -> i32;
26 fn getFileName(self: &rcMeshLoaderObj) -> &CxxString;
27
28 unsafe fn loadNavMesh(path: &str) -> *mut dtNavMesh;
29 unsafe fn saveNavMesh(mesh: *const dtNavMesh, path: &str);
30
31 type rcChunkyTriMeshNode = crate::demo::demo::RcChunkyTriMeshNode;
32 type rcChunkyTriMesh = crate::demo::demo::CxxRcChunkyTriMesh;
33
34 unsafe fn rcctm_new() -> *mut rcChunkyTriMesh;
35 unsafe fn rcctm_delete(cm: *mut rcChunkyTriMesh);
36 unsafe fn rcCreateChunkyTriMesh(
37 verts: *const f32,
38 tris: *const i32,
39 ntris: i32,
40 tris_per_chunk: i32,
41 cm: *mut rcChunkyTriMesh,
42 ) -> bool;
43 unsafe fn rcGetChunksOverlappingRect(
44 cm: *const rcChunkyTriMesh,
45 bmin: *const f32,
46 bmax: *const f32,
47 ids: *mut i32,
48 max_ids: i32,
49 ) -> i32;
50 unsafe fn rcGetChunksOverlappingSegment(
51 cm: *const rcChunkyTriMesh,
52 p: *const f32,
53 q: *const f32,
54 ids: *mut i32,
55 max_ids: i32,
56 ) -> i32;
57 }
58}
59
60pub struct RcMeshLoaderObj(UniquePtr<ffi::rcMeshLoaderObj>);
61
62impl Default for RcMeshLoaderObj {
63 fn default() -> Self {
64 return RcMeshLoaderObj::new();
65 }
66}
67
68impl RcMeshLoaderObj {
69 pub fn new() -> RcMeshLoaderObj {
70 return RcMeshLoaderObj(ffi::rcNewMeshLoaderObj());
71 }
72
73 pub fn load(&mut self, file_name: &str) -> bool {
74 let_cxx_string!(file_name = file_name);
75 return self.0.pin_mut().load(&file_name);
76 }
77
78 pub fn get_verts(&self) -> &[[f32; 3]] {
79 return unsafe { slice::from_raw_parts(self.0.getVerts() as *const _, self.get_vert_count() as usize) };
80 }
81
82 pub fn get_normals(&self) -> &[[f32; 3]] {
83 return unsafe { slice::from_raw_parts(self.0.getNormals() as *const _, self.get_vert_count() as usize) };
84 }
85
86 pub fn get_tris(&self) -> &[[i32; 3]] {
87 return unsafe { slice::from_raw_parts(self.0.getTris() as *const _, self.get_tri_count() as usize) };
88 }
89
90 pub fn get_vert_count(&self) -> i32 {
91 return self.0.getVertCount();
92 }
93
94 pub fn get_tri_count(&self) -> i32 {
95 return self.0.getTriCount();
96 }
97
98 pub fn get_file_name(&self) -> &str {
99 return self.0.getFileName().to_str().unwrap_or("");
100 }
101}
102
103pub fn load_nav_mesh(path: &str) -> Result<DtNavMesh, XError> {
104 unsafe {
105 let mesh = ffi::loadNavMesh(path);
106 if mesh.is_null() {
107 return Err(XError::Failed);
108 }
109 return Ok(DtNavMesh::from_ptr(mesh));
110 };
111}
112
113pub fn save_nav_mesh(mesh: &DtNavMesh, path: &str) {
114 unsafe { ffi::saveNavMesh(mesh.as_ptr(), path) };
115}
116
117#[repr(C)]
118#[derive(Debug, Clone)]
119pub struct RcChunkyTriMeshNode {
120 pub bmin: [f32; 2],
121 pub bmax: [f32; 2],
122 pub i: i32,
123 pub n: i32,
124}
125
126const_assert_eq!(mem::size_of::<RcChunkyTriMeshNode>(), 24);
127
128unsafe impl ExternType for RcChunkyTriMeshNode {
129 type Id = type_id!("rcChunkyTriMeshNode");
130 type Kind = cxx::kind::Trivial;
131}
132
133#[repr(C)]
134#[derive(Debug, Clone)]
135pub(crate) struct CxxRcChunkyTriMesh {
136 nodes: *mut RcChunkyTriMeshNode,
137 nnodes: i32,
138 tris: *mut i32,
139 ntris: i32,
140 max_tris_per_chunk: i32,
141}
142
143#[cfg(target_pointer_width = "64")]
144const_assert_eq!(mem::size_of::<CxxRcChunkyTriMesh>(), 32);
145
146#[cfg(target_pointer_width = "32")]
147const_assert_eq!(mem::size_of::<CxxRcChunkyTriMesh>(), 20);
148
149unsafe impl ExternType for CxxRcChunkyTriMesh {
150 type Id = type_id!("rcChunkyTriMesh");
151 type Kind = cxx::kind::Trivial;
152}
153
154#[derive(Debug)]
155pub struct RcChunkyTriMesh(*mut CxxRcChunkyTriMesh);
156
157impl Drop for RcChunkyTriMesh {
158 fn drop(&mut self) {
159 unsafe { ffi::rcctm_delete(self.0) };
160 self.0 = std::ptr::null_mut();
161 }
162}
163
164impl RcChunkyTriMesh {
165 fn inner(&self) -> &CxxRcChunkyTriMesh {
166 return unsafe { &*self.0 };
167 }
168
169 fn inner_mut(&mut self) -> Pin<&mut CxxRcChunkyTriMesh> {
170 return unsafe { Pin::new_unchecked(&mut *self.0) };
171 }
172
173 pub fn new() -> RcChunkyTriMesh {
174 return RcChunkyTriMesh(unsafe { ffi::rcctm_new() });
175 }
176
177 pub fn nodes(&self) -> &[RcChunkyTriMeshNode] {
178 return unsafe { slice::from_raw_parts(self.inner().nodes, self.inner().nnodes as usize) };
179 }
180
181 pub fn nodes_mut(&mut self) -> &mut [RcChunkyTriMeshNode] {
182 return unsafe { slice::from_raw_parts_mut(self.inner_mut().nodes, self.inner().nnodes as usize) };
183 }
184
185 pub fn tris(&self) -> &[[i32; 3]] {
186 return unsafe { slice::from_raw_parts(self.inner().tris as *const _, self.inner().ntris as usize) };
187 }
188
189 pub fn tris_mut(&mut self) -> &mut [[i32; 3]] {
190 return unsafe { slice::from_raw_parts_mut(self.inner_mut().tris as *mut _, self.inner().ntris as usize) };
191 }
192
193 pub fn max_tris_per_chunk(&self) -> usize {
194 return self.inner().max_tris_per_chunk as usize;
195 }
196}
197
198pub fn rc_create_chunky_tri_mesh(
199 cm: &mut RcChunkyTriMesh,
200 verts: &[[f32; 3]],
201 tris: &[[i32; 3]],
202 tris_per_chunk: i32,
203) -> Result<(), XError> {
204 let verts_ptr = verts.as_ptr() as *const f32;
205 let tris_ptr = tris.as_ptr() as *const i32;
206 let ntris = tris.len() as i32;
207 let result = unsafe { ffi::rcCreateChunkyTriMesh(verts_ptr, tris_ptr, ntris, tris_per_chunk, cm.0) };
208 if !result {
209 return Err(XError::Failed);
210 }
211 return Ok(());
212}
213
214pub fn rc_get_chunks_overlapping_rect(
215 cm: &RcChunkyTriMesh,
216 bmin: &[f32; 2],
217 bmax: &[f32; 2],
218 ids: &mut [i32],
219) -> usize {
220 let n = unsafe {
221 ffi::rcGetChunksOverlappingRect(cm.0, bmin.as_ptr(), bmax.as_ptr(), ids.as_mut_ptr(), ids.len() as i32)
222 };
223 return n as usize;
224}
225
226pub fn rc_get_chunks_overlapping_segment(cm: &RcChunkyTriMesh, p: &[f32; 2], q: &[f32; 2], ids: &mut [i32]) -> usize {
227 let n =
228 unsafe { ffi::rcGetChunksOverlappingSegment(cm.0, p.as_ptr(), q.as_ptr(), ids.as_mut_ptr(), ids.len() as i32) };
229 return n as usize;
230}