Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_mesh/src/index.rs
6595 views
1
use bevy_reflect::Reflect;
2
use core::iter;
3
use core::iter::FusedIterator;
4
#[cfg(feature = "serialize")]
5
use serde::{Deserialize, Serialize};
6
use thiserror::Error;
7
use 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.
12
pub(crate) enum FourIterators<A, B, C, D> {
13
First(A),
14
Second(B),
15
Third(C),
16
Fourth(D),
17
}
18
19
impl<A, B, C, D, I> Iterator for FourIterators<A, B, C, D>
20
where
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)]
40
pub 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)]
54
pub 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))]
77
pub enum Indices {
78
U16(Vec<u16>),
79
U32(Vec<u32>),
80
}
81
82
impl 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.
117
impl 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`].
145
enum IndicesIter<'a> {
146
U16(core::slice::Iter<'a, u16>),
147
U32(core::slice::Iter<'a, u32>),
148
}
149
150
impl 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
168
impl<'a> ExactSizeIterator for IndicesIter<'a> {}
169
170
impl<'a> FusedIterator for IndicesIter<'a> {}
171
172
impl 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)]
182
mod 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
}
230
231