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/// Different representations of the index buffer.
8#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10pub enum IndexBuffer {
11    /// The vertex, normal, and uvs share the same indices.
12    Unified(Vec<Point3<u32>>),
13    /// The vertex, normal, and uvs have different indices.
14    Split(Vec<Point3<Point3<u32>>>),
15}
16
17impl IndexBuffer {
18    /// Returns the unified index buffer data or fails.
19    #[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    /// Returns the split index buffer data or fails.
28    #[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))]
39/// Geometric description of a mesh.
40pub struct TriMesh<N: RealField + Copy> {
41    // FIXME: those should *not* be public.
42    /// Coordinates of the mesh vertices.
43    pub coords: Vec<Point<N>>,
44    /// Coordinates of the mesh normals.
45    pub normals: Option<Vec<Vector<N>>>,
46    /// Textures coordinates of the mesh.
47    pub uvs: Option<Vec<Point2<N>>>,
48    /// Index buffer of the mesh.
49    pub indices: IndexBuffer,
50}
51
52impl<N: RealField + Copy> TriMesh<N> {
53    /// Creates a new `TriMesh`.
54    ///
55    /// If no `indices` is provided, trivial, sequential indices are generated.
56    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        // generate trivial indices
63        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    /// Whether or not this triangle mesh has normals.
80    #[inline]
81    pub fn has_normals(&self) -> bool {
82        self.normals.is_some()
83    }
84
85    /// Whether or not this triangle mesh has texture coordinates.
86    #[inline]
87    pub fn has_uvs(&self) -> bool {
88        self.uvs.is_some()
89    }
90
91    /// Translates each vertex of this mesh.
92    #[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    /// Transforms each vertex and rotates each normal of this mesh.
100    #[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    /// The number of triangles on this mesh.
114    #[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    /// Returns only the vertex ids from the index buffer.
123    #[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    /// Recomputes the mesh normals using its vertex coordinates and adjascency informations
150    /// infered from the index buffer.
151    #[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                // XXX: too bad we have to reconstruct the index buffer here.
161                // The utils::recompute_normals function should be generic wrt. the index buffer
162                // type (it could use an iterator instead).
163                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    /// Flips all the normals of this mesh.
176    #[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    /// Flips the orientation of every triangle of this mesh.
186    #[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    /// Scales each vertex of this mesh.
203    #[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        // FIXME: do something for the normals?
211    }
212}
213
214impl<N: RealField + Copy> TriMesh<N> {
215    /// Scales each vertex of this mesh.
216    #[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    // FIXME: looks very similar to the `reformat` on obj.rs
226    /// Force the mesh to use the same index for vertices, normals and uvs.
227    ///
228    /// This might cause the duplication of some vertices, normals and uvs.
229    /// Use this method to transform the mesh data to a OpenGL-compliant format.
230    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    /// Unifies the index buffer and ensure duplicate each vertex
289    /// are duplicated such that no two vertex entry of the index buffer
290    /// are equal.
291    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    /// Forces the mesh to use a different index for the vertices, normals and uvs.
351    ///
352    /// If `recover_topology` is true, this will merge exactly identical vertices together.
353    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}