bevy_mesh/
vertex.rs

1use alloc::sync::Arc;
2use bevy_derive::EnumVariantMeta;
3use bevy_ecs::system::Resource;
4use bevy_math::Vec3;
5use bevy_utils::HashSet;
6use bytemuck::cast_slice;
7use core::hash::{Hash, Hasher};
8use derive_more::derive::{Display, Error};
9use wgpu::{BufferAddress, VertexAttribute, VertexFormat, VertexStepMode};
10
11#[derive(Debug, Clone, Copy)]
12pub struct MeshVertexAttribute {
13    /// The friendly name of the vertex attribute
14    pub name: &'static str,
15
16    /// The _unique_ id of the vertex attribute. This will also determine sort ordering
17    /// when generating vertex buffers. Built-in / standard attributes will use "close to zero"
18    /// indices. When in doubt, use a random / very large u64 to avoid conflicts.
19    pub id: MeshVertexAttributeId,
20
21    /// The format of the vertex attribute.
22    pub format: VertexFormat,
23}
24
25impl MeshVertexAttribute {
26    pub const fn new(name: &'static str, id: u64, format: VertexFormat) -> Self {
27        Self {
28            name,
29            id: MeshVertexAttributeId(id),
30            format,
31        }
32    }
33
34    pub const fn at_shader_location(&self, shader_location: u32) -> VertexAttributeDescriptor {
35        VertexAttributeDescriptor::new(shader_location, self.id, self.name)
36    }
37}
38
39#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
40pub struct MeshVertexAttributeId(u64);
41
42impl From<MeshVertexAttribute> for MeshVertexAttributeId {
43    fn from(attribute: MeshVertexAttribute) -> Self {
44        attribute.id
45    }
46}
47
48#[derive(Debug, Clone, Hash, Eq, PartialEq)]
49pub struct MeshVertexBufferLayout {
50    pub(crate) attribute_ids: Vec<MeshVertexAttributeId>,
51    pub(crate) layout: VertexBufferLayout,
52}
53
54impl MeshVertexBufferLayout {
55    pub fn new(attribute_ids: Vec<MeshVertexAttributeId>, layout: VertexBufferLayout) -> Self {
56        Self {
57            attribute_ids,
58            layout,
59        }
60    }
61
62    #[inline]
63    pub fn contains(&self, attribute_id: impl Into<MeshVertexAttributeId>) -> bool {
64        self.attribute_ids.contains(&attribute_id.into())
65    }
66
67    #[inline]
68    pub fn attribute_ids(&self) -> &[MeshVertexAttributeId] {
69        &self.attribute_ids
70    }
71
72    #[inline]
73    pub fn layout(&self) -> &VertexBufferLayout {
74        &self.layout
75    }
76
77    pub fn get_layout(
78        &self,
79        attribute_descriptors: &[VertexAttributeDescriptor],
80    ) -> Result<VertexBufferLayout, MissingVertexAttributeError> {
81        let mut attributes = Vec::with_capacity(attribute_descriptors.len());
82        for attribute_descriptor in attribute_descriptors {
83            if let Some(index) = self
84                .attribute_ids
85                .iter()
86                .position(|id| *id == attribute_descriptor.id)
87            {
88                let layout_attribute = &self.layout.attributes[index];
89                attributes.push(VertexAttribute {
90                    format: layout_attribute.format,
91                    offset: layout_attribute.offset,
92                    shader_location: attribute_descriptor.shader_location,
93                });
94            } else {
95                return Err(MissingVertexAttributeError {
96                    id: attribute_descriptor.id,
97                    name: attribute_descriptor.name,
98                    pipeline_type: None,
99                });
100            }
101        }
102
103        Ok(VertexBufferLayout {
104            array_stride: self.layout.array_stride,
105            step_mode: self.layout.step_mode,
106            attributes,
107        })
108    }
109}
110
111#[derive(Error, Display, Debug)]
112#[display("Mesh is missing requested attribute: {name} ({id:?}, pipeline type: {pipeline_type:?})")]
113pub struct MissingVertexAttributeError {
114    pub pipeline_type: Option<&'static str>,
115    id: MeshVertexAttributeId,
116    name: &'static str,
117}
118
119pub struct VertexAttributeDescriptor {
120    pub shader_location: u32,
121    pub id: MeshVertexAttributeId,
122    name: &'static str,
123}
124
125impl VertexAttributeDescriptor {
126    pub const fn new(shader_location: u32, id: MeshVertexAttributeId, name: &'static str) -> Self {
127        Self {
128            shader_location,
129            id,
130            name,
131        }
132    }
133}
134
135#[derive(Debug, Clone)]
136pub(crate) struct MeshAttributeData {
137    pub(crate) attribute: MeshVertexAttribute,
138    pub(crate) values: VertexAttributeValues,
139}
140
141pub(crate) fn face_normal(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> [f32; 3] {
142    let (a, b, c) = (Vec3::from(a), Vec3::from(b), Vec3::from(c));
143    (b - a).cross(c - a).normalize().into()
144}
145
146pub trait VertexFormatSize {
147    fn get_size(self) -> u64;
148}
149
150impl VertexFormatSize for VertexFormat {
151    #[allow(clippy::match_same_arms)]
152    fn get_size(self) -> u64 {
153        match self {
154            VertexFormat::Uint8x2 => 2,
155            VertexFormat::Uint8x4 => 4,
156            VertexFormat::Sint8x2 => 2,
157            VertexFormat::Sint8x4 => 4,
158            VertexFormat::Unorm8x2 => 2,
159            VertexFormat::Unorm8x4 => 4,
160            VertexFormat::Snorm8x2 => 2,
161            VertexFormat::Snorm8x4 => 4,
162            VertexFormat::Unorm10_10_10_2 => 4,
163            VertexFormat::Uint16x2 => 2 * 2,
164            VertexFormat::Uint16x4 => 2 * 4,
165            VertexFormat::Sint16x2 => 2 * 2,
166            VertexFormat::Sint16x4 => 2 * 4,
167            VertexFormat::Unorm16x2 => 2 * 2,
168            VertexFormat::Unorm16x4 => 2 * 4,
169            VertexFormat::Snorm16x2 => 2 * 2,
170            VertexFormat::Snorm16x4 => 2 * 4,
171            VertexFormat::Float16x2 => 2 * 2,
172            VertexFormat::Float16x4 => 2 * 4,
173            VertexFormat::Float32 => 4,
174            VertexFormat::Float32x2 => 4 * 2,
175            VertexFormat::Float32x3 => 4 * 3,
176            VertexFormat::Float32x4 => 4 * 4,
177            VertexFormat::Uint32 => 4,
178            VertexFormat::Uint32x2 => 4 * 2,
179            VertexFormat::Uint32x3 => 4 * 3,
180            VertexFormat::Uint32x4 => 4 * 4,
181            VertexFormat::Sint32 => 4,
182            VertexFormat::Sint32x2 => 4 * 2,
183            VertexFormat::Sint32x3 => 4 * 3,
184            VertexFormat::Sint32x4 => 4 * 4,
185            VertexFormat::Float64 => 8,
186            VertexFormat::Float64x2 => 8 * 2,
187            VertexFormat::Float64x3 => 8 * 3,
188            VertexFormat::Float64x4 => 8 * 4,
189        }
190    }
191}
192
193/// Contains an array where each entry describes a property of a single vertex.
194/// Matches the [`VertexFormats`](VertexFormat).
195#[derive(Clone, Debug, EnumVariantMeta)]
196pub enum VertexAttributeValues {
197    Float32(Vec<f32>),
198    Sint32(Vec<i32>),
199    Uint32(Vec<u32>),
200    Float32x2(Vec<[f32; 2]>),
201    Sint32x2(Vec<[i32; 2]>),
202    Uint32x2(Vec<[u32; 2]>),
203    Float32x3(Vec<[f32; 3]>),
204    Sint32x3(Vec<[i32; 3]>),
205    Uint32x3(Vec<[u32; 3]>),
206    Float32x4(Vec<[f32; 4]>),
207    Sint32x4(Vec<[i32; 4]>),
208    Uint32x4(Vec<[u32; 4]>),
209    Sint16x2(Vec<[i16; 2]>),
210    Snorm16x2(Vec<[i16; 2]>),
211    Uint16x2(Vec<[u16; 2]>),
212    Unorm16x2(Vec<[u16; 2]>),
213    Sint16x4(Vec<[i16; 4]>),
214    Snorm16x4(Vec<[i16; 4]>),
215    Uint16x4(Vec<[u16; 4]>),
216    Unorm16x4(Vec<[u16; 4]>),
217    Sint8x2(Vec<[i8; 2]>),
218    Snorm8x2(Vec<[i8; 2]>),
219    Uint8x2(Vec<[u8; 2]>),
220    Unorm8x2(Vec<[u8; 2]>),
221    Sint8x4(Vec<[i8; 4]>),
222    Snorm8x4(Vec<[i8; 4]>),
223    Uint8x4(Vec<[u8; 4]>),
224    Unorm8x4(Vec<[u8; 4]>),
225}
226
227impl VertexAttributeValues {
228    /// Returns the number of vertices in this [`VertexAttributeValues`]. For a single
229    /// mesh, all of the [`VertexAttributeValues`] must have the same length.
230    #[allow(clippy::match_same_arms)]
231    pub fn len(&self) -> usize {
232        match self {
233            VertexAttributeValues::Float32(values) => values.len(),
234            VertexAttributeValues::Sint32(values) => values.len(),
235            VertexAttributeValues::Uint32(values) => values.len(),
236            VertexAttributeValues::Float32x2(values) => values.len(),
237            VertexAttributeValues::Sint32x2(values) => values.len(),
238            VertexAttributeValues::Uint32x2(values) => values.len(),
239            VertexAttributeValues::Float32x3(values) => values.len(),
240            VertexAttributeValues::Sint32x3(values) => values.len(),
241            VertexAttributeValues::Uint32x3(values) => values.len(),
242            VertexAttributeValues::Float32x4(values) => values.len(),
243            VertexAttributeValues::Sint32x4(values) => values.len(),
244            VertexAttributeValues::Uint32x4(values) => values.len(),
245            VertexAttributeValues::Sint16x2(values) => values.len(),
246            VertexAttributeValues::Snorm16x2(values) => values.len(),
247            VertexAttributeValues::Uint16x2(values) => values.len(),
248            VertexAttributeValues::Unorm16x2(values) => values.len(),
249            VertexAttributeValues::Sint16x4(values) => values.len(),
250            VertexAttributeValues::Snorm16x4(values) => values.len(),
251            VertexAttributeValues::Uint16x4(values) => values.len(),
252            VertexAttributeValues::Unorm16x4(values) => values.len(),
253            VertexAttributeValues::Sint8x2(values) => values.len(),
254            VertexAttributeValues::Snorm8x2(values) => values.len(),
255            VertexAttributeValues::Uint8x2(values) => values.len(),
256            VertexAttributeValues::Unorm8x2(values) => values.len(),
257            VertexAttributeValues::Sint8x4(values) => values.len(),
258            VertexAttributeValues::Snorm8x4(values) => values.len(),
259            VertexAttributeValues::Uint8x4(values) => values.len(),
260            VertexAttributeValues::Unorm8x4(values) => values.len(),
261        }
262    }
263
264    /// Returns `true` if there are no vertices in this [`VertexAttributeValues`].
265    pub fn is_empty(&self) -> bool {
266        self.len() == 0
267    }
268
269    /// Returns the values as float triples if possible.
270    pub fn as_float3(&self) -> Option<&[[f32; 3]]> {
271        match self {
272            VertexAttributeValues::Float32x3(values) => Some(values),
273            _ => None,
274        }
275    }
276
277    // TODO: add vertex format as parameter here and perform type conversions
278    /// Flattens the [`VertexAttributeValues`] into a sequence of bytes. This is
279    /// useful for serialization and sending to the GPU.
280    #[allow(clippy::match_same_arms)]
281    pub fn get_bytes(&self) -> &[u8] {
282        match self {
283            VertexAttributeValues::Float32(values) => cast_slice(values),
284            VertexAttributeValues::Sint32(values) => cast_slice(values),
285            VertexAttributeValues::Uint32(values) => cast_slice(values),
286            VertexAttributeValues::Float32x2(values) => cast_slice(values),
287            VertexAttributeValues::Sint32x2(values) => cast_slice(values),
288            VertexAttributeValues::Uint32x2(values) => cast_slice(values),
289            VertexAttributeValues::Float32x3(values) => cast_slice(values),
290            VertexAttributeValues::Sint32x3(values) => cast_slice(values),
291            VertexAttributeValues::Uint32x3(values) => cast_slice(values),
292            VertexAttributeValues::Float32x4(values) => cast_slice(values),
293            VertexAttributeValues::Sint32x4(values) => cast_slice(values),
294            VertexAttributeValues::Uint32x4(values) => cast_slice(values),
295            VertexAttributeValues::Sint16x2(values) => cast_slice(values),
296            VertexAttributeValues::Snorm16x2(values) => cast_slice(values),
297            VertexAttributeValues::Uint16x2(values) => cast_slice(values),
298            VertexAttributeValues::Unorm16x2(values) => cast_slice(values),
299            VertexAttributeValues::Sint16x4(values) => cast_slice(values),
300            VertexAttributeValues::Snorm16x4(values) => cast_slice(values),
301            VertexAttributeValues::Uint16x4(values) => cast_slice(values),
302            VertexAttributeValues::Unorm16x4(values) => cast_slice(values),
303            VertexAttributeValues::Sint8x2(values) => cast_slice(values),
304            VertexAttributeValues::Snorm8x2(values) => cast_slice(values),
305            VertexAttributeValues::Uint8x2(values) => cast_slice(values),
306            VertexAttributeValues::Unorm8x2(values) => cast_slice(values),
307            VertexAttributeValues::Sint8x4(values) => cast_slice(values),
308            VertexAttributeValues::Snorm8x4(values) => cast_slice(values),
309            VertexAttributeValues::Uint8x4(values) => cast_slice(values),
310            VertexAttributeValues::Unorm8x4(values) => cast_slice(values),
311        }
312    }
313}
314
315impl From<&VertexAttributeValues> for VertexFormat {
316    fn from(values: &VertexAttributeValues) -> Self {
317        match values {
318            VertexAttributeValues::Float32(_) => VertexFormat::Float32,
319            VertexAttributeValues::Sint32(_) => VertexFormat::Sint32,
320            VertexAttributeValues::Uint32(_) => VertexFormat::Uint32,
321            VertexAttributeValues::Float32x2(_) => VertexFormat::Float32x2,
322            VertexAttributeValues::Sint32x2(_) => VertexFormat::Sint32x2,
323            VertexAttributeValues::Uint32x2(_) => VertexFormat::Uint32x2,
324            VertexAttributeValues::Float32x3(_) => VertexFormat::Float32x3,
325            VertexAttributeValues::Sint32x3(_) => VertexFormat::Sint32x3,
326            VertexAttributeValues::Uint32x3(_) => VertexFormat::Uint32x3,
327            VertexAttributeValues::Float32x4(_) => VertexFormat::Float32x4,
328            VertexAttributeValues::Sint32x4(_) => VertexFormat::Sint32x4,
329            VertexAttributeValues::Uint32x4(_) => VertexFormat::Uint32x4,
330            VertexAttributeValues::Sint16x2(_) => VertexFormat::Sint16x2,
331            VertexAttributeValues::Snorm16x2(_) => VertexFormat::Snorm16x2,
332            VertexAttributeValues::Uint16x2(_) => VertexFormat::Uint16x2,
333            VertexAttributeValues::Unorm16x2(_) => VertexFormat::Unorm16x2,
334            VertexAttributeValues::Sint16x4(_) => VertexFormat::Sint16x4,
335            VertexAttributeValues::Snorm16x4(_) => VertexFormat::Snorm16x4,
336            VertexAttributeValues::Uint16x4(_) => VertexFormat::Uint16x4,
337            VertexAttributeValues::Unorm16x4(_) => VertexFormat::Unorm16x4,
338            VertexAttributeValues::Sint8x2(_) => VertexFormat::Sint8x2,
339            VertexAttributeValues::Snorm8x2(_) => VertexFormat::Snorm8x2,
340            VertexAttributeValues::Uint8x2(_) => VertexFormat::Uint8x2,
341            VertexAttributeValues::Unorm8x2(_) => VertexFormat::Unorm8x2,
342            VertexAttributeValues::Sint8x4(_) => VertexFormat::Sint8x4,
343            VertexAttributeValues::Snorm8x4(_) => VertexFormat::Snorm8x4,
344            VertexAttributeValues::Uint8x4(_) => VertexFormat::Uint8x4,
345            VertexAttributeValues::Unorm8x4(_) => VertexFormat::Unorm8x4,
346        }
347    }
348}
349
350/// Describes how the vertex buffer is interpreted.
351#[derive(Default, Clone, Debug, Hash, Eq, PartialEq)]
352pub struct VertexBufferLayout {
353    /// The stride, in bytes, between elements of this buffer.
354    pub array_stride: BufferAddress,
355    /// How often this vertex buffer is "stepped" forward.
356    pub step_mode: VertexStepMode,
357    /// The list of attributes which comprise a single vertex.
358    pub attributes: Vec<VertexAttribute>,
359}
360
361impl VertexBufferLayout {
362    /// Creates a new densely packed [`VertexBufferLayout`] from an iterator of vertex formats.
363    /// Iteration order determines the `shader_location` and `offset` of the [`VertexAttributes`](VertexAttribute).
364    /// The first iterated item will have a `shader_location` and `offset` of zero.
365    /// The `array_stride` is the sum of the size of the iterated [`VertexFormats`](VertexFormat) (in bytes).
366    pub fn from_vertex_formats<T: IntoIterator<Item = VertexFormat>>(
367        step_mode: VertexStepMode,
368        vertex_formats: T,
369    ) -> Self {
370        let mut offset = 0;
371        let mut attributes = Vec::new();
372        for (shader_location, format) in vertex_formats.into_iter().enumerate() {
373            attributes.push(VertexAttribute {
374                format,
375                offset,
376                shader_location: shader_location as u32,
377            });
378            offset += format.size();
379        }
380
381        VertexBufferLayout {
382            array_stride: offset,
383            step_mode,
384            attributes,
385        }
386    }
387
388    /// Returns a [`VertexBufferLayout`] with the shader location of every attribute offset by
389    /// `location`.
390    pub fn offset_locations_by(mut self, location: u32) -> Self {
391        self.attributes.iter_mut().for_each(|attr| {
392            attr.shader_location += location;
393        });
394        self
395    }
396}
397
398/// Describes the layout of the mesh vertices in GPU memory.
399///
400/// At most one copy of a mesh vertex buffer layout ever exists in GPU memory at
401/// once. Therefore, comparing these for equality requires only a single pointer
402/// comparison, and this type's [`PartialEq`] and [`Hash`] implementations take
403/// advantage of this. To that end, this type doesn't implement
404/// [`bevy_derive::Deref`] or [`bevy_derive::DerefMut`] in order to reduce the
405/// possibility of accidental deep comparisons, which would be needlessly
406/// expensive.
407#[derive(Clone, Debug)]
408pub struct MeshVertexBufferLayoutRef(pub Arc<MeshVertexBufferLayout>);
409
410/// Stores the single copy of each mesh vertex buffer layout.
411#[derive(Clone, Default, Resource)]
412pub struct MeshVertexBufferLayouts(HashSet<Arc<MeshVertexBufferLayout>>);
413
414impl MeshVertexBufferLayouts {
415    /// Inserts a new mesh vertex buffer layout in the store and returns a
416    /// reference to it, reusing the existing reference if this mesh vertex
417    /// buffer layout was already in the store.
418    pub fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef {
419        // Because the special `PartialEq` and `Hash` implementations that
420        // compare by pointer are on `MeshVertexBufferLayoutRef`, not on
421        // `Arc<MeshVertexBufferLayout>`, this compares the mesh vertex buffer
422        // structurally, not by pointer.
423        MeshVertexBufferLayoutRef(
424            self.0
425                .get_or_insert_with(&layout, |layout| Arc::new(layout.clone()))
426                .clone(),
427        )
428    }
429}
430
431impl PartialEq for MeshVertexBufferLayoutRef {
432    fn eq(&self, other: &Self) -> bool {
433        Arc::ptr_eq(&self.0, &other.0)
434    }
435}
436
437impl Eq for MeshVertexBufferLayoutRef {}
438
439impl Hash for MeshVertexBufferLayoutRef {
440    fn hash<H: Hasher>(&self, state: &mut H) {
441        // Hash the address of the underlying data, so two layouts that share the same
442        // `MeshVertexBufferLayout` will have the same hash.
443        (Arc::as_ptr(&self.0) as usize).hash(state);
444    }
445}