ncollide3d/procedural/
trimesh.rs
1use super::utils;
2use crate::math::{Isometry, Point, Translation, Vector, DIM};
3use crate::utils::DeterministicState;
4use na::{self, Point2, Point3, RealField};
5use std::collections::HashMap;
6
7#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10pub enum IndexBuffer {
11 Unified(Vec<Point3<u32>>),
13 Split(Vec<Point3<Point3<u32>>>),
15}
16
17impl IndexBuffer {
18 #[inline]
20 pub fn unwrap_unified(self) -> Vec<Point3<u32>> {
21 match self {
22 IndexBuffer::Unified(b) => b,
23 _ => panic!("Unable to unwrap to an unified buffer."),
24 }
25 }
26
27 #[inline]
29 pub fn unwrap_split(self) -> Vec<Point3<Point3<u32>>> {
30 match self {
31 IndexBuffer::Split(b) => b,
32 _ => panic!("Unable to unwrap to a split buffer."),
33 }
34 }
35}
36
37#[derive(Clone, Debug)]
38#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
39pub struct TriMesh<N: RealField + Copy> {
41 pub coords: Vec<Point<N>>,
44 pub normals: Option<Vec<Vector<N>>>,
46 pub uvs: Option<Vec<Point2<N>>>,
48 pub indices: IndexBuffer,
50}
51
52impl<N: RealField + Copy> TriMesh<N> {
53 pub fn new(
57 coords: Vec<Point<N>>,
58 normals: Option<Vec<Vector<N>>>,
59 uvs: Option<Vec<Point2<N>>>,
60 indices: Option<IndexBuffer>,
61 ) -> TriMesh<N> {
62 let idx = indices.unwrap_or_else(|| {
64 IndexBuffer::Unified(
65 (0..coords.len() / 3)
66 .map(|i| Point3::new(i as u32 * 3, i as u32 * 3 + 1, i as u32 * 3 + 2))
67 .collect(),
68 )
69 });
70
71 TriMesh {
72 coords: coords,
73 normals: normals,
74 uvs: uvs,
75 indices: idx,
76 }
77 }
78
79 #[inline]
81 pub fn has_normals(&self) -> bool {
82 self.normals.is_some()
83 }
84
85 #[inline]
87 pub fn has_uvs(&self) -> bool {
88 self.uvs.is_some()
89 }
90
91 #[inline]
93 pub fn translate_by(&mut self, t: &Translation<N>) {
94 for c in self.coords.iter_mut() {
95 *c = t * &*c;
96 }
97 }
98
99 #[inline]
101 pub fn transform_by(&mut self, t: &Isometry<N>) {
102 for c in self.coords.iter_mut() {
103 *c = t * &*c;
104 }
105
106 for n in self.normals.iter_mut() {
107 for n in n.iter_mut() {
108 *n = t * &*n;
109 }
110 }
111 }
112
113 #[inline]
115 pub fn num_triangles(&self) -> usize {
116 match self.indices {
117 IndexBuffer::Unified(ref idx) => idx.len(),
118 IndexBuffer::Split(ref idx) => idx.len(),
119 }
120 }
121
122 #[inline]
124 pub fn flat_indices(&self) -> Vec<u32> {
125 let mut res = Vec::with_capacity(self.num_triangles() * 3);
126
127 match self.indices {
128 IndexBuffer::Unified(ref idx) => {
129 for i in idx {
130 res.push(i[0]);
131 res.push(i[1]);
132 res.push(i[2]);
133 }
134 }
135 IndexBuffer::Split(ref idx) => {
136 for i in idx {
137 res.push(i[0][0]);
138 res.push(i[1][0]);
139 res.push(i[2][0]);
140 }
141 }
142 }
143
144 res
145 }
146}
147
148impl<N: RealField + Copy> TriMesh<N> {
149 #[inline]
152 pub fn recompute_normals(&mut self) {
153 let mut new_normals = Vec::new();
154
155 match self.indices {
156 IndexBuffer::Unified(ref idx) => {
157 utils::compute_normals(&self.coords[..], &idx[..], &mut new_normals);
158 }
159 IndexBuffer::Split(ref idx) => {
160 let coord_idx: Vec<Point3<u32>> = idx
164 .iter()
165 .map(|t| Point3::new(t.x.x, t.y.x, t.z.x))
166 .collect();
167
168 utils::compute_normals(&self.coords[..], &coord_idx[..], &mut new_normals);
169 }
170 }
171
172 self.normals = Some(new_normals);
173 }
174
175 #[inline]
177 pub fn flip_normals(&mut self) {
178 if let Some(ref mut normals) = self.normals {
179 for n in normals {
180 *n = *n
181 }
182 }
183 }
184
185 #[inline]
187 pub fn flip_triangles(&mut self) {
188 match self.indices {
189 IndexBuffer::Unified(ref mut idx) => {
190 for i in idx {
191 i.coords.swap((1, 0), (2, 0))
192 }
193 }
194 IndexBuffer::Split(ref mut idx) => {
195 for i in idx {
196 i.coords.swap((1, 0), (2, 0))
197 }
198 }
199 }
200 }
201
202 #[inline]
204 pub fn scale_by(&mut self, s: &Vector<N>) {
205 for c in self.coords.iter_mut() {
206 for i in 0..DIM {
207 c[i] = (*c)[i] * s[i];
208 }
209 }
210 }
212}
213
214impl<N: RealField + Copy> TriMesh<N> {
215 #[inline]
217 pub fn scale_by_scalar(&mut self, s: N) {
218 for c in self.coords.iter_mut() {
219 *c = *c * s
220 }
221 }
222}
223
224impl<N: RealField + Copy> TriMesh<N> {
225 pub fn unify_index_buffer(&mut self) {
231 let new_indices = match self.indices {
232 IndexBuffer::Split(ref ids) => {
233 let mut vt2id: HashMap<Point3<u32>, u32, _> =
234 HashMap::with_hasher(DeterministicState::new());
235 let mut resi: Vec<u32> = Vec::new();
236 let mut resc: Vec<Point<N>> = Vec::new();
237 let mut resn: Option<Vec<Vector<N>>> = self.normals.as_ref().map(|_| Vec::new());
238 let mut resu: Option<Vec<Point2<N>>> = self.uvs.as_ref().map(|_| Vec::new());
239
240 for triangle in ids.iter() {
241 for point in triangle.iter() {
242 let idx = match vt2id.get(point) {
243 Some(i) => {
244 resi.push(*i);
245 None
246 }
247 None => {
248 let idx = resc.len() as u32;
249
250 resc.push(self.coords[point.x as usize].clone());
251
252 let _ = resn.as_mut().map(|l| {
253 l.push(self.normals.as_ref().unwrap()[point.y as usize].clone())
254 });
255 let _ = resu.as_mut().map(|l| {
256 l.push(self.uvs.as_ref().unwrap()[point.z as usize].clone())
257 });
258
259 resi.push(idx);
260
261 Some(idx)
262 }
263 };
264
265 let _ = idx.map(|i| vt2id.insert(point.clone(), i));
266 }
267 }
268
269 self.coords = resc;
270 self.normals = resn;
271 self.uvs = resu;
272
273 let mut batched_indices = Vec::new();
274
275 assert!(resi.len() % 3 == 0);
276 for f in resi[..].chunks(3) {
277 batched_indices.push(Point3::new(f[0], f[1], f[2]));
278 }
279
280 Some(IndexBuffer::Unified(batched_indices))
281 }
282 _ => None,
283 };
284
285 let _ = new_indices.map(|nids| self.indices = nids);
286 }
287
288 pub fn replicate_vertices(&mut self) {
292 let mut resi: Vec<u32> = Vec::new();
293 let mut resc: Vec<Point<N>> = Vec::new();
294 let mut resn: Option<Vec<Vector<N>>> = self.normals.as_ref().map(|_| Vec::new());
295 let mut resu: Option<Vec<Point2<N>>> = self.uvs.as_ref().map(|_| Vec::new());
296
297 match self.indices {
298 IndexBuffer::Split(ref ids) => {
299 for triangle in ids.iter() {
300 for point in triangle.iter() {
301 let idx = resc.len() as u32;
302 resc.push(self.coords[point.x as usize].clone());
303
304 let _ = resn.as_mut().map(|l| {
305 l.push(self.normals.as_ref().unwrap()[point.y as usize].clone())
306 });
307 let _ = resu
308 .as_mut()
309 .map(|l| l.push(self.uvs.as_ref().unwrap()[point.z as usize].clone()));
310
311 resi.push(idx);
312 }
313 }
314 }
315 IndexBuffer::Unified(ref ids) => {
316 for triangle in ids.iter() {
317 for point in triangle.iter() {
318 let idx = resc.len() as u32;
319 resc.push(self.coords[*point as usize].clone());
320
321 let _ = resn.as_mut().map(|l| {
322 l.push(self.normals.as_ref().unwrap()[*point as usize].clone())
323 });
324 let _ = resu
325 .as_mut()
326 .map(|l| l.push(self.uvs.as_ref().unwrap()[*point as usize].clone()));
327
328 resi.push(idx);
329 }
330 }
331 }
332 };
333
334 self.coords = resc;
335 self.normals = resn;
336 self.uvs = resu;
337
338 let mut batched_indices = Vec::new();
339
340 assert!(resi.len() % 3 == 0);
341 for f in resi[..].chunks(3) {
342 batched_indices.push(Point3::new(f[0], f[1], f[2]));
343 }
344
345 self.indices = IndexBuffer::Unified(batched_indices)
346 }
347}
348
349impl<N: RealField + Copy> TriMesh<N> {
350 pub fn split_index_buffer(&mut self, recover_topology: bool) {
354 let new_indices = match self.indices {
355 IndexBuffer::Unified(ref ids) => {
356 let resi;
357
358 if recover_topology {
359 let (idx, coords) =
360 utils::split_index_buffer_and_recover_topology(&ids[..], &self.coords[..]);
361 self.coords = coords;
362 resi = idx;
363 } else {
364 resi = utils::split_index_buffer(&ids[..]);
365 }
366
367 Some(IndexBuffer::Split(resi))
368 }
369 _ => None,
370 };
371
372 let _ = new_indices.map(|nids| self.indices = nids);
373 }
374}