bevy_mesh/
index.rs

1use bevy_reflect::Reflect;
2use core::iter;
3use core::iter::FusedIterator;
4use derive_more::derive::{Display, Error};
5use wgpu::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, Display)]
38pub enum MeshWindingInvertError {
39    /// This error occurs when you try to invert the winding for a mesh with [`PrimitiveTopology::PointList`](super::PrimitiveTopology::PointList).
40    #[display("Mesh winding invertation 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    #[display("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, Display)]
52pub enum MeshTrianglesError {
53    #[display("Source mesh does not have primitive topology TriangleList or TriangleStrip")]
54    WrongTopology,
55
56    #[display("Source mesh lacks position data")]
57    MissingPositions,
58
59    #[display("Source mesh position data is not Float32x3")]
60    PositionsFormat,
61
62    #[display("Source mesh lacks face index data")]
63    MissingIndices,
64
65    #[display("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)]
73pub enum Indices {
74    U16(Vec<u16>),
75    U32(Vec<u32>),
76}
77
78impl Indices {
79    /// Returns an iterator over the indices.
80    pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
81        match self {
82            Indices::U16(vec) => IndicesIter::U16(vec.iter()),
83            Indices::U32(vec) => IndicesIter::U32(vec.iter()),
84        }
85    }
86
87    /// Returns the number of indices.
88    pub fn len(&self) -> usize {
89        match self {
90            Indices::U16(vec) => vec.len(),
91            Indices::U32(vec) => vec.len(),
92        }
93    }
94
95    /// Returns `true` if there are no indices.
96    pub fn is_empty(&self) -> bool {
97        match self {
98            Indices::U16(vec) => vec.is_empty(),
99            Indices::U32(vec) => vec.is_empty(),
100        }
101    }
102
103    /// Add an index. If the index is greater than `u16::MAX`,
104    /// the storage will be converted to `u32`.
105    pub fn push(&mut self, index: u32) {
106        match self {
107            Indices::U32(vec) => vec.push(index),
108            Indices::U16(vec) => match u16::try_from(index) {
109                Ok(index) => vec.push(index),
110                Err(_) => {
111                    let new_vec = vec
112                        .iter()
113                        .map(|&index| u32::from(index))
114                        .chain(iter::once(index))
115                        .collect::<Vec<u32>>();
116                    *self = Indices::U32(new_vec);
117                }
118            },
119        }
120    }
121}
122
123/// An Iterator for the [`Indices`].
124enum IndicesIter<'a> {
125    U16(core::slice::Iter<'a, u16>),
126    U32(core::slice::Iter<'a, u32>),
127}
128
129impl Iterator for IndicesIter<'_> {
130    type Item = usize;
131
132    fn next(&mut self) -> Option<Self::Item> {
133        match self {
134            IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
135            IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
136        }
137    }
138
139    fn size_hint(&self) -> (usize, Option<usize>) {
140        match self {
141            IndicesIter::U16(iter) => iter.size_hint(),
142            IndicesIter::U32(iter) => iter.size_hint(),
143        }
144    }
145}
146
147impl<'a> ExactSizeIterator for IndicesIter<'a> {}
148impl<'a> FusedIterator for IndicesIter<'a> {}
149
150impl From<&Indices> for IndexFormat {
151    fn from(indices: &Indices) -> Self {
152        match indices {
153            Indices::U16(_) => IndexFormat::Uint16,
154            Indices::U32(_) => IndexFormat::Uint32,
155        }
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use crate::Indices;
162    use wgpu::IndexFormat;
163
164    #[test]
165    fn test_indices_push() {
166        let mut indices = Indices::U16(Vec::new());
167        indices.push(10);
168        assert_eq!(IndexFormat::Uint16, IndexFormat::from(&indices));
169        assert_eq!(vec![10], indices.iter().collect::<Vec<_>>());
170
171        // Add a value that is too large for `u16` so the storage should be converted to `U32`.
172        indices.push(0x10000);
173        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
174        assert_eq!(vec![10, 0x10000], indices.iter().collect::<Vec<_>>());
175
176        indices.push(20);
177        indices.push(0x20000);
178        assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
179        assert_eq!(
180            vec![10, 0x10000, 20, 0x20000],
181            indices.iter().collect::<Vec<_>>()
182        );
183    }
184}