recastnavigation_rs/demo/
demo.rs

1use 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}