Skip to main content

bevy_mesh/
index.rs

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