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