Mesh::merge to return a Result (#17475)
# Objective Make `Mesh::merge` more resilient to use. Currently, it's difficult to make sure `Mesh::merge` will not panic (we'd have to check if all attributes are compatible). - I'd appreciate it for utility function to convert different mesh representations such as: https://github.com/dimforge/bevy_rapier/pull/628. ## Solution - Make `Mesh::merge` return a `Result`. ## Testing - It builds ## Migration Guide - `Mesh::merge` now returns a `Result<(), MeshMergeError>`. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com> Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
This commit is contained in:
parent
9387fcfbf2
commit
fd2afeefda
@ -14,6 +14,7 @@ use bevy_image::Image;
|
||||
use bevy_math::{primitives::Triangle3d, *};
|
||||
use bevy_reflect::Reflect;
|
||||
use bytemuck::cast_slice;
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode};
|
||||
|
||||
@ -280,7 +281,7 @@ impl Mesh {
|
||||
self.attributes.contains_key(&id.into())
|
||||
}
|
||||
|
||||
/// Retrieves the data currently set to the vertex attribute with the specified `name`.
|
||||
/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
|
||||
#[inline]
|
||||
pub fn attribute(
|
||||
&self,
|
||||
@ -289,6 +290,15 @@ impl Mesh {
|
||||
self.attributes.get(&id.into()).map(|data| &data.values)
|
||||
}
|
||||
|
||||
/// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
|
||||
#[inline]
|
||||
pub(crate) fn attribute_data(
|
||||
&self,
|
||||
id: impl Into<MeshVertexAttributeId>,
|
||||
) -> Option<&MeshAttributeData> {
|
||||
self.attributes.get(&id.into())
|
||||
}
|
||||
|
||||
/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
|
||||
#[inline]
|
||||
pub fn attribute_mut(
|
||||
@ -788,11 +798,11 @@ impl Mesh {
|
||||
///
|
||||
/// `Aabb` of entities with modified mesh are not updated automatically.
|
||||
///
|
||||
/// # Panics
|
||||
/// # Errors
|
||||
///
|
||||
/// Panics if the vertex attribute values of `other` are incompatible with `self`.
|
||||
/// Returns [`Err(MergeMeshError)`](MergeMeshError) if the vertex attribute values of `other` are incompatible with `self`.
|
||||
/// For example, [`VertexAttributeValues::Float32`] is incompatible with [`VertexAttributeValues::Float32x3`].
|
||||
pub fn merge(&mut self, other: &Mesh) {
|
||||
pub fn merge(&mut self, other: &Mesh) -> Result<(), MergeMeshError> {
|
||||
use VertexAttributeValues::*;
|
||||
|
||||
// The indices of `other` should start after the last vertex of `self`.
|
||||
@ -800,7 +810,6 @@ impl Mesh {
|
||||
|
||||
// Extend attributes of `self` with attributes of `other`.
|
||||
for (attribute, values) in self.attributes_mut() {
|
||||
let enum_variant_name = values.enum_variant_name();
|
||||
if let Some(other_values) = other.attribute(attribute.id) {
|
||||
#[expect(
|
||||
clippy::match_same_arms,
|
||||
@ -835,11 +844,14 @@ impl Mesh {
|
||||
(Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
|
||||
(Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
|
||||
(Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
|
||||
_ => panic!(
|
||||
"Incompatible vertex attribute types {} and {}",
|
||||
enum_variant_name,
|
||||
other_values.enum_variant_name()
|
||||
),
|
||||
_ => {
|
||||
return Err(MergeMeshError {
|
||||
self_attribute: *attribute,
|
||||
other_attribute: other
|
||||
.attribute_data(attribute.id)
|
||||
.map(|data| data.attribute),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -848,6 +860,7 @@ impl Mesh {
|
||||
if let (Some(indices), Some(other_indices)) = (self.indices_mut(), other.indices()) {
|
||||
indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
|
||||
@ -1213,6 +1226,14 @@ impl core::ops::Mul<Mesh> for Transform {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can occur when calling [`Mesh::merge`].
|
||||
#[derive(Error, Debug, Clone)]
|
||||
#[error("Incompatible vertex attribute types {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
|
||||
pub struct MergeMeshError {
|
||||
pub self_attribute: MeshVertexAttribute,
|
||||
pub other_attribute: Option<MeshVertexAttribute>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Mesh;
|
||||
|
@ -216,7 +216,7 @@ where
|
||||
|
||||
// An extrusion of depth 0 does not need a mantel
|
||||
if self.half_depth == 0. {
|
||||
front_face.merge(&back_face);
|
||||
front_face.merge(&back_face).unwrap();
|
||||
return front_face;
|
||||
}
|
||||
|
||||
@ -408,8 +408,8 @@ where
|
||||
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
|
||||
};
|
||||
|
||||
front_face.merge(&back_face);
|
||||
front_face.merge(&mantel);
|
||||
front_face.merge(&back_face).unwrap();
|
||||
front_face.merge(&mantel).unwrap();
|
||||
front_face
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user