Skip to main content

draco_core/
mesh.rs

1use crate::geometry_indices::{FaceIndex, PointIndex};
2use crate::point_cloud::PointCloud;
3use crate::status::{DracoError, Status};
4use std::collections::HashMap;
5use std::ops::{Deref, DerefMut};
6
7/// Triangle face represented by three point indices.
8pub type Face = [PointIndex; 3];
9
10/// Triangle mesh geometry decoded from, or prepared for, a Draco bitstream.
11///
12/// A mesh owns triangle topology and dereferences to its underlying
13/// [`PointCloud`], where attributes and metadata are stored.
14#[derive(Debug, Default, Clone)]
15pub struct Mesh {
16    point_cloud: PointCloud,
17    faces: Vec<Face>,
18}
19
20impl Mesh {
21    /// Creates an empty mesh with no faces, points, attributes, or metadata.
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Appends one triangle face.
27    pub fn add_face(&mut self, face: Face) {
28        self.faces.push(face);
29    }
30
31    /// Sets a face, growing the face list with zeroed faces when needed.
32    pub fn set_face(&mut self, face_id: FaceIndex, face: Face) {
33        if face_id.0 as usize >= self.faces.len() {
34            self.faces
35                .resize(face_id.0 as usize + 1, [PointIndex(0); 3]);
36        }
37        self.faces[face_id.0 as usize] = face;
38    }
39
40    /// Bulk-set all faces from a flat u32 index array (3 indices per face).
41    /// Assumes `set_num_faces` has already been called with the right count.
42    #[inline]
43    pub fn set_faces_from_flat_indices(&mut self, indices: &[u32]) {
44        debug_assert_eq!(indices.len(), self.faces.len() * 3);
45        for (i, face) in self.faces.iter_mut().enumerate() {
46            let base = i * 3;
47            *face = [
48                PointIndex(indices[base]),
49                PointIndex(indices[base + 1]),
50                PointIndex(indices[base + 2]),
51            ];
52        }
53    }
54
55    /// Bulk-set all faces from tightly packed u8 indices.
56    /// Assumes `set_num_faces` has already been called with the right count.
57    #[inline]
58    pub fn set_faces_from_u8_indices(&mut self, bytes: &[u8]) {
59        debug_assert_eq!(bytes.len(), self.faces.len() * 3);
60        for (face, chunk) in self.faces.iter_mut().zip(bytes.chunks_exact(3)) {
61            *face = [
62                PointIndex(chunk[0] as u32),
63                PointIndex(chunk[1] as u32),
64                PointIndex(chunk[2] as u32),
65            ];
66        }
67    }
68
69    /// Bulk-set all faces from tightly packed little-endian u16 indices.
70    /// Assumes `set_num_faces` has already been called with the right count.
71    #[inline]
72    pub fn set_faces_from_le_u16_indices(&mut self, bytes: &[u8]) {
73        debug_assert_eq!(bytes.len(), self.faces.len() * 3 * 2);
74        for (face, chunk) in self.faces.iter_mut().zip(bytes.chunks_exact(6)) {
75            *face = [
76                PointIndex(u16::from_le_bytes([chunk[0], chunk[1]]) as u32),
77                PointIndex(u16::from_le_bytes([chunk[2], chunk[3]]) as u32),
78                PointIndex(u16::from_le_bytes([chunk[4], chunk[5]]) as u32),
79            ];
80        }
81    }
82
83    /// Bulk-set all faces from tightly packed little-endian u32 indices.
84    /// Assumes `set_num_faces` has already been called with the right count.
85    #[inline]
86    pub fn set_faces_from_le_u32_indices(&mut self, bytes: &[u8]) {
87        debug_assert_eq!(bytes.len(), self.faces.len() * 3 * 4);
88        for (face, chunk) in self.faces.iter_mut().zip(bytes.chunks_exact(12)) {
89            *face = [
90                PointIndex(u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])),
91                PointIndex(u32::from_le_bytes([chunk[4], chunk[5], chunk[6], chunk[7]])),
92                PointIndex(u32::from_le_bytes([
93                    chunk[8], chunk[9], chunk[10], chunk[11],
94                ])),
95            ];
96        }
97    }
98
99    /// Sets one face from raw u32 point ids.
100    #[inline]
101    pub fn set_face_from_indices(&mut self, face_id: usize, indices: [u32; 3]) {
102        self.faces[face_id] = [
103            PointIndex(indices[0]),
104            PointIndex(indices[1]),
105            PointIndex(indices[2]),
106        ];
107    }
108
109    /// Returns the point indices for a face.
110    pub fn face(&self, face_id: FaceIndex) -> Face {
111        self.faces[face_id.0 as usize]
112    }
113
114    /// Returns the number of triangle faces.
115    pub fn num_faces(&self) -> usize {
116        self.faces.len()
117    }
118
119    /// Resizes the face list, filling new faces with point index zero.
120    pub fn set_num_faces(&mut self, num_faces: usize) {
121        self.faces.resize(num_faces, [PointIndex(0); 3]);
122    }
123
124    /// Fallibly resizes the face list.
125    pub fn try_set_num_faces(&mut self, num_faces: usize) -> Status {
126        if num_faces > self.faces.len() {
127            self.faces
128                .try_reserve_exact(num_faces - self.faces.len())
129                .map_err(|_| DracoError::DracoError("Failed to allocate mesh faces".to_string()))?;
130        }
131        self.faces.resize(num_faces, [PointIndex(0); 3]);
132        Ok(())
133    }
134
135    /// Deduplicate point IDs to match C++ Draco behavior.
136    ///
137    /// This function remaps point indices such that:
138    /// 1. Points are assigned new IDs in the order they're first encountered in faces
139    /// 2. Face indices are updated to use the new point IDs
140    /// 3. Attribute point mappings are updated accordingly
141    ///
142    /// This is needed for binary compatibility with C++ Draco, which internally
143    /// creates separate points for each face corner during OBJ loading and then
144    /// deduplicates them in face-traversal order.
145    pub fn deduplicate_point_ids(&mut self) {
146        if self.faces.is_empty() || self.num_points() == 0 {
147            return;
148        }
149
150        // Build mapping from old point ID to new point ID
151        // Points are assigned new IDs in the order they're first seen in faces
152        let mut old_to_new: HashMap<u32, u32> = HashMap::new();
153        let mut new_id = 0u32;
154
155        // First pass: determine the mapping
156        for face in &self.faces {
157            for &point_idx in face.iter() {
158                if let std::collections::hash_map::Entry::Vacant(e) = old_to_new.entry(point_idx.0)
159                {
160                    e.insert(new_id);
161                    new_id += 1;
162                }
163            }
164        }
165
166        // If no remapping needed (already in correct order), skip
167        let needs_remap = old_to_new.iter().any(|(&old, &new)| old != new);
168        if !needs_remap {
169            return;
170        }
171
172        // Build reverse mapping for reordering attributes
173        let num_unique = new_id as usize;
174        let mut new_to_old = vec![0u32; num_unique];
175        for (&old, &new) in &old_to_new {
176            new_to_old[new as usize] = old;
177        }
178
179        // Second pass: update face indices
180        for face in &mut self.faces {
181            for point_idx in face.iter_mut() {
182                point_idx.0 = old_to_new[&point_idx.0];
183            }
184        }
185
186        // Third pass: reorder attribute data
187        // For each attribute, create new buffer with data in new order
188        for att_idx in 0..self.num_attributes() {
189            let att = self.attribute(att_idx);
190            let stride = att.byte_stride() as usize;
191            let old_buffer = att.buffer().data().to_vec();
192
193            // Create new buffer with reordered data
194            let mut new_buffer = vec![0u8; num_unique * stride];
195            for new_idx in 0..num_unique {
196                let old_idx = new_to_old[new_idx] as usize;
197                if old_idx * stride + stride <= old_buffer.len() {
198                    new_buffer[new_idx * stride..new_idx * stride + stride]
199                        .copy_from_slice(&old_buffer[old_idx * stride..old_idx * stride + stride]);
200                }
201            }
202
203            // Update attribute buffer - resize and write the new data
204            let att_mut = self.attribute_mut(att_idx);
205            att_mut.buffer_mut().resize(new_buffer.len());
206            att_mut.buffer_mut().write(0, &new_buffer);
207        }
208
209        // Update point count
210        self.set_num_points(num_unique);
211    }
212}
213
214impl Deref for Mesh {
215    type Target = PointCloud;
216
217    fn deref(&self) -> &Self::Target {
218        &self.point_cloud
219    }
220}
221
222impl DerefMut for Mesh {
223    fn deref_mut(&mut self) -> &mut Self::Target {
224        &mut self.point_cloud
225    }
226}