bevy_mesh/
mesh.rs

1use bevy_transform::components::Transform;
2pub use wgpu_types::PrimitiveTopology;
3
4use super::{
5    triangle_area_normal, triangle_normal, FourIterators, Indices, MeshAttributeData,
6    MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId, MeshVertexBufferLayout,
7    MeshVertexBufferLayoutRef, MeshVertexBufferLayouts, MeshWindingInvertError,
8    VertexAttributeValues, VertexBufferLayout,
9};
10#[cfg(feature = "serialize")]
11use crate::SerializedMeshAttributeData;
12use alloc::collections::BTreeMap;
13#[cfg(feature = "morph")]
14use bevy_asset::Handle;
15use bevy_asset::{Asset, RenderAssetUsages};
16#[cfg(feature = "morph")]
17use bevy_image::Image;
18use bevy_math::{bounding::Aabb3d, primitives::Triangle3d, *};
19#[cfg(feature = "serialize")]
20use bevy_platform::collections::HashMap;
21use bevy_reflect::Reflect;
22use bytemuck::cast_slice;
23#[cfg(feature = "serialize")]
24use serde::{Deserialize, Serialize};
25use thiserror::Error;
26use tracing::warn;
27use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode};
28
29pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
30pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
31
32/// Error from accessing mesh vertex attributes or indices
33#[derive(Error, Debug, Clone)]
34pub enum MeshAccessError {
35    #[error("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)")]
36    ExtractedToRenderWorld,
37    #[error("The requested mesh data wasn't found in this mesh")]
38    NotFound,
39}
40
41const MESH_EXTRACTED_ERROR: &str = "Mesh has been extracted to RenderWorld. To access vertex attributes, the mesh `asset_usage` must include `MAIN_WORLD`";
42
43// storage for extractable data with access methods which return errors if the
44// contents have already been extracted
45#[derive(Debug, Clone, PartialEq, Reflect, Default)]
46enum MeshExtractableData<T> {
47    Data(T),
48    #[default]
49    NoData,
50    ExtractedToRenderWorld,
51}
52
53impl<T> MeshExtractableData<T> {
54    // get a reference to internal data. returns error if data has been extracted, or if no
55    // data exists
56    fn as_ref(&self) -> Result<&T, MeshAccessError> {
57        match self {
58            MeshExtractableData::Data(data) => Ok(data),
59            MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
60            MeshExtractableData::ExtractedToRenderWorld => {
61                Err(MeshAccessError::ExtractedToRenderWorld)
62            }
63        }
64    }
65
66    // get an optional reference to internal data. returns error if data has been extracted
67    fn as_ref_option(&self) -> Result<Option<&T>, MeshAccessError> {
68        match self {
69            MeshExtractableData::Data(data) => Ok(Some(data)),
70            MeshExtractableData::NoData => Ok(None),
71            MeshExtractableData::ExtractedToRenderWorld => {
72                Err(MeshAccessError::ExtractedToRenderWorld)
73            }
74        }
75    }
76
77    // get a mutable reference to internal data. returns error if data has been extracted,
78    // or if no data exists
79    fn as_mut(&mut self) -> Result<&mut T, MeshAccessError> {
80        match self {
81            MeshExtractableData::Data(data) => Ok(data),
82            MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
83            MeshExtractableData::ExtractedToRenderWorld => {
84                Err(MeshAccessError::ExtractedToRenderWorld)
85            }
86        }
87    }
88
89    // get an optional mutable reference to internal data. returns error if data has been extracted
90    fn as_mut_option(&mut self) -> Result<Option<&mut T>, MeshAccessError> {
91        match self {
92            MeshExtractableData::Data(data) => Ok(Some(data)),
93            MeshExtractableData::NoData => Ok(None),
94            MeshExtractableData::ExtractedToRenderWorld => {
95                Err(MeshAccessError::ExtractedToRenderWorld)
96            }
97        }
98    }
99
100    // extract data and replace self with `ExtractedToRenderWorld`. returns error if
101    // data has been extracted
102    fn extract(&mut self) -> Result<MeshExtractableData<T>, MeshAccessError> {
103        match core::mem::replace(self, MeshExtractableData::ExtractedToRenderWorld) {
104            MeshExtractableData::ExtractedToRenderWorld => {
105                Err(MeshAccessError::ExtractedToRenderWorld)
106            }
107            not_extracted => Ok(not_extracted),
108        }
109    }
110
111    // replace internal data. returns the existing data, or an error if data has been extracted
112    fn replace(
113        &mut self,
114        data: impl Into<MeshExtractableData<T>>,
115    ) -> Result<Option<T>, MeshAccessError> {
116        match core::mem::replace(self, data.into()) {
117            MeshExtractableData::ExtractedToRenderWorld => {
118                *self = MeshExtractableData::ExtractedToRenderWorld;
119                Err(MeshAccessError::ExtractedToRenderWorld)
120            }
121            MeshExtractableData::Data(t) => Ok(Some(t)),
122            MeshExtractableData::NoData => Ok(None),
123        }
124    }
125}
126
127impl<T> From<Option<T>> for MeshExtractableData<T> {
128    fn from(value: Option<T>) -> Self {
129        match value {
130            Some(data) => MeshExtractableData::Data(data),
131            None => MeshExtractableData::NoData,
132        }
133    }
134}
135
136/// A 3D object made out of vertices representing triangles, lines, or points,
137/// with "attribute" values for each vertex.
138///
139/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
140/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
141/// It is also possible to create one manually. They can be edited after creation.
142///
143/// Meshes can be rendered with a [`Mesh2d`](crate::Mesh2d) and `MeshMaterial2d`
144/// or [`Mesh3d`](crate::Mesh3d) and `MeshMaterial3d` for 2D and 3D respectively.
145///
146/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
147/// glTF Mesh representation, see `GltfMesh`.
148///
149/// ## Manual creation
150///
151/// The following function will construct a flat mesh, to be rendered with a
152/// `StandardMaterial` or `ColorMaterial`:
153///
154/// ```
155/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
156/// # use bevy_asset::RenderAssetUsages;
157/// fn create_simple_parallelogram() -> Mesh {
158///     // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
159///     Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
160///         // Add 4 vertices, each with its own position attribute (coordinate in
161///         // 3D space), for each of the corners of the parallelogram.
162///         .with_inserted_attribute(
163///             Mesh::ATTRIBUTE_POSITION,
164///             vec![[0.0, 0.0, 0.0], [1.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 0.0, 0.0]]
165///         )
166///         // Assign a UV coordinate to each vertex.
167///         .with_inserted_attribute(
168///             Mesh::ATTRIBUTE_UV_0,
169///             vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
170///         )
171///         // Assign normals (everything points outwards)
172///         .with_inserted_attribute(
173///             Mesh::ATTRIBUTE_NORMAL,
174///             vec![[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]
175///         )
176///         // After defining all the vertices and their attributes, build each triangle using the
177///         // indices of the vertices that make it up in a counter-clockwise order.
178///         .with_inserted_indices(Indices::U32(vec![
179///             // First triangle
180///             0, 3, 1,
181///             // Second triangle
182///             1, 3, 2
183///         ]))
184/// }
185/// ```
186///
187/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
188/// used in a [`Mesh3d`](crate::Mesh3d) with a square bevy logo texture, with added axis, points,
189/// lines and text for clarity.
190///
191/// ## Other examples
192///
193/// For further visualization, explanation, and examples, see the built-in Bevy examples,
194/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
195/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
196/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
197///
198/// ## Common points of confusion
199///
200/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
201///   other APIs can have other conventions, `OpenGL` starts at bottom-left.
202/// - It is possible and sometimes useful for multiple vertices to have the same
203///   [position attribute](Mesh::ATTRIBUTE_POSITION) value,
204///   it's a common technique in 3D modeling for complex UV mapping or other calculations.
205/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
206///   and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
207///   needs to be updated manually or deleted so that it is re-calculated.
208///
209/// ## Use with `StandardMaterial`
210///
211/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
212/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
213///   (also true for `ColorMaterial`).
214/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
215///   [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
216///   because simple meshes are smooth and they don't require complex light calculations.
217/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
218///   which means that Bevy would *only* render the "front" of each triangle, which
219///   is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
220///
221/// ## Remote Inspection
222///
223/// To transmit a [`Mesh`] between two running Bevy apps, e.g. through BRP, use [`SerializedMesh`].
224/// This type is only meant for short-term transmission between same versions and should not be stored anywhere.
225#[derive(Asset, Debug, Clone, Reflect, PartialEq)]
226#[reflect(Clone)]
227pub struct Mesh {
228    #[reflect(ignore, clone)]
229    primitive_topology: PrimitiveTopology,
230    /// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
231    /// for this mesh. Attribute ids to attribute values.
232    /// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
233    /// which allows easy stable `VertexBuffers` (i.e. same buffer order)
234    #[reflect(ignore, clone)]
235    attributes: MeshExtractableData<BTreeMap<MeshVertexAttributeId, MeshAttributeData>>,
236    indices: MeshExtractableData<Indices>,
237    #[cfg(feature = "morph")]
238    morph_targets: MeshExtractableData<Handle<Image>>,
239    #[cfg(feature = "morph")]
240    morph_target_names: MeshExtractableData<Vec<String>>,
241    pub asset_usage: RenderAssetUsages,
242    /// Whether or not to build a BLAS for use with `bevy_solari` raytracing.
243    ///
244    /// Note that this is _not_ whether the mesh is _compatible_ with `bevy_solari` raytracing.
245    /// This field just controls whether or not a BLAS gets built for this mesh, assuming that
246    /// the mesh is compatible.
247    ///
248    /// The use case for this field is using lower-resolution proxy meshes for raytracing (to save on BLAS memory usage),
249    /// while using higher-resolution meshes for raster. You can set this field to true for the lower-resolution proxy mesh,
250    /// and to false for the high-resolution raster mesh.
251    ///
252    /// Alternatively, you can use the same mesh for both raster and raytracing, with this field set to true.
253    ///
254    /// Does nothing if not used with `bevy_solari`, or if the mesh is not compatible
255    /// with `bevy_solari` (see `bevy_solari`'s docs).
256    pub enable_raytracing: bool,
257    /// Precomputed min and max extents of the mesh position data. Used mainly for constructing `Aabb`s for frustum culling.
258    /// This data will be set if/when a mesh is extracted to the GPU
259    pub final_aabb: Option<Aabb3d>,
260}
261
262impl Mesh {
263    /// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
264    /// or [`Mesh::with_inserted_attribute`].
265    ///
266    /// The format of this attribute is [`VertexFormat::Float32x3`].
267    pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
268        MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
269
270    /// The direction the vertex normal is facing in.
271    /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
272    ///
273    /// The format of this attribute is [`VertexFormat::Float32x3`].
274    pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
275        MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
276
277    /// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
278    /// or [`Mesh::with_inserted_attribute`].
279    ///
280    /// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
281    ///
282    /// By default values outside will be clamped per pixel not for the vertex,
283    /// "stretching" the borders of the texture.
284    /// This behavior can be useful in some cases, usually when the borders have only
285    /// one color, for example a logo, and you want to "extend" those borders.
286    ///
287    /// For different mapping outside of `0..=1` range,
288    /// see [`ImageAddressMode`](bevy_image::ImageAddressMode).
289    ///
290    /// The format of this attribute is [`VertexFormat::Float32x2`].
291    pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
292        MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
293
294    /// Alternate texture coordinates for the vertex. Use in conjunction with
295    /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
296    ///
297    /// Typically, these are used for lightmaps, textures that provide
298    /// precomputed illumination.
299    ///
300    /// The format of this attribute is [`VertexFormat::Float32x2`].
301    pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
302        MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
303
304    /// The direction of the vertex tangent. Used for normal mapping.
305    /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
306    /// [`with_generated_tangents`](Mesh::with_generated_tangents).
307    ///
308    /// The format of this attribute is [`VertexFormat::Float32x4`].
309    pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
310        MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
311
312    /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
313    /// or [`Mesh::with_inserted_attribute`].
314    ///
315    /// The format of this attribute is [`VertexFormat::Float32x4`].
316    pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
317        MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
318
319    /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
320    /// or [`Mesh::with_inserted_attribute`].
321    ///
322    /// The format of this attribute is [`VertexFormat::Float32x4`].
323    pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
324        MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
325
326    /// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
327    /// or [`Mesh::with_inserted_attribute`].
328    ///
329    /// The format of this attribute is [`VertexFormat::Uint16x4`].
330    pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
331        MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
332
333    /// The first index that can be used for custom vertex attributes.
334    /// Only the attributes with an index below this are used by Bevy.
335    pub const FIRST_AVAILABLE_CUSTOM_ATTRIBUTE: u64 = 8;
336
337    /// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
338    /// renderer knows how to treat the vertex data. Most of the time this will be
339    /// [`PrimitiveTopology::TriangleList`].
340    pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
341        Mesh {
342            primitive_topology,
343            attributes: MeshExtractableData::Data(Default::default()),
344            indices: MeshExtractableData::NoData,
345            #[cfg(feature = "morph")]
346            morph_targets: MeshExtractableData::NoData,
347            #[cfg(feature = "morph")]
348            morph_target_names: MeshExtractableData::NoData,
349            asset_usage,
350            enable_raytracing: true,
351            final_aabb: None,
352        }
353    }
354
355    /// Returns the topology of the mesh.
356    pub fn primitive_topology(&self) -> PrimitiveTopology {
357        self.primitive_topology
358    }
359
360    /// Sets the data for a vertex attribute (position, normal, etc.). The name will
361    /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
362    ///
363    /// `Aabb` of entities with modified mesh are not updated automatically.
364    ///
365    /// # Panics
366    /// Panics when the format of the values does not match the attribute's format.
367    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
368    /// this as an error use [`Mesh::try_insert_attribute`]
369    #[inline]
370    pub fn insert_attribute(
371        &mut self,
372        attribute: MeshVertexAttribute,
373        values: impl Into<VertexAttributeValues>,
374    ) {
375        self.try_insert_attribute(attribute, values)
376            .expect(MESH_EXTRACTED_ERROR);
377    }
378
379    /// Sets the data for a vertex attribute (position, normal, etc.). The name will
380    /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
381    ///
382    /// `Aabb` of entities with modified mesh are not updated automatically.
383    ///
384    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
385    ///
386    /// # Panics
387    /// Panics when the format of the values does not match the attribute's format.
388    #[inline]
389    pub fn try_insert_attribute(
390        &mut self,
391        attribute: MeshVertexAttribute,
392        values: impl Into<VertexAttributeValues>,
393    ) -> Result<(), MeshAccessError> {
394        let values = values.into();
395        let values_format = VertexFormat::from(&values);
396        if values_format != attribute.format {
397            panic!(
398                "Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
399                attribute.name, attribute.format
400            );
401        }
402
403        self.attributes
404            .as_mut()?
405            .insert(attribute.id, MeshAttributeData { attribute, values });
406        Ok(())
407    }
408
409    /// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
410    /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
411    ///
412    /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
413    ///
414    /// `Aabb` of entities with modified mesh are not updated automatically.
415    ///
416    /// # Panics
417    /// Panics when the format of the values does not match the attribute's format.
418    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
419    /// this as an error use [`Mesh::try_with_inserted_attribute`]
420    #[must_use]
421    #[inline]
422    pub fn with_inserted_attribute(
423        mut self,
424        attribute: MeshVertexAttribute,
425        values: impl Into<VertexAttributeValues>,
426    ) -> Self {
427        self.insert_attribute(attribute, values);
428        self
429    }
430
431    /// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
432    /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
433    ///
434    /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
435    ///
436    /// `Aabb` of entities with modified mesh are not updated automatically.
437    ///
438    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
439    #[inline]
440    pub fn try_with_inserted_attribute(
441        mut self,
442        attribute: MeshVertexAttribute,
443        values: impl Into<VertexAttributeValues>,
444    ) -> Result<Self, MeshAccessError> {
445        self.try_insert_attribute(attribute, values)?;
446        Ok(self)
447    }
448
449    /// Removes the data for a vertex attribute
450    ///
451    /// # Panics
452    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
453    /// this as an error use [`Mesh::try_remove_attribute`]
454    pub fn remove_attribute(
455        &mut self,
456        attribute: impl Into<MeshVertexAttributeId>,
457    ) -> Option<VertexAttributeValues> {
458        self.attributes
459            .as_mut()
460            .expect(MESH_EXTRACTED_ERROR)
461            .remove(&attribute.into())
462            .map(|data| data.values)
463    }
464
465    /// Removes the data for a vertex attribute
466    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
467    /// if the attribute does not exist.
468    pub fn try_remove_attribute(
469        &mut self,
470        attribute: impl Into<MeshVertexAttributeId>,
471    ) -> Result<VertexAttributeValues, MeshAccessError> {
472        Ok(self
473            .attributes
474            .as_mut()?
475            .remove(&attribute.into())
476            .ok_or(MeshAccessError::NotFound)?
477            .values)
478    }
479
480    /// Consumes the mesh and returns a mesh without the data for a vertex attribute
481    ///
482    /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
483    ///
484    /// # Panics
485    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
486    /// this as an error use [`Mesh::try_with_removed_attribute`]
487    #[must_use]
488    pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
489        self.remove_attribute(attribute);
490        self
491    }
492
493    /// Consumes the mesh and returns a mesh without the data for a vertex attribute
494    ///
495    /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
496    ///
497    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
498    /// if the attribute does not exist.
499    pub fn try_with_removed_attribute(
500        mut self,
501        attribute: impl Into<MeshVertexAttributeId>,
502    ) -> Result<Self, MeshAccessError> {
503        self.try_remove_attribute(attribute)?;
504        Ok(self)
505    }
506
507    /// Returns a bool indicating if the attribute is present in this mesh's vertex data.
508    ///
509    /// # Panics
510    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
511    /// this as an error use [`Mesh::try_contains_attribute`]
512    #[inline]
513    pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
514        self.attributes
515            .as_ref()
516            .expect(MESH_EXTRACTED_ERROR)
517            .contains_key(&id.into())
518    }
519
520    /// Returns a bool indicating if the attribute is present in this mesh's vertex data.
521    ///
522    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
523    #[inline]
524    pub fn try_contains_attribute(
525        &self,
526        id: impl Into<MeshVertexAttributeId>,
527    ) -> Result<bool, MeshAccessError> {
528        Ok(self.attributes.as_ref()?.contains_key(&id.into()))
529    }
530
531    /// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
532    ///
533    /// # Panics
534    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
535    /// this as an error use [`Mesh::try_attribute`] or [`Mesh::try_attribute_option`]
536    #[inline]
537    pub fn attribute(
538        &self,
539        id: impl Into<MeshVertexAttributeId>,
540    ) -> Option<&VertexAttributeValues> {
541        self.try_attribute_option(id).expect(MESH_EXTRACTED_ERROR)
542    }
543
544    /// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
545    ///
546    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
547    /// if the attribute does not exist.
548    #[inline]
549    pub fn try_attribute(
550        &self,
551        id: impl Into<MeshVertexAttributeId>,
552    ) -> Result<&VertexAttributeValues, MeshAccessError> {
553        self.try_attribute_option(id)?
554            .ok_or(MeshAccessError::NotFound)
555    }
556
557    /// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
558    ///
559    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
560    #[inline]
561    pub fn try_attribute_option(
562        &self,
563        id: impl Into<MeshVertexAttributeId>,
564    ) -> Result<Option<&VertexAttributeValues>, MeshAccessError> {
565        Ok(self
566            .attributes
567            .as_ref()?
568            .get(&id.into())
569            .map(|data| &data.values))
570    }
571
572    /// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
573    #[inline]
574    pub(crate) fn try_attribute_data(
575        &self,
576        id: impl Into<MeshVertexAttributeId>,
577    ) -> Result<Option<&MeshAttributeData>, MeshAccessError> {
578        Ok(self.attributes.as_ref()?.get(&id.into()))
579    }
580
581    /// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
582    ///
583    /// # Panics
584    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
585    /// this as an error use [`Mesh::try_attribute_mut`]
586    #[inline]
587    pub fn attribute_mut(
588        &mut self,
589        id: impl Into<MeshVertexAttributeId>,
590    ) -> Option<&mut VertexAttributeValues> {
591        self.try_attribute_mut_option(id)
592            .expect(MESH_EXTRACTED_ERROR)
593    }
594
595    /// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
596    ///
597    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
598    /// if the attribute does not exist.
599    #[inline]
600    pub fn try_attribute_mut(
601        &mut self,
602        id: impl Into<MeshVertexAttributeId>,
603    ) -> Result<&mut VertexAttributeValues, MeshAccessError> {
604        self.try_attribute_mut_option(id)?
605            .ok_or(MeshAccessError::NotFound)
606    }
607
608    /// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
609    ///
610    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
611    #[inline]
612    pub fn try_attribute_mut_option(
613        &mut self,
614        id: impl Into<MeshVertexAttributeId>,
615    ) -> Result<Option<&mut VertexAttributeValues>, MeshAccessError> {
616        Ok(self
617            .attributes
618            .as_mut()?
619            .get_mut(&id.into())
620            .map(|data| &mut data.values))
621    }
622
623    /// Returns an iterator that yields references to the data of each vertex attribute.
624    ///
625    /// # Panics
626    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
627    /// this as an error use [`Mesh::try_attributes`]
628    pub fn attributes(
629        &self,
630    ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
631        self.try_attributes().expect(MESH_EXTRACTED_ERROR)
632    }
633
634    /// Returns an iterator that yields references to the data of each vertex attribute.
635    /// Returns an error if data has been extracted to `RenderWorld`
636    pub fn try_attributes(
637        &self,
638    ) -> Result<impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)>, MeshAccessError>
639    {
640        Ok(self
641            .attributes
642            .as_ref()?
643            .values()
644            .map(|data| (&data.attribute, &data.values)))
645    }
646
647    /// Returns an iterator that yields mutable references to the data of each vertex attribute.
648    ///
649    /// # Panics
650    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
651    /// this as an error use [`Mesh::try_attributes_mut`]
652    pub fn attributes_mut(
653        &mut self,
654    ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
655        self.try_attributes_mut().expect(MESH_EXTRACTED_ERROR)
656    }
657
658    /// Returns an iterator that yields mutable references to the data of each vertex attribute.
659    ///
660    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
661    pub fn try_attributes_mut(
662        &mut self,
663    ) -> Result<
664        impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)>,
665        MeshAccessError,
666    > {
667        Ok(self
668            .attributes
669            .as_mut()?
670            .values_mut()
671            .map(|data| (&data.attribute, &mut data.values)))
672    }
673
674    /// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
675    /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
676    /// that use triangles.
677    ///
678    /// # Panics
679    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
680    /// this as an error use [`Mesh::try_insert_indices`]
681    #[inline]
682    pub fn insert_indices(&mut self, indices: Indices) {
683        self.indices
684            .replace(Some(indices))
685            .expect(MESH_EXTRACTED_ERROR);
686    }
687
688    /// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
689    /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
690    /// that use triangles.
691    ///
692    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
693    #[inline]
694    pub fn try_insert_indices(&mut self, indices: Indices) -> Result<(), MeshAccessError> {
695        self.indices.replace(Some(indices))?;
696        Ok(())
697    }
698
699    /// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
700    /// are constructed out of the vertex attributes and are therefore only useful for the
701    /// [`PrimitiveTopology`] variants that use triangles.
702    ///
703    /// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
704    ///
705    /// # Panics
706    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
707    /// this as an error use [`Mesh::try_with_inserted_indices`]
708    #[must_use]
709    #[inline]
710    pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
711        self.insert_indices(indices);
712        self
713    }
714
715    /// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
716    /// are constructed out of the vertex attributes and are therefore only useful for the
717    /// [`PrimitiveTopology`] variants that use triangles.
718    ///
719    /// (Alternatively, you can use [`Mesh::try_insert_indices`] to mutate an existing mesh in-place)
720    ///
721    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
722    #[inline]
723    pub fn try_with_inserted_indices(mut self, indices: Indices) -> Result<Self, MeshAccessError> {
724        self.try_insert_indices(indices)?;
725        Ok(self)
726    }
727
728    /// Retrieves the vertex `indices` of the mesh, returns None if not found.
729    ///
730    /// # Panics
731    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
732    /// this as an error use [`Mesh::try_indices`]
733    #[inline]
734    pub fn indices(&self) -> Option<&Indices> {
735        self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR)
736    }
737
738    /// Retrieves the vertex `indices` of the mesh.
739    ///
740    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
741    /// if the attribute does not exist.
742    #[inline]
743    pub fn try_indices(&self) -> Result<&Indices, MeshAccessError> {
744        self.indices.as_ref()
745    }
746
747    /// Retrieves the vertex `indices` of the mesh, returns None if not found.
748    ///
749    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
750    #[inline]
751    pub fn try_indices_option(&self) -> Result<Option<&Indices>, MeshAccessError> {
752        self.indices.as_ref_option()
753    }
754
755    /// Retrieves the vertex `indices` of the mesh mutably.
756    #[inline]
757    pub fn indices_mut(&mut self) -> Option<&mut Indices> {
758        self.try_indices_mut_option().expect(MESH_EXTRACTED_ERROR)
759    }
760
761    /// Retrieves the vertex `indices` of the mesh mutably.
762    ///
763    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
764    #[inline]
765    pub fn try_indices_mut(&mut self) -> Result<&mut Indices, MeshAccessError> {
766        self.indices.as_mut()
767    }
768
769    /// Retrieves the vertex `indices` of the mesh mutably.
770    ///
771    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
772    #[inline]
773    pub fn try_indices_mut_option(&mut self) -> Result<Option<&mut Indices>, MeshAccessError> {
774        self.indices.as_mut_option()
775    }
776
777    /// Removes the vertex `indices` from the mesh and returns them.
778    ///
779    /// # Panics
780    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
781    /// this as an error use [`Mesh::try_remove_indices`]
782    #[inline]
783    pub fn remove_indices(&mut self) -> Option<Indices> {
784        self.try_remove_indices().expect(MESH_EXTRACTED_ERROR)
785    }
786
787    /// Removes the vertex `indices` from the mesh and returns them.
788    ///
789    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
790    #[inline]
791    pub fn try_remove_indices(&mut self) -> Result<Option<Indices>, MeshAccessError> {
792        self.indices.replace(None)
793    }
794
795    /// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
796    ///
797    /// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
798    ///
799    /// # Panics
800    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
801    /// this as an error use [`Mesh::try_with_removed_indices`]
802    #[must_use]
803    pub fn with_removed_indices(mut self) -> Self {
804        self.remove_indices();
805        self
806    }
807
808    /// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
809    ///
810    /// (Alternatively, you can use [`Mesh::try_remove_indices`] to mutate an existing mesh in-place)
811    ///
812    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
813    pub fn try_with_removed_indices(mut self) -> Result<Self, MeshAccessError> {
814        self.try_remove_indices()?;
815        Ok(self)
816    }
817
818    /// Returns the size of a vertex in bytes.
819    ///
820    /// # Panics
821    /// Panics when the mesh data has already been extracted to `RenderWorld`.
822    pub fn get_vertex_size(&self) -> u64 {
823        self.attributes
824            .as_ref()
825            .expect(MESH_EXTRACTED_ERROR)
826            .values()
827            .map(|data| data.attribute.format.size())
828            .sum()
829    }
830
831    /// Returns the size required for the vertex buffer in bytes.
832    ///
833    /// # Panics
834    /// Panics when the mesh data has already been extracted to `RenderWorld`.
835    pub fn get_vertex_buffer_size(&self) -> usize {
836        let vertex_size = self.get_vertex_size() as usize;
837        let vertex_count = self.count_vertices();
838        vertex_count * vertex_size
839    }
840
841    /// Computes and returns the index data of the mesh as bytes.
842    /// This is used to transform the index data into a GPU friendly format.
843    ///
844    /// # Panics
845    /// Panics when the mesh data has already been extracted to `RenderWorld`.
846    pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
847        let mesh_indices = self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR);
848
849        mesh_indices.as_ref().map(|indices| match &indices {
850            Indices::U16(indices) => cast_slice(&indices[..]),
851            Indices::U32(indices) => cast_slice(&indices[..]),
852        })
853    }
854
855    /// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
856    ///
857    /// # Panics
858    /// Panics when the mesh data has already been extracted to `RenderWorld`.
859    pub fn get_mesh_vertex_buffer_layout(
860        &self,
861        mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
862    ) -> MeshVertexBufferLayoutRef {
863        let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
864
865        let mut attributes = Vec::with_capacity(mesh_attributes.len());
866        let mut attribute_ids = Vec::with_capacity(mesh_attributes.len());
867        let mut accumulated_offset = 0;
868        for (index, data) in mesh_attributes.values().enumerate() {
869            attribute_ids.push(data.attribute.id);
870            attributes.push(VertexAttribute {
871                offset: accumulated_offset,
872                format: data.attribute.format,
873                shader_location: index as u32,
874            });
875            accumulated_offset += data.attribute.format.size();
876        }
877
878        let layout = MeshVertexBufferLayout {
879            layout: VertexBufferLayout {
880                array_stride: accumulated_offset,
881                step_mode: VertexStepMode::Vertex,
882                attributes,
883            },
884            attribute_ids,
885        };
886        mesh_vertex_buffer_layouts.insert(layout)
887    }
888
889    /// Counts all vertices of the mesh.
890    ///
891    /// If the attributes have different vertex counts, the smallest is returned.
892    ///
893    /// # Panics
894    /// Panics when the mesh data has already been extracted to `RenderWorld`.
895    pub fn count_vertices(&self) -> usize {
896        let mut vertex_count: Option<usize> = None;
897        let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
898
899        for (attribute_id, attribute_data) in mesh_attributes {
900            let attribute_len = attribute_data.values.len();
901            if let Some(previous_vertex_count) = vertex_count {
902                if previous_vertex_count != attribute_len {
903                    let name = mesh_attributes
904                        .get(attribute_id)
905                        .map(|data| data.attribute.name.to_string())
906                        .unwrap_or_else(|| format!("{attribute_id:?}"));
907
908                    warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
909                        all attributes will be truncated to match the smallest.");
910                    vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
911                }
912            } else {
913                vertex_count = Some(attribute_len);
914            }
915        }
916
917        vertex_count.unwrap_or(0)
918    }
919
920    /// Computes and returns the vertex data of the mesh as bytes.
921    /// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
922    /// This is used to transform the vertex data into a GPU friendly format.
923    ///
924    /// If the vertex attributes have different lengths, they are all truncated to
925    /// the length of the smallest.
926    ///
927    /// This is a convenience method which allocates a Vec.
928    /// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
929    ///
930    /// # Panics
931    /// Panics when the mesh data has already been extracted to `RenderWorld`.
932    pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
933        let mut attributes_interleaved_buffer = vec![0; self.get_vertex_buffer_size()];
934        self.write_packed_vertex_buffer_data(&mut attributes_interleaved_buffer);
935        attributes_interleaved_buffer
936    }
937
938    /// Computes and write the vertex data of the mesh into a mutable byte slice.
939    /// The attributes are located in the order of their [`MeshVertexAttribute::id`].
940    /// This is used to transform the vertex data into a GPU friendly format.
941    ///
942    /// If the vertex attributes have different lengths, they are all truncated to
943    /// the length of the smallest.
944    ///
945    /// # Panics
946    /// Panics when the mesh data has already been extracted to `RenderWorld`.
947    pub fn write_packed_vertex_buffer_data(&self, slice: &mut [u8]) {
948        let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
949
950        let vertex_size = self.get_vertex_size() as usize;
951        let vertex_count = self.count_vertices();
952        // bundle into interleaved buffers
953        let mut attribute_offset = 0;
954        for attribute_data in mesh_attributes.values() {
955            let attribute_size = attribute_data.attribute.format.size() as usize;
956            let attributes_bytes = attribute_data.values.get_bytes();
957            for (vertex_index, attribute_bytes) in attributes_bytes
958                .chunks_exact(attribute_size)
959                .take(vertex_count)
960                .enumerate()
961            {
962                let offset = vertex_index * vertex_size + attribute_offset;
963                slice[offset..offset + attribute_size].copy_from_slice(attribute_bytes);
964            }
965
966            attribute_offset += attribute_size;
967        }
968    }
969
970    /// Duplicates the vertex attributes so that no vertices are shared.
971    ///
972    /// This can dramatically increase the vertex count, so make sure this is what you want.
973    /// Does nothing if no [Indices] are set.
974    ///
975    /// # Panics
976    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
977    /// this as an error use [`Mesh::try_duplicate_vertices`]
978    pub fn duplicate_vertices(&mut self) {
979        self.try_duplicate_vertices().expect(MESH_EXTRACTED_ERROR);
980    }
981
982    /// Duplicates the vertex attributes so that no vertices are shared.
983    ///
984    /// This can dramatically increase the vertex count, so make sure this is what you want.
985    /// Does nothing if no [Indices] are set.
986    ///
987    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
988    pub fn try_duplicate_vertices(&mut self) -> Result<(), MeshAccessError> {
989        fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
990            indices.map(|i| values[i]).collect()
991        }
992
993        let Some(indices) = self.indices.replace(None)? else {
994            return Ok(());
995        };
996
997        let mesh_attributes = self.attributes.as_mut()?;
998
999        for attributes in mesh_attributes.values_mut() {
1000            let indices = indices.iter();
1001            #[expect(
1002                clippy::match_same_arms,
1003                reason = "Although the `vec` binding on some match arms may have different types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
1004            )]
1005            match &mut attributes.values {
1006                VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
1007                VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
1008                VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
1009                VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
1010                VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
1011                VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
1012                VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
1013                VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
1014                VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
1015                VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
1016                VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
1017                VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
1018                VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
1019                VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
1020                VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
1021                VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
1022                VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
1023                VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
1024                VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
1025                VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
1026                VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
1027                VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
1028                VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
1029                VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
1030                VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
1031                VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
1032                VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
1033                VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
1034            }
1035        }
1036
1037        Ok(())
1038    }
1039
1040    /// Consumes the mesh and returns a mesh with no shared vertices.
1041    ///
1042    /// This can dramatically increase the vertex count, so make sure this is what you want.
1043    /// Does nothing if no [`Indices`] are set.
1044    ///
1045    /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
1046    ///
1047    /// # Panics
1048    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1049    /// this as an error use [`Mesh::try_with_duplicated_vertices`]
1050    #[must_use]
1051    pub fn with_duplicated_vertices(mut self) -> Self {
1052        self.duplicate_vertices();
1053        self
1054    }
1055
1056    /// Consumes the mesh and returns a mesh with no shared vertices.
1057    ///
1058    /// This can dramatically increase the vertex count, so make sure this is what you want.
1059    /// Does nothing if no [`Indices`] are set.
1060    ///
1061    /// (Alternatively, you can use [`Mesh::try_duplicate_vertices`] to mutate an existing mesh in-place)
1062    ///
1063    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1064    pub fn try_with_duplicated_vertices(mut self) -> Result<Self, MeshAccessError> {
1065        self.try_duplicate_vertices()?;
1066        Ok(self)
1067    }
1068
1069    /// Inverts the winding of the indices such that all counter-clockwise triangles are now
1070    /// clockwise and vice versa.
1071    /// For lines, their start and end indices are flipped.
1072    ///
1073    /// Does nothing if no [`Indices`] are set.
1074    /// If this operation succeeded, an [`Ok`] result is returned.
1075    pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
1076        fn invert<I>(
1077            indices: &mut [I],
1078            topology: PrimitiveTopology,
1079        ) -> Result<(), MeshWindingInvertError> {
1080            match topology {
1081                PrimitiveTopology::TriangleList => {
1082                    // Early return if the index count doesn't match
1083                    if !indices.len().is_multiple_of(3) {
1084                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
1085                    }
1086                    for chunk in indices.chunks_mut(3) {
1087                        // This currently can only be optimized away with unsafe, rework this when `feature(slice_as_chunks)` gets stable.
1088                        let [_, b, c] = chunk else {
1089                            return Err(MeshWindingInvertError::AbruptIndicesEnd);
1090                        };
1091                        core::mem::swap(b, c);
1092                    }
1093                    Ok(())
1094                }
1095                PrimitiveTopology::LineList => {
1096                    // Early return if the index count doesn't match
1097                    if !indices.len().is_multiple_of(2) {
1098                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
1099                    }
1100                    indices.reverse();
1101                    Ok(())
1102                }
1103                PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
1104                    indices.reverse();
1105                    Ok(())
1106                }
1107                _ => Err(MeshWindingInvertError::WrongTopology),
1108            }
1109        }
1110
1111        let mesh_indices = self.indices.as_mut_option()?;
1112
1113        match mesh_indices {
1114            Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
1115            Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
1116            None => Ok(()),
1117        }
1118    }
1119
1120    /// Consumes the mesh and returns a mesh with inverted winding of the indices such
1121    /// that all counter-clockwise triangles are now clockwise and vice versa.
1122    ///
1123    /// Does nothing if no [`Indices`] are set.
1124    pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
1125        self.invert_winding().map(|_| self)
1126    }
1127
1128    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1129    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1130    /// normals.
1131    ///
1132    /// # Panics
1133    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1134    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1135    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1136    /// this as an error use [`Mesh::try_compute_normals`]
1137    pub fn compute_normals(&mut self) {
1138        self.try_compute_normals().expect(MESH_EXTRACTED_ERROR);
1139    }
1140
1141    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1142    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1143    /// normals.
1144    ///
1145    /// # Panics
1146    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1147    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1148    pub fn try_compute_normals(&mut self) -> Result<(), MeshAccessError> {
1149        assert!(
1150            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1151            "`compute_normals` can only work on `TriangleList`s"
1152        );
1153        if self.try_indices_option()?.is_none() {
1154            self.try_compute_flat_normals()
1155        } else {
1156            self.try_compute_smooth_normals()
1157        }
1158    }
1159
1160    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1161    ///
1162    /// # Panics
1163    /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1164    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1165    /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1166    /// attributes.
1167    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1168    /// this as an error use [`Mesh::try_compute_flat_normals`]
1169    ///
1170    /// FIXME: This should handle more cases since this is called as a part of gltf
1171    /// mesh loading where we can't really blame users for loading meshes that might
1172    /// not conform to the limitations here!
1173    pub fn compute_flat_normals(&mut self) {
1174        self.try_compute_flat_normals().expect(MESH_EXTRACTED_ERROR);
1175    }
1176
1177    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1178    ///
1179    /// # Panics
1180    /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1181    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1182    /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1183    /// attributes.
1184    ///
1185    /// FIXME: This should handle more cases since this is called as a part of gltf
1186    /// mesh loading where we can't really blame users for loading meshes that might
1187    /// not conform to the limitations here!
1188    pub fn try_compute_flat_normals(&mut self) -> Result<(), MeshAccessError> {
1189        assert!(
1190            self.try_indices_option()?.is_none(),
1191            "`compute_flat_normals` can't work on indexed geometry. Consider calling either `Mesh::compute_smooth_normals` or `Mesh::duplicate_vertices` followed by `Mesh::compute_flat_normals`."
1192        );
1193        assert!(
1194            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1195            "`compute_flat_normals` can only work on `TriangleList`s"
1196        );
1197
1198        let positions = self
1199            .try_attribute(Mesh::ATTRIBUTE_POSITION)?
1200            .as_float3()
1201            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
1202
1203        let normals: Vec<_> = positions
1204            .chunks_exact(3)
1205            .map(|p| triangle_normal(p[0], p[1], p[2]))
1206            .flat_map(|normal| [normal; 3])
1207            .collect();
1208
1209        self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1210    }
1211
1212    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1213    /// vertices.
1214    ///
1215    /// This method weights normals by the angles of the corners of connected triangles, thus
1216    /// eliminating triangle area and count as factors in the final normal. This does make it
1217    /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1218    /// greedily normalize each triangle's normal or calculate corner angles.
1219    ///
1220    /// If you would rather have the computed normals be weighted by triangle area, see
1221    /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1222    /// way, see [`Mesh::compute_custom_smooth_normals`].
1223    ///
1224    /// # Panics
1225    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1226    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1227    /// Panics if the mesh does not have indices defined.
1228    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1229    /// this as an error use [`Mesh::try_compute_smooth_normals`]
1230    pub fn compute_smooth_normals(&mut self) {
1231        self.try_compute_smooth_normals()
1232            .expect(MESH_EXTRACTED_ERROR);
1233    }
1234
1235    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1236    /// vertices.
1237    ///
1238    /// This method weights normals by the angles of the corners of connected triangles, thus
1239    /// eliminating triangle area and count as factors in the final normal. This does make it
1240    /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1241    /// greedily normalize each triangle's normal or calculate corner angles.
1242    ///
1243    /// If you would rather have the computed normals be weighted by triangle area, see
1244    /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1245    /// way, see [`Mesh::compute_custom_smooth_normals`].
1246    ///
1247    /// # Panics
1248    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1249    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1250    /// Panics if the mesh does not have indices defined.
1251    pub fn try_compute_smooth_normals(&mut self) -> Result<(), MeshAccessError> {
1252        self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1253            let pa = Vec3::from(positions[a]);
1254            let pb = Vec3::from(positions[b]);
1255            let pc = Vec3::from(positions[c]);
1256
1257            let ab = pb - pa;
1258            let ba = pa - pb;
1259            let bc = pc - pb;
1260            let cb = pb - pc;
1261            let ca = pa - pc;
1262            let ac = pc - pa;
1263
1264            const EPS: f32 = f32::EPSILON;
1265            let weight_a = if ab.length_squared() * ac.length_squared() > EPS {
1266                ab.angle_between(ac)
1267            } else {
1268                0.0
1269            };
1270            let weight_b = if ba.length_squared() * bc.length_squared() > EPS {
1271                ba.angle_between(bc)
1272            } else {
1273                0.0
1274            };
1275            let weight_c = if ca.length_squared() * cb.length_squared() > EPS {
1276                ca.angle_between(cb)
1277            } else {
1278                0.0
1279            };
1280
1281            let normal = Vec3::from(triangle_normal(positions[a], positions[b], positions[c]));
1282
1283            normals[a] += normal * weight_a;
1284            normals[b] += normal * weight_b;
1285            normals[c] += normal * weight_c;
1286        })
1287    }
1288
1289    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1290    /// vertices.
1291    ///
1292    /// This method weights normals by the area of each triangle containing the vertex. Thus,
1293    /// larger triangles will skew the normals of their vertices towards their own normal more
1294    /// than smaller triangles will.
1295    ///
1296    /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1297    /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1298    ///
1299    /// If you would rather have the computed normals be influenced only by the angles of connected
1300    /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1301    /// other way, see [`Mesh::compute_custom_smooth_normals`].
1302    ///
1303    /// # Panics
1304    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1305    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1306    /// Panics if the mesh does not have indices defined.
1307    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1308    /// this as an error use [`Mesh::try_compute_area_weighted_normals`]
1309    pub fn compute_area_weighted_normals(&mut self) {
1310        self.try_compute_area_weighted_normals()
1311            .expect(MESH_EXTRACTED_ERROR);
1312    }
1313
1314    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1315    /// vertices.
1316    ///
1317    /// This method weights normals by the area of each triangle containing the vertex. Thus,
1318    /// larger triangles will skew the normals of their vertices towards their own normal more
1319    /// than smaller triangles will.
1320    ///
1321    /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1322    /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1323    ///
1324    /// If you would rather have the computed normals be influenced only by the angles of connected
1325    /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1326    /// other way, see [`Mesh::compute_custom_smooth_normals`].
1327    ///
1328    /// # Panics
1329    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1330    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1331    /// Panics if the mesh does not have indices defined.
1332    pub fn try_compute_area_weighted_normals(&mut self) -> Result<(), MeshAccessError> {
1333        self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1334            let normal = Vec3::from(triangle_area_normal(
1335                positions[a],
1336                positions[b],
1337                positions[c],
1338            ));
1339            [a, b, c].into_iter().for_each(|pos| {
1340                normals[pos] += normal;
1341            });
1342        })
1343    }
1344
1345    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1346    /// vertices.
1347    ///
1348    /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1349    /// which must be a function or closure that accepts 3 parameters:
1350    /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1351    /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1352    /// - A mutable reference to the sums of all normals so far.
1353    ///
1354    /// See also the standard methods included in Bevy for calculating smooth normals:
1355    /// - [`Mesh::compute_smooth_normals`]
1356    /// - [`Mesh::compute_area_weighted_normals`]
1357    ///
1358    /// An example that would weight each connected triangle's normal equally, thus skewing normals
1359    /// towards the planes divided into the most triangles:
1360    /// ```
1361    /// # use bevy_asset::RenderAssetUsages;
1362    /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1363    /// # use bevy_math::{Vec3, primitives::Cuboid};
1364    /// # let mut mesh = Cuboid::default().mesh().build();
1365    /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1366    ///     let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1367    ///     for idx in [a, b, c] {
1368    ///         normals[idx] += normal;
1369    ///     }
1370    /// });
1371    /// ```
1372    ///
1373    /// # Panics
1374    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1375    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1376    /// Panics if the mesh does not have indices defined.
1377    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1378    /// this as an error use [`Mesh::try_compute_custom_smooth_normals`]
1379    //
1380    // FIXME: This should handle more cases since this is called as a part of gltf
1381    // mesh loading where we can't really blame users for loading meshes that might
1382    // not conform to the limitations here!
1383    //
1384    // When fixed, also update "Panics" sections of
1385    // - [Mesh::compute_smooth_normals]
1386    // - [Mesh::with_computed_smooth_normals]
1387    // - [Mesh::compute_area_weighted_normals]
1388    // - [Mesh::with_computed_area_weighted_normals]
1389    pub fn compute_custom_smooth_normals(
1390        &mut self,
1391        per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1392    ) {
1393        self.try_compute_custom_smooth_normals(per_triangle)
1394            .expect(MESH_EXTRACTED_ERROR);
1395    }
1396
1397    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1398    /// vertices.
1399    ///
1400    /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1401    /// which must be a function or closure that accepts 3 parameters:
1402    /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1403    /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1404    /// - A mutable reference to the sums of all normals so far.
1405    ///
1406    /// See also the standard methods included in Bevy for calculating smooth normals:
1407    /// - [`Mesh::compute_smooth_normals`]
1408    /// - [`Mesh::compute_area_weighted_normals`]
1409    ///
1410    /// An example that would weight each connected triangle's normal equally, thus skewing normals
1411    /// towards the planes divided into the most triangles:
1412    /// ```
1413    /// # use bevy_asset::RenderAssetUsages;
1414    /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1415    /// # use bevy_math::{Vec3, primitives::Cuboid};
1416    /// # let mut mesh = Cuboid::default().mesh().build();
1417    /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1418    ///     let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1419    ///     for idx in [a, b, c] {
1420    ///         normals[idx] += normal;
1421    ///     }
1422    /// });
1423    /// ```
1424    ///
1425    /// # Panics
1426    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1427    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1428    /// Panics if the mesh does not have indices defined.
1429    //
1430    // FIXME: This should handle more cases since this is called as a part of gltf
1431    // mesh loading where we can't really blame users for loading meshes that might
1432    // not conform to the limitations here!
1433    //
1434    // When fixed, also update "Panics" sections of
1435    // - [Mesh::compute_smooth_normals]
1436    // - [Mesh::with_computed_smooth_normals]
1437    // - [Mesh::compute_area_weighted_normals]
1438    // - [Mesh::with_computed_area_weighted_normals]
1439    pub fn try_compute_custom_smooth_normals(
1440        &mut self,
1441        mut per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1442    ) -> Result<(), MeshAccessError> {
1443        assert!(
1444            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1445            "smooth normals can only be computed on `TriangleList`s"
1446        );
1447        assert!(
1448            self.try_indices_option()?.is_some(),
1449            "smooth normals can only be computed on indexed meshes"
1450        );
1451
1452        let positions = self
1453            .try_attribute(Mesh::ATTRIBUTE_POSITION)?
1454            .as_float3()
1455            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
1456
1457        let mut normals = vec![Vec3::ZERO; positions.len()];
1458
1459        self.try_indices()?
1460            .iter()
1461            .collect::<Vec<usize>>()
1462            .chunks_exact(3)
1463            .for_each(|face| per_triangle([face[0], face[1], face[2]], positions, &mut normals));
1464
1465        for normal in &mut normals {
1466            *normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
1467        }
1468
1469        self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1470    }
1471
1472    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1473    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1474    /// normals.
1475    ///
1476    /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1477    ///
1478    /// # Panics
1479    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1480    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1481    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1482    /// this as an error use [`Mesh::try_with_computed_normals`]
1483    #[must_use]
1484    pub fn with_computed_normals(self) -> Self {
1485        self.try_with_computed_normals()
1486            .expect(MESH_EXTRACTED_ERROR)
1487    }
1488
1489    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1490    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1491    /// normals.
1492    ///
1493    /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1494    ///
1495    /// # Panics
1496    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1497    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1498    pub fn try_with_computed_normals(mut self) -> Result<Self, MeshAccessError> {
1499        self.try_compute_normals()?;
1500        Ok(self)
1501    }
1502
1503    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1504    ///
1505    /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1506    ///
1507    /// # Panics
1508    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1509    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1510    /// Panics if the mesh has indices defined
1511    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1512    /// this as an error use [`Mesh::try_with_computed_flat_normals`]
1513    pub fn with_computed_flat_normals(mut self) -> Self {
1514        self.compute_flat_normals();
1515        self
1516    }
1517
1518    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1519    ///
1520    /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1521    ///
1522    /// # Panics
1523    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1524    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1525    /// Panics if the mesh has indices defined
1526    pub fn try_with_computed_flat_normals(mut self) -> Result<Self, MeshAccessError> {
1527        self.try_compute_flat_normals()?;
1528        Ok(self)
1529    }
1530
1531    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1532    ///
1533    /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1534    ///
1535    /// This method weights normals by the angles of triangle corners connected to each vertex. If
1536    /// you would rather have the computed normals be weighted by triangle area, see
1537    /// [`Mesh::with_computed_area_weighted_normals`] instead.
1538    ///
1539    /// # Panics
1540    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1541    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1542    /// Panics if the mesh does not have indices defined.
1543    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1544    /// this as an error use [`Mesh::try_with_computed_smooth_normals`]
1545    pub fn with_computed_smooth_normals(mut self) -> Self {
1546        self.compute_smooth_normals();
1547        self
1548    }
1549    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1550    ///
1551    /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1552    ///
1553    /// This method weights normals by the angles of triangle corners connected to each vertex. If
1554    /// you would rather have the computed normals be weighted by triangle area, see
1555    /// [`Mesh::with_computed_area_weighted_normals`] instead.
1556    ///
1557    /// # Panics
1558    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1559    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1560    /// Panics if the mesh does not have indices defined.
1561    pub fn try_with_computed_smooth_normals(mut self) -> Result<Self, MeshAccessError> {
1562        self.try_compute_smooth_normals()?;
1563        Ok(self)
1564    }
1565
1566    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1567    ///
1568    /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1569    ///
1570    /// This method weights normals by the area of each triangle containing the vertex. Thus,
1571    /// larger triangles will skew the normals of their vertices towards their own normal more
1572    /// than smaller triangles will. If you would rather have the computed normals be influenced
1573    /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1574    ///
1575    /// # Panics
1576    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1577    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1578    /// Panics if the mesh does not have indices defined.
1579    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1580    /// this as an error use [`Mesh::try_with_computed_area_weighted_normals`]
1581    pub fn with_computed_area_weighted_normals(mut self) -> Self {
1582        self.compute_area_weighted_normals();
1583        self
1584    }
1585
1586    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1587    ///
1588    /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1589    ///
1590    /// This method weights normals by the area of each triangle containing the vertex. Thus,
1591    /// larger triangles will skew the normals of their vertices towards their own normal more
1592    /// than smaller triangles will. If you would rather have the computed normals be influenced
1593    /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1594    ///
1595    /// # Panics
1596    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1597    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1598    /// Panics if the mesh does not have indices defined.
1599    pub fn try_with_computed_area_weighted_normals(mut self) -> Result<Self, MeshAccessError> {
1600        self.try_compute_area_weighted_normals()?;
1601        Ok(self)
1602    }
1603
1604    /// Generate tangents for the mesh using the `mikktspace` algorithm.
1605    ///
1606    /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1607    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1608    #[cfg(feature = "bevy_mikktspace")]
1609    pub fn generate_tangents(&mut self) -> Result<(), super::GenerateTangentsError> {
1610        let tangents = super::generate_tangents_for_mesh(self)?;
1611        self.try_insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents)?;
1612        Ok(())
1613    }
1614
1615    /// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
1616    ///
1617    /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1618    ///
1619    /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
1620    ///
1621    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1622    #[cfg(feature = "bevy_mikktspace")]
1623    pub fn with_generated_tangents(mut self) -> Result<Mesh, super::GenerateTangentsError> {
1624        self.generate_tangents()?;
1625        Ok(self)
1626    }
1627
1628    /// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
1629    ///
1630    /// Note that attributes of `other` that don't exist on `self` will be ignored.
1631    ///
1632    /// `Aabb` of entities with modified mesh are not updated automatically.
1633    ///
1634    /// # Errors
1635    ///
1636    /// If any of the following conditions are not met, this function errors:
1637    /// * All of the vertex attributes that have the same attribute id, must also
1638    ///   have the same attribute type.
1639    ///   For example two attributes with the same id, but where one is a
1640    ///   [`VertexAttributeValues::Float32`] and the other is a
1641    ///   [`VertexAttributeValues::Float32x3`], would be invalid.
1642    /// * Both meshes must have the same primitive topology.
1643    pub fn merge(&mut self, other: &Mesh) -> Result<(), MeshMergeError> {
1644        use VertexAttributeValues::*;
1645
1646        // Check if the meshes `primitive_topology` field is the same,
1647        // as if that is not the case, the resulting mesh could (and most likely would)
1648        // be invalid.
1649        if self.primitive_topology != other.primitive_topology {
1650            return Err(MeshMergeError::IncompatiblePrimitiveTopology {
1651                self_primitive_topology: self.primitive_topology,
1652                other_primitive_topology: other.primitive_topology,
1653            });
1654        }
1655
1656        // The indices of `other` should start after the last vertex of `self`.
1657        let index_offset = self.count_vertices();
1658
1659        // Extend attributes of `self` with attributes of `other`.
1660        for (attribute, values) in self.try_attributes_mut()? {
1661            if let Some(other_values) = other.try_attribute_option(attribute.id)? {
1662                #[expect(
1663                    clippy::match_same_arms,
1664                    reason = "Although the bindings on some match arms may have different types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
1665                )]
1666                match (values, other_values) {
1667                    (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
1668                    (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
1669                    (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
1670                    (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
1671                    (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
1672                    (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
1673                    (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
1674                    (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
1675                    (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
1676                    (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
1677                    (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
1678                    (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
1679                    (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
1680                    (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
1681                    (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
1682                    (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
1683                    (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
1684                    (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
1685                    (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
1686                    (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
1687                    (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
1688                    (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
1689                    (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
1690                    (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
1691                    (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
1692                    (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
1693                    (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
1694                    (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
1695                    _ => {
1696                        return Err(MeshMergeError::IncompatibleVertexAttributes {
1697                            self_attribute: *attribute,
1698                            other_attribute: other
1699                                .try_attribute_data(attribute.id)?
1700                                .map(|data| data.attribute),
1701                        })
1702                    }
1703                }
1704            }
1705        }
1706
1707        // Extend indices of `self` with indices of `other`.
1708        if let (Some(indices), Some(other_indices)) =
1709            (self.try_indices_mut_option()?, other.try_indices_option()?)
1710        {
1711            indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
1712        }
1713        Ok(())
1714    }
1715
1716    /// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1717    ///
1718    /// `Aabb` of entities with modified mesh are not updated automatically.
1719    ///
1720    /// # Panics
1721    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1722    /// this as an error use [`Mesh::try_transformed_by`]
1723    pub fn transformed_by(mut self, transform: Transform) -> Self {
1724        self.transform_by(transform);
1725        self
1726    }
1727
1728    /// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1729    ///
1730    /// `Aabb` of entities with modified mesh are not updated automatically.
1731    pub fn try_transformed_by(mut self, transform: Transform) -> Result<Self, MeshAccessError> {
1732        self.try_transform_by(transform)?;
1733        Ok(self)
1734    }
1735
1736    /// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1737    ///
1738    /// `Aabb` of entities with modified mesh are not updated automatically.
1739    ///
1740    /// # Panics
1741    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1742    /// this as an error use [`Mesh::try_transform_by`]
1743    pub fn transform_by(&mut self, transform: Transform) {
1744        self.try_transform_by(transform)
1745            .expect(MESH_EXTRACTED_ERROR);
1746    }
1747
1748    /// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1749    ///
1750    /// `Aabb` of entities with modified mesh are not updated automatically.
1751    pub fn try_transform_by(&mut self, transform: Transform) -> Result<(), MeshAccessError> {
1752        // Needed when transforming normals and tangents
1753        let scale_recip = 1. / transform.scale;
1754        debug_assert!(
1755            transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
1756            "mesh transform scale cannot be zero on more than one axis"
1757        );
1758
1759        if let Some(VertexAttributeValues::Float32x3(positions)) =
1760            self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1761        {
1762            // Apply scale, rotation, and translation to vertex positions
1763            positions
1764                .iter_mut()
1765                .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
1766        }
1767
1768        // No need to transform normals or tangents if rotation is near identity and scale is uniform
1769        if transform.rotation.is_near_identity()
1770            && transform.scale.x == transform.scale.y
1771            && transform.scale.y == transform.scale.z
1772        {
1773            return Ok(());
1774        }
1775
1776        if let Some(VertexAttributeValues::Float32x3(normals)) =
1777            self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
1778        {
1779            // Transform normals, taking into account non-uniform scaling and rotation
1780            normals.iter_mut().for_each(|normal| {
1781                *normal = (transform.rotation
1782                    * scale_normal(Vec3::from_array(*normal), scale_recip))
1783                .to_array();
1784            });
1785        }
1786
1787        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1788            self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
1789        {
1790            // Transform tangents, taking into account non-uniform scaling and rotation
1791            tangents.iter_mut().for_each(|tangent| {
1792                let handedness = tangent[3];
1793                let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
1794                *tangent = (transform.rotation * scaled_tangent.normalize_or_zero())
1795                    .extend(handedness)
1796                    .to_array();
1797            });
1798        }
1799
1800        Ok(())
1801    }
1802
1803    /// Translates the vertex positions of the mesh by the given [`Vec3`].
1804    ///
1805    /// `Aabb` of entities with modified mesh are not updated automatically.
1806    ///
1807    /// # Panics
1808    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1809    /// this as an error use [`Mesh::try_translated_by`]
1810    pub fn translated_by(mut self, translation: Vec3) -> Self {
1811        self.translate_by(translation);
1812        self
1813    }
1814
1815    /// Translates the vertex positions of the mesh by the given [`Vec3`].
1816    ///
1817    /// `Aabb` of entities with modified mesh are not updated automatically.
1818    pub fn try_translated_by(mut self, translation: Vec3) -> Result<Self, MeshAccessError> {
1819        self.try_translate_by(translation)?;
1820        Ok(self)
1821    }
1822
1823    /// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1824    ///
1825    /// `Aabb` of entities with modified mesh are not updated automatically.
1826    ///
1827    /// # Panics
1828    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1829    /// this as an error use [`Mesh::try_translate_by`]
1830    pub fn translate_by(&mut self, translation: Vec3) {
1831        self.try_translate_by(translation)
1832            .expect(MESH_EXTRACTED_ERROR);
1833    }
1834
1835    /// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1836    ///
1837    /// `Aabb` of entities with modified mesh are not updated automatically.
1838    pub fn try_translate_by(&mut self, translation: Vec3) -> Result<(), MeshAccessError> {
1839        if translation == Vec3::ZERO {
1840            return Ok(());
1841        }
1842
1843        if let Some(VertexAttributeValues::Float32x3(positions)) =
1844            self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1845        {
1846            // Apply translation to vertex positions
1847            positions
1848                .iter_mut()
1849                .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
1850        }
1851
1852        Ok(())
1853    }
1854
1855    /// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
1856    ///
1857    /// `Aabb` of entities with modified mesh are not updated automatically.
1858    ///
1859    /// # Panics
1860    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1861    /// this as an error use [`Mesh::try_rotated_by`]
1862    pub fn rotated_by(mut self, rotation: Quat) -> Self {
1863        self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
1864        self
1865    }
1866
1867    /// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
1868    ///
1869    /// `Aabb` of entities with modified mesh are not updated automatically.
1870    pub fn try_rotated_by(mut self, rotation: Quat) -> Result<Self, MeshAccessError> {
1871        self.try_rotate_by(rotation)?;
1872        Ok(self)
1873    }
1874
1875    /// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
1876    ///
1877    /// `Aabb` of entities with modified mesh are not updated automatically.
1878    ///
1879    /// # Panics
1880    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1881    /// this as an error use [`Mesh::try_rotate_by`]
1882    pub fn rotate_by(&mut self, rotation: Quat) {
1883        self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
1884    }
1885
1886    /// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
1887    ///
1888    /// `Aabb` of entities with modified mesh are not updated automatically.
1889    pub fn try_rotate_by(&mut self, rotation: Quat) -> Result<(), MeshAccessError> {
1890        if let Some(VertexAttributeValues::Float32x3(positions)) =
1891            self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1892        {
1893            // Apply rotation to vertex positions
1894            positions
1895                .iter_mut()
1896                .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
1897        }
1898
1899        // No need to transform normals or tangents if rotation is near identity
1900        if rotation.is_near_identity() {
1901            return Ok(());
1902        }
1903
1904        if let Some(VertexAttributeValues::Float32x3(normals)) =
1905            self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
1906        {
1907            // Transform normals
1908            normals.iter_mut().for_each(|normal| {
1909                *normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
1910            });
1911        }
1912
1913        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1914            self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
1915        {
1916            // Transform tangents
1917            tangents.iter_mut().for_each(|tangent| {
1918                let handedness = tangent[3];
1919                *tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero())
1920                    .extend(handedness)
1921                    .to_array();
1922            });
1923        }
1924
1925        Ok(())
1926    }
1927
1928    /// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
1929    ///
1930    /// `Aabb` of entities with modified mesh are not updated automatically.
1931    ///
1932    /// # Panics
1933    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1934    /// this as an error use [`Mesh::try_scaled_by`]
1935    pub fn scaled_by(mut self, scale: Vec3) -> Self {
1936        self.scale_by(scale);
1937        self
1938    }
1939
1940    /// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
1941    ///
1942    /// `Aabb` of entities with modified mesh are not updated automatically.
1943    pub fn try_scaled_by(mut self, scale: Vec3) -> Result<Self, MeshAccessError> {
1944        self.try_scale_by(scale)?;
1945        Ok(self)
1946    }
1947
1948    /// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
1949    ///
1950    /// `Aabb` of entities with modified mesh are not updated automatically.
1951    ///
1952    /// # Panics
1953    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1954    /// this as an error use [`Mesh::try_scale_by`]
1955    pub fn scale_by(&mut self, scale: Vec3) {
1956        self.try_scale_by(scale).expect(MESH_EXTRACTED_ERROR);
1957    }
1958
1959    /// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
1960    ///
1961    /// `Aabb` of entities with modified mesh are not updated automatically.
1962    pub fn try_scale_by(&mut self, scale: Vec3) -> Result<(), MeshAccessError> {
1963        // Needed when transforming normals and tangents
1964        let scale_recip = 1. / scale;
1965        debug_assert!(
1966            scale.yzx() * scale.zxy() != Vec3::ZERO,
1967            "mesh transform scale cannot be zero on more than one axis"
1968        );
1969
1970        if let Some(VertexAttributeValues::Float32x3(positions)) =
1971            self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1972        {
1973            // Apply scale to vertex positions
1974            positions
1975                .iter_mut()
1976                .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
1977        }
1978
1979        // No need to transform normals or tangents if scale is uniform
1980        if scale.x == scale.y && scale.y == scale.z {
1981            return Ok(());
1982        }
1983
1984        if let Some(VertexAttributeValues::Float32x3(normals)) =
1985            self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
1986        {
1987            // Transform normals, taking into account non-uniform scaling
1988            normals.iter_mut().for_each(|normal| {
1989                *normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
1990            });
1991        }
1992
1993        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1994            self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
1995        {
1996            // Transform tangents, taking into account non-uniform scaling
1997            tangents.iter_mut().for_each(|tangent| {
1998                let handedness = tangent[3];
1999                let scaled_tangent = Vec3::from_slice(tangent) * scale;
2000                *tangent = scaled_tangent
2001                    .normalize_or_zero()
2002                    .extend(handedness)
2003                    .to_array();
2004            });
2005        }
2006
2007        Ok(())
2008    }
2009
2010    /// Normalize joint weights so they sum to 1.
2011    ///
2012    /// # Panics
2013    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2014    /// this as an error use [`Mesh::try_normalize_joint_weights`]
2015    pub fn normalize_joint_weights(&mut self) {
2016        self.try_normalize_joint_weights()
2017            .expect(MESH_EXTRACTED_ERROR);
2018    }
2019
2020    /// Normalize joint weights so they sum to 1.
2021    pub fn try_normalize_joint_weights(&mut self) -> Result<(), MeshAccessError> {
2022        if let Some(VertexAttributeValues::Float32x4(joints)) =
2023            self.try_attribute_mut_option(Self::ATTRIBUTE_JOINT_WEIGHT)?
2024        {
2025            for weights in joints.iter_mut() {
2026                // force negative weights to zero
2027                weights.iter_mut().for_each(|w| *w = w.max(0.0));
2028
2029                let sum: f32 = weights.iter().sum();
2030                if sum == 0.0 {
2031                    // all-zero weights are invalid
2032                    weights[0] = 1.0;
2033                } else {
2034                    let recip = sum.recip();
2035                    for weight in weights.iter_mut() {
2036                        *weight *= recip;
2037                    }
2038                }
2039            }
2040        }
2041
2042        Ok(())
2043    }
2044
2045    /// Get a list of this Mesh's [triangles] as an iterator if possible.
2046    ///
2047    /// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
2048    /// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
2049    /// * The Mesh is missing position or index data.
2050    /// * The Mesh's position data has the wrong format (not `Float32x3`).
2051    ///
2052    /// [primitive topology]: PrimitiveTopology
2053    /// [triangles]: Triangle3d
2054    pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
2055        let position_data = self.try_attribute(Mesh::ATTRIBUTE_POSITION)?;
2056
2057        let Some(vertices) = position_data.as_float3() else {
2058            return Err(MeshTrianglesError::PositionsFormat);
2059        };
2060
2061        let indices = self.try_indices()?;
2062
2063        match self.primitive_topology {
2064            PrimitiveTopology::TriangleList => {
2065                // When indices reference out-of-bounds vertex data, the triangle is omitted.
2066                // This implicitly truncates the indices to a multiple of 3.
2067                let iterator = match indices {
2068                    Indices::U16(vec) => FourIterators::First(
2069                        vec.as_slice()
2070                            .chunks_exact(3)
2071                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
2072                    ),
2073                    Indices::U32(vec) => FourIterators::Second(
2074                        vec.as_slice()
2075                            .chunks_exact(3)
2076                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
2077                    ),
2078                };
2079
2080                return Ok(iterator);
2081            }
2082
2083            PrimitiveTopology::TriangleStrip => {
2084                // When indices reference out-of-bounds vertex data, the triangle is omitted.
2085                // If there aren't enough indices to make a triangle, then an empty vector will be
2086                // returned.
2087                let iterator = match indices {
2088                    Indices::U16(vec) => {
2089                        FourIterators::Third(vec.as_slice().windows(3).enumerate().flat_map(
2090                            move |(i, indices)| {
2091                                if i % 2 == 0 {
2092                                    indices_to_triangle(vertices, indices)
2093                                } else {
2094                                    indices_to_triangle(
2095                                        vertices,
2096                                        &[indices[1], indices[0], indices[2]],
2097                                    )
2098                                }
2099                            },
2100                        ))
2101                    }
2102                    Indices::U32(vec) => {
2103                        FourIterators::Fourth(vec.as_slice().windows(3).enumerate().flat_map(
2104                            move |(i, indices)| {
2105                                if i % 2 == 0 {
2106                                    indices_to_triangle(vertices, indices)
2107                                } else {
2108                                    indices_to_triangle(
2109                                        vertices,
2110                                        &[indices[1], indices[0], indices[2]],
2111                                    )
2112                                }
2113                            },
2114                        ))
2115                    }
2116                };
2117
2118                return Ok(iterator);
2119            }
2120
2121            _ => {
2122                return Err(MeshTrianglesError::WrongTopology);
2123            }
2124        };
2125
2126        fn indices_to_triangle<T: TryInto<usize> + Copy>(
2127            vertices: &[[f32; 3]],
2128            indices: &[T],
2129        ) -> Option<Triangle3d> {
2130            let vert0: Vec3 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
2131            let vert1: Vec3 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
2132            let vert2: Vec3 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
2133            Some(Triangle3d {
2134                vertices: [vert0, vert1, vert2],
2135            })
2136        }
2137    }
2138
2139    /// Extracts the mesh vertex, index and morph target data for GPU upload.
2140    /// This function is called internally in render world extraction, it is
2141    /// unlikely to be useful outside of that context.
2142    ///
2143    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2144    pub fn take_gpu_data(&mut self) -> Result<Self, MeshAccessError> {
2145        let attributes = self.attributes.extract()?;
2146        let indices = self.indices.extract()?;
2147        #[cfg(feature = "morph")]
2148        let morph_targets = self.morph_targets.extract()?;
2149        #[cfg(feature = "morph")]
2150        let morph_target_names = self.morph_target_names.extract()?;
2151
2152        // store the aabb extents as they cannot be computed after extraction
2153        if let Some(MeshAttributeData {
2154            values: VertexAttributeValues::Float32x3(position_values),
2155            ..
2156        }) = attributes
2157            .as_ref_option()?
2158            .and_then(|attrs| attrs.get(&Self::ATTRIBUTE_POSITION.id))
2159            && !position_values.is_empty()
2160        {
2161            let mut iter = position_values.iter().map(|p| Vec3::from_slice(p));
2162            let mut min = iter.next().unwrap();
2163            let mut max = min;
2164            for v in iter {
2165                min = Vec3::min(min, v);
2166                max = Vec3::max(max, v);
2167            }
2168            self.final_aabb = Some(Aabb3d::from_min_max(min, max));
2169        }
2170
2171        Ok(Self {
2172            attributes,
2173            indices,
2174            #[cfg(feature = "morph")]
2175            morph_targets,
2176            #[cfg(feature = "morph")]
2177            morph_target_names,
2178            ..self.clone()
2179        })
2180    }
2181}
2182
2183#[cfg(feature = "morph")]
2184impl Mesh {
2185    /// Whether this mesh has morph targets.
2186    ///
2187    /// # Panics
2188    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2189    /// this as an error use [`Mesh::try_has_morph_targets`]
2190    pub fn has_morph_targets(&self) -> bool {
2191        self.try_has_morph_targets().expect(MESH_EXTRACTED_ERROR)
2192    }
2193
2194    /// Whether this mesh has morph targets.
2195    pub fn try_has_morph_targets(&self) -> Result<bool, MeshAccessError> {
2196        Ok(self.morph_targets.as_ref_option()?.is_some())
2197    }
2198
2199    /// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2200    ///
2201    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2202    ///
2203    /// # Panics
2204    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2205    /// this as an error use [`Mesh::try_set_morph_targets`]
2206    pub fn set_morph_targets(&mut self, morph_targets: Handle<Image>) {
2207        self.try_set_morph_targets(morph_targets)
2208            .expect(MESH_EXTRACTED_ERROR);
2209    }
2210
2211    /// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2212    ///
2213    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2214    pub fn try_set_morph_targets(
2215        &mut self,
2216        morph_targets: Handle<Image>,
2217    ) -> Result<(), MeshAccessError> {
2218        self.morph_targets.replace(Some(morph_targets))?;
2219        Ok(())
2220    }
2221
2222    /// Retrieve the morph targets for this mesh, or None if there are no morph targets.
2223    /// # Panics
2224    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2225    /// this as an error use [`Mesh::try_morph_targets`]
2226    pub fn morph_targets(&self) -> Option<&Handle<Image>> {
2227        self.morph_targets
2228            .as_ref_option()
2229            .expect(MESH_EXTRACTED_ERROR)
2230    }
2231
2232    /// Retrieve the morph targets for this mesh, or None if there are no morph targets.
2233    ///
2234    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2235    /// if the morph targets do not exist.
2236    pub fn try_morph_targets(&self) -> Result<&Handle<Image>, MeshAccessError> {
2237        self.morph_targets.as_ref()
2238    }
2239
2240    /// Consumes the mesh and returns a mesh with the given [morph targets].
2241    ///
2242    /// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2243    ///
2244    /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2245    ///
2246    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2247    ///
2248    /// # Panics
2249    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2250    /// this as an error use [`Mesh::try_with_morph_targets`]
2251    #[must_use]
2252    pub fn with_morph_targets(mut self, morph_targets: Handle<Image>) -> Self {
2253        self.set_morph_targets(morph_targets);
2254        self
2255    }
2256
2257    /// Consumes the mesh and returns a mesh with the given [morph targets].
2258    ///
2259    /// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2260    ///
2261    /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2262    ///
2263    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2264    ///
2265    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2266    pub fn try_with_morph_targets(
2267        mut self,
2268        morph_targets: Handle<Image>,
2269    ) -> Result<Self, MeshAccessError> {
2270        self.try_set_morph_targets(morph_targets)?;
2271        Ok(self)
2272    }
2273
2274    /// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2275    ///
2276    /// # Panics
2277    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2278    /// this as an error use [`Mesh::try_set_morph_target_names`]
2279    pub fn set_morph_target_names(&mut self, names: Vec<String>) {
2280        self.try_set_morph_target_names(names)
2281            .expect(MESH_EXTRACTED_ERROR);
2282    }
2283
2284    /// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2285    ///
2286    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2287    pub fn try_set_morph_target_names(
2288        &mut self,
2289        names: Vec<String>,
2290    ) -> Result<(), MeshAccessError> {
2291        self.morph_target_names.replace(Some(names))?;
2292        Ok(())
2293    }
2294
2295    /// Consumes the mesh and returns a mesh with morph target names.
2296    /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2297    ///
2298    /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2299    ///
2300    /// # Panics
2301    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2302    /// this as an error use [`Mesh::try_set_morph_target_names`]
2303    #[must_use]
2304    pub fn with_morph_target_names(self, names: Vec<String>) -> Self {
2305        self.try_with_morph_target_names(names)
2306            .expect(MESH_EXTRACTED_ERROR)
2307    }
2308
2309    /// Consumes the mesh and returns a mesh with morph target names.
2310    /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2311    ///
2312    /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2313    ///
2314    /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2315    pub fn try_with_morph_target_names(
2316        mut self,
2317        names: Vec<String>,
2318    ) -> Result<Self, MeshAccessError> {
2319        self.try_set_morph_target_names(names)?;
2320        Ok(self)
2321    }
2322
2323    /// Gets a list of all morph target names, if they exist.
2324    ///
2325    /// # Panics
2326    /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2327    /// this as an error use [`Mesh::try_morph_target_names`]
2328    pub fn morph_target_names(&self) -> Option<&[String]> {
2329        self.try_morph_target_names().expect(MESH_EXTRACTED_ERROR)
2330    }
2331
2332    /// Gets a list of all morph target names, if they exist.
2333    ///
2334    /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2335    /// if the morph targets do not exist.
2336    pub fn try_morph_target_names(&self) -> Result<Option<&[String]>, MeshAccessError> {
2337        Ok(self
2338            .morph_target_names
2339            .as_ref_option()?
2340            .map(core::ops::Deref::deref))
2341    }
2342}
2343
2344/// Correctly scales and renormalizes an already normalized `normal` by the scale determined by its reciprocal `scale_recip`
2345pub(crate) fn scale_normal(normal: Vec3, scale_recip: Vec3) -> Vec3 {
2346    // This is basically just `normal * scale_recip` but with the added rule that `0. * anything == 0.`
2347    // This is necessary because components of `scale_recip` may be infinities, which do not multiply to zero
2348    let n = Vec3::select(normal.cmpeq(Vec3::ZERO), Vec3::ZERO, normal * scale_recip);
2349
2350    // If n is finite, no component of `scale_recip` was infinite or the normal was perpendicular to the scale
2351    // else the scale had at least one zero-component and the normal needs to point along the direction of that component
2352    if n.is_finite() {
2353        n.normalize_or_zero()
2354    } else {
2355        Vec3::select(n.abs().cmpeq(Vec3::INFINITY), n.signum(), Vec3::ZERO).normalize()
2356    }
2357}
2358
2359impl core::ops::Mul<Mesh> for Transform {
2360    type Output = Mesh;
2361
2362    fn mul(self, rhs: Mesh) -> Self::Output {
2363        rhs.transformed_by(self)
2364    }
2365}
2366
2367/// A version of [`Mesh`] suitable for serializing for short-term transfer.
2368///
2369/// [`Mesh`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.
2370/// It is not a general-purpose mesh implementation, and its internals are subject to frequent change.
2371/// As such, storing a [`Mesh`] on disk is highly discouraged.
2372///
2373/// But there are still some valid use cases for serializing a [`Mesh`], namely transferring meshes between processes.
2374/// To support this, you can create a [`SerializedMesh`] from a [`Mesh`] with [`SerializedMesh::from_mesh`],
2375/// and then deserialize it with [`SerializedMesh::deserialize`]. The caveats are:
2376/// - The mesh representation is not valid across different versions of Bevy.
2377/// - This conversion is lossy. Only the following information is preserved:
2378///   - Primitive topology
2379///   - Vertex attributes
2380///   - Indices
2381/// - Custom attributes that were not specified with [`MeshDeserializer::add_custom_vertex_attribute`] will be ignored while deserializing.
2382#[cfg(feature = "serialize")]
2383#[derive(Debug, Clone, Serialize, Deserialize)]
2384pub struct SerializedMesh {
2385    primitive_topology: PrimitiveTopology,
2386    attributes: Vec<(MeshVertexAttributeId, SerializedMeshAttributeData)>,
2387    indices: Option<Indices>,
2388}
2389
2390#[cfg(feature = "serialize")]
2391impl SerializedMesh {
2392    /// Create a [`SerializedMesh`] from a [`Mesh`]. See the documentation for [`SerializedMesh`] for caveats.
2393    pub fn from_mesh(mut mesh: Mesh) -> Self {
2394        Self {
2395            primitive_topology: mesh.primitive_topology,
2396            attributes: mesh
2397                .attributes
2398                .replace(None)
2399                .expect(MESH_EXTRACTED_ERROR)
2400                .unwrap()
2401                .into_iter()
2402                .map(|(id, data)| {
2403                    (
2404                        id,
2405                        SerializedMeshAttributeData::from_mesh_attribute_data(data),
2406                    )
2407                })
2408                .collect(),
2409            indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),
2410        }
2411    }
2412
2413    /// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
2414    ///
2415    /// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
2416    pub fn into_mesh(self) -> Mesh {
2417        MeshDeserializer::default().deserialize(self)
2418    }
2419}
2420
2421/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
2422#[cfg(feature = "serialize")]
2423pub struct MeshDeserializer {
2424    custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
2425}
2426
2427#[cfg(feature = "serialize")]
2428impl Default for MeshDeserializer {
2429    fn default() -> Self {
2430        // Written like this so that the compiler can validate that we use all the built-in attributes.
2431        // If you just added a new attribute and got a compile error, please add it to this list :)
2432        const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
2433            Mesh::ATTRIBUTE_POSITION,
2434            Mesh::ATTRIBUTE_NORMAL,
2435            Mesh::ATTRIBUTE_UV_0,
2436            Mesh::ATTRIBUTE_UV_1,
2437            Mesh::ATTRIBUTE_TANGENT,
2438            Mesh::ATTRIBUTE_COLOR,
2439            Mesh::ATTRIBUTE_JOINT_WEIGHT,
2440            Mesh::ATTRIBUTE_JOINT_INDEX,
2441        ];
2442        Self {
2443            custom_vertex_attributes: BUILTINS
2444                .into_iter()
2445                .map(|attribute| (attribute.name.into(), attribute))
2446                .collect(),
2447        }
2448    }
2449}
2450
2451#[cfg(feature = "serialize")]
2452impl MeshDeserializer {
2453    /// Create a new [`MeshDeserializer`].
2454    pub fn new() -> Self {
2455        Self::default()
2456    }
2457
2458    /// Register a custom vertex attribute to the deserializer. Custom vertex attributes that were not added with this method will be ignored while deserializing.
2459    pub fn add_custom_vertex_attribute(
2460        &mut self,
2461        name: &str,
2462        attribute: MeshVertexAttribute,
2463    ) -> &mut Self {
2464        self.custom_vertex_attributes.insert(name.into(), attribute);
2465        self
2466    }
2467
2468    /// Deserialize a [`SerializedMesh`] into a [`Mesh`].
2469    ///
2470    /// See the documentation for [`SerializedMesh`] for caveats.
2471    pub fn deserialize(&self, serialized_mesh: SerializedMesh) -> Mesh {
2472        Mesh {
2473            attributes: MeshExtractableData::Data(
2474                serialized_mesh
2475                .attributes
2476                .into_iter()
2477                .filter_map(|(id, data)| {
2478                    let attribute = data.attribute.clone();
2479                    let Some(data) =
2480                        data.try_into_mesh_attribute_data(&self.custom_vertex_attributes)
2481                    else {
2482                        warn!(
2483                            "Deserialized mesh contains custom vertex attribute {attribute:?} that \
2484                            was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring."
2485                        );
2486                        return None;
2487                    };
2488                    Some((id, data))
2489                })
2490                .collect()),
2491            indices: serialized_mesh.indices.into(),
2492            ..Mesh::new(serialized_mesh.primitive_topology, RenderAssetUsages::default())
2493        }
2494    }
2495}
2496
2497/// Error that can occur when calling [`Mesh::merge`].
2498#[derive(Error, Debug, Clone)]
2499pub enum MeshMergeError {
2500    #[error("Incompatible vertex attribute types: {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
2501    IncompatibleVertexAttributes {
2502        self_attribute: MeshVertexAttribute,
2503        other_attribute: Option<MeshVertexAttribute>,
2504    },
2505    #[error(
2506        "Incompatible primitive topologies: {:?} and {:?}",
2507        self_primitive_topology,
2508        other_primitive_topology
2509    )]
2510    IncompatiblePrimitiveTopology {
2511        self_primitive_topology: PrimitiveTopology,
2512        other_primitive_topology: PrimitiveTopology,
2513    },
2514    #[error("Mesh access error: {0}")]
2515    MeshAccessError(#[from] MeshAccessError),
2516}
2517
2518#[cfg(test)]
2519mod tests {
2520    use super::Mesh;
2521    #[cfg(feature = "serialize")]
2522    use super::SerializedMesh;
2523    use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
2524    use crate::PrimitiveTopology;
2525    use bevy_asset::RenderAssetUsages;
2526    use bevy_math::bounding::Aabb3d;
2527    use bevy_math::primitives::Triangle3d;
2528    use bevy_math::Vec3;
2529    use bevy_transform::components::Transform;
2530
2531    #[test]
2532    #[should_panic]
2533    fn panic_invalid_format() {
2534        let _mesh = Mesh::new(
2535            PrimitiveTopology::TriangleList,
2536            RenderAssetUsages::default(),
2537        )
2538        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
2539    }
2540
2541    #[test]
2542    fn transform_mesh() {
2543        let mesh = Mesh::new(
2544            PrimitiveTopology::TriangleList,
2545            RenderAssetUsages::default(),
2546        )
2547        .with_inserted_attribute(
2548            Mesh::ATTRIBUTE_POSITION,
2549            vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
2550        )
2551        .with_inserted_attribute(
2552            Mesh::ATTRIBUTE_NORMAL,
2553            vec![
2554                Vec3::new(-1., -1., 1.).normalize().to_array(),
2555                Vec3::new(1., -1., 1.).normalize().to_array(),
2556                [0., 0., 1.],
2557            ],
2558        )
2559        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
2560
2561        let mesh = mesh.transformed_by(
2562            Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
2563        );
2564
2565        if let Some(VertexAttributeValues::Float32x3(positions)) =
2566            mesh.attribute(Mesh::ATTRIBUTE_POSITION)
2567        {
2568            // All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
2569            // and then shifted by `-2.` along each axis
2570            assert_eq!(
2571                positions,
2572                &vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
2573            );
2574        } else {
2575            panic!("Mesh does not have a position attribute");
2576        }
2577
2578        if let Some(VertexAttributeValues::Float32x3(normals)) =
2579            mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
2580        {
2581            assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
2582        } else {
2583            panic!("Mesh does not have a normal attribute");
2584        }
2585
2586        if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
2587            assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
2588        } else {
2589            panic!("Mesh does not have a uv attribute");
2590        }
2591    }
2592
2593    #[test]
2594    fn point_list_mesh_invert_winding() {
2595        let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
2596            .with_inserted_indices(Indices::U32(vec![]));
2597        assert!(matches!(
2598            mesh.with_inverted_winding(),
2599            Err(MeshWindingInvertError::WrongTopology)
2600        ));
2601    }
2602
2603    #[test]
2604    fn line_list_mesh_invert_winding() {
2605        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2606            .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
2607        let mesh = mesh.with_inverted_winding().unwrap();
2608        assert_eq!(
2609            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2610            vec![3, 2, 2, 1, 1, 0]
2611        );
2612    }
2613
2614    #[test]
2615    fn line_list_mesh_invert_winding_fail() {
2616        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2617            .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
2618        assert!(matches!(
2619            mesh.with_inverted_winding(),
2620            Err(MeshWindingInvertError::AbruptIndicesEnd)
2621        ));
2622    }
2623
2624    #[test]
2625    fn line_strip_mesh_invert_winding() {
2626        let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
2627            .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2628        let mesh = mesh.with_inverted_winding().unwrap();
2629        assert_eq!(
2630            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2631            vec![3, 2, 1, 0]
2632        );
2633    }
2634
2635    #[test]
2636    fn triangle_list_mesh_invert_winding() {
2637        let mesh = Mesh::new(
2638            PrimitiveTopology::TriangleList,
2639            RenderAssetUsages::default(),
2640        )
2641        .with_inserted_indices(Indices::U32(vec![
2642            0, 3, 1, // First triangle
2643            1, 3, 2, // Second triangle
2644        ]));
2645        let mesh = mesh.with_inverted_winding().unwrap();
2646        assert_eq!(
2647            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2648            vec![
2649                0, 1, 3, // First triangle
2650                1, 2, 3, // Second triangle
2651            ]
2652        );
2653    }
2654
2655    #[test]
2656    fn triangle_list_mesh_invert_winding_fail() {
2657        let mesh = Mesh::new(
2658            PrimitiveTopology::TriangleList,
2659            RenderAssetUsages::default(),
2660        )
2661        .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
2662        assert!(matches!(
2663            mesh.with_inverted_winding(),
2664            Err(MeshWindingInvertError::AbruptIndicesEnd)
2665        ));
2666    }
2667
2668    #[test]
2669    fn triangle_strip_mesh_invert_winding() {
2670        let mesh = Mesh::new(
2671            PrimitiveTopology::TriangleStrip,
2672            RenderAssetUsages::default(),
2673        )
2674        .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2675        let mesh = mesh.with_inverted_winding().unwrap();
2676        assert_eq!(
2677            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2678            vec![3, 2, 1, 0]
2679        );
2680    }
2681
2682    #[test]
2683    fn compute_area_weighted_normals() {
2684        let mut mesh = Mesh::new(
2685            PrimitiveTopology::TriangleList,
2686            RenderAssetUsages::default(),
2687        );
2688
2689        //  z      y
2690        //  |    /
2691        //  3---2
2692        //  | /  \
2693        //  0-----1--x
2694
2695        mesh.insert_attribute(
2696            Mesh::ATTRIBUTE_POSITION,
2697            vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2698        );
2699        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2700        mesh.compute_area_weighted_normals();
2701        let normals = mesh
2702            .attribute(Mesh::ATTRIBUTE_NORMAL)
2703            .unwrap()
2704            .as_float3()
2705            .unwrap();
2706        assert_eq!(4, normals.len());
2707        // 0
2708        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
2709        // 1
2710        assert_eq!([0., 0., 1.], normals[1]);
2711        // 2
2712        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
2713        // 3
2714        assert_eq!([1., 0., 0.], normals[3]);
2715    }
2716
2717    #[test]
2718    fn compute_area_weighted_normals_proportionate() {
2719        let mut mesh = Mesh::new(
2720            PrimitiveTopology::TriangleList,
2721            RenderAssetUsages::default(),
2722        );
2723
2724        //  z      y
2725        //  |    /
2726        //  3---2..
2727        //  | /    \
2728        //  0-------1---x
2729
2730        mesh.insert_attribute(
2731            Mesh::ATTRIBUTE_POSITION,
2732            vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2733        );
2734        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2735        mesh.compute_area_weighted_normals();
2736        let normals = mesh
2737            .attribute(Mesh::ATTRIBUTE_NORMAL)
2738            .unwrap()
2739            .as_float3()
2740            .unwrap();
2741        assert_eq!(4, normals.len());
2742        // 0
2743        assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
2744        // 1
2745        assert_eq!([0., 0., 1.], normals[1]);
2746        // 2
2747        assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
2748        // 3
2749        assert_eq!([1., 0., 0.], normals[3]);
2750    }
2751
2752    #[test]
2753    fn compute_angle_weighted_normals() {
2754        // CuboidMeshBuilder duplicates vertices (even though it is indexed)
2755
2756        //   5---------4
2757        //  /|        /|
2758        // 1-+-------0 |
2759        // | 6-------|-7
2760        // |/        |/
2761        // 2---------3
2762        let verts = vec![
2763            [1.0, 1.0, 1.0],
2764            [-1.0, 1.0, 1.0],
2765            [-1.0, -1.0, 1.0],
2766            [1.0, -1.0, 1.0],
2767            [1.0, 1.0, -1.0],
2768            [-1.0, 1.0, -1.0],
2769            [-1.0, -1.0, -1.0],
2770            [1.0, -1.0, -1.0],
2771        ];
2772
2773        let indices = Indices::U16(vec![
2774            0, 1, 2, 2, 3, 0, // front
2775            5, 4, 7, 7, 6, 5, // back
2776            1, 5, 6, 6, 2, 1, // left
2777            4, 0, 3, 3, 7, 4, // right
2778            4, 5, 1, 1, 0, 4, // top
2779            3, 2, 6, 6, 7, 3, // bottom
2780        ]);
2781        let mut mesh = Mesh::new(
2782            PrimitiveTopology::TriangleList,
2783            RenderAssetUsages::default(),
2784        );
2785        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, verts);
2786        mesh.insert_indices(indices);
2787        mesh.compute_smooth_normals();
2788
2789        let normals = mesh
2790            .attribute(Mesh::ATTRIBUTE_NORMAL)
2791            .unwrap()
2792            .as_float3()
2793            .unwrap();
2794
2795        for new in normals.iter().copied().flatten() {
2796            // std impl is unstable
2797            const FRAC_1_SQRT_3: f32 = 0.57735026;
2798            const MIN: f32 = FRAC_1_SQRT_3 - f32::EPSILON;
2799            const MAX: f32 = FRAC_1_SQRT_3 + f32::EPSILON;
2800            assert!(new.abs() >= MIN, "{new} < {MIN}");
2801            assert!(new.abs() <= MAX, "{new} > {MAX}");
2802        }
2803    }
2804
2805    #[test]
2806    fn triangles_from_triangle_list() {
2807        let mut mesh = Mesh::new(
2808            PrimitiveTopology::TriangleList,
2809            RenderAssetUsages::default(),
2810        );
2811        mesh.insert_attribute(
2812            Mesh::ATTRIBUTE_POSITION,
2813            vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
2814        );
2815        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
2816        assert_eq!(
2817            vec![
2818                Triangle3d {
2819                    vertices: [
2820                        Vec3::new(0., 0., 0.),
2821                        Vec3::new(1., 0., 0.),
2822                        Vec3::new(1., 1., 0.),
2823                    ]
2824                },
2825                Triangle3d {
2826                    vertices: [
2827                        Vec3::new(1., 1., 0.),
2828                        Vec3::new(0., 1., 0.),
2829                        Vec3::new(0., 0., 0.),
2830                    ]
2831                }
2832            ],
2833            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
2834        );
2835    }
2836
2837    #[test]
2838    fn triangles_from_triangle_strip() {
2839        let mut mesh = Mesh::new(
2840            PrimitiveTopology::TriangleStrip,
2841            RenderAssetUsages::default(),
2842        );
2843        // Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
2844        //
2845        // 4 - 5
2846        // | \ |
2847        // 2 - 3
2848        // | \ |
2849        // 0 - 1
2850        let positions: Vec<Vec3> = [
2851            [0., 0., 0.],
2852            [1., 0., 0.],
2853            [0., 1., 0.],
2854            [1., 1., 0.],
2855            [0., 2., 0.],
2856            [1., 2., 0.],
2857        ]
2858        .into_iter()
2859        .map(Vec3::from_array)
2860        .collect();
2861        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
2862        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
2863        assert_eq!(
2864            vec![
2865                Triangle3d {
2866                    vertices: [positions[0], positions[1], positions[2]]
2867                },
2868                Triangle3d {
2869                    vertices: [positions[2], positions[1], positions[3]]
2870                },
2871                Triangle3d {
2872                    vertices: [positions[2], positions[3], positions[4]]
2873                },
2874                Triangle3d {
2875                    vertices: [positions[4], positions[3], positions[5]]
2876                },
2877            ],
2878            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
2879        );
2880    }
2881
2882    #[test]
2883    fn take_gpu_data_calculates_aabb() {
2884        let mut mesh = Mesh::new(
2885            PrimitiveTopology::TriangleList,
2886            RenderAssetUsages::default(),
2887        );
2888        mesh.insert_attribute(
2889            Mesh::ATTRIBUTE_POSITION,
2890            vec![
2891                [-0.5, 0., 0.],
2892                [-1., 0., 0.],
2893                [-1., -1., 0.],
2894                [-0.5, -1., 0.],
2895            ],
2896        );
2897        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
2898        mesh = mesh.take_gpu_data().unwrap();
2899        assert_eq!(
2900            mesh.final_aabb,
2901            Some(Aabb3d::from_min_max([-1., -1., 0.], [-0.5, 0., 0.]))
2902        );
2903    }
2904
2905    #[cfg(feature = "serialize")]
2906    #[test]
2907    fn serialize_deserialize_mesh() {
2908        let mut mesh = Mesh::new(
2909            PrimitiveTopology::TriangleList,
2910            RenderAssetUsages::default(),
2911        );
2912
2913        mesh.insert_attribute(
2914            Mesh::ATTRIBUTE_POSITION,
2915            vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2916        );
2917        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2918
2919        let serialized_mesh = SerializedMesh::from_mesh(mesh.clone());
2920        let serialized_string = serde_json::to_string(&serialized_mesh).unwrap();
2921        let serialized_mesh_from_string: SerializedMesh =
2922            serde_json::from_str(&serialized_string).unwrap();
2923        let deserialized_mesh = serialized_mesh_from_string.into_mesh();
2924        assert_eq!(mesh, deserialized_mesh);
2925    }
2926}