bevy_mesh/
index.rs

1use bevy_reflect::Reflect;
2use core::iter;
3use core::iter::FusedIterator;
4use thiserror::Error;
5use wgpu_types::IndexFormat;
6
7/// A disjunction of four iterators. This is necessary to have a well-formed type for the output
8/// of [`Mesh::triangles`](super::Mesh::triangles), which produces iterators of four different types depending on the
9/// branch taken.
10pub(crate) enum FourIterators<A, B, C, D> {
11    First(A),
12    Second(B),
13    Third(C),
14    Fourth(D),
15}
16
17impl<A, B, C, D, I> Iterator for FourIterators<A, B, C, D>
18where
19    A: Iterator<Item = I>,
20    B: Iterator<Item = I>,
21    C: Iterator<Item = I>,
22    D: Iterator<Item = I>,
23{
24    type Item = I;
25
26    fn next(&mut self) -> Option<Self::Item> {
27        match self {
28            FourIterators::First(iter) => iter.next(),
29            FourIterators::Second(iter) => iter.next(),
30            FourIterators::Third(iter) => iter.next(),
31            FourIterators::Fourth(iter) => iter.next(),
32        }
33    }
34}
35
36/// An error that occurred while trying to invert the winding of a [`Mesh`](super::Mesh).
37#[derive(Debug, Error)]
38pub enum MeshWindingInvertError {
39    /// This error occurs when you try to invert the winding for a mesh with [`PrimitiveTopology::PointList`](super::PrimitiveTopology::PointList).
40    #[error("Mesh winding inversion does not work for primitive topology `PointList`")]
41    WrongTopology,
42
43    /// This error occurs when you try to invert the winding for a mesh with
44    /// * [`PrimitiveTopology::TriangleList`](super::PrimitiveTopology::TriangleList), but the indices are not in chunks of 3.
45    /// * [`PrimitiveTopology::LineList`](super::PrimitiveTopology::LineList), but the indices are not in chunks of 2.
46    #[error("Indices weren't in chunks according to topology")]
47    AbruptIndicesEnd,
48}
49
50/// An error that occurred while trying to extract a collection of triangles from a [`Mesh`](super::Mesh).
51#[derive(Debug, Error)]
52pub enum MeshTrianglesError {
53    #[error("Source mesh does not have primitive topology TriangleList or TriangleStrip")]
54    WrongTopology,
55
56    #[error("Source mesh lacks position data")]
57    MissingPositions,
58
59    #[error("Source mesh position data is not Float32x3")]
60    PositionsFormat,
61
62    #[error("Source mesh lacks face index data")]
63    MissingIndices,
64
65    #[error("Face index data references vertices that do not exist")]
66    BadIndices,
67}
68
69/// An array of indices into the [`VertexAttributeValues`](super::VertexAttributeValues) for a mesh.
70///
71/// It describes the order in which the vertex attributes should be joined into faces.
72#[derive(Debug, Clone, Reflect)]
73#[reflect(Clone)]
74pub enum Indices {
75    U16(Vec<u16>),
76    U32(Vec<u32>),
77}
78
79impl Indices {
80    /// Returns an iterator over the indices.
81    pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
82        match self {
83            Indices::U16(vec) => IndicesIter::U16(vec.iter()),
84            Indices::U32(vec) => IndicesIter::U32(vec.iter()),
85        }
86    }
87
88    /// Returns the number of indices.
89    pub fn len(&self) -> usize {
90        match self {
91            Indices::U16(vec) => vec.len(),
92            Indices::U32(vec) => vec.len(),
93        }
94    }
95
96    /// Returns `true` if there are no indices.
97    pub fn is_empty(&self) -> bool {
98        match self {
99            Indices::U16(vec) => vec.is_empty(),
100            Indices::U32(vec) => vec.is_empty(),
101        }
102    }
103
104    /// Add an index. If the index is greater than `u16::MAX`,
105    /// the storage will be converted to `u32`.
106    pub fn push(&mut self, index: u32) {
107        self.extend([index]);
108    }
109}
110
111/// Extend the indices with indices from an iterator.
112/// Semantically equivalent to calling [`push`](Indices::push) for each element in the iterator,
113/// but more efficient.
114impl Extend<u32> for Indices {
115    fn extend<T: IntoIterator<Item = u32>>(&mut self, iter: T) {
116        let mut iter = iter.into_iter();
117        match self {
118            Indices::U32(indices) => indices.extend(iter),
119            Indices::U16(indices) => {
120                indices.reserve(iter.size_hint().0);
121                while let Some(index) = iter.next() {
122                    match u16::try_from(index) {
123                        Ok(index) => indices.push(index),
124                        Err(_) => {
125                            let new_vec = indices
126                                .iter()
127                                .map(|&index| u32::from(index))
128                                .chain(iter::once(index))
129                                .chain(iter)
130                                .collect::<Vec<u32>>();
131                            *self = Indices::U32(new_vec);
132                            break;
133                        }
134                    }
135                }
136            }
137        }
138    }
139}
140
141/// An Iterator for the [`Indices`].
142enum IndicesIter<'a> {
143    U16(core::slice::Iter<'a, u16>),
144    U32(core::slice::Iter<'a, u32>),
145}
146
147impl Iterator for IndicesIter<'_> {
148    type Item = usize;
149
150    fn next(&mut self) -> Option<Self::Item> {
151        match self {
152            IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
153            IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
154        }
155    }
156
157    fn size_hint(&self) -> (usize, Option<usize>) {
158        match self {
159            IndicesIter::U16(iter) => iter.size_hint(),
160            IndicesIter::U32(iter) => iter.size_hint(),
161        }
162    }
163}
164
165impl<'a> ExactSizeIterator for IndicesIter<'a> {}
166impl<'a> FusedIterator for IndicesIter<'a> {}
167
168impl From<&Indices> for IndexFormat {
169    fn from(indices: &Indices) -> Self {
170        match indices {
171            Indices::U16(_) => IndexFormat::Uint16,
172            Indices::U32(_) => IndexFormat::Uint32,
173        }
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use crate::Indices;
180    use wgpu_types::IndexFormat;
181
182    #[test]
183    fn test_indices_push() {
184        let mut indices = Indices::U16(Vec::new());
185        indices.push(10);
186        assert_eq!(IndexFormat::Uint16, IndexFormat::from(&indices));
187        assert_eq!(vec![10], indices.iter().collect::<Vec<_>>());
188
189        // Add a value that is too large for `u16` so the storage should be converted to `U32`.
190        indices.push(0x10000);
191        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
192        assert_eq!(vec![10, 0x10000], indices.iter().collect::<Vec<_>>());
193
194        indices.push(20);
195        indices.push(0x20000);
196        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
197        assert_eq!(
198            vec![10, 0x10000, 20, 0x20000],
199            indices.iter().collect::<Vec<_>>()
200        );
201    }
202
203    #[test]
204    fn test_indices_extend() {
205        let mut indices = Indices::U16(Vec::new());
206        indices.extend([10, 11]);
207        assert_eq!(IndexFormat::Uint16, IndexFormat::from(&indices));
208        assert_eq!(vec![10, 11], indices.iter().collect::<Vec<_>>());
209
210        // Add a value that is too large for `u16` so the storage should be converted to `U32`.
211        indices.extend([12, 0x10013, 0x10014]);
212        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
213        assert_eq!(
214            vec![10, 11, 12, 0x10013, 0x10014],
215            indices.iter().collect::<Vec<_>>()
216        );
217
218        indices.extend([15, 0x10016]);
219        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
220        assert_eq!(
221            vec![10, 11, 12, 0x10013, 0x10014, 15, 0x10016],
222            indices.iter().collect::<Vec<_>>()
223        );
224    }
225}