Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_mesh/src/index.rs
9371 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
use 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.
14
pub(crate) enum FourIterators<A, B, C, D> {
15
First(A),
16
Second(B),
17
Third(C),
18
Fourth(D),
19
}
20
21
impl<A, B, C, D, I> Iterator for FourIterators<A, B, C, D>
22
where
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)]
51
pub 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)]
67
pub 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))]
86
pub enum Indices {
87
U16(Vec<u16>),
88
U32(Vec<u32>),
89
}
90
91
impl 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
impl Extend<u32> for Indices {
127
fn extend<T: IntoIterator<Item = u32>>(&mut self, iter: T) {
128
let mut iter = iter.into_iter();
129
match self {
130
Indices::U32(indices) => indices.extend(iter),
131
Indices::U16(indices) => {
132
indices.reserve(iter.size_hint().0);
133
while let Some(index) = iter.next() {
134
match u16::try_from(index) {
135
Ok(index) => indices.push(index),
136
Err(_) => {
137
let new_vec = indices
138
.iter()
139
.map(|&index| u32::from(index))
140
.chain(iter::once(index))
141
.chain(iter)
142
.collect::<Vec<u32>>();
143
*self = Indices::U32(new_vec);
144
break;
145
}
146
}
147
}
148
}
149
}
150
}
151
}
152
153
/// An Iterator for the [`Indices`].
154
enum IndicesIter<'a> {
155
U16(core::slice::Iter<'a, u16>),
156
U32(core::slice::Iter<'a, u32>),
157
}
158
159
impl Iterator for IndicesIter<'_> {
160
type Item = usize;
161
162
fn next(&mut self) -> Option<Self::Item> {
163
match self {
164
IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
165
IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
166
}
167
}
168
169
fn size_hint(&self) -> (usize, Option<usize>) {
170
match self {
171
IndicesIter::U16(iter) => iter.size_hint(),
172
IndicesIter::U32(iter) => iter.size_hint(),
173
}
174
}
175
}
176
177
impl<'a> ExactSizeIterator for IndicesIter<'a> {}
178
179
impl<'a> FusedIterator for IndicesIter<'a> {}
180
181
impl From<&Indices> for IndexFormat {
182
fn from(indices: &Indices) -> Self {
183
match indices {
184
Indices::U16(_) => IndexFormat::Uint16,
185
Indices::U32(_) => IndexFormat::Uint32,
186
}
187
}
188
}
189
190
#[cfg(test)]
191
mod tests {
192
use crate::Indices;
193
use wgpu_types::IndexFormat;
194
195
#[test]
196
fn test_indices_push() {
197
let mut indices = Indices::U16(Vec::new());
198
indices.push(10);
199
assert_eq!(IndexFormat::Uint16, IndexFormat::from(&indices));
200
assert_eq!(vec![10], indices.iter().collect::<Vec<_>>());
201
202
// Add a value that is too large for `u16` so the storage should be converted to `U32`.
203
indices.push(0x10000);
204
assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
205
assert_eq!(vec![10, 0x10000], indices.iter().collect::<Vec<_>>());
206
207
indices.push(20);
208
indices.push(0x20000);
209
assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
210
assert_eq!(
211
vec![10, 0x10000, 20, 0x20000],
212
indices.iter().collect::<Vec<_>>()
213
);
214
}
215
216
#[test]
217
fn test_indices_extend() {
218
let mut indices = Indices::U16(Vec::new());
219
indices.extend([10, 11]);
220
assert_eq!(IndexFormat::Uint16, IndexFormat::from(&indices));
221
assert_eq!(vec![10, 11], indices.iter().collect::<Vec<_>>());
222
223
// Add a value that is too large for `u16` so the storage should be converted to `U32`.
224
indices.extend([12, 0x10013, 0x10014]);
225
assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
226
assert_eq!(
227
vec![10, 11, 12, 0x10013, 0x10014],
228
indices.iter().collect::<Vec<_>>()
229
);
230
231
indices.extend([15, 0x10016]);
232
assert_eq!(IndexFormat::Uint32, IndexFormat::from(&indices));
233
assert_eq!(
234
vec![10, 11, 12, 0x10013, 0x10014, 15, 0x10016],
235
indices.iter().collect::<Vec<_>>()
236
);
237
}
238
}
239
240