openrr_planner/collision/
mesh.rs
1use std::{io, path::Path};
2
3use k::{nalgebra as na, RealField};
4use ncollide3d::shape::TriMesh;
5
6use crate::errors::*;
7
8#[cfg(feature = "assimp")]
9pub(crate) fn load_mesh<P, T>(filename: P, scale: &[f64; 3]) -> Result<TriMesh<T>>
10where
11 P: AsRef<Path>,
12 T: RealField + Copy,
13{
14 let filename = filename.as_ref();
15 let mut importer = assimp::Importer::new();
16 importer.pre_transform_vertices(|x| x.enable = true);
17 importer.collada_ignore_up_direction(true);
18 importer.triangulate(true);
19 if let Some(file_string) = filename.to_str() {
20 match importer.read_file(file_string) {
21 Ok(assimp_scene) => Ok(assimp_scene_to_ncollide_mesh(assimp_scene, scale)),
22 Err(err) => Err(Error::MeshError(err.to_owned())),
23 }
24 } else {
25 load_mesh_with_mesh_loader(filename, scale)
27 }
28}
29
30#[cfg(not(feature = "assimp"))]
31pub(crate) use load_mesh_with_mesh_loader as load_mesh;
32pub(crate) fn load_mesh_with_mesh_loader<P, T>(filename: P, scale: &[f64; 3]) -> Result<TriMesh<T>>
33where
34 P: AsRef<Path>,
35 T: RealField + Copy,
36{
37 let filename = filename.as_ref();
38 let mesh = mesh_loader::Loader::default()
39 .merge_meshes(true)
40 .load(filename)
41 .map_err(|e| {
42 if e.kind() == io::ErrorKind::Unsupported {
43 if cfg!(feature = "assimp") {
44 Error::MeshError(format!(
45 "assimp feature is enabled but filename is not UTF-8: could not parse {filename:?}"
46 ))
47 } else {
48 Error::MeshError(format!(
49 "assimp feature is disabled: could not parse {filename:?}"
50 ))
51 }
52 } else {
53 e.into()
54 }
55 })?
56 .meshes
57 .pop()
58 .unwrap(); let vertices = mesh
61 .vertices
62 .iter()
63 .map(|v| {
64 na::Point3::<T>::new(
65 na::convert(v[0] as f64 * scale[0]),
66 na::convert(v[1] as f64 * scale[1]),
67 na::convert(v[2] as f64 * scale[2]),
68 )
69 })
70 .collect();
71 let indices = mesh
72 .faces
73 .iter()
74 .map(|face| na::Point3::new(face[0] as usize, face[1] as usize, face[2] as usize))
75 .collect();
76
77 Ok(TriMesh::new(vertices, indices, None))
78}
79
80#[cfg(feature = "assimp")]
81fn assimp_scene_to_ncollide_mesh<T>(scene: assimp::Scene<'_>, scale: &[f64; 3]) -> TriMesh<T>
82where
83 T: RealField + Copy,
84{
85 let mut vertices = Vec::new();
86 let mut indices = Vec::new();
87 let mut last_index: usize = 0;
88 for mesh in scene.mesh_iter() {
89 vertices.extend(mesh.vertex_iter().map(|v| {
90 na::Point3::<T>::new(
91 na::convert(v.x as f64 * scale[0]),
92 na::convert(v.y as f64 * scale[1]),
93 na::convert(v.z as f64 * scale[2]),
94 )
95 }));
96 indices.extend(mesh.face_iter().filter_map(|f| {
97 if f.num_indices == 3 {
98 Some(na::Point3::new(
99 f[0] as usize + last_index,
100 f[1] as usize + last_index,
101 f[2] as usize + last_index,
102 ))
103 } else {
104 None
105 }
106 }));
107 last_index = vertices.len();
108 }
109 TriMesh::new(vertices, indices, None)
110}