1use bevy_transform::components::Transform;
2pub use wgpu_types::PrimitiveTopology;
34use super::{
5 skinning::{SkinnedMeshBounds, SkinnedMeshBoundsError},
6triangle_area_normal, triangle_normal, FourIterators, Indices, MeshAttributeData,
7MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId, MeshVertexBufferLayout,
8MeshVertexBufferLayoutRef, MeshVertexBufferLayouts, MeshWindingInvertError,
9VertexAttributeValues, VertexBufferLayout,
10};
11#[cfg(feature = "morph")]
12use crate::morph::MorphAttributes;
13use crate::AttributeQuantization;
14#[cfg(feature = "serialize")]
15use crate::SerializedMeshAttributeData;
16use alloc::borrow::Cow;
17use alloc::collections::BTreeMap;
18use bevy_asset::{Asset, RenderAssetUsages};
19use bevy_math::*;
20use bevy_platform::collections::{hash_map, HashMap};
21use bevy_reflect::{std_traits::ReflectDefault, Reflect};
22use bevy_shape::{Aabb2d, Aabb3d, Triangle3d};
23use bytemuck::cast_slice;
24use core::hash::{Hash, Hasher};
25use core::ptr;
26#[cfg(feature = "serialize")]
27use serde::{Deserialize, Serialize};
28use thiserror::Error;
29use tracing::warn;
30use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode, WriteOnly};
3132pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
33pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
3435/// Error from accessing mesh vertex attributes or indices
36#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for MeshAccessError { }
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for MeshAccessError {
fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
#[allow(unused_variables, deprecated, clippy ::
used_underscore_binding)]
match self {
MeshAccessError::ExtractedToRenderWorld {} =>
__formatter.write_str("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)"),
MeshAccessError::NotFound {} =>
__formatter.write_str("The requested mesh data wasn't found in this mesh"),
}
}
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshAccessError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
MeshAccessError::ExtractedToRenderWorld =>
"ExtractedToRenderWorld",
MeshAccessError::NotFound => "NotFound",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshAccessError {
#[inline]
fn clone(&self) -> Self {
match self {
Self::ExtractedToRenderWorld => Self::ExtractedToRenderWorld,
Self::NotFound => Self::NotFound,
}
}
}Clone)]
37pub enum MeshAccessError {
38#[error("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)")]
39ExtractedToRenderWorld,
40#[error("The requested mesh data wasn't found in this mesh")]
41NotFound,
42}
4344const MESH_EXTRACTED_ERROR: &str = "Mesh has been extracted to RenderWorld. To access vertex attributes, the mesh `asset_usage` must include `MAIN_WORLD`";
4546// storage for extractable data with access methods which return errors if the
47// contents have already been extracted
48#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for MeshExtractableData<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Data(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Data",
&__self_0),
Self::NoData => ::core::fmt::Formatter::write_str(f, "NoData"),
Self::ExtractedToRenderWorld =>
::core::fmt::Formatter::write_str(f,
"ExtractedToRenderWorld"),
}
}
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for MeshExtractableData<T>
{
#[inline]
fn clone(&self) -> Self {
match self {
Self::Data(__self_0) =>
Self::Data(::core::clone::Clone::clone(__self_0)),
Self::NoData => Self::NoData,
Self::ExtractedToRenderWorld => Self::ExtractedToRenderWorld,
}
}
}Clone, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
MeshExtractableData<T> {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for
MeshExtractableData<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::Data(__self_0), Self::Data(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, const _: () =
{
impl<T> bevy_reflect::GetTypeRegistration for MeshExtractableData<T>
where MeshExtractableData<T>: ::core::any::Any +
::core::marker::Send + ::core::marker::Sync,
T: bevy_reflect::TypePath, T: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<T as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl<T> bevy_reflect::Typed for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::GenericTypeInfoCell =
bevy_reflect::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Tuple(bevy_reflect::enums::TupleVariantInfo::new("Data",
&[bevy_reflect::UnnamedField::new::<T>(0usize)])),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("NoData")),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("ExtractedToRenderWorld"))]).with_generics(bevy_reflect::Generics::from_iter([bevy_reflect::GenericInfo::Type(bevy_reflect::TypeParamInfo::new::<T>(bevy_reflect::__macro_exports::alloc_utils::Cow::Borrowed("T")))])))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl<T> bevy_reflect::TypePath for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath {
fn type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("bevy_mesh::mesh::MeshExtractableData<"),
<T as bevy_reflect::TypePath>::type_path()), ">")
})
}
fn short_type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("MeshExtractableData<"),
<T as bevy_reflect::TypePath>::short_type_path()), ">")
})
}
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("MeshExtractableData")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl<T> bevy_reflect::Reflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl<T> bevy_reflect::enums::Enum for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn field(&self, __name_param: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at(&self, __index_param: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self {
MeshExtractableData::Data { 0: __value, .. } if
__index_param == 0usize =>
::core::option::Option::Some(__value),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, __name_param: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at_mut(&mut self, __index_param: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self {
MeshExtractableData::Data { 0: __value, .. } if
__index_param == 0usize =>
::core::option::Option::Some(__value),
_ => ::core::option::Option::None,
}
}
fn index_of(&self, __name_param: &str)
-> ::core::option::Option<usize> {
match self { _ => ::core::option::Option::None, }
}
fn name_at(&self, __index_param: usize)
-> ::core::option::Option<&str> {
match self { _ => ::core::option::Option::None, }
}
fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
bevy_reflect::enums::VariantFieldIter::new(self)
}
#[inline]
fn field_len(&self) -> usize {
match self {
MeshExtractableData::Data { .. } => 1usize,
MeshExtractableData::NoData { .. } => 0usize,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
0usize,
_ => 0,
}
}
#[inline]
fn variant_name(&self) -> &str {
match self {
MeshExtractableData::Data { .. } => "Data",
MeshExtractableData::NoData { .. } => "NoData",
MeshExtractableData::ExtractedToRenderWorld { .. } =>
"ExtractedToRenderWorld",
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_index(&self) -> usize {
match self {
MeshExtractableData::Data { .. } => 0usize,
MeshExtractableData::NoData { .. } => 1usize,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
2usize,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_type(&self) -> bevy_reflect::enums::VariantType {
match self {
MeshExtractableData::Data { .. } =>
bevy_reflect::enums::VariantType::Tuple,
MeshExtractableData::NoData { .. } =>
bevy_reflect::enums::VariantType::Unit,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
bevy_reflect::enums::VariantType::Unit,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
fn to_dynamic_enum(&self)
->
::core::result::Result<bevy_reflect::enums::DynamicEnum,
bevy_reflect::ReflectCloneError> {
bevy_reflect::enums::DynamicEnum::try_from_ref::<Self>(self)
}
}
impl<T> bevy_reflect::PartialReflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self,
__value_param: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Enum(__value_param) =
bevy_reflect::PartialReflect::reflect_ref(__value_param) {
if bevy_reflect::enums::Enum::variant_name(self) ==
bevy_reflect::enums::Enum::variant_name(__value_param) {
match bevy_reflect::enums::Enum::variant_type(__value_param)
{
bevy_reflect::enums::VariantType::Struct => {
for field in
bevy_reflect::enums::Enum::iter_fields(__value_param) {
let name = field.name().unwrap();
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
bevy_reflect::enums::VariantType::Tuple => {
for (index, field) in
::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
{
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_at_mut(self, index) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
_ => {}
}
} else {
match bevy_reflect::enums::Enum::variant_name(__value_param)
{
"Data" => {
*self =
MeshExtractableData::Data {
0: {
let __0 = __value_param.field_at(0usize);
let __0 =
__0.ok_or(bevy_reflect::ApplyError::MissingEnumField {
variant_name: ::core::convert::Into::into("Data"),
field_name: ::core::convert::Into::into(".0"),
})?;
<T as
bevy_reflect::FromReflect>::from_reflect(__0).ok_or(bevy_reflect::ApplyError::MismatchedTypes {
from_type: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(__0)),
to_type: ::core::convert::Into::into(<T as
bevy_reflect::TypePath>::type_path()),
})?
},
}
}
"NoData" => { *self = MeshExtractableData::NoData {} }
"ExtractedToRenderWorld" => {
*self = MeshExtractableData::ExtractedToRenderWorld {}
}
name => {
return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
variant_name: ::core::convert::Into::into(name),
});
}
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
to_kind: bevy_reflect::ReflectKind::Enum,
});
}
::core::result::Result::Ok(())
}
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Enum
}
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Enum(self)
}
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Enum(self)
}
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Enum(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_hash(&self) -> ::core::option::Option<u64> {
(bevy_reflect::enums::enum_hash)(self)
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::enums::enum_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::enums::enum_partial_cmp)(self, value)
}
#[inline]
#[allow(unreachable_code, reason =
"Ignored fields without a `clone` attribute will early-return with an error")]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
let this = self;
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(match this
{
MeshExtractableData::Data { 0: __0 } =>
MeshExtractableData::Data {
0: <T as
bevy_reflect::PartialReflect>::reflect_clone_and_take(__0)?,
},
MeshExtractableData::NoData {} =>
MeshExtractableData::NoData {},
MeshExtractableData::ExtractedToRenderWorld {} =>
MeshExtractableData::ExtractedToRenderWorld {},
}))
}
}
impl<T> bevy_reflect::FromReflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Enum(__param0) =
bevy_reflect::PartialReflect::reflect_ref(__param0) {
match bevy_reflect::enums::Enum::variant_name(__param0) {
"Data" =>
::core::option::Option::Some(MeshExtractableData::Data {
0: {
let __0 = __param0.field_at(0usize);
let __0 = __0?;
<T as bevy_reflect::FromReflect>::from_reflect(__0)?
},
}),
"NoData" =>
::core::option::Option::Some(MeshExtractableData::NoData {}),
"ExtractedToRenderWorld" =>
::core::option::Option::Some(MeshExtractableData::ExtractedToRenderWorld {}),
name => ::core::option::Option::None,
}
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl<T> ::core::default::Default for MeshExtractableData<T> {
#[inline]
fn default() -> Self { Self::NoData }
}Default)]
49enum MeshExtractableData<T> {
50 Data(T),
51#[default]
52NoData,
53 ExtractedToRenderWorld,
54}
5556impl<T> MeshExtractableData<T> {
57// get a reference to internal data. returns error if data has been extracted, or if no
58 // data exists
59fn as_ref(&self) -> Result<&T, MeshAccessError> {
60match self {
61 MeshExtractableData::Data(data) => Ok(data),
62 MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
63 MeshExtractableData::ExtractedToRenderWorld => {
64Err(MeshAccessError::ExtractedToRenderWorld)
65 }
66 }
67 }
6869// get an optional reference to internal data. returns error if data has been extracted
70fn as_ref_option(&self) -> Result<Option<&T>, MeshAccessError> {
71match self {
72 MeshExtractableData::Data(data) => Ok(Some(data)),
73 MeshExtractableData::NoData => Ok(None),
74 MeshExtractableData::ExtractedToRenderWorld => {
75Err(MeshAccessError::ExtractedToRenderWorld)
76 }
77 }
78 }
7980// get a mutable reference to internal data. returns error if data has been extracted,
81 // or if no data exists
82fn as_mut(&mut self) -> Result<&mut T, MeshAccessError> {
83match self {
84 MeshExtractableData::Data(data) => Ok(data),
85 MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
86 MeshExtractableData::ExtractedToRenderWorld => {
87Err(MeshAccessError::ExtractedToRenderWorld)
88 }
89 }
90 }
9192// get an optional mutable reference to internal data. returns error if data has been extracted
93fn as_mut_option(&mut self) -> Result<Option<&mut T>, MeshAccessError> {
94match self {
95 MeshExtractableData::Data(data) => Ok(Some(data)),
96 MeshExtractableData::NoData => Ok(None),
97 MeshExtractableData::ExtractedToRenderWorld => {
98Err(MeshAccessError::ExtractedToRenderWorld)
99 }
100 }
101 }
102103// extract data and replace self with `ExtractedToRenderWorld`. returns error if
104 // data has been extracted
105fn extract(&mut self) -> Result<MeshExtractableData<T>, MeshAccessError> {
106match core::mem::replace(self, MeshExtractableData::ExtractedToRenderWorld) {
107 MeshExtractableData::ExtractedToRenderWorld => {
108Err(MeshAccessError::ExtractedToRenderWorld)
109 }
110 not_extracted => Ok(not_extracted),
111 }
112 }
113114// replace internal data. returns the existing data, or an error if data has been extracted
115fn replace(
116&mut self,
117 data: impl Into<MeshExtractableData<T>>,
118 ) -> Result<Option<T>, MeshAccessError> {
119match core::mem::replace(self, data.into()) {
120 MeshExtractableData::ExtractedToRenderWorld => {
121*self = MeshExtractableData::ExtractedToRenderWorld;
122Err(MeshAccessError::ExtractedToRenderWorld)
123 }
124 MeshExtractableData::Data(t) => Ok(Some(t)),
125 MeshExtractableData::NoData => Ok(None),
126 }
127 }
128}
129130impl<T> From<Option<T>> for MeshExtractableData<T> {
131fn from(value: Option<T>) -> Self {
132match value {
133Some(data) => MeshExtractableData::Data(data),
134None => MeshExtractableData::NoData,
135 }
136 }
137}
138139/// A 3D object made out of vertices representing triangles, lines, or points,
140/// with "attribute" values for each vertex.
141///
142/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
143/// or by converting a [primitive](bevy_shape) using [`into`](Into).
144/// It is also possible to create one manually. They can be edited after creation.
145///
146/// Meshes can be rendered with a [`Mesh2d`](crate::Mesh2d) and `MeshMaterial2d`
147/// or [`Mesh3d`](crate::Mesh3d) and `MeshMaterial3d` for 2D and 3D respectively.
148///
149/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
150/// glTF Mesh representation, see `GltfMesh`.
151///
152/// ## Manual creation
153///
154/// The following function will construct a flat mesh, to be rendered with a
155/// `StandardMaterial` or `ColorMaterial`:
156///
157/// ```
158/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
159/// # use bevy_asset::RenderAssetUsages;
160/// fn create_simple_parallelogram() -> Mesh {
161/// // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
162/// Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
163/// // Add 4 vertices, each with its own position attribute (coordinate in
164/// // 3D space), for each of the corners of the parallelogram.
165/// .with_inserted_attribute(
166/// Mesh::ATTRIBUTE_POSITION,
167/// 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]]
168/// )
169/// // Assign a UV coordinate to each vertex.
170/// .with_inserted_attribute(
171/// Mesh::ATTRIBUTE_UV_0,
172/// vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
173/// )
174/// // Assign normals (everything points outwards)
175/// .with_inserted_attribute(
176/// Mesh::ATTRIBUTE_NORMAL,
177/// 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]]
178/// )
179/// // After defining all the vertices and their attributes, build each triangle using the
180/// // indices of the vertices that make it up in a counter-clockwise order.
181/// .with_inserted_indices(Indices::U32(vec![
182/// // First triangle
183/// 0, 3, 1,
184/// // Second triangle
185/// 1, 3, 2
186/// ]))
187/// }
188/// ```
189///
190/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
191/// used in a [`Mesh3d`](crate::Mesh3d) with a square bevy logo texture, with added axis, points,
192/// lines and text for clarity.
193///
194/// ## Other examples
195///
196/// For further visualization, explanation, and examples, see the built-in Bevy examples,
197/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
198/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
199/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
200///
201/// ## Common points of confusion
202///
203/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
204/// other APIs can have other conventions, `OpenGL` starts at bottom-left.
205/// - It is possible and sometimes useful for multiple vertices to have the same
206/// [position attribute](Mesh::ATTRIBUTE_POSITION) value,
207/// it's a common technique in 3D modeling for complex UV mapping or other calculations.
208/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
209/// and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
210/// needs to be updated manually or deleted so that it is re-calculated.
211///
212/// ## Use with `StandardMaterial`
213///
214/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
215/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
216/// (also true for `ColorMaterial`).
217/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
218/// [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
219/// because simple meshes are smooth and they don't require complex light calculations.
220/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
221/// which means that Bevy would *only* render the "front" of each triangle, which
222/// is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
223///
224/// ## Remote Inspection
225///
226/// To transmit a [`Mesh`] between two running Bevy apps, e.g. through BRP, use [`SerializedMesh`].
227/// This type is only meant for short-term transmission between same versions and should not be stored anywhere.
228#[derive(impl bevy_asset::Asset for Mesh {}
impl bevy_asset::VisitAssetDependencies for Mesh {
fn visit_dependencies(&self,
visit: &mut impl ::core::ops::FnMut(bevy_asset::UntypedAssetId)) {}
}Asset, #[automatically_derived]
impl ::core::fmt::Debug for Mesh {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["primitive_topology", "attributes", "indices", "morph_targets",
"morph_target_names", "asset_usage", "enable_raytracing",
"attribute_compression", "final_aabb", "final_uv_ranges",
"skinned_mesh_bounds"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.primitive_topology, &self.attributes, &self.indices,
&self.morph_targets, &self.morph_target_names,
&self.asset_usage, &self.enable_raytracing,
&self.attribute_compression, &self.final_aabb,
&self.final_uv_ranges, &&self.skinned_mesh_bounds];
::core::fmt::Formatter::debug_struct_fields_finish(f, "Mesh", names,
values)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Mesh {
#[inline]
fn clone(&self) -> Self {
Self {
primitive_topology: ::core::clone::Clone::clone(&self.primitive_topology),
attributes: ::core::clone::Clone::clone(&self.attributes),
indices: ::core::clone::Clone::clone(&self.indices),
morph_targets: ::core::clone::Clone::clone(&self.morph_targets),
morph_target_names: ::core::clone::Clone::clone(&self.morph_target_names),
asset_usage: ::core::clone::Clone::clone(&self.asset_usage),
enable_raytracing: ::core::clone::Clone::clone(&self.enable_raytracing),
attribute_compression: ::core::clone::Clone::clone(&self.attribute_compression),
final_aabb: ::core::clone::Clone::clone(&self.final_aabb),
final_uv_ranges: ::core::clone::Clone::clone(&self.final_uv_ranges),
skinned_mesh_bounds: ::core::clone::Clone::clone(&self.skinned_mesh_bounds),
}
}
}Clone, const _: () =
{
impl bevy_reflect::GetTypeRegistration for Mesh where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<MeshExtractableData<Indices> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<MeshExtractableData<Vec<MorphAttributes>> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<MeshExtractableData<Vec<String>> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<RenderAssetUsages as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<bool as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<MeshAttributeCompressionFlags as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<Option<Aabb3d> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<[Option<Aabb2d>; 2] as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<Option<SkinnedMeshBounds> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for Mesh where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<MeshExtractableData<Indices>>("indices"),
bevy_reflect::NamedField::new::<MeshExtractableData<Vec<MorphAttributes>>>("morph_targets"),
bevy_reflect::NamedField::new::<MeshExtractableData<Vec<String>>>("morph_target_names"),
bevy_reflect::NamedField::new::<RenderAssetUsages>("asset_usage"),
bevy_reflect::NamedField::new::<bool>("enable_raytracing"),
bevy_reflect::NamedField::new::<MeshAttributeCompressionFlags>("attribute_compression"),
bevy_reflect::NamedField::new::<Option<Aabb3d>>("final_aabb"),
bevy_reflect::NamedField::new::<[Option<Aabb2d>; 2]>("final_uv_ranges"),
bevy_reflect::NamedField::new::<Option<SkinnedMeshBounds>>("skinned_mesh_bounds")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for Mesh where {
fn type_path() -> &'static str { "bevy_mesh::mesh::Mesh" }
fn short_type_path() -> &'static str { "Mesh" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("Mesh")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl bevy_reflect::Reflect for Mesh where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
#[allow(non_upper_case_globals)]
const _: () =
{
static __INVENTORY: ::inventory::Node =
::inventory::Node {
value: &{
bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<Mesh
as
bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
},
next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
};
#[link_section = ".text.startup"]
unsafe extern "C" fn __ctor() {
unsafe {
::inventory::ErasedNode::submit(__INVENTORY.value,
&__INVENTORY)
}
}
#[used]
#[link_section = ".init_array"]
static __CTOR: unsafe extern "C" fn() = __ctor;
};
impl bevy_reflect::structs::Struct for Mesh where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"indices" => ::core::option::Option::Some(&self.indices),
"morph_targets" =>
::core::option::Option::Some(&self.morph_targets),
"morph_target_names" =>
::core::option::Option::Some(&self.morph_target_names),
"asset_usage" =>
::core::option::Option::Some(&self.asset_usage),
"enable_raytracing" =>
::core::option::Option::Some(&self.enable_raytracing),
"attribute_compression" =>
::core::option::Option::Some(&self.attribute_compression),
"final_aabb" =>
::core::option::Option::Some(&self.final_aabb),
"final_uv_ranges" =>
::core::option::Option::Some(&self.final_uv_ranges),
"skinned_mesh_bounds" =>
::core::option::Option::Some(&self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"indices" =>
::core::option::Option::Some(&mut self.indices),
"morph_targets" =>
::core::option::Option::Some(&mut self.morph_targets),
"morph_target_names" =>
::core::option::Option::Some(&mut self.morph_target_names),
"asset_usage" =>
::core::option::Option::Some(&mut self.asset_usage),
"enable_raytracing" =>
::core::option::Option::Some(&mut self.enable_raytracing),
"attribute_compression" =>
::core::option::Option::Some(&mut self.attribute_compression),
"final_aabb" =>
::core::option::Option::Some(&mut self.final_aabb),
"final_uv_ranges" =>
::core::option::Option::Some(&mut self.final_uv_ranges),
"skinned_mesh_bounds" =>
::core::option::Option::Some(&mut self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.indices),
1usize => ::core::option::Option::Some(&self.morph_targets),
2usize =>
::core::option::Option::Some(&self.morph_target_names),
3usize => ::core::option::Option::Some(&self.asset_usage),
4usize =>
::core::option::Option::Some(&self.enable_raytracing),
5usize =>
::core::option::Option::Some(&self.attribute_compression),
6usize => ::core::option::Option::Some(&self.final_aabb),
7usize =>
::core::option::Option::Some(&self.final_uv_ranges),
8usize =>
::core::option::Option::Some(&self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.indices),
1usize =>
::core::option::Option::Some(&mut self.morph_targets),
2usize =>
::core::option::Option::Some(&mut self.morph_target_names),
3usize =>
::core::option::Option::Some(&mut self.asset_usage),
4usize =>
::core::option::Option::Some(&mut self.enable_raytracing),
5usize =>
::core::option::Option::Some(&mut self.attribute_compression),
6usize =>
::core::option::Option::Some(&mut self.final_aabb),
7usize =>
::core::option::Option::Some(&mut self.final_uv_ranges),
8usize =>
::core::option::Option::Some(&mut self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("indices"),
1usize => ::core::option::Option::Some("morph_targets"),
2usize =>
::core::option::Option::Some("morph_target_names"),
3usize => ::core::option::Option::Some("asset_usage"),
4usize => ::core::option::Option::Some("enable_raytracing"),
5usize =>
::core::option::Option::Some("attribute_compression"),
6usize => ::core::option::Option::Some("final_aabb"),
7usize => ::core::option::Option::Some("final_uv_ranges"),
8usize =>
::core::option::Option::Some("skinned_mesh_bounds"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"indices" => ::core::option::Option::Some(0usize),
"morph_targets" => ::core::option::Option::Some(1usize),
"morph_target_names" =>
::core::option::Option::Some(2usize),
"asset_usage" => ::core::option::Option::Some(3usize),
"enable_raytracing" => ::core::option::Option::Some(4usize),
"attribute_compression" =>
::core::option::Option::Some(5usize),
"final_aabb" => ::core::option::Option::Some(6usize),
"final_uv_ranges" => ::core::option::Option::Some(7usize),
"skinned_mesh_bounds" =>
::core::option::Option::Some(8usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 9usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("indices",
bevy_reflect::PartialReflect::to_dynamic(&self.indices)?);
dynamic.insert_boxed("morph_targets",
bevy_reflect::PartialReflect::to_dynamic(&self.morph_targets)?);
dynamic.insert_boxed("morph_target_names",
bevy_reflect::PartialReflect::to_dynamic(&self.morph_target_names)?);
dynamic.insert_boxed("asset_usage",
bevy_reflect::PartialReflect::to_dynamic(&self.asset_usage)?);
dynamic.insert_boxed("enable_raytracing",
bevy_reflect::PartialReflect::to_dynamic(&self.enable_raytracing)?);
dynamic.insert_boxed("attribute_compression",
bevy_reflect::PartialReflect::to_dynamic(&self.attribute_compression)?);
dynamic.insert_boxed("final_aabb",
bevy_reflect::PartialReflect::to_dynamic(&self.final_aabb)?);
dynamic.insert_boxed("final_uv_ranges",
bevy_reflect::PartialReflect::to_dynamic(&self.final_uv_ranges)?);
dynamic.insert_boxed("skinned_mesh_bounds",
bevy_reflect::PartialReflect::to_dynamic(&self.skinned_mesh_bounds)?);
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for Mesh where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::structs::struct_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for Mesh where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
indices: <MeshExtractableData<Indices> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"indices")?)?,
morph_targets: <MeshExtractableData<Vec<MorphAttributes>> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"morph_targets")?)?,
morph_target_names: <MeshExtractableData<Vec<String>> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"morph_target_names")?)?,
asset_usage: <RenderAssetUsages as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"asset_usage")?)?,
enable_raytracing: <bool as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"enable_raytracing")?)?,
attribute_compression: <MeshAttributeCompressionFlags as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"attribute_compression")?)?,
final_aabb: <Option<Aabb3d> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"final_aabb")?)?,
final_uv_ranges: <[Option<Aabb2d>; 2] as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"final_uv_ranges")?)?,
skinned_mesh_bounds: <Option<SkinnedMeshBounds> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"skinned_mesh_bounds")?)?,
primitive_topology: ::core::default::Default::default(),
attributes: ::core::default::Default::default(),
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Mesh { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Mesh {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.enable_raytracing == other.enable_raytracing &&
self.primitive_topology == other.primitive_topology &&
self.attributes == other.attributes &&
self.indices == other.indices &&
self.morph_targets == other.morph_targets &&
self.morph_target_names == other.morph_target_names &&
self.asset_usage == other.asset_usage &&
self.attribute_compression == other.attribute_compression &&
self.final_aabb == other.final_aabb &&
self.final_uv_ranges == other.final_uv_ranges &&
self.skinned_mesh_bounds == other.skinned_mesh_bounds
}
}PartialEq)]
229#[reflect(Clone)]
230pub struct Mesh {
231#[reflect(ignore, clone)]
232primitive_topology: PrimitiveTopology,
233/// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
234 /// for this mesh. Attribute ids to attribute values.
235 /// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
236 /// which allows easy stable `VertexBuffers` (i.e. same buffer order)
237#[reflect(ignore, clone)]
238attributes: MeshExtractableData<BTreeMap<MeshVertexAttributeId, MeshAttributeData>>,
239 indices: MeshExtractableData<Indices>,
240#[cfg(feature = "morph")]
241morph_targets: MeshExtractableData<Vec<MorphAttributes>>,
242#[cfg(feature = "morph")]
243morph_target_names: MeshExtractableData<Vec<String>>,
244pub asset_usage: RenderAssetUsages,
245/// Whether or not to build a BLAS for use with `bevy_solari` raytracing.
246 ///
247 /// Note that this is _not_ whether the mesh is _compatible_ with `bevy_solari` raytracing.
248 /// This field just controls whether or not a BLAS gets built for this mesh, assuming that
249 /// the mesh is compatible.
250 ///
251 /// The use case for this field is using lower-resolution proxy meshes for raytracing (to save on BLAS memory usage),
252 /// while using higher-resolution meshes for raster. You can set this field to true for the lower-resolution proxy mesh,
253 /// and to false for the high-resolution raster mesh.
254 ///
255 /// Alternatively, you can use the same mesh for both raster and raytracing, with this field set to true.
256 ///
257 /// Does nothing if not used with `bevy_solari`, or if the mesh is not compatible
258 /// with `bevy_solari` (see `bevy_solari`'s docs).
259pub enable_raytracing: bool,
260/// Indicate whether vertex attributes are compressed.
261attribute_compression: MeshAttributeCompressionFlags,
262/// Precomputed min and max extents of the mesh position data. Used mainly for constructing `Aabb`s for frustum culling and decompressing vertex positions.
263 /// This data will be set if/when a mesh is extracted to the GPU or when compressing positions.
264pub final_aabb: Option<Aabb3d>,
265/// Precomputed min and max extents of the mesh UV channels data. Used mainly for decompressing vertex UVs.
266 /// This will be set when compressing UVs.
267pub final_uv_ranges: [Option<Aabb2d>; 2],
268 skinned_mesh_bounds: Option<SkinnedMeshBounds>,
269}
270271/// Mesh compression arguments used in [`Mesh::compressed_mesh`].
272#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MeshCompressionArgs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"MeshCompressionArgs", "compress_indices", &self.compress_indices,
"quantize_attributes", &self.quantize_attributes,
"compress_attributes", &&self.compress_attributes)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshCompressionArgs {
#[inline]
fn clone(&self) -> Self {
Self {
compress_indices: ::core::clone::Clone::clone(&self.compress_indices),
quantize_attributes: ::core::clone::Clone::clone(&self.quantize_attributes),
compress_attributes: ::core::clone::Clone::clone(&self.compress_attributes),
}
}
}Clone)]
273#[cfg_attr(feature = "serialize", derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for MeshCompressionArgs {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer,
"MeshCompressionArgs", false as usize + 1 + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"compress_indices", &self.compress_indices)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"quantize_attributes", &self.quantize_attributes)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"compress_attributes", &self.compress_attributes)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for MeshCompressionArgs {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __field2, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private229::Ok(__Field::__field0),
1u64 => _serde::__private229::Ok(__Field::__field1),
2u64 => _serde::__private229::Ok(__Field::__field2),
_ => _serde::__private229::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"compress_indices" =>
_serde::__private229::Ok(__Field::__field0),
"quantize_attributes" =>
_serde::__private229::Ok(__Field::__field1),
"compress_attributes" =>
_serde::__private229::Ok(__Field::__field2),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"compress_indices" =>
_serde::__private229::Ok(__Field::__field0),
b"quantize_attributes" =>
_serde::__private229::Ok(__Field::__field1),
b"compress_attributes" =>
_serde::__private229::Ok(__Field::__field2),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<MeshCompressionArgs>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = MeshCompressionArgs;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"struct MeshCompressionArgs")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"struct MeshCompressionArgs with 3 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<Cow<'static,
[(MeshVertexAttributeId,
AttributeQuantization)]>>(&mut __seq)? {
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(1usize,
&"struct MeshCompressionArgs with 3 elements")),
};
let __field2 =
match _serde::de::SeqAccess::next_element::<MeshAttributeCompressionFlags>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(2usize,
&"struct MeshCompressionArgs with 3 elements")),
};
_serde::__private229::Ok(MeshCompressionArgs {
compress_indices: __field0,
quantize_attributes: __field1,
compress_attributes: __field2,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0: _serde::__private229::Option<bool> =
_serde::__private229::None;
let mut __field1:
_serde::__private229::Option<Cow<'static,
[(MeshVertexAttributeId, AttributeQuantization)]>> =
_serde::__private229::None;
let mut __field2:
_serde::__private229::Option<MeshAttributeCompressionFlags> =
_serde::__private229::None;
while let _serde::__private229::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private229::Option::is_some(&__field0) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("compress_indices"));
}
__field0 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private229::Option::is_some(&__field1) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("quantize_attributes"));
}
__field1 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Cow<'static,
[(MeshVertexAttributeId,
AttributeQuantization)]>>(&mut __map)?);
}
__Field::__field2 => {
if _serde::__private229::Option::is_some(&__field2) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("compress_attributes"));
}
__field2 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<MeshAttributeCompressionFlags>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private229::Some(__field0) => __field0,
_serde::__private229::None =>
_serde::__private229::de::missing_field("compress_indices")?,
};
let __field1 =
match __field1 {
_serde::__private229::Some(__field1) => __field1,
_serde::__private229::None =>
_serde::__private229::de::missing_field("quantize_attributes")?,
};
let __field2 =
match __field2 {
_serde::__private229::Some(__field2) => __field2,
_serde::__private229::None =>
_serde::__private229::de::missing_field("compress_attributes")?,
};
_serde::__private229::Ok(MeshCompressionArgs {
compress_indices: __field0,
quantize_attributes: __field1,
compress_attributes: __field2,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] =
&["compress_indices", "quantize_attributes",
"compress_attributes"];
_serde::Deserializer::deserialize_struct(__deserializer,
"MeshCompressionArgs", FIELDS,
__Visitor {
marker: _serde::__private229::PhantomData::<MeshCompressionArgs>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};Deserialize))]
274pub struct MeshCompressionArgs {
275/// Whether to compress indices to [`Indices::U16`] when possible.
276pub compress_indices: bool,
277/// Quantize Float32 to smaller types for some attributes. No change is needed in shaders.
278pub quantize_attributes: Cow<'static, [(MeshVertexAttributeId, AttributeQuantization)]>,
279/// Compress some attributes to smaller representation. Shaders need change to decode them correctly.
280 /// See [`MeshAttributeCompressionFlags`] for the details.
281pub compress_attributes: MeshAttributeCompressionFlags,
282}
283284impl MeshCompressionArgs {
285/// None of compression/quantization is enabled.
286pub fn none() -> Self {
287Self {
288 compress_indices: false,
289 quantize_attributes: (&[]).into(),
290 compress_attributes: MeshAttributeCompressionFlags::empty(),
291 }
292 }
293294/// Compression with all attributes compressed and with colors quantized to unorm8 and joint weights quantized to unorm16.
295pub fn regular() -> Self {
296Self {
297 compress_indices: true,
298 quantize_attributes: (&[
299// Unorm8 is chosen by default as glTF vertex color is clamped to [0, 1] and HDR vertex color isn't common.
300(Mesh::ATTRIBUTE_COLOR.id, AttributeQuantization::Unorm8),
301 (
302Mesh::ATTRIBUTE_JOINT_WEIGHT.id,
303 AttributeQuantization::Unorm16,
304 ),
305 ])
306 .into(),
307 compress_attributes: MeshAttributeCompressionFlags::all(),
308 }
309 }
310}
311312#[doc = r" If the corresponding attribute compression is enabled:"]
#[doc =
r" - Position will be Snorm16x4 relative to the mesh's AABB. The w component is unused."]
#[doc =
r" - Normal and tangent will be Snorm16x2 with octahedral encoding, using [`octahedral_encode_signed`] and [`octahedral_encode_tangent`]."]
#[doc =
r" - UV0 and UV1 will be Unorm16x2. UVs are remapped based on their min/max values so they can go beyond [0, 1], though a larger range will reduce precision."]
#[doc = r""]
#[doc =
r" [`octahedral_encode_signed`]: crate::vertex::octahedral_encode_signed"]
#[doc =
r" [`octahedral_encode_tangent`]: crate::vertex::octahedral_encode_tangent"]
#[repr(transparent)]
#[reflect(opaque)]
#[reflect(Hash, Clone, PartialEq, Debug)]
pub struct MeshAttributeCompressionFlags(<MeshAttributeCompressionFlags as
::bitflags::__private::PublicFlags>::Internal);
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for MeshAttributeCompressionFlags {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
_serde::Serializer::serialize_newtype_struct(__serializer,
"MeshAttributeCompressionFlags", &self.0)
}
}
};
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for MeshAttributeCompressionFlags {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<MeshAttributeCompressionFlags>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = MeshAttributeCompressionFlags;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"tuple struct MeshAttributeCompressionFlags")
}
#[inline]
fn visit_newtype_struct<__E>(self, __e: __E)
-> _serde::__private229::Result<Self::Value, __E::Error>
where __E: _serde::Deserializer<'de> {
let __field0:
<MeshAttributeCompressionFlags as
::bitflags::__private::PublicFlags>::Internal =
<<MeshAttributeCompressionFlags as
::bitflags::__private::PublicFlags>::Internal as
_serde::Deserialize>::deserialize(__e)?;
_serde::__private229::Ok(MeshAttributeCompressionFlags(__field0))
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<<MeshAttributeCompressionFlags
as
::bitflags::__private::PublicFlags>::Internal>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"tuple struct MeshAttributeCompressionFlags with 1 element")),
};
_serde::__private229::Ok(MeshAttributeCompressionFlags(__field0))
}
}
_serde::Deserializer::deserialize_newtype_struct(__deserializer,
"MeshAttributeCompressionFlags",
__Visitor {
marker: _serde::__private229::PhantomData::<MeshAttributeCompressionFlags>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};
#[automatically_derived]
impl ::core::hash::Hash for MeshAttributeCompressionFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for MeshAttributeCompressionFlags { }
#[automatically_derived]
impl ::core::clone::Clone for MeshAttributeCompressionFlags {
#[inline]
fn clone(&self) -> Self {
let _:
::core::clone::AssertParamIsClone<<MeshAttributeCompressionFlags
as ::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for MeshAttributeCompressionFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for MeshAttributeCompressionFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for MeshAttributeCompressionFlags {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for MeshAttributeCompressionFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<<MeshAttributeCompressionFlags as
::bitflags::__private::PublicFlags>::Internal>;
}
}
#[automatically_derived]
impl ::core::fmt::Debug for MeshAttributeCompressionFlags {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MeshAttributeCompressionFlags", &&self.0)
}
}
const _: () =
{
impl bevy_reflect::GetTypeRegistration for
MeshAttributeCompressionFlags where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for MeshAttributeCompressionFlags where {
fn type_path() -> &'static str {
"bevy_mesh::mesh::MeshAttributeCompressionFlags"
}
fn short_type_path() -> &'static str {
"MeshAttributeCompressionFlags"
}
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("MeshAttributeCompressionFlags")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl bevy_reflect::Typed for MeshAttributeCompressionFlags where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
let info = bevy_reflect::OpaqueInfo::new::<Self>();
bevy_reflect::TypeInfo::Opaque(bevy_reflect::OpaqueInfo::new::<Self>())
})
}
}
impl bevy_reflect::Reflect for MeshAttributeCompressionFlags where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
#[allow(non_upper_case_globals)]
const _: () =
{
static __INVENTORY: ::inventory::Node =
::inventory::Node {
value: &{
bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<MeshAttributeCompressionFlags
as
bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
},
next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
};
#[link_section = ".text.startup"]
unsafe extern "C" fn __ctor() {
unsafe {
::inventory::ErasedNode::submit(__INVENTORY.value,
&__INVENTORY)
}
}
#[used]
#[link_section = ".init_array"]
static __CTOR: unsafe extern "C" fn() = __ctor;
};
impl bevy_reflect::PartialReflect for MeshAttributeCompressionFlags
where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn to_dynamic(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let ::core::option::Option::Some(value) =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value)
{
*self = ::core::clone::Clone::clone(value);
return ::core::result::Result::Ok(());
}
::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedTypes {
from_type: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(value)),
to_type: ::core::convert::Into::into(<Self as
bevy_reflect::TypePath>::type_path()),
})
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Opaque
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Opaque(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Opaque(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Opaque(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_hash(&self) -> ::core::option::Option<u64> {
use ::core::hash::{Hash, Hasher};
let mut hasher = bevy_reflect::utility::reflect_hasher();
Hash::hash(&::core::any::Any::type_id(self), &mut hasher);
Hash::hash(self, &mut hasher);
::core::option::Option::Some(Hasher::finish(&hasher))
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
let value =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
if let ::core::option::Option::Some(value) = value {
::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
value))
} else { ::core::option::Option::Some(false) }
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for MeshAttributeCompressionFlags where
{
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
::core::option::Option::Some(::core::clone::Clone::clone(<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<MeshAttributeCompressionFlags>(reflect)?))
}
}
};
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl MeshAttributeCompressionFlags {
pub const COMPRESS_POSITION: Self = Self::from_bits_retain(1 << 0);
pub const COMPRESS_NORMAL: Self = Self::from_bits_retain(1 << 1);
pub const COMPRESS_TANGENT: Self = Self::from_bits_retain(1 << 2);
pub const COMPRESS_UV0: Self = Self::from_bits_retain(1 << 3);
pub const COMPRESS_UV1: Self = Self::from_bits_retain(1 << 4);
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl ::bitflags::Flags for MeshAttributeCompressionFlags {
const FLAGS: &'static [::bitflags::Flag<MeshAttributeCompressionFlags>] =
{
mod __bitflags_flag_names {
#[allow(unused_imports)]
use super::*;
pub(super) const COMPRESS_POSITION: &'static str =
"COMPRESS_POSITION";
pub(super) const COMPRESS_NORMAL: &'static str =
"COMPRESS_NORMAL";
pub(super) const COMPRESS_TANGENT: &'static str =
"COMPRESS_TANGENT";
pub(super) const COMPRESS_UV0: &'static str = "COMPRESS_UV0";
pub(super) const COMPRESS_UV1: &'static str = "COMPRESS_UV1";
}
&[{
::bitflags::Flag::new(__bitflags_flag_names::COMPRESS_POSITION,
MeshAttributeCompressionFlags::COMPRESS_POSITION)
},
{
::bitflags::Flag::new(__bitflags_flag_names::COMPRESS_NORMAL,
MeshAttributeCompressionFlags::COMPRESS_NORMAL)
},
{
::bitflags::Flag::new(__bitflags_flag_names::COMPRESS_TANGENT,
MeshAttributeCompressionFlags::COMPRESS_TANGENT)
},
{
::bitflags::Flag::new(__bitflags_flag_names::COMPRESS_UV0,
MeshAttributeCompressionFlags::COMPRESS_UV0)
},
{
::bitflags::Flag::new(__bitflags_flag_names::COMPRESS_UV1,
MeshAttributeCompressionFlags::COMPRESS_UV1)
}]
};
type Bits = u8;
fn bits(&self) -> u8 { MeshAttributeCompressionFlags::bits(self) }
fn from_bits_retain(bits: u8) -> MeshAttributeCompressionFlags {
MeshAttributeCompressionFlags::from_bits_retain(bits)
}
fn all_named() -> MeshAttributeCompressionFlags {
const ALL_NAMED: u8 =
{
let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
&<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
let _ = i;
truncated
};
MeshAttributeCompressionFlags::from_bits_retain(ALL_NAMED)
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
pub struct InternalBitFlags(u8);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self,
other))
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::bitflags::__private::PublicFlags for
MeshAttributeCompressionFlags {
type Primitive = u8;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u8 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&MeshAttributeCompressionFlags(*self),
f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<MeshAttributeCompressionFlags>(s).map(|flags|
flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u8> for
InternalBitFlags {
fn as_ref(&self) -> &u8 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u8> for
InternalBitFlags {
fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
}
impl InternalBitFlags {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self {
Self(<u8 as ::bitflags::Bits>::EMPTY)
}
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self {
const ALL: InternalBitFlags =
{
let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
let mut _i = 0;
{
{
truncated |=
<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<MeshAttributeCompressionFlags as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
InternalBitFlags(truncated)
};
ALL
}
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0 }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(bits & Self::all().0)
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
mod __bitflags_flag_names {
#[allow(unused_imports)]
use super::*;
pub(super) const COMPRESS_POSITION: &'static str =
"COMPRESS_POSITION";
pub(super) const COMPRESS_NORMAL: &'static str =
"COMPRESS_NORMAL";
pub(super) const COMPRESS_TANGENT: &'static str =
"COMPRESS_TANGENT";
pub(super) const COMPRESS_UV0: &'static str =
"COMPRESS_UV0";
pub(super) const COMPRESS_UV1: &'static str =
"COMPRESS_UV1";
}
{
{
if name == __bitflags_flag_names::COMPRESS_POSITION {
return ::bitflags::__private::core::option::Option::Some(Self(MeshAttributeCompressionFlags::COMPRESS_POSITION.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::COMPRESS_NORMAL {
return ::bitflags::__private::core::option::Option::Some(Self(MeshAttributeCompressionFlags::COMPRESS_NORMAL.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::COMPRESS_TANGENT {
return ::bitflags::__private::core::option::Option::Some(Self(MeshAttributeCompressionFlags::COMPRESS_TANGENT.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::COMPRESS_UV0 {
return ::bitflags::__private::core::option::Option::Some(Self(MeshAttributeCompressionFlags::COMPRESS_UV0.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::COMPRESS_UV1 {
return ::bitflags::__private::core::option::Option::Some(Self(MeshAttributeCompressionFlags::COMPRESS_UV1.bits()));
}
};
};
let _ = name;
::bitflags::__private::core::option::Option::None
}
/// Whether all bits in `self` are unset.
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
/// Whether any set bits in `other` are also set in `self`.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all set bits in `other` are also set in `self`.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<MeshAttributeCompressionFlags> {
::bitflags::iter::Iter::__private_const_new(<MeshAttributeCompressionFlags
as ::bitflags::Flags>::FLAGS,
MeshAttributeCompressionFlags::from_bits_retain(self.bits()),
MeshAttributeCompressionFlags::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
->
::bitflags::iter::IterNames<MeshAttributeCompressionFlags> {
::bitflags::iter::IterNames::__private_const_new(<MeshAttributeCompressionFlags
as ::bitflags::Flags>::FLAGS,
MeshAttributeCompressionFlags::from_bits_retain(self.bits()),
MeshAttributeCompressionFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = MeshAttributeCompressionFlags;
type IntoIter =
::bitflags::iter::Iter<MeshAttributeCompressionFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
/// Returns a mutable reference to the raw value of the flags currently stored.
#[inline]
pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
}
impl ::bitflags::__private::serde::Serialize for InternalBitFlags {
fn serialize<S: ::bitflags::__private::serde::Serializer>(&self,
serializer: S)
->
::bitflags::__private::core::result::Result<S::Ok,
S::Error> {
::bitflags::serde::serialize(&MeshAttributeCompressionFlags::from_bits_retain(self.bits()),
serializer)
}
}
impl<'de> ::bitflags::__private::serde::Deserialize<'de> for
InternalBitFlags {
fn deserialize<D: ::bitflags::__private::serde::Deserializer<'de>>(deserializer:
D)
->
::bitflags::__private::core::result::Result<Self,
D::Error> {
let flags: MeshAttributeCompressionFlags =
::bitflags::serde::deserialize(deserializer)?;
::bitflags::__private::core::result::Result::Ok(flags.0)
}
}
impl MeshAttributeCompressionFlags {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0.bits() }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Whether all bits in `self` are unset.
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
/// Whether any set bits in `other` are also set in `self`.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
/// Whether all set bits in `other` are also set in `self`.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for
MeshAttributeCompressionFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for
MeshAttributeCompressionFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for
MeshAttributeCompressionFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for
MeshAttributeCompressionFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for
MeshAttributeCompressionFlags {
type Output = Self;
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor(self, other: MeshAttributeCompressionFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
MeshAttributeCompressionFlags {
/// The bitwise or (`|`) of the bits in `self` and `other`.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for
MeshAttributeCompressionFlags {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
MeshAttributeCompressionFlags {
/// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for
MeshAttributeCompressionFlags {
type Output = Self;
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
MeshAttributeCompressionFlags {
/// The bitwise and (`&`) of the bits in `self` and `other`.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for
MeshAttributeCompressionFlags {
type Output = Self;
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for
MeshAttributeCompressionFlags {
/// The intersection of `self` with the complement of `other` (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for
MeshAttributeCompressionFlags {
type Output = Self;
/// The bitwise negation (`!`) of the bits in `self`, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<MeshAttributeCompressionFlags>
for MeshAttributeCompressionFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<MeshAttributeCompressionFlags>
for MeshAttributeCompressionFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl MeshAttributeCompressionFlags {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<MeshAttributeCompressionFlags> {
::bitflags::iter::Iter::__private_const_new(<MeshAttributeCompressionFlags
as ::bitflags::Flags>::FLAGS,
MeshAttributeCompressionFlags::from_bits_retain(self.bits()),
MeshAttributeCompressionFlags::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
->
::bitflags::iter::IterNames<MeshAttributeCompressionFlags> {
::bitflags::iter::IterNames::__private_const_new(<MeshAttributeCompressionFlags
as ::bitflags::Flags>::FLAGS,
MeshAttributeCompressionFlags::from_bits_retain(self.bits()),
MeshAttributeCompressionFlags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
MeshAttributeCompressionFlags {
type Item = MeshAttributeCompressionFlags;
type IntoIter =
::bitflags::iter::Iter<MeshAttributeCompressionFlags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};bitflags::bitflags! {
313/// If the corresponding attribute compression is enabled:
314 /// - Position will be Snorm16x4 relative to the mesh's AABB. The w component is unused.
315 /// - Normal and tangent will be Snorm16x2 with octahedral encoding, using [`octahedral_encode_signed`] and [`octahedral_encode_tangent`].
316 /// - UV0 and UV1 will be Unorm16x2. UVs are remapped based on their min/max values so they can go beyond [0, 1], though a larger range will reduce precision.
317 ///
318 /// [`octahedral_encode_signed`]: crate::vertex::octahedral_encode_signed
319 /// [`octahedral_encode_tangent`]: crate::vertex::octahedral_encode_tangent
320#[repr(transparent)]
321 #[derive(Hash, Clone, Copy, PartialEq, Eq, Debug, Reflect)]
322 #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
323 #[reflect(opaque)]
324 #[reflect(Hash, Clone, PartialEq, Debug)]
325pub struct MeshAttributeCompressionFlags: u8 {
326const COMPRESS_POSITION = 1 << 0;
327const COMPRESS_NORMAL = 1 << 1;
328const COMPRESS_TANGENT = 1 << 2;
329const COMPRESS_UV0 = 1 << 3;
330const COMPRESS_UV1 = 1 << 4;
331 }
332}333334impl Mesh {
335/// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
336 /// or [`Mesh::with_inserted_attribute`].
337 ///
338 /// The format of this attribute is [`VertexFormat::Float32x3`].
339pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
340MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
341342/// The direction the vertex normal is facing in.
343 /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
344 ///
345 /// The format of this attribute is [`VertexFormat::Float32x3`].
346pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
347MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
348349/// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
350 /// or [`Mesh::with_inserted_attribute`].
351 ///
352 /// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
353 ///
354 /// By default values outside will be clamped per pixel not for the vertex,
355 /// "stretching" the borders of the texture.
356 /// This behavior can be useful in some cases, usually when the borders have only
357 /// one color, for example a logo, and you want to "extend" those borders.
358 ///
359 /// For different mapping outside of `0..=1` range,
360 /// see [`ImageAddressMode`](https://docs.rs/bevy_image/latest/bevy_image/enum.ImageAddressMode.html).
361 ///
362 /// The format of this attribute is [`VertexFormat::Float32x2`].
363pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
364MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
365366/// Alternate texture coordinates for the vertex. Use in conjunction with
367 /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
368 ///
369 /// Typically, these are used for lightmaps, textures that provide
370 /// precomputed illumination.
371 ///
372 /// The format of this attribute is [`VertexFormat::Float32x2`].
373pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
374MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
375376/// The direction of the vertex tangent. Used for normal mapping.
377 /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
378 /// [`with_generated_tangents`](Mesh::with_generated_tangents).
379 ///
380 /// The format of this attribute is [`VertexFormat::Float32x4`].
381pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
382MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
383384/// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
385 /// or [`Mesh::with_inserted_attribute`].
386 ///
387 /// The format of this attribute is [`VertexFormat::Float32x4`].
388pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
389MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
390391/// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
392 /// or [`Mesh::with_inserted_attribute`].
393 ///
394 /// The format of this attribute is [`VertexFormat::Float32x4`].
395pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
396MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
397398/// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
399 /// or [`Mesh::with_inserted_attribute`].
400 ///
401 /// The format of this attribute is [`VertexFormat::Uint16x4`].
402pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
403MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
404405/// The first index that can be used for custom vertex attributes.
406 /// Only the attributes with an index below this are used by Bevy.
407pub const FIRST_AVAILABLE_CUSTOM_ATTRIBUTE: u64 = 8;
408409/// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
410 /// renderer knows how to treat the vertex data. Most of the time this will be
411 /// [`PrimitiveTopology::TriangleList`].
412pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
413Mesh {
414primitive_topology,
415 attributes: MeshExtractableData::Data(Default::default()),
416 indices: MeshExtractableData::NoData,
417#[cfg(feature = "morph")]
418morph_targets: MeshExtractableData::NoData,
419#[cfg(feature = "morph")]
420morph_target_names: MeshExtractableData::NoData,
421asset_usage,
422 enable_raytracing: true,
423 attribute_compression: MeshAttributeCompressionFlags::empty(),
424 final_aabb: None,
425 skinned_mesh_bounds: None,
426 final_uv_ranges: [None; 2],
427 }
428 }
429430/// Returns the topology of the mesh.
431pub fn primitive_topology(&self) -> PrimitiveTopology {
432self.primitive_topology
433 }
434435/// Sets the data for a vertex attribute (position, normal, etc.). The name will
436 /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
437 ///
438 /// `Aabb` of entities with modified mesh are not updated automatically.
439 ///
440 /// # Panics
441 /// Panics when the format of the values does not match the attribute's format.
442 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
443 /// this as an error use [`Mesh::try_insert_attribute`]
444#[inline]
445pub fn insert_attribute(
446&mut self,
447 attribute: MeshVertexAttribute,
448 values: impl Into<VertexAttributeValues>,
449 ) {
450self.try_insert_attribute(attribute, values)
451 .expect(MESH_EXTRACTED_ERROR);
452 }
453454/// Sets the data for a vertex attribute (position, normal, etc.). The name will
455 /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
456 ///
457 /// `Aabb` of entities with modified mesh are not updated automatically.
458 ///
459 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
460 ///
461 /// # Panics
462 /// Panics when the format of the values does not match the attribute's format.
463#[inline]
464pub fn try_insert_attribute(
465&mut self,
466 attribute: MeshVertexAttribute,
467 values: impl Into<VertexAttributeValues>,
468 ) -> Result<(), MeshAccessError> {
469let values = values.into();
470let values_format = VertexFormat::from(&values);
471if values_format != attribute.format {
472{
::core::panicking::panic_fmt(format_args!("Failed to insert attribute. Invalid attribute format for {0}. Given format is {2:?} but expected {1:?}",
attribute.name, attribute.format, values_format));
};panic!(
473"Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
474 attribute.name, attribute.format
475 );
476 }
477478self.attributes
479 .as_mut()?
480.insert(attribute.id, MeshAttributeData { attribute, values });
481Ok(())
482 }
483484/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
485 /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
486 ///
487 /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
488 ///
489 /// `Aabb` of entities with modified mesh are not updated automatically.
490 ///
491 /// # Panics
492 /// Panics when the format of the values does not match the attribute's format.
493 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
494 /// this as an error use [`Mesh::try_with_inserted_attribute`]
495#[must_use]
496 #[inline]
497pub fn with_inserted_attribute(
498mut self,
499 attribute: MeshVertexAttribute,
500 values: impl Into<VertexAttributeValues>,
501 ) -> Self {
502self.insert_attribute(attribute, values);
503self504 }
505506/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
507 /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
508 ///
509 /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
510 ///
511 /// `Aabb` of entities with modified mesh are not updated automatically.
512 ///
513 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
514#[inline]
515pub fn try_with_inserted_attribute(
516mut self,
517 attribute: MeshVertexAttribute,
518 values: impl Into<VertexAttributeValues>,
519 ) -> Result<Self, MeshAccessError> {
520self.try_insert_attribute(attribute, values)?;
521Ok(self)
522 }
523524/// Removes the data for a vertex attribute
525 ///
526 /// # Panics
527 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
528 /// this as an error use [`Mesh::try_remove_attribute`]
529pub fn remove_attribute(
530&mut self,
531 attribute: impl Into<MeshVertexAttributeId>,
532 ) -> Option<VertexAttributeValues> {
533self.attributes
534 .as_mut()
535 .expect(MESH_EXTRACTED_ERROR)
536 .remove(&attribute.into())
537 .map(|data| data.values)
538 }
539540/// Removes the data for a vertex attribute
541 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
542 /// if the attribute does not exist.
543pub fn try_remove_attribute(
544&mut self,
545 attribute: impl Into<MeshVertexAttributeId>,
546 ) -> Result<VertexAttributeValues, MeshAccessError> {
547Ok(self
548.attributes
549 .as_mut()?
550.remove(&attribute.into())
551 .ok_or(MeshAccessError::NotFound)?
552.values)
553 }
554555/// Consumes the mesh and returns a mesh without the data for a vertex attribute
556 ///
557 /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
558 ///
559 /// # Panics
560 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
561 /// this as an error use [`Mesh::try_with_removed_attribute`]
562#[must_use]
563pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
564self.remove_attribute(attribute);
565self566 }
567568/// Consumes the mesh and returns a mesh without the data for a vertex attribute
569 ///
570 /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
571 ///
572 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
573 /// if the attribute does not exist.
574pub fn try_with_removed_attribute(
575mut self,
576 attribute: impl Into<MeshVertexAttributeId>,
577 ) -> Result<Self, MeshAccessError> {
578self.try_remove_attribute(attribute)?;
579Ok(self)
580 }
581582/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
583 ///
584 /// # Panics
585 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
586 /// this as an error use [`Mesh::try_contains_attribute`]
587#[inline]
588pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
589self.attributes
590 .as_ref()
591 .expect(MESH_EXTRACTED_ERROR)
592 .contains_key(&id.into())
593 }
594595/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
596 ///
597 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
598#[inline]
599pub fn try_contains_attribute(
600&self,
601 id: impl Into<MeshVertexAttributeId>,
602 ) -> Result<bool, MeshAccessError> {
603Ok(self.attributes.as_ref()?.contains_key(&id.into()))
604 }
605606/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
607 ///
608 /// # Panics
609 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
610 /// this as an error use [`Mesh::try_attribute`] or [`Mesh::try_attribute_option`]
611#[inline]
612pub fn attribute(
613&self,
614 id: impl Into<MeshVertexAttributeId>,
615 ) -> Option<&VertexAttributeValues> {
616self.try_attribute_option(id).expect(MESH_EXTRACTED_ERROR)
617 }
618619/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
620 ///
621 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
622 /// if the attribute does not exist.
623#[inline]
624pub fn try_attribute(
625&self,
626 id: impl Into<MeshVertexAttributeId>,
627 ) -> Result<&VertexAttributeValues, MeshAccessError> {
628self.try_attribute_option(id)?
629.ok_or(MeshAccessError::NotFound)
630 }
631632/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
633 ///
634 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
635#[inline]
636pub fn try_attribute_option(
637&self,
638 id: impl Into<MeshVertexAttributeId>,
639 ) -> Result<Option<&VertexAttributeValues>, MeshAccessError> {
640Ok(self
641.attributes
642 .as_ref()?
643.get(&id.into())
644 .map(|data| &data.values))
645 }
646647/// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
648#[inline]
649pub(crate) fn try_attribute_data(
650&self,
651 id: impl Into<MeshVertexAttributeId>,
652 ) -> Result<Option<&MeshAttributeData>, MeshAccessError> {
653Ok(self.attributes.as_ref()?.get(&id.into()))
654 }
655656/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
657 ///
658 /// # Panics
659 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
660 /// this as an error use [`Mesh::try_attribute_mut`]
661#[inline]
662pub fn attribute_mut(
663&mut self,
664 id: impl Into<MeshVertexAttributeId>,
665 ) -> Option<&mut VertexAttributeValues> {
666self.try_attribute_mut_option(id)
667 .expect(MESH_EXTRACTED_ERROR)
668 }
669670/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
671 ///
672 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
673 /// if the attribute does not exist.
674#[inline]
675pub fn try_attribute_mut(
676&mut self,
677 id: impl Into<MeshVertexAttributeId>,
678 ) -> Result<&mut VertexAttributeValues, MeshAccessError> {
679self.try_attribute_mut_option(id)?
680.ok_or(MeshAccessError::NotFound)
681 }
682683/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
684 ///
685 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
686#[inline]
687pub fn try_attribute_mut_option(
688&mut self,
689 id: impl Into<MeshVertexAttributeId>,
690 ) -> Result<Option<&mut VertexAttributeValues>, MeshAccessError> {
691Ok(self
692.attributes
693 .as_mut()?
694.get_mut(&id.into())
695 .map(|data| &mut data.values))
696 }
697698/// Returns an iterator that yields references to the data of each vertex attribute.
699 ///
700 /// # Panics
701 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
702 /// this as an error use [`Mesh::try_attributes`]
703pub fn attributes(
704&self,
705 ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
706self.try_attributes().expect(MESH_EXTRACTED_ERROR)
707 }
708709/// Returns an iterator that yields references to the data of each vertex attribute.
710 /// Returns an error if data has been extracted to `RenderWorld`
711pub fn try_attributes(
712&self,
713 ) -> Result<impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)>, MeshAccessError>
714 {
715Ok(self
716.attributes
717 .as_ref()?
718.values()
719 .map(|data| (&data.attribute, &data.values)))
720 }
721722/// Returns an iterator that yields mutable references to the data of each vertex attribute.
723 ///
724 /// # Panics
725 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
726 /// this as an error use [`Mesh::try_attributes_mut`]
727pub fn attributes_mut(
728&mut self,
729 ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
730self.try_attributes_mut().expect(MESH_EXTRACTED_ERROR)
731 }
732733/// Returns an iterator that yields mutable references to the data of each vertex attribute.
734 ///
735 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
736pub fn try_attributes_mut(
737&mut self,
738 ) -> Result<
739impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)>,
740MeshAccessError,
741 > {
742Ok(self
743.attributes
744 .as_mut()?
745.values_mut()
746 .map(|data| (&data.attribute, &mut data.values)))
747 }
748749/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
750 /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
751 /// that use triangles.
752 ///
753 /// # Panics
754 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
755 /// this as an error use [`Mesh::try_insert_indices`]
756#[inline]
757pub fn insert_indices(&mut self, indices: Indices) {
758self.indices
759 .replace(Some(indices))
760 .expect(MESH_EXTRACTED_ERROR);
761 }
762763/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
764 /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
765 /// that use triangles.
766 ///
767 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
768#[inline]
769pub fn try_insert_indices(&mut self, indices: Indices) -> Result<(), MeshAccessError> {
770self.indices.replace(Some(indices))?;
771Ok(())
772 }
773774/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
775 /// are constructed out of the vertex attributes and are therefore only useful for the
776 /// [`PrimitiveTopology`] variants that use triangles.
777 ///
778 /// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
779 ///
780 /// # Panics
781 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
782 /// this as an error use [`Mesh::try_with_inserted_indices`]
783#[must_use]
784 #[inline]
785pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
786self.insert_indices(indices);
787self788 }
789790/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
791 /// are constructed out of the vertex attributes and are therefore only useful for the
792 /// [`PrimitiveTopology`] variants that use triangles.
793 ///
794 /// (Alternatively, you can use [`Mesh::try_insert_indices`] to mutate an existing mesh in-place)
795 ///
796 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
797#[inline]
798pub fn try_with_inserted_indices(mut self, indices: Indices) -> Result<Self, MeshAccessError> {
799self.try_insert_indices(indices)?;
800Ok(self)
801 }
802803/// Retrieves the vertex `indices` of the mesh, returns None if not found.
804 ///
805 /// # Panics
806 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
807 /// this as an error use [`Mesh::try_indices`]
808#[inline]
809pub fn indices(&self) -> Option<&Indices> {
810self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR)
811 }
812813/// Retrieves the vertex `indices` of the mesh.
814 ///
815 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
816 /// if the attribute does not exist.
817#[inline]
818pub fn try_indices(&self) -> Result<&Indices, MeshAccessError> {
819self.indices.as_ref()
820 }
821822/// Retrieves the vertex `indices` of the mesh, returns None if not found.
823 ///
824 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
825#[inline]
826pub fn try_indices_option(&self) -> Result<Option<&Indices>, MeshAccessError> {
827self.indices.as_ref_option()
828 }
829830/// Retrieves the vertex `indices` of the mesh mutably.
831#[inline]
832pub fn indices_mut(&mut self) -> Option<&mut Indices> {
833self.try_indices_mut_option().expect(MESH_EXTRACTED_ERROR)
834 }
835836/// Retrieves the vertex `indices` of the mesh mutably.
837 ///
838 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
839#[inline]
840pub fn try_indices_mut(&mut self) -> Result<&mut Indices, MeshAccessError> {
841self.indices.as_mut()
842 }
843844/// Retrieves the vertex `indices` of the mesh mutably.
845 ///
846 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
847#[inline]
848pub fn try_indices_mut_option(&mut self) -> Result<Option<&mut Indices>, MeshAccessError> {
849self.indices.as_mut_option()
850 }
851852/// Removes the vertex `indices` from the mesh and returns them.
853 ///
854 /// # Panics
855 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
856 /// this as an error use [`Mesh::try_remove_indices`]
857#[inline]
858pub fn remove_indices(&mut self) -> Option<Indices> {
859self.try_remove_indices().expect(MESH_EXTRACTED_ERROR)
860 }
861862/// Removes the vertex `indices` from the mesh and returns them.
863 ///
864 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
865#[inline]
866pub fn try_remove_indices(&mut self) -> Result<Option<Indices>, MeshAccessError> {
867self.indices.replace(None)
868 }
869870/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
871 ///
872 /// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
873 ///
874 /// # Panics
875 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
876 /// this as an error use [`Mesh::try_with_removed_indices`]
877#[must_use]
878pub fn with_removed_indices(mut self) -> Self {
879self.remove_indices();
880self881 }
882883/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
884 ///
885 /// (Alternatively, you can use [`Mesh::try_remove_indices`] to mutate an existing mesh in-place)
886 ///
887 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
888pub fn try_with_removed_indices(mut self) -> Result<Self, MeshAccessError> {
889self.try_remove_indices()?;
890Ok(self)
891 }
892893/// Returns the size of a vertex in bytes.
894 ///
895 /// # Panics
896 /// Panics when the mesh data has already been extracted to `RenderWorld`.
897pub fn get_vertex_size(&self) -> u64 {
898self.attributes
899 .as_ref()
900 .expect(MESH_EXTRACTED_ERROR)
901 .values()
902 .map(|data| data.attribute.format.size())
903 .sum()
904 }
905906/// Returns the size required for the vertex buffer in bytes.
907 ///
908 /// # Panics
909 /// Panics when the mesh data has already been extracted to `RenderWorld`.
910pub fn get_vertex_buffer_size(&self) -> usize {
911let vertex_size = self.get_vertex_size() as usize;
912let vertex_count = self.count_vertices();
913vertex_count * vertex_size914 }
915916/// Computes and returns the index data of the mesh as bytes.
917 /// This is used to transform the index data into a GPU friendly format.
918 ///
919 /// # Panics
920 /// Panics when the mesh data has already been extracted to `RenderWorld`.
921pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
922let mesh_indices = self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR);
923924mesh_indices.as_ref().map(|indices| match &indices {
925 Indices::U16(indices) => cast_slice(&indices[..]),
926 Indices::U32(indices) => cast_slice(&indices[..]),
927 })
928 }
929930/// If any morph displacements are present, returns them as a
931 /// [`MorphAttributes`] array.
932 ///
933 /// # Panics
934 /// Panics when the mesh data has already been extracted to the render
935 /// world.
936#[cfg(feature = "morph")]
937pub fn get_morph_targets(&self) -> Option<&[MorphAttributes]> {
938self.morph_targets
939 .as_ref_option()
940 .expect(MESH_EXTRACTED_ERROR)
941 .map(|morph_attributes| &morph_attributes[..])
942 }
943944/// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
945 ///
946 /// # Panics
947 /// Panics when the mesh data has already been extracted to `RenderWorld`.
948pub fn get_mesh_vertex_buffer_layout(
949&self,
950 mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
951 ) -> MeshVertexBufferLayoutRef {
952let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
953954let mut attributes = Vec::with_capacity(mesh_attributes.len());
955let mut attribute_ids = Vec::with_capacity(mesh_attributes.len());
956let mut accumulated_offset = 0;
957for (index, data) in mesh_attributes.values().enumerate() {
958 attribute_ids.push(data.attribute.id);
959 attributes.push(VertexAttribute {
960 offset: accumulated_offset,
961 format: data.attribute.format,
962 shader_location: index as u32,
963 });
964 accumulated_offset += data.attribute.format.size();
965 }
966967let layout = MeshVertexBufferLayout {
968 layout: VertexBufferLayout {
969 array_stride: accumulated_offset,
970 step_mode: VertexStepMode::Vertex,
971attributes,
972 },
973attribute_ids,
974 attribute_compression: self.attribute_compression,
975 };
976mesh_vertex_buffer_layouts.insert(layout)
977 }
978979/// Counts all vertices of the mesh.
980 ///
981 /// If the attributes have different vertex counts, the smallest is returned.
982 ///
983 /// # Panics
984 /// Panics when the mesh data has already been extracted to `RenderWorld`.
985pub fn count_vertices(&self) -> usize {
986let mut vertex_count: Option<usize> = None;
987let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
988989for (attribute_id, attribute_data) in mesh_attributes {
990let attribute_len = attribute_data.values.len();
991if let Some(previous_vertex_count) = vertex_count {
992if previous_vertex_count != attribute_len {
993let name = mesh_attributes
994 .get(attribute_id)
995 .map(|data| data.attribute.name.to_string())
996 .unwrap_or_else(|| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", attribute_id))
})format!("{attribute_id:?}"));
997998{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event src/mesh.rs:998",
"bevy_mesh::mesh", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("src/mesh.rs"),
::tracing_core::__macro_support::Option::Some(998u32),
::tracing_core::__macro_support::Option::Some("bevy_mesh::mesh"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0} has a different vertex count ({1}) than other attributes ({2}) in this mesh, all attributes will be truncated to match the smallest.",
name, attribute_len, previous_vertex_count) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
999 all attributes will be truncated to match the smallest.");
1000 vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
1001 }
1002 } else {
1003 vertex_count = Some(attribute_len);
1004 }
1005 }
10061007vertex_count.unwrap_or(0)
1008 }
10091010/// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space
1011 ///
1012 /// Returns `None` if `positions` isn't [`VertexAttributeValues::Float32x3`], or if `positions` is empty.
1013fn compute_aabb(positions: &VertexAttributeValues) -> Option<Aabb3d> {
1014match positions {
1015 VertexAttributeValues::Float32x3(val) => {
1016let mut iter = val.iter().map(|a| Vec3A::from_array(*a));
1017let first = iter.next()?;
1018let (min, max) = iter.fold((first, first), |(prev_min, prev_max), point| {
1019 (point.min(prev_min), point.max(prev_max))
1020 });
1021Some(Aabb3d { min, max })
1022 }
1023_ => None,
1024 }
1025 }
10261027/// Compute the UV range.
1028 ///
1029 /// Returns `None` if `uvs` isn't [`VertexAttributeValues::Float32x2`], or if `uvs` is empty.
1030fn compute_uv_range(uvs: &VertexAttributeValues) -> Option<Aabb2d> {
1031match uvs {
1032 VertexAttributeValues::Float32x2(val) => {
1033let mut iter = val.iter().map(|a| Vec2::from_array(*a));
1034let first = iter.next()?;
1035let (min, max) = iter.fold((first, first), |(prev_min, prev_max), point| {
1036 (point.min(prev_min), point.max(prev_max))
1037 });
1038Some(Aabb2d { min, max })
1039 }
1040_ => None,
1041 }
1042 }
10431044/// Compress positions and apply [`MeshAttributeCompressionFlags::COMPRESS_POSITION`].
1045 /// See [`MeshAttributeCompressionFlags`] for the details.
1046 ///
1047 /// Return an error if [`Mesh::ATTRIBUTE_POSITION`] is missing or is empty or is not Float32x3.
1048 ///
1049 /// # Panics
1050 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1051pub fn compress_positions(&mut self) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1052let mut attr = Mesh::ATTRIBUTE_POSITION;
1053let Some(values) = self.attribute(attr) else {
1054return Err(MeshAttributeCompressionError::MissingAttribute(attr.id));
1055 };
1056if values.is_empty() {
1057return Err(MeshAttributeCompressionError::EmptyAttribute(attr));
1058 }
10591060let expected = VertexFormat::Snorm16x4;
1061let Some(aabb) = Self::compute_aabb(values) else {
1062return Err(
1063 MeshAttributeCompressionError::UnsupportedAttributeForCompression {
1064attr,
1065expected,
1066 },
1067 );
1068 };
1069attr.format = expected;
1070self.insert_attribute(
1071attr,
1072values1073 .create_compressed_positions(aabb)
1074 .expect("Compression should succeed since `compute_aabb` is checked above"),
1075 );
1076self.final_aabb = Some(aabb);
1077self.attribute_compression |= MeshAttributeCompressionFlags::COMPRESS_POSITION;
1078Ok(self)
1079 }
10801081fn compress_uvs(
1082&mut self,
1083mut attr: MeshVertexAttribute,
1084 on_compressed: impl Fn(&mut Mesh, Aabb2d),
1085 ) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1086let Some(values) = self.attribute(attr) else {
1087return Err(MeshAttributeCompressionError::MissingAttribute(attr.id));
1088 };
1089if values.is_empty() {
1090return Err(MeshAttributeCompressionError::EmptyAttribute(attr));
1091 }
10921093let expected = VertexFormat::Unorm16x2;
1094let Some(uv_range) = Self::compute_uv_range(values) else {
1095return Err(
1096 MeshAttributeCompressionError::UnsupportedAttributeForCompression {
1097attr,
1098expected,
1099 },
1100 );
1101 };
1102attr.format = expected;
1103self.insert_attribute(
1104attr,
1105values1106 .create_compressed_uvs(uv_range)
1107 .expect("Compression should succeed since `compute_uv_range` is checked above"),
1108 );
1109on_compressed(self, uv_range);
1110Ok(self)
1111 }
11121113/// Compress UV0 and apply [`MeshAttributeCompressionFlags::COMPRESS_UV0`].
1114 /// See [`MeshAttributeCompressionFlags`] for the details.
1115 ///
1116 /// Return an error if [`Mesh::ATTRIBUTE_UV_0`] is missing or is empty or is not Float32x2.
1117 ///
1118 /// # Panics
1119 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1120pub fn compress_uv0(&mut self) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1121self.compress_uvs(Mesh::ATTRIBUTE_UV_0, |mesh, uv_range| {
1122mesh.final_uv_ranges[0] = Some(uv_range);
1123mesh.attribute_compression |= MeshAttributeCompressionFlags::COMPRESS_UV0;
1124 })
1125 }
11261127/// Compress UV1 and apply [`MeshAttributeCompressionFlags::COMPRESS_UV1`].
1128 /// See [`MeshAttributeCompressionFlags`] for the details.
1129 ///
1130 /// Return an error if [`Mesh::ATTRIBUTE_UV_1`] is missing or is empty or is not Float32x2.
1131 ///
1132 /// # Panics
1133 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1134pub fn compress_uv1(&mut self) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1135self.compress_uvs(Mesh::ATTRIBUTE_UV_1, |mesh, uv_range| {
1136mesh.final_uv_ranges[1] = Some(uv_range);
1137mesh.attribute_compression |= MeshAttributeCompressionFlags::COMPRESS_UV1;
1138 })
1139 }
11401141/// Compress normals and apply [`MeshAttributeCompressionFlags::COMPRESS_NORMAL`].
1142 /// See [`MeshAttributeCompressionFlags`] for the details.
1143 ///
1144 /// Return an error if [`Mesh::ATTRIBUTE_NORMAL`] is missing or is not Float32x3.
1145 ///
1146 /// # Panics
1147 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1148pub fn compress_normals(&mut self) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1149let mut attr = Mesh::ATTRIBUTE_NORMAL;
1150let Some(values) = self.attribute(attr) else {
1151return Err(MeshAttributeCompressionError::MissingAttribute(attr.id));
1152 };
11531154let expected = VertexFormat::Snorm16x2;
1155let Some(values) = values.create_octahedral_encode_normals() else {
1156return Err(
1157 MeshAttributeCompressionError::UnsupportedAttributeForCompression {
1158attr,
1159expected,
1160 },
1161 );
1162 };
1163attr.format = expected;
1164self.insert_attribute(attr, values);
1165self.attribute_compression |= MeshAttributeCompressionFlags::COMPRESS_NORMAL;
1166Ok(self)
1167 }
11681169/// Compress tangents and apply [`MeshAttributeCompressionFlags::COMPRESS_TANGENT`].
1170 /// See [`MeshAttributeCompressionFlags`] for the details.
1171 ///
1172 /// Return an error if [`Mesh::ATTRIBUTE_TANGENT`] is missing or is not Float32x4.
1173 ///
1174 /// # Panics
1175 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1176pub fn compress_tangents(&mut self) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1177let mut attr = Mesh::ATTRIBUTE_TANGENT;
1178let Some(values) = self.attribute(attr) else {
1179return Err(MeshAttributeCompressionError::MissingAttribute(attr.id));
1180 };
11811182let expected = VertexFormat::Snorm16x2;
1183let Some(values) = values.create_octahedral_encode_tangents() else {
1184return Err(
1185 MeshAttributeCompressionError::UnsupportedAttributeForCompression {
1186attr,
1187expected,
1188 },
1189 );
1190 };
1191attr.format = expected;
1192self.insert_attribute(attr, values);
1193self.attribute_compression |= MeshAttributeCompressionFlags::COMPRESS_TANGENT;
1194Ok(self)
1195 }
11961197/// Quantize `Float32`, `Float32x2` or `Float32x4` vertex attribute to the format of `quantization`.
1198 ///
1199 /// Return an error if `attr_id` is missing or is not `Float32`, `Float32x2` or `Float32x4`.
1200 ///
1201 /// # Panics
1202 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1203pub fn quantize_float32_attribute(
1204&mut self,
1205 attr_id: impl Into<MeshVertexAttributeId>,
1206 quantization: AttributeQuantization,
1207 ) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1208let attr_id = attr_id.into();
1209let Some(MeshAttributeData { attribute, values }) =
1210self.attributes.as_mut().unwrap().get_mut(&attr_id)
1211else {
1212return Err(MeshAttributeCompressionError::MissingAttribute(attr_id));
1213 };
1214let Some(quantized_values) = values.create_quantized_values(quantization) else {
1215return Err(
1216 MeshAttributeCompressionError::UnsupportedAttributeForQuantizing {
1217 attr: *attribute,
1218 },
1219 );
1220 };
1221attribute.format = (&quantized_values).into();
1222*values = quantized_values;
1223Ok(self)
1224 }
12251226/// Quantize `Float32x4` colors to the format of `quantization` using [`Mesh::quantize_float32_attribute`].
1227 /// [`AttributeQuantization::Unorm8`] is recommended if you don't need higher precision or floating-point range.
1228pub fn quantize_colors(
1229&mut self,
1230 quantization: AttributeQuantization,
1231 ) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1232self.quantize_float32_attribute(Mesh::ATTRIBUTE_COLOR, quantization)
1233 }
12341235/// Quantize `Float32x4` joint weights to the format of `quantization` using [`Mesh::quantize_float32_attribute`].
1236 /// [`AttributeQuantization::Unorm16`] is recommended.
1237pub fn quantize_joint_weights(
1238&mut self,
1239 quantization: AttributeQuantization,
1240 ) -> Result<&mut Mesh, MeshAttributeCompressionError> {
1241self.quantize_float32_attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT, quantization)
1242 }
12431244/// If indices are u32 and vertex count <= 65535, indices will be converted to u16, otherwise this does nothing.
1245 ///
1246 /// # Panics
1247 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1248pub fn compress_indices(&mut self) -> &mut Mesh {
1249// Vertex count should be <= 65535 (max index <= 65534), not 65536 because of primitive restart value.
1250if let Some(Indices::U32(indices)) = self.indices()
1251 && self.count_vertices() <= 65535
1252{
1253self.insert_indices(Indices::U16(
1254indices.iter().map(|idx| *idxas u16).collect(),
1255 ));
1256 }
1257self1258 }
12591260/// Compress the mesh with [`MeshCompressionArgs`] using `Mesh::compress_*` and `Mesh::quantize_*` methods.
1261 ///
1262 /// If any compression error except [`MeshAttributeCompressionError::MissingAttribute`] (which is ignored) occurs,
1263 /// returns a `Vec` of the errors.
1264 ///
1265 /// This is best-effort: any failed compression won't prevent other compressions.
1266 ///
1267 /// # Panics
1268 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1269pub fn compress_mesh(
1270&mut self,
1271 args: &MeshCompressionArgs,
1272 ) -> Result<(), Vec<MeshAttributeCompressionError>> {
1273let mut errors = Vec::new();
1274let mut push_error_ignore_missing_attribute =
1275 |res: Result<&mut Mesh, MeshAttributeCompressionError>| {
1276match res {
1277Ok(_) => {}
1278Err(err) => match err {
1279 MeshAttributeCompressionError::MissingAttribute(_) => {}
1280 e => errors.push(e),
1281 },
1282 };
1283 };
12841285if args1286 .compress_attributes
1287 .contains(MeshAttributeCompressionFlags::COMPRESS_POSITION)
1288 {
1289push_error_ignore_missing_attribute(self.compress_positions());
1290 }
1291if args1292 .compress_attributes
1293 .contains(MeshAttributeCompressionFlags::COMPRESS_NORMAL)
1294 {
1295push_error_ignore_missing_attribute(self.compress_normals());
1296 }
1297if args1298 .compress_attributes
1299 .contains(MeshAttributeCompressionFlags::COMPRESS_TANGENT)
1300 {
1301push_error_ignore_missing_attribute(self.compress_tangents());
1302 }
1303if args1304 .compress_attributes
1305 .contains(MeshAttributeCompressionFlags::COMPRESS_UV0)
1306 {
1307push_error_ignore_missing_attribute(self.compress_uv0());
1308 }
1309if args1310 .compress_attributes
1311 .contains(MeshAttributeCompressionFlags::COMPRESS_UV1)
1312 {
1313push_error_ignore_missing_attribute(self.compress_uv1());
1314 }
1315for (attr, quantization) in args.quantize_attributes.iter().copied() {
1316 push_error_ignore_missing_attribute(
1317self.quantize_float32_attribute(attr, quantization),
1318 );
1319 }
1320if args.compress_indices {
1321self.compress_indices();
1322 }
1323if errors.is_empty() {
1324Ok(())
1325 } else {
1326Err(errors)
1327 }
1328 }
13291330/// Same as [`Self::compress_mesh`], except this is passed by value instead of by mutable reference.
1331#[expect(
1332 clippy::result_large_err,
1333 reason = "Returning the passed `Mesh` in `Err`"
1334)]
1335pub fn compressed_mesh(
1336mut self,
1337 args: &MeshCompressionArgs,
1338 ) -> Result<Mesh, (Mesh, Vec<MeshAttributeCompressionError>)> {
1339let result = self.compress_mesh(args);
1340match result {
1341Ok(_) => Ok(self),
1342Err(err) => Err((self, err)),
1343 }
1344 }
13451346/// Computes and returns the vertex data of the mesh as bytes.
1347 /// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
1348 /// This is used to transform the vertex data into a GPU friendly format.
1349 ///
1350 /// If the vertex attributes have different lengths, they are all truncated to
1351 /// the length of the smallest.
1352 ///
1353 /// This is a convenience method which allocates a Vec.
1354 /// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
1355 ///
1356 /// # Panics
1357 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1358pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
1359let mut attributes_interleaved_buffer = ::alloc::vec::from_elem(0, self.get_vertex_buffer_size())vec![0; self.get_vertex_buffer_size()];
1360self.write_packed_vertex_buffer_data(WriteOnly::from_mut(
1361&mut attributes_interleaved_buffer,
1362 ));
1363attributes_interleaved_buffer1364 }
13651366/// Computes and write the vertex data of the mesh into a mutable byte slice.
1367 /// The attributes are located in the order of their [`MeshVertexAttribute::id`].
1368 /// This is used to transform the vertex data into a GPU friendly format.
1369 ///
1370 /// If the vertex attributes have different lengths, they are all truncated to
1371 /// the length of the smallest.
1372 ///
1373 /// # Panics
1374 /// Panics when the mesh data has already been extracted to `RenderWorld`.
1375pub fn write_packed_vertex_buffer_data(&self, mut slice: WriteOnly<'_, [u8]>) {
1376let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
13771378let vertex_size = self.get_vertex_size() as usize;
1379let vertex_count = self.count_vertices();
1380// bundle into interleaved buffers
1381let mut attribute_offset = 0;
1382for attribute_data in mesh_attributes.values() {
1383let attribute_size = attribute_data.attribute.format.size() as usize;
1384let attributes_bytes = attribute_data.values.get_bytes();
1385for (vertex_index, attribute_bytes) in attributes_bytes
1386 .chunks_exact(attribute_size)
1387 .take(vertex_count)
1388 .enumerate()
1389 {
1390let offset = vertex_index * vertex_size + attribute_offset;
1391 slice
1392 .slice(offset..offset + attribute_size)
1393 .copy_from_slice(attribute_bytes);
1394 }
13951396 attribute_offset += attribute_size;
1397 }
1398 }
13991400/// Duplicates the vertex attributes so that no vertices are shared.
1401 ///
1402 /// This can dramatically increase the vertex count, so make sure this is what you want.
1403 /// Does nothing if no [Indices] are set.
1404 ///
1405 /// # Panics
1406 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1407 /// this as an error use [`Mesh::try_duplicate_vertices`]
1408pub fn duplicate_vertices(&mut self) {
1409self.try_duplicate_vertices().expect(MESH_EXTRACTED_ERROR);
1410 }
14111412/// Duplicates the vertex attributes so that no vertices are shared.
1413 ///
1414 /// This can dramatically increase the vertex count, so make sure this is what you want.
1415 /// Does nothing if no [Indices] are set.
1416 ///
1417 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1418pub fn try_duplicate_vertices(&mut self) -> Result<(), MeshAccessError> {
1419fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
1420indices.map(|i| values[i]).collect()
1421 }
14221423let Some(indices) = self.indices.replace(None)? else {
1424return Ok(());
1425 };
14261427let mesh_attributes = self.attributes.as_mut()?;
14281429for attributes in mesh_attributes.values_mut() {
1430let indices = indices.iter();
1431#[expect(
1432 clippy::match_same_arms,
1433 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."
1434)]
1435match &mut attributes.values {
1436 VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
1437 VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
1438 VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
1439 VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
1440 VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
1441 VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
1442 VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
1443 VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
1444 VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
1445 VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
1446 VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
1447 VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
1448 VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
1449 VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
1450 VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
1451 VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
1452 VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
1453 VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
1454 VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
1455 VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
1456 VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
1457 VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
1458 VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
1459 VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
1460 VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
1461 VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
1462 VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
1463 VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
1464 VertexAttributeValues::Uint8(vec) => *vec = duplicate(vec, indices),
1465 VertexAttributeValues::Sint8(vec) => *vec = duplicate(vec, indices),
1466 VertexAttributeValues::Unorm8(vec) => *vec = duplicate(vec, indices),
1467 VertexAttributeValues::Snorm8(vec) => *vec = duplicate(vec, indices),
1468 VertexAttributeValues::Uint16(vec) => *vec = duplicate(vec, indices),
1469 VertexAttributeValues::Sint16(vec) => *vec = duplicate(vec, indices),
1470 VertexAttributeValues::Unorm16(vec) => *vec = duplicate(vec, indices),
1471 VertexAttributeValues::Snorm16(vec) => *vec = duplicate(vec, indices),
1472 VertexAttributeValues::Float16(vec) => *vec = duplicate(vec, indices),
1473 VertexAttributeValues::Float16x2(vec) => *vec = duplicate(vec, indices),
1474 VertexAttributeValues::Float16x4(vec) => *vec = duplicate(vec, indices),
1475 VertexAttributeValues::Float64(vec) => *vec = duplicate(vec, indices),
1476 VertexAttributeValues::Float64x2(vec) => *vec = duplicate(vec, indices),
1477 VertexAttributeValues::Float64x3(vec) => *vec = duplicate(vec, indices),
1478 VertexAttributeValues::Float64x4(vec) => *vec = duplicate(vec, indices),
1479 VertexAttributeValues::Unorm10_10_10_2(vec) => *vec = duplicate(vec, indices),
1480 VertexAttributeValues::Unorm8x4Bgra(vec) => *vec = duplicate(vec, indices),
1481 }
1482 }
14831484Ok(())
1485 }
14861487/// Consumes the mesh and returns a mesh with no shared vertices.
1488 ///
1489 /// This can dramatically increase the vertex count, so make sure this is what you want.
1490 /// Does nothing if no [`Indices`] are set.
1491 ///
1492 /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
1493 ///
1494 /// # Panics
1495 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1496 /// this as an error use [`Mesh::try_with_duplicated_vertices`]
1497#[must_use]
1498pub fn with_duplicated_vertices(mut self) -> Self {
1499self.duplicate_vertices();
1500self1501 }
15021503/// Consumes the mesh and returns a mesh with no shared vertices.
1504 ///
1505 /// This can dramatically increase the vertex count, so make sure this is what you want.
1506 /// Does nothing if no [`Indices`] are set.
1507 ///
1508 /// (Alternatively, you can use [`Mesh::try_duplicate_vertices`] to mutate an existing mesh in-place)
1509 ///
1510 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1511pub fn try_with_duplicated_vertices(mut self) -> Result<Self, MeshAccessError> {
1512self.try_duplicate_vertices()?;
1513Ok(self)
1514 }
15151516/// Remove duplicate vertices and create the index pointing to the unique vertices.
1517 ///
1518 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1519 /// Returns an error if the mesh already has [`Indices`] set, even if there
1520 /// are duplicate vertices. If deduplication is needed with indices already set,
1521 /// consider calling [`Mesh::duplicate_vertices`] and then this function.
1522pub fn merge_duplicate_vertices(&mut self) -> Result<(), MeshMergeDuplicateVerticesError> {
1523match self.try_indices() {
1524Ok(_) => return Err(MeshMergeDuplicateVerticesError::IndicesAlreadySet),
1525Err(err) => match err {
1526 MeshAccessError::ExtractedToRenderWorld => return Err(err.into()),
1527 MeshAccessError::NotFound => (),
1528 },
1529 }
15301531#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for VertexRef<'a> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'a> ::core::clone::TrivialClone for VertexRef<'a> { }
#[automatically_derived]
impl<'a> ::core::clone::Clone for VertexRef<'a> {
#[inline]
fn clone(&self) -> Self {
let _:
::core::clone::AssertParamIsClone<&'a BTreeMap<MeshVertexAttributeId,
MeshAttributeData>>;
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone)]
1532struct VertexRef<'a> {
1533 mesh_attributes: &'a BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
1534 i: usize,
1535 }
1536impl<'a> VertexRef<'a> {
1537fn push_to(&self, target: &mut BTreeMap<MeshVertexAttributeId, MeshAttributeData>) {
1538for (key, this_attribute_data) in self.mesh_attributes.iter() {
1539let target_attribute_data = target.get_mut(key).unwrap(); // ok to unwrap, all keys added to new_attributes below
1540target_attribute_data
1541 .values
1542 .push_from(&this_attribute_data.values, self.i);
1543 }
1544 }
1545 }
1546impl<'a> PartialEqfor VertexRef<'a> {
1547fn eq(&self, other: &Self) -> bool {
1548if !ptr::eq(self.mesh_attributes, other.mesh_attributes) {
::core::panicking::panic("assertion failed: ptr::eq(self.mesh_attributes, other.mesh_attributes)")
};assert!(ptr::eq(self.mesh_attributes, other.mesh_attributes));
1549for values in self.mesh_attributes.values() {
1550if values.values.get_bytes_at(self.i) != values.values.get_bytes_at(other.i) {
1551return false;
1552 }
1553 }
1554true
1555}
1556 }
1557impl<'a> Eqfor VertexRef<'a> {}
1558impl<'a> Hashfor VertexRef<'a> {
1559fn hash<H: Hasher>(&self, state: &mut H) {
1560for values in self.mesh_attributes.values() {
1561 values.values.get_bytes_at(self.i).hash(state);
1562 }
1563 }
1564 }
15651566let old_attributes = self.attributes.as_ref()?;
15671568let mut new_attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData> = self
1569.attributes
1570 .as_ref()?
1571.iter()
1572 .map(|(k, v)| {
1573 (
1574*k,
1575MeshAttributeData {
1576 attribute: v.attribute,
1577 values: VertexAttributeValues::new(VertexFormat::from(&v.values)),
1578 },
1579 )
1580 })
1581 .collect();
15821583let mut vertex_to_new_index: HashMap<VertexRef, u32> = HashMap::new();
1584let mut indices = Vec::with_capacity(self.count_vertices());
1585for i in 0..self.count_vertices() {
1586let len: u32 = vertex_to_new_index
1587 .len()
1588 .try_into()
1589 .expect("The number of vertices exceeds u32::MAX");
1590let vertex_ref = VertexRef {
1591 mesh_attributes: old_attributes,
1592 i,
1593 };
1594let j = match vertex_to_new_index.entry(vertex_ref) {
1595 hash_map::Entry::Occupied(e) => *e.get(),
1596 hash_map::Entry::Vacant(e) => {
1597 e.insert(len);
1598 vertex_ref.push_to(&mut new_attributes);
1599 len
1600 }
1601 };
1602 indices.push(j);
1603 }
1604drop(vertex_to_new_index);
16051606for v in new_attributes.values_mut() {
1607 v.values.shrink_to_fit();
1608 }
16091610self.attributes = MeshExtractableData::Data(new_attributes);
1611self.indices = MeshExtractableData::Data(Indices::U32(indices));
16121613Ok(())
1614 }
16151616/// Consumes the mesh and returns a mesh with merged vertices.
1617 ///
1618 /// (Alternatively, you can use [`Mesh::merge_duplicate_vertices`] to mutate an existing mesh in-place)
1619 ///
1620 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1621 /// Returns an error if the mesh already has [`Indices`] set, even if there
1622 /// are duplicate vertices. If deduplication is needed with indices already set,
1623 /// consider calling [`Mesh::duplicate_vertices`] and then this function.
1624pub fn with_merge_duplicate_vertices(
1625mut self,
1626 ) -> Result<Self, MeshMergeDuplicateVerticesError> {
1627self.merge_duplicate_vertices()?;
1628Ok(self)
1629 }
16301631/// Inverts the winding of the indices such that all counter-clockwise triangles are now
1632 /// clockwise and vice versa.
1633 /// For lines, their start and end indices are flipped.
1634 ///
1635 /// Does nothing if no [`Indices`] are set.
1636 /// If this operation succeeded, an [`Ok`] result is returned.
1637pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
1638fn invert<I>(
1639 indices: &mut [I],
1640 topology: PrimitiveTopology,
1641 ) -> Result<(), MeshWindingInvertError> {
1642match topology {
1643 PrimitiveTopology::TriangleList => {
1644let (chunks, []) = indices.as_chunks_mut() else {
1645// Early return if the index count doesn't match
1646return Err(MeshWindingInvertError::AbruptIndicesEnd);
1647 };
16481649for [_, b, c] in chunks {
1650 core::mem::swap(b, c);
1651 }
1652Ok(())
1653 }
1654 PrimitiveTopology::LineList => {
1655// Early return if the index count doesn't match
1656if !indices.len().is_multiple_of(2) {
1657return Err(MeshWindingInvertError::AbruptIndicesEnd);
1658 }
1659indices.reverse();
1660Ok(())
1661 }
1662 PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
1663indices.reverse();
1664Ok(())
1665 }
1666_ => Err(MeshWindingInvertError::WrongTopology),
1667 }
1668 }
16691670let mesh_indices = self.indices.as_mut_option()?;
16711672match mesh_indices {
1673Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
1674Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
1675None => Ok(()),
1676 }
1677 }
16781679/// Consumes the mesh and returns a mesh with inverted winding of the indices such
1680 /// that all counter-clockwise triangles are now clockwise and vice versa.
1681 ///
1682 /// Does nothing if no [`Indices`] are set.
1683pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
1684self.invert_winding().map(|_| self)
1685 }
16861687/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1688 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1689 /// normals.
1690 ///
1691 /// # Panics
1692 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1693 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1694 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1695 /// this as an error use [`Mesh::try_compute_normals`]
1696pub fn compute_normals(&mut self) {
1697self.try_compute_normals().expect(MESH_EXTRACTED_ERROR);
1698 }
16991700/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1701 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1702 /// normals.
1703 ///
1704 /// # Panics
1705 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1706 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1707pub fn try_compute_normals(&mut self) -> Result<(), MeshAccessError> {
1708if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("`compute_normals` can only work on `TriangleList`s"));
}
};assert!(
1709matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1710"`compute_normals` can only work on `TriangleList`s"
1711);
1712if self.try_indices_option()?.is_none() {
1713self.try_compute_flat_normals()
1714 } else {
1715self.try_compute_smooth_normals()
1716 }
1717 }
17181719/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1720 ///
1721 /// # Panics
1722 /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1723 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1724 /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1725 /// attributes.
1726 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1727 /// this as an error use [`Mesh::try_compute_flat_normals`]
1728 ///
1729 /// FIXME: This should handle more cases since this is called as a part of gltf
1730 /// mesh loading where we can't really blame users for loading meshes that might
1731 /// not conform to the limitations here!
1732pub fn compute_flat_normals(&mut self) {
1733self.try_compute_flat_normals().expect(MESH_EXTRACTED_ERROR);
1734 }
17351736/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1737 ///
1738 /// # Panics
1739 /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1740 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1741 /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1742 /// attributes.
1743 ///
1744 /// FIXME: This should handle more cases since this is called as a part of gltf
1745 /// mesh loading where we can't really blame users for loading meshes that might
1746 /// not conform to the limitations here!
1747pub fn try_compute_flat_normals(&mut self) -> Result<(), MeshAccessError> {
1748if !self.try_indices_option()?.is_none() {
{
::core::panicking::panic_fmt(format_args!("`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`."));
}
};assert!(
1749self.try_indices_option()?.is_none(),
1750"`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`."
1751);
1752if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("`compute_flat_normals` can only work on `TriangleList`s"));
}
};assert!(
1753matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1754"`compute_flat_normals` can only work on `TriangleList`s"
1755);
17561757let positions = self
1758.try_attribute(Mesh::ATTRIBUTE_POSITION)?
1759.as_float3()
1760 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
17611762let normals: Vec<_> = positions1763 .as_chunks()
1764 .0
1765.iter()
1766 .flat_map(|&[a, b, c]| [triangle_normal(a, b, c); 3])
1767 .collect();
17681769self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1770 }
17711772/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1773 /// vertices.
1774 ///
1775 /// This method weights normals by the angles of the corners of connected triangles, thus
1776 /// eliminating triangle area and count as factors in the final normal. This does make it
1777 /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1778 /// greedily normalize each triangle's normal or calculate corner angles.
1779 ///
1780 /// If you would rather have the computed normals be weighted by triangle area, see
1781 /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1782 /// way, see [`Mesh::compute_custom_smooth_normals`].
1783 ///
1784 /// # Panics
1785 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1786 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1787 /// Panics if the mesh does not have indices defined.
1788 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1789 /// this as an error use [`Mesh::try_compute_smooth_normals`]
1790pub fn compute_smooth_normals(&mut self) {
1791self.try_compute_smooth_normals()
1792 .expect(MESH_EXTRACTED_ERROR);
1793 }
17941795/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1796 /// vertices.
1797 ///
1798 /// This method weights normals by the angles of the corners of connected triangles, thus
1799 /// eliminating triangle area and count as factors in the final normal. This does make it
1800 /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1801 /// greedily normalize each triangle's normal or calculate corner angles.
1802 ///
1803 /// If you would rather have the computed normals be weighted by triangle area, see
1804 /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1805 /// way, see [`Mesh::compute_custom_smooth_normals`].
1806 ///
1807 /// # Panics
1808 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1809 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1810 /// Panics if the mesh does not have indices defined.
1811pub fn try_compute_smooth_normals(&mut self) -> Result<(), MeshAccessError> {
1812self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1813let pa = Vec3::from(positions[a]);
1814let pb = Vec3::from(positions[b]);
1815let pc = Vec3::from(positions[c]);
18161817let ab = pb - pa;
1818let ba = pa - pb;
1819let bc = pc - pb;
1820let cb = pb - pc;
1821let ca = pa - pc;
1822let ac = pc - pa;
18231824const EPS: f32 = f32::EPSILON;
1825let weight_a = if ab.length_squared() * ac.length_squared() > EPS {
1826ab.angle_between(ac)
1827 } else {
18280.0
1829};
1830let weight_b = if ba.length_squared() * bc.length_squared() > EPS {
1831ba.angle_between(bc)
1832 } else {
18330.0
1834};
1835let weight_c = if ca.length_squared() * cb.length_squared() > EPS {
1836ca.angle_between(cb)
1837 } else {
18380.0
1839};
18401841let normal = Vec3::from(triangle_normal(positions[a], positions[b], positions[c]));
18421843normals[a] += normal * weight_a;
1844normals[b] += normal * weight_b;
1845normals[c] += normal * weight_c;
1846 })
1847 }
18481849/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1850 /// vertices.
1851 ///
1852 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1853 /// larger triangles will skew the normals of their vertices towards their own normal more
1854 /// than smaller triangles will.
1855 ///
1856 /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1857 /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1858 ///
1859 /// If you would rather have the computed normals be influenced only by the angles of connected
1860 /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1861 /// other way, see [`Mesh::compute_custom_smooth_normals`].
1862 ///
1863 /// # Panics
1864 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1865 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1866 /// Panics if the mesh does not have indices defined.
1867 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1868 /// this as an error use [`Mesh::try_compute_area_weighted_normals`]
1869pub fn compute_area_weighted_normals(&mut self) {
1870self.try_compute_area_weighted_normals()
1871 .expect(MESH_EXTRACTED_ERROR);
1872 }
18731874/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1875 /// vertices.
1876 ///
1877 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1878 /// larger triangles will skew the normals of their vertices towards their own normal more
1879 /// than smaller triangles will.
1880 ///
1881 /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1882 /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1883 ///
1884 /// If you would rather have the computed normals be influenced only by the angles of connected
1885 /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1886 /// other way, see [`Mesh::compute_custom_smooth_normals`].
1887 ///
1888 /// # Panics
1889 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1890 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1891 /// Panics if the mesh does not have indices defined.
1892pub fn try_compute_area_weighted_normals(&mut self) -> Result<(), MeshAccessError> {
1893self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1894let normal = Vec3::from(triangle_area_normal(
1895positions[a],
1896positions[b],
1897positions[c],
1898 ));
1899 [a, b, c].into_iter().for_each(|pos| {
1900normals[pos] += normal;
1901 });
1902 })
1903 }
19041905/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1906 /// vertices.
1907 ///
1908 /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1909 /// which must be a function or closure that accepts 3 parameters:
1910 /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1911 /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1912 /// - A mutable reference to the sums of all normals so far.
1913 ///
1914 /// See also the standard methods included in Bevy for calculating smooth normals:
1915 /// - [`Mesh::compute_smooth_normals`]
1916 /// - [`Mesh::compute_area_weighted_normals`]
1917 ///
1918 /// An example that would weight each connected triangle's normal equally, thus skewing normals
1919 /// towards the planes divided into the most triangles:
1920 /// ```
1921 /// # use bevy_asset::RenderAssetUsages;
1922 /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1923 /// # use bevy_math::Vec3;
1924 /// # use bevy_shape::Cuboid;
1925 /// # let mut mesh = Cuboid::default().mesh().build();
1926 /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1927 /// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1928 /// for idx in [a, b, c] {
1929 /// normals[idx] += normal;
1930 /// }
1931 /// });
1932 /// ```
1933 ///
1934 /// # Panics
1935 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1936 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1937 /// Panics if the mesh does not have indices defined.
1938 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1939 /// this as an error use [`Mesh::try_compute_custom_smooth_normals`]
1940//
1941 // FIXME: This should handle more cases since this is called as a part of gltf
1942 // mesh loading where we can't really blame users for loading meshes that might
1943 // not conform to the limitations here!
1944 //
1945 // When fixed, also update "Panics" sections of
1946 // - [Mesh::compute_smooth_normals]
1947 // - [Mesh::with_computed_smooth_normals]
1948 // - [Mesh::compute_area_weighted_normals]
1949 // - [Mesh::with_computed_area_weighted_normals]
1950pub fn compute_custom_smooth_normals(
1951&mut self,
1952 per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1953 ) {
1954self.try_compute_custom_smooth_normals(per_triangle)
1955 .expect(MESH_EXTRACTED_ERROR);
1956 }
19571958/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1959 /// vertices.
1960 ///
1961 /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1962 /// which must be a function or closure that accepts 3 parameters:
1963 /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1964 /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1965 /// - A mutable reference to the sums of all normals so far.
1966 ///
1967 /// See also the standard methods included in Bevy for calculating smooth normals:
1968 /// - [`Mesh::compute_smooth_normals`]
1969 /// - [`Mesh::compute_area_weighted_normals`]
1970 ///
1971 /// An example that would weight each connected triangle's normal equally, thus skewing normals
1972 /// towards the planes divided into the most triangles:
1973 /// ```
1974 /// # use bevy_asset::RenderAssetUsages;
1975 /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1976 /// # use bevy_math::Vec3;
1977 /// # use bevy_shape::Cuboid;
1978 /// # let mut mesh = Cuboid::default().mesh().build();
1979 /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1980 /// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1981 /// for idx in [a, b, c] {
1982 /// normals[idx] += normal;
1983 /// }
1984 /// });
1985 /// ```
1986 ///
1987 /// # Panics
1988 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1989 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1990 /// Panics if the mesh does not have indices defined.
1991//
1992 // FIXME: This should handle more cases since this is called as a part of gltf
1993 // mesh loading where we can't really blame users for loading meshes that might
1994 // not conform to the limitations here!
1995 //
1996 // When fixed, also update "Panics" sections of
1997 // - [Mesh::compute_smooth_normals]
1998 // - [Mesh::with_computed_smooth_normals]
1999 // - [Mesh::compute_area_weighted_normals]
2000 // - [Mesh::with_computed_area_weighted_normals]
2001pub fn try_compute_custom_smooth_normals(
2002&mut self,
2003mut per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
2004 ) -> Result<(), MeshAccessError> {
2005if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("smooth normals can only be computed on `TriangleList`s"));
}
};assert!(
2006matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
2007"smooth normals can only be computed on `TriangleList`s"
2008);
2009if !self.try_indices_option()?.is_some() {
{
::core::panicking::panic_fmt(format_args!("smooth normals can only be computed on indexed meshes"));
}
};assert!(
2010self.try_indices_option()?.is_some(),
2011"smooth normals can only be computed on indexed meshes"
2012);
20132014let positions = self
2015.try_attribute(Mesh::ATTRIBUTE_POSITION)?
2016.as_float3()
2017 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
20182019let mut normals = ::alloc::vec::from_elem(Vec3::ZERO, positions.len())vec![Vec3::ZERO; positions.len()];
20202021match self.try_indices()? {
2022 Indices::U16(vec) => vec.as_chunks().0.iter().for_each(|&chunk| {
2023per_triangle(chunk.map(|i| ias usize), positions, &mut normals);
2024 }),
2025 Indices::U32(vec) => vec.as_chunks().0.iter().for_each(|&chunk| {
2026per_triangle(chunk.map(|i| ias usize), positions, &mut normals);
2027 }),
2028 }
20292030for normal in &mut normals {
2031*normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
2032 }
20332034self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
2035 }
20362037/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2038 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
2039 /// normals.
2040 ///
2041 /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
2042 ///
2043 /// # Panics
2044 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2045 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2046 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2047 /// this as an error use [`Mesh::try_with_computed_normals`]
2048#[must_use]
2049pub fn with_computed_normals(self) -> Self {
2050self.try_with_computed_normals()
2051 .expect(MESH_EXTRACTED_ERROR)
2052 }
20532054/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2055 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
2056 /// normals.
2057 ///
2058 /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
2059 ///
2060 /// # Panics
2061 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2062 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2063pub fn try_with_computed_normals(mut self) -> Result<Self, MeshAccessError> {
2064self.try_compute_normals()?;
2065Ok(self)
2066 }
20672068/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2069 ///
2070 /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
2071 ///
2072 /// # Panics
2073 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2074 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2075 /// Panics if the mesh has indices defined
2076 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2077 /// this as an error use [`Mesh::try_with_computed_flat_normals`]
2078pub fn with_computed_flat_normals(mut self) -> Self {
2079self.compute_flat_normals();
2080self2081 }
20822083/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2084 ///
2085 /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
2086 ///
2087 /// # Panics
2088 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2089 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2090 /// Panics if the mesh has indices defined
2091pub fn try_with_computed_flat_normals(mut self) -> Result<Self, MeshAccessError> {
2092self.try_compute_flat_normals()?;
2093Ok(self)
2094 }
20952096/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2097 ///
2098 /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
2099 ///
2100 /// This method weights normals by the angles of triangle corners connected to each vertex. If
2101 /// you would rather have the computed normals be weighted by triangle area, see
2102 /// [`Mesh::with_computed_area_weighted_normals`] instead.
2103 ///
2104 /// # Panics
2105 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2106 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2107 /// Panics if the mesh does not have indices defined.
2108 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2109 /// this as an error use [`Mesh::try_with_computed_smooth_normals`]
2110pub fn with_computed_smooth_normals(mut self) -> Self {
2111self.compute_smooth_normals();
2112self2113 }
2114/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2115 ///
2116 /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
2117 ///
2118 /// This method weights normals by the angles of triangle corners connected to each vertex. If
2119 /// you would rather have the computed normals be weighted by triangle area, see
2120 /// [`Mesh::with_computed_area_weighted_normals`] instead.
2121 ///
2122 /// # Panics
2123 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2124 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2125 /// Panics if the mesh does not have indices defined.
2126pub fn try_with_computed_smooth_normals(mut self) -> Result<Self, MeshAccessError> {
2127self.try_compute_smooth_normals()?;
2128Ok(self)
2129 }
21302131/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2132 ///
2133 /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
2134 ///
2135 /// This method weights normals by the area of each triangle containing the vertex. Thus,
2136 /// larger triangles will skew the normals of their vertices towards their own normal more
2137 /// than smaller triangles will. If you would rather have the computed normals be influenced
2138 /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
2139 ///
2140 /// # Panics
2141 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2142 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2143 /// Panics if the mesh does not have indices defined.
2144 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2145 /// this as an error use [`Mesh::try_with_computed_area_weighted_normals`]
2146pub fn with_computed_area_weighted_normals(mut self) -> Self {
2147self.compute_area_weighted_normals();
2148self2149 }
21502151/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
2152 ///
2153 /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
2154 ///
2155 /// This method weights normals by the area of each triangle containing the vertex. Thus,
2156 /// larger triangles will skew the normals of their vertices towards their own normal more
2157 /// than smaller triangles will. If you would rather have the computed normals be influenced
2158 /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
2159 ///
2160 /// # Panics
2161 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
2162 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
2163 /// Panics if the mesh does not have indices defined.
2164pub fn try_with_computed_area_weighted_normals(mut self) -> Result<Self, MeshAccessError> {
2165self.try_compute_area_weighted_normals()?;
2166Ok(self)
2167 }
21682169/// Generate tangents for the mesh using the `mikktspace` algorithm.
2170 ///
2171 /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
2172 /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
2173#[cfg(feature = "bevy_mikktspace")]
2174pub fn generate_tangents(&mut self) -> Result<(), super::GenerateTangentsError> {
2175let tangents = super::generate_tangents_for_mesh(self)?;
2176self.try_insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents)?;
2177Ok(())
2178 }
21792180/// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
2181 ///
2182 /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
2183 ///
2184 /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
2185 ///
2186 /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
2187#[cfg(feature = "bevy_mikktspace")]
2188pub fn with_generated_tangents(mut self) -> Result<Mesh, super::GenerateTangentsError> {
2189self.generate_tangents()?;
2190Ok(self)
2191 }
21922193/// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
2194 ///
2195 /// Note that attributes of `other` that don't exist on `self` will be ignored.
2196 ///
2197 /// `Aabb` of entities with modified mesh are not updated automatically.
2198 ///
2199 /// # Errors
2200 ///
2201 /// If any of the following conditions are not met, this function errors:
2202 /// * All of the vertex attributes that have the same attribute id, must also
2203 /// have the same attribute type.
2204 /// For example two attributes with the same id, but where one is a
2205 /// [`VertexAttributeValues::Float32`] and the other is a
2206 /// [`VertexAttributeValues::Float32x3`], would be invalid.
2207 /// * Both meshes must have the same primitive topology.
2208pub fn merge(&mut self, other: &Mesh) -> Result<(), MeshMergeError> {
2209use VertexAttributeValues::*;
22102211// Check if the meshes `primitive_topology` field is the same,
2212 // as if that is not the case, the resulting mesh could (and most likely would)
2213 // be invalid.
2214if self.primitive_topology != other.primitive_topology {
2215return Err(MeshMergeError::IncompatiblePrimitiveTopology {
2216 self_primitive_topology: self.primitive_topology,
2217 other_primitive_topology: other.primitive_topology,
2218 });
2219 }
22202221// The indices of `other` should start after the last vertex of `self`.
2222let index_offset = self.count_vertices();
22232224// Extend attributes of `self` with attributes of `other`.
2225for (attribute, values) in self.try_attributes_mut()? {
2226if let Some(other_values) = other.try_attribute_option(attribute.id)? {
2227#[expect(
2228 clippy::match_same_arms,
2229 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."
2230)]
2231match (values, other_values) {
2232 (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
2233 (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
2234 (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
2235 (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
2236 (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
2237 (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
2238 (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
2239 (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
2240 (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
2241 (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
2242 (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
2243 (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
2244 (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
2245 (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
2246 (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
2247 (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
2248 (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
2249 (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
2250 (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
2251 (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
2252 (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
2253 (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
2254 (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
2255 (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
2256 (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
2257 (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
2258 (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
2259 (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
2260_ => {
2261return Err(MeshMergeError::IncompatibleVertexAttributes {
2262 self_attribute: *attribute,
2263 other_attribute: other
2264 .try_attribute_data(attribute.id)?
2265.map(|data| data.attribute),
2266 })
2267 }
2268 }
2269 }
2270 }
22712272// Extend indices of `self` with indices of `other`.
2273if let (Some(indices), Some(other_indices)) =
2274 (self.try_indices_mut_option()?, other.try_indices_option()?)
2275 {
2276indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
2277 }
2278Ok(())
2279 }
22802281/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
2282 ///
2283 /// `Aabb` of entities with modified mesh are not updated automatically.
2284 ///
2285 /// # Panics
2286 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2287 /// this as an error use [`Mesh::try_transformed_by`]
2288pub fn transformed_by(mut self, transform: Transform) -> Self {
2289self.transform_by(transform);
2290self2291 }
22922293/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
2294 ///
2295 /// `Aabb` of entities with modified mesh are not updated automatically.
2296pub fn try_transformed_by(mut self, transform: Transform) -> Result<Self, MeshAccessError> {
2297self.try_transform_by(transform)?;
2298Ok(self)
2299 }
23002301/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
2302 ///
2303 /// `Aabb` of entities with modified mesh are not updated automatically.
2304 ///
2305 /// # Panics
2306 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2307 /// this as an error use [`Mesh::try_transform_by`]
2308pub fn transform_by(&mut self, transform: Transform) {
2309self.try_transform_by(transform)
2310 .expect(MESH_EXTRACTED_ERROR);
2311 }
23122313/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
2314 ///
2315 /// `Aabb` of entities with modified mesh are not updated automatically.
2316pub fn try_transform_by(&mut self, transform: Transform) -> Result<(), MeshAccessError> {
2317// Needed when transforming normals and tangents
2318let scale_recip = 1. / transform.scale;
2319if true {
if !(transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO) {
{
::core::panicking::panic_fmt(format_args!("mesh transform scale cannot be zero on more than one axis"));
}
};
};debug_assert!(
2320 transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
2321"mesh transform scale cannot be zero on more than one axis"
2322);
23232324if let Some(VertexAttributeValues::Float32x3(positions)) =
2325self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2326{
2327// Apply scale, rotation, and translation to vertex positions
2328positions2329 .iter_mut()
2330 .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
2331 }
23322333// No need to transform normals or tangents if rotation is near identity and scale is uniform
2334if transform.rotation.is_near_identity()
2335 && transform.scale.x == transform.scale.y
2336 && transform.scale.y == transform.scale.z
2337 {
2338return Ok(());
2339 }
23402341if let Some(VertexAttributeValues::Float32x3(normals)) =
2342self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2343{
2344// Transform normals, taking into account non-uniform scaling and rotation
2345normals.iter_mut().for_each(|normal| {
2346*normal = (transform.rotation
2347 * scale_normal(Vec3::from_array(*normal), scale_recip))
2348 .to_array();
2349 });
2350 }
23512352if let Some(VertexAttributeValues::Float32x4(tangents)) =
2353self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2354{
2355// Transform tangents, taking into account non-uniform scaling and rotation
2356tangents.iter_mut().for_each(|tangent| {
2357let handedness = tangent[3];
2358let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
2359*tangent = (transform.rotation * scaled_tangent.normalize_or_zero())
2360 .extend(handedness)
2361 .to_array();
2362 });
2363 }
23642365Ok(())
2366 }
23672368/// Translates the vertex positions of the mesh by the given [`Vec3`].
2369 ///
2370 /// `Aabb` of entities with modified mesh are not updated automatically.
2371 ///
2372 /// # Panics
2373 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2374 /// this as an error use [`Mesh::try_translated_by`]
2375pub fn translated_by(mut self, translation: Vec3) -> Self {
2376self.translate_by(translation);
2377self2378 }
23792380/// Translates the vertex positions of the mesh by the given [`Vec3`].
2381 ///
2382 /// `Aabb` of entities with modified mesh are not updated automatically.
2383pub fn try_translated_by(mut self, translation: Vec3) -> Result<Self, MeshAccessError> {
2384self.try_translate_by(translation)?;
2385Ok(self)
2386 }
23872388/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
2389 ///
2390 /// `Aabb` of entities with modified mesh are not updated automatically.
2391 ///
2392 /// # Panics
2393 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2394 /// this as an error use [`Mesh::try_translate_by`]
2395pub fn translate_by(&mut self, translation: Vec3) {
2396self.try_translate_by(translation)
2397 .expect(MESH_EXTRACTED_ERROR);
2398 }
23992400/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
2401 ///
2402 /// `Aabb` of entities with modified mesh are not updated automatically.
2403pub fn try_translate_by(&mut self, translation: Vec3) -> Result<(), MeshAccessError> {
2404if translation == Vec3::ZERO {
2405return Ok(());
2406 }
24072408if let Some(VertexAttributeValues::Float32x3(positions)) =
2409self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2410{
2411// Apply translation to vertex positions
2412positions2413 .iter_mut()
2414 .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
2415 }
24162417Ok(())
2418 }
24192420/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
2421 ///
2422 /// `Aabb` of entities with modified mesh are not updated automatically.
2423 ///
2424 /// # Panics
2425 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2426 /// this as an error use [`Mesh::try_rotated_by`]
2427pub fn rotated_by(mut self, rotation: Quat) -> Self {
2428self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
2429self2430 }
24312432/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
2433 ///
2434 /// `Aabb` of entities with modified mesh are not updated automatically.
2435pub fn try_rotated_by(mut self, rotation: Quat) -> Result<Self, MeshAccessError> {
2436self.try_rotate_by(rotation)?;
2437Ok(self)
2438 }
24392440/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
2441 ///
2442 /// `Aabb` of entities with modified mesh are not updated automatically.
2443 ///
2444 /// # Panics
2445 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2446 /// this as an error use [`Mesh::try_rotate_by`]
2447pub fn rotate_by(&mut self, rotation: Quat) {
2448self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
2449 }
24502451/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
2452 ///
2453 /// `Aabb` of entities with modified mesh are not updated automatically.
2454pub fn try_rotate_by(&mut self, rotation: Quat) -> Result<(), MeshAccessError> {
2455if let Some(VertexAttributeValues::Float32x3(positions)) =
2456self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2457{
2458// Apply rotation to vertex positions
2459positions2460 .iter_mut()
2461 .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
2462 }
24632464// No need to transform normals or tangents if rotation is near identity
2465if rotation.is_near_identity() {
2466return Ok(());
2467 }
24682469if let Some(VertexAttributeValues::Float32x3(normals)) =
2470self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2471{
2472// Transform normals
2473normals.iter_mut().for_each(|normal| {
2474*normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
2475 });
2476 }
24772478if let Some(VertexAttributeValues::Float32x4(tangents)) =
2479self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2480{
2481// Transform tangents
2482tangents.iter_mut().for_each(|tangent| {
2483let handedness = tangent[3];
2484*tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero())
2485 .extend(handedness)
2486 .to_array();
2487 });
2488 }
24892490Ok(())
2491 }
24922493/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2494 ///
2495 /// `Aabb` of entities with modified mesh are not updated automatically.
2496 ///
2497 /// # Panics
2498 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2499 /// this as an error use [`Mesh::try_scaled_by`]
2500pub fn scaled_by(mut self, scale: Vec3) -> Self {
2501self.scale_by(scale);
2502self2503 }
25042505/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2506 ///
2507 /// `Aabb` of entities with modified mesh are not updated automatically.
2508pub fn try_scaled_by(mut self, scale: Vec3) -> Result<Self, MeshAccessError> {
2509self.try_scale_by(scale)?;
2510Ok(self)
2511 }
25122513/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2514 ///
2515 /// `Aabb` of entities with modified mesh are not updated automatically.
2516 ///
2517 /// # Panics
2518 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2519 /// this as an error use [`Mesh::try_scale_by`]
2520pub fn scale_by(&mut self, scale: Vec3) {
2521self.try_scale_by(scale).expect(MESH_EXTRACTED_ERROR);
2522 }
25232524/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2525 ///
2526 /// `Aabb` of entities with modified mesh are not updated automatically.
2527pub fn try_scale_by(&mut self, scale: Vec3) -> Result<(), MeshAccessError> {
2528// Needed when transforming normals and tangents
2529let scale_recip = 1. / scale;
2530if true {
if !(scale.yzx() * scale.zxy() != Vec3::ZERO) {
{
::core::panicking::panic_fmt(format_args!("mesh transform scale cannot be zero on more than one axis"));
}
};
};debug_assert!(
2531 scale.yzx() * scale.zxy() != Vec3::ZERO,
2532"mesh transform scale cannot be zero on more than one axis"
2533);
25342535if let Some(VertexAttributeValues::Float32x3(positions)) =
2536self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2537{
2538// Apply scale to vertex positions
2539positions2540 .iter_mut()
2541 .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
2542 }
25432544// No need to transform normals or tangents if scale is uniform
2545if scale.x == scale.y && scale.y == scale.z {
2546return Ok(());
2547 }
25482549if let Some(VertexAttributeValues::Float32x3(normals)) =
2550self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2551{
2552// Transform normals, taking into account non-uniform scaling
2553normals.iter_mut().for_each(|normal| {
2554*normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
2555 });
2556 }
25572558if let Some(VertexAttributeValues::Float32x4(tangents)) =
2559self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2560{
2561// Transform tangents, taking into account non-uniform scaling
2562tangents.iter_mut().for_each(|tangent| {
2563let handedness = tangent[3];
2564let scaled_tangent = Vec3::from_slice(tangent) * scale;
2565*tangent = scaled_tangent2566 .normalize_or_zero()
2567 .extend(handedness)
2568 .to_array();
2569 });
2570 }
25712572Ok(())
2573 }
25742575/// Normalize joint weights so they sum to 1.
2576 ///
2577 /// # Panics
2578 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2579 /// this as an error use [`Mesh::try_normalize_joint_weights`]
2580pub fn normalize_joint_weights(&mut self) {
2581self.try_normalize_joint_weights()
2582 .expect(MESH_EXTRACTED_ERROR);
2583 }
25842585/// Normalize joint weights so they sum to 1.
2586pub fn try_normalize_joint_weights(&mut self) -> Result<(), MeshAccessError> {
2587if let Some(VertexAttributeValues::Float32x4(joints)) =
2588self.try_attribute_mut_option(Self::ATTRIBUTE_JOINT_WEIGHT)?
2589{
2590for weights in joints.iter_mut() {
2591// force negative weights to zero
2592weights.iter_mut().for_each(|w| *w = w.max(0.0));
25932594let sum: f32 = weights.iter().sum();
2595if sum == 0.0 {
2596// all-zero weights are invalid
2597weights[0] = 1.0;
2598 } else {
2599let recip = sum.recip();
2600for weight in weights.iter_mut() {
2601*weight *= recip;
2602 }
2603 }
2604 }
2605 }
26062607Ok(())
2608 }
26092610/// Get a list of this Mesh's [triangles] as an iterator if possible.
2611 ///
2612 /// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
2613 /// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
2614 /// * The Mesh is missing position or index data.
2615 /// * The Mesh's position data has the wrong format (not `Float32x3`).
2616 ///
2617 /// [primitive topology]: PrimitiveTopology
2618 /// [triangles]: Triangle3d
2619pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
2620fn indices_to_triangle<T: TryInto<usize> + Copy>(
2621 vertices: &[[f32; 3]],
2622 indices: &[T; 3],
2623 ) -> Option<Triangle3d> {
2624let vert0 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
2625let vert1 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
2626let vert2 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
2627Some(Triangle3d {
2628 vertices: [vert0, vert1, vert2],
2629 })
2630 }
26312632let position_data = self.try_attribute(Mesh::ATTRIBUTE_POSITION)?;
26332634let Some(vertices) = position_data.as_float3() else {
2635return Err(MeshTrianglesError::PositionsFormat);
2636 };
26372638let indices = self.try_indices()?;
26392640match self.primitive_topology {
2641 PrimitiveTopology::TriangleList => {
2642// When indices reference out-of-bounds vertex data, the triangle is omitted.
2643 // This implicitly truncates the indices to a multiple of 3.
2644let iterator = match indices {
2645 Indices::U16(vec) => FourIterators::First(
2646vec.as_chunks()
2647 .0
2648.iter()
2649 .flat_map(|indices| indices_to_triangle(vertices, indices)),
2650 ),
2651 Indices::U32(vec) => FourIterators::Second(
2652vec.as_chunks()
2653 .0
2654.iter()
2655 .flat_map(|indices| indices_to_triangle(vertices, indices)),
2656 ),
2657 };
26582659Ok(iterator)
2660 }
2661 PrimitiveTopology::TriangleStrip => {
2662// When indices reference out-of-bounds vertex data, the triangle is omitted.
2663 // If there aren't enough indices to make a triangle, then an empty vector will be
2664 // returned.
2665let iterator = match indices {
2666 Indices::U16(vec) => {
2667 FourIterators::Third(vec.array_windows().enumerate().flat_map(
2668 |(i, indices @ &[idx0, idx1, idx2])| {
2669if i % 2 == 0 {
2670indices_to_triangle(vertices, indices)
2671 } else {
2672indices_to_triangle(vertices, &[idx1, idx0, idx2])
2673 }
2674 },
2675 ))
2676 }
2677 Indices::U32(vec) => {
2678 FourIterators::Fourth(vec.array_windows().enumerate().flat_map(
2679 |(i, indices @ &[idx0, idx1, idx2])| {
2680if i % 2 == 0 {
2681indices_to_triangle(vertices, indices)
2682 } else {
2683indices_to_triangle(vertices, &[idx1, idx0, idx2])
2684 }
2685 },
2686 ))
2687 }
2688 };
26892690Ok(iterator)
2691 }
2692_ => Err(MeshTrianglesError::WrongTopology),
2693 }
2694 }
26952696/// Extracts the mesh vertex, index and morph target data for GPU upload.
2697 /// This function is called internally in render world extraction, it is
2698 /// unlikely to be useful outside of that context.
2699 ///
2700 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2701pub fn take_gpu_data(&mut self) -> Result<Self, MeshAccessError> {
2702let attributes = self.attributes.extract()?;
2703let indices = self.indices.extract()?;
2704#[cfg(feature = "morph")]
2705let morph_targets = self.morph_targets.extract()?;
2706#[cfg(feature = "morph")]
2707let morph_target_names = self.morph_target_names.extract()?;
27082709// store the aabb extents as they cannot be computed after extraction
2710if let Some(MeshAttributeData { values, .. }) = attributes
2711 .as_ref_option()?
2712.and_then(|attrs| attrs.get(&Self::ATTRIBUTE_POSITION.id))
2713 {
2714self.final_aabb = Self::compute_aabb(values);
2715 }
2716Ok(Self {
2717attributes,
2718indices,
2719#[cfg(feature = "morph")]
2720morph_targets,
2721#[cfg(feature = "morph")]
2722morph_target_names,
2723 ..self.clone()
2724 })
2725 }
27262727/// Get this mesh's [`SkinnedMeshBounds`].
2728pub fn skinned_mesh_bounds(&self) -> Option<&SkinnedMeshBounds> {
2729self.skinned_mesh_bounds.as_ref()
2730 }
27312732/// Set this mesh's [`SkinnedMeshBounds`].
2733pub fn set_skinned_mesh_bounds(&mut self, skinned_mesh_bounds: Option<SkinnedMeshBounds>) {
2734self.skinned_mesh_bounds = skinned_mesh_bounds;
2735 }
27362737/// Consumes the mesh and returns a mesh with the given [`SkinnedMeshBounds`].
2738pub fn with_skinned_mesh_bounds(
2739mut self,
2740 skinned_mesh_bounds: Option<SkinnedMeshBounds>,
2741 ) -> Self {
2742self.set_skinned_mesh_bounds(skinned_mesh_bounds);
2743self2744 }
27452746/// Generate [`SkinnedMeshBounds`] for this mesh.
2747pub fn generate_skinned_mesh_bounds(&mut self) -> Result<(), SkinnedMeshBoundsError> {
2748self.skinned_mesh_bounds = Some(SkinnedMeshBounds::from_mesh(self)?);
2749Ok(())
2750 }
27512752/// Consumes the mesh and returns a mesh with generated [`SkinnedMeshBounds`].
2753pub fn with_generated_skinned_mesh_bounds(mut self) -> Result<Self, SkinnedMeshBoundsError> {
2754self.generate_skinned_mesh_bounds()?;
2755Ok(self)
2756 }
27572758/// Get multiple vertex attributes of the [`Mesh`] mutably.
2759 ///
2760 /// The result, if attributes are available and not extracted into the
2761 /// render world, will have the same length as `attributes`, and missing
2762 /// or duplicated ids will be returned as [`None`].
2763 ///
2764 /// ## Example
2765 /// ```
2766 /// # use bevy_asset::RenderAssetUsages;
2767 /// # use bevy_math::{Vec3, Vec4};
2768 /// # use bevy_mesh::{Mesh, PrimitiveTopology};
2769 /// # let mut mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
2770 /// # .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vec![Vec3::new(0., 0., 0.)])
2771 /// # .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![Vec3::new(1., 1., 1.)])
2772 /// # .with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, vec![Vec4::new(2., 2., 2., 2.)]);
2773 /// let Ok([pos1, pos2, pos3, normal, color]) = mesh.try_disjoint_attributes_mut([
2774 /// &Mesh::ATTRIBUTE_POSITION.id,
2775 /// &Mesh::ATTRIBUTE_POSITION.id,
2776 /// &Mesh::ATTRIBUTE_POSITION.id,
2777 /// &Mesh::ATTRIBUTE_NORMAL.id,
2778 /// &Mesh::ATTRIBUTE_COLOR.id,
2779 /// ]) else {
2780 /// // Data may have been extracted to the render world
2781 /// return;
2782 /// };
2783 /// assert_eq!(pos1.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
2784 /// assert!(pos2.is_none());
2785 /// assert!(pos3.is_none());
2786 /// assert_eq!(normal.unwrap().0, &Mesh::ATTRIBUTE_NORMAL);
2787 /// assert_eq!(color.unwrap().0, &Mesh::ATTRIBUTE_COLOR);
2788 /// ```
2789pub fn try_disjoint_attributes_mut<'a, const N: usize>(
2790&'a mut self,
2791 mesh_vertex_attribute_ids: [&MeshVertexAttributeId; N],
2792 ) -> Result<
2793 [Option<(&'a MeshVertexAttribute, &'a mut VertexAttributeValues)>; N],
2794MeshAccessError,
2795 > {
2796let attrs = self.attributes.as_mut()?;
2797let mut mut_attrs = attrs.iter_mut();
2798let mut attrs: [_; N] = std::array::from_fn(|_| {
2799for (attr_id, mut_attr) in mut_attrs.by_ref() {
2800if mesh_vertex_attribute_ids.contains(&attr_id) {
2801return Some((&mut_attr.attribute, &mut mut_attr.values));
2802 }
2803 }
2804None2805 });
28062807let mut attrs_slice = attrs.as_mut_slice();
2808for mesh_vertex_attribute_id in mesh_vertex_attribute_ids {
2809// If current key is different from top of attributes slice,
2810 // swap is needed
2811if attrs_slice[0]
2812 .as_ref()
2813 .filter(|(attr, _)| &attr.id != mesh_vertex_attribute_id)
2814 .is_some()
2815 {
2816if let Some(pos) = attrs_slice.iter().position(|attr| {
2817 attr.as_ref()
2818 .filter(|(attr, _)| &attr.id == mesh_vertex_attribute_id)
2819 .is_some()
2820 }) {
2821// Swap for the attribute with the correct id
2822attrs_slice.swap(0, pos);
2823 } else if attrs_slice[0].is_some() {
2824// If attribute with id does not exist and current attribute is not `None`
2825 // swap for a `None`
2826if let Some(pos) = attrs_slice[1..].iter().position(Option::is_none) {
2827 attrs_slice.swap(0, pos + 1);
2828 } else {
2829// attrs_slice will always have a least the same length as ks
2830{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Attribute list must have enough `None`s to be able to sort.")));
};unreachable!("Attribute list must have enough `None`s to be able to sort.");
2831 }
2832 }
2833 }
2834 attrs_slice = &mut attrs_slice[1..];
2835 }
28362837Ok(attrs)
2838 }
2839}
28402841#[cfg(feature = "morph")]
2842impl Mesh {
2843/// Whether this mesh has morph targets.
2844 ///
2845 /// # Panics
2846 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2847 /// this as an error use [`Mesh::try_has_morph_targets`]
2848pub fn has_morph_targets(&self) -> bool {
2849self.try_has_morph_targets().expect(MESH_EXTRACTED_ERROR)
2850 }
28512852/// Whether this mesh has morph targets.
2853pub fn try_has_morph_targets(&self) -> Result<bool, MeshAccessError> {
2854Ok(self.morph_targets.as_ref_option()?.is_some())
2855 }
28562857/// Set the [morph target] displacements for this mesh.
2858 ///
2859 /// [morph target]: https://en.wikipedia.org/wiki/Morph_target_animation
2860 ///
2861 /// # Panics
2862 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2863 /// this as an error use [`Mesh::try_set_morph_targets`]
2864#[cfg(feature = "morph")]
2865pub fn set_morph_targets(&mut self, morph_targets: Vec<MorphAttributes>) {
2866self.try_set_morph_targets(morph_targets)
2867 .expect(MESH_EXTRACTED_ERROR);
2868 }
28692870/// Set the [morph target] displacements for this mesh.
2871 ///
2872 /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2873#[cfg(feature = "morph")]
2874pub fn try_set_morph_targets(
2875&mut self,
2876 morph_targets: Vec<MorphAttributes>,
2877 ) -> Result<(), MeshAccessError> {
2878self.morph_targets.replace(Some(morph_targets))?;
2879Ok(())
2880 }
28812882/// Retrieve the morph target displacements for this mesh, or None if there
2883 /// are no morph targets.
2884 ///
2885 /// # Panics
2886 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2887 /// this as an error use [`Mesh::try_morph_targets`]
2888#[cfg(feature = "morph")]
2889pub fn morph_targets(&self) -> Option<&Vec<MorphAttributes>> {
2890self.morph_targets
2891 .as_ref_option()
2892 .expect(MESH_EXTRACTED_ERROR)
2893 }
28942895/// Retrieve the morph displacements for this mesh, or None if there are no
2896 /// morph targets.
2897 ///
2898 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2899 /// if the morph targets do not exist.
2900#[cfg(feature = "morph")]
2901pub fn try_morph_targets(&self) -> Result<&Vec<MorphAttributes>, MeshAccessError> {
2902self.morph_targets.as_ref()
2903 }
29042905/// Consumes the mesh and returns a mesh with the given [morph target]
2906 /// displacements.
2907 ///
2908 /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2909 ///
2910 /// [morph target]: https://en.wikipedia.org/wiki/Morph_target_animation
2911 ///
2912 /// # Panics
2913 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2914 /// this as an error use [`Mesh::try_with_morph_targets`]
2915#[must_use]
2916 #[cfg(feature = "morph")]
2917pub fn with_morph_targets(mut self, morph_targets: Vec<MorphAttributes>) -> Self {
2918self.set_morph_targets(morph_targets);
2919self2920 }
29212922/// Consumes the mesh and returns a mesh with the given [morph targets].
2923 ///
2924 /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2925 ///
2926 /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2927 ///
2928 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2929#[cfg(feature = "morph")]
2930pub fn try_with_morph_targets(
2931mut self,
2932 morph_targets: Vec<MorphAttributes>,
2933 ) -> Result<Self, MeshAccessError> {
2934self.try_set_morph_targets(morph_targets)?;
2935Ok(self)
2936 }
29372938/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2939 ///
2940 /// # Panics
2941 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2942 /// this as an error use [`Mesh::try_set_morph_target_names`]
2943pub fn set_morph_target_names(&mut self, names: Vec<String>) {
2944self.try_set_morph_target_names(names)
2945 .expect(MESH_EXTRACTED_ERROR);
2946 }
29472948/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2949 ///
2950 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2951pub fn try_set_morph_target_names(
2952&mut self,
2953 names: Vec<String>,
2954 ) -> Result<(), MeshAccessError> {
2955self.morph_target_names.replace(Some(names))?;
2956Ok(())
2957 }
29582959/// Consumes the mesh and returns a mesh with morph target names.
2960 /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2961 ///
2962 /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2963 ///
2964 /// # Panics
2965 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2966 /// this as an error use [`Mesh::try_set_morph_target_names`]
2967#[must_use]
2968pub fn with_morph_target_names(self, names: Vec<String>) -> Self {
2969self.try_with_morph_target_names(names)
2970 .expect(MESH_EXTRACTED_ERROR)
2971 }
29722973/// Consumes the mesh and returns a mesh with morph target names.
2974 /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2975 ///
2976 /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2977 ///
2978 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2979pub fn try_with_morph_target_names(
2980mut self,
2981 names: Vec<String>,
2982 ) -> Result<Self, MeshAccessError> {
2983self.try_set_morph_target_names(names)?;
2984Ok(self)
2985 }
29862987/// Gets a list of all morph target names, if they exist.
2988 ///
2989 /// # Panics
2990 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2991 /// this as an error use [`Mesh::try_morph_target_names`]
2992pub fn morph_target_names(&self) -> Option<&[String]> {
2993self.try_morph_target_names().expect(MESH_EXTRACTED_ERROR)
2994 }
29952996/// Gets a list of all morph target names, if they exist.
2997 ///
2998 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2999 /// if the morph targets do not exist.
3000pub fn try_morph_target_names(&self) -> Result<Option<&[String]>, MeshAccessError> {
3001Ok(self
3002.morph_target_names
3003 .as_ref_option()?
3004.map(core::ops::Deref::deref))
3005 }
3006}
30073008/// An enum to define which UV attribute to use for a texture.
3009///
3010/// It only supports two UV attributes, [`Mesh::ATTRIBUTE_UV_0`] and
3011/// [`Mesh::ATTRIBUTE_UV_1`].
3012/// The default is [`UvChannel::Uv0`].
3013#[derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for UvChannel where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectDefault, Self,
_>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {}
}
impl bevy_reflect::Typed for UvChannel where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Uv0")),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Uv1"))]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for UvChannel where {
fn type_path() -> &'static str { "bevy_mesh::mesh::UvChannel" }
fn short_type_path() -> &'static str { "UvChannel" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("UvChannel")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl bevy_reflect::Reflect for UvChannel where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
#[allow(non_upper_case_globals)]
const _: () =
{
static __INVENTORY: ::inventory::Node =
::inventory::Node {
value: &{
bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<UvChannel
as
bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
},
next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
};
#[link_section = ".text.startup"]
unsafe extern "C" fn __ctor() {
unsafe {
::inventory::ErasedNode::submit(__INVENTORY.value,
&__INVENTORY)
}
}
#[used]
#[link_section = ".init_array"]
static __CTOR: unsafe extern "C" fn() = __ctor;
};
impl bevy_reflect::enums::Enum for UvChannel where {
fn field(&self, __name_param: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at(&self, __index_param: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_mut(&mut self, __name_param: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at_mut(&mut self, __index_param: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn index_of(&self, __name_param: &str)
-> ::core::option::Option<usize> {
match self { _ => ::core::option::Option::None, }
}
fn name_at(&self, __index_param: usize)
-> ::core::option::Option<&str> {
match self { _ => ::core::option::Option::None, }
}
fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
bevy_reflect::enums::VariantFieldIter::new(self)
}
#[inline]
fn field_len(&self) -> usize {
match self {
UvChannel::Uv0 { .. } => 0usize,
UvChannel::Uv1 { .. } => 0usize,
_ => 0,
}
}
#[inline]
fn variant_name(&self) -> &str {
match self {
UvChannel::Uv0 { .. } => "Uv0",
UvChannel::Uv1 { .. } => "Uv1",
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_index(&self) -> usize {
match self {
UvChannel::Uv0 { .. } => 0usize,
UvChannel::Uv1 { .. } => 1usize,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_type(&self) -> bevy_reflect::enums::VariantType {
match self {
UvChannel::Uv0 { .. } =>
bevy_reflect::enums::VariantType::Unit,
UvChannel::Uv1 { .. } =>
bevy_reflect::enums::VariantType::Unit,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
fn to_dynamic_enum(&self)
->
::core::result::Result<bevy_reflect::enums::DynamicEnum,
bevy_reflect::ReflectCloneError> {
bevy_reflect::enums::DynamicEnum::try_from_ref::<Self>(self)
}
}
impl bevy_reflect::PartialReflect for UvChannel where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self,
__value_param: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Enum(__value_param) =
bevy_reflect::PartialReflect::reflect_ref(__value_param) {
if bevy_reflect::enums::Enum::variant_name(self) ==
bevy_reflect::enums::Enum::variant_name(__value_param) {
match bevy_reflect::enums::Enum::variant_type(__value_param)
{
bevy_reflect::enums::VariantType::Struct => {
for field in
bevy_reflect::enums::Enum::iter_fields(__value_param) {
let name = field.name().unwrap();
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
bevy_reflect::enums::VariantType::Tuple => {
for (index, field) in
::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
{
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_at_mut(self, index) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
_ => {}
}
} else {
match bevy_reflect::enums::Enum::variant_name(__value_param)
{
"Uv0" => { *self = UvChannel::Uv0 {} }
"Uv1" => { *self = UvChannel::Uv1 {} }
name => {
return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
variant_name: ::core::convert::Into::into(name),
});
}
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
to_kind: bevy_reflect::ReflectKind::Enum,
});
}
::core::result::Result::Ok(())
}
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Enum
}
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Enum(self)
}
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Enum(self)
}
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Enum(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_hash(&self) -> ::core::option::Option<u64> {
(bevy_reflect::enums::enum_hash)(self)
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
let value =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
if let ::core::option::Option::Some(value) = value {
::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
value))
} else { ::core::option::Option::Some(false) }
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::enums::enum_partial_cmp)(self, value)
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for UvChannel where {
fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Enum(__param0) =
bevy_reflect::PartialReflect::reflect_ref(__param0) {
match bevy_reflect::enums::Enum::variant_name(__param0) {
"Uv0" => ::core::option::Option::Some(UvChannel::Uv0 {}),
"Uv1" => ::core::option::Option::Some(UvChannel::Uv1 {}),
name => ::core::option::Option::None,
}
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl ::core::default::Default for UvChannel {
#[inline]
fn default() -> Self { Self::Uv0 }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for UvChannel {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self { UvChannel::Uv0 => "Uv0", UvChannel::Uv1 => "Uv1", })
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for UvChannel {
#[inline]
fn clone(&self) -> Self {
match self { Self::Uv0 => Self::Uv0, Self::Uv1 => Self::Uv1, }
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for UvChannel { }
#[automatically_derived]
impl ::core::cmp::PartialEq for UvChannel {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UvChannel { }Eq)]
3014#[reflect(Default, Debug, Clone, PartialEq)]
3015pub enum UvChannel {
3016#[default]
3017Uv0,
3018 Uv1,
3019}
30203021/// Correctly scales and renormalizes an already normalized `normal` by the scale determined by its reciprocal `scale_recip`
3022pub(crate) fn scale_normal(normal: Vec3, scale_recip: Vec3) -> Vec3 {
3023// This is basically just `normal * scale_recip` but with the added rule that `0. * anything == 0.`
3024 // This is necessary because components of `scale_recip` may be infinities, which do not multiply to zero
3025let n = Vec3::select(normal.cmpeq(Vec3::ZERO), Vec3::ZERO, normal * scale_recip);
30263027// If n is finite, no component of `scale_recip` was infinite or the normal was perpendicular to the scale
3028 // else the scale had at least one zero-component and the normal needs to point along the direction of that component
3029if n.is_finite() {
3030n.normalize_or_zero()
3031 } else {
3032Vec3::select(n.abs().cmpeq(Vec3::INFINITY), n.signum(), Vec3::ZERO).normalize()
3033 }
3034}
30353036impl core::ops::Mul<Mesh> for Transform {
3037type Output = Mesh;
30383039fn mul(self, rhs: Mesh) -> Self::Output {
3040rhs.transformed_by(self)
3041 }
3042}
30433044/// A version of [`Mesh`] suitable for serializing for short-term transfer.
3045///
3046/// [`Mesh`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.
3047/// It is not a general-purpose mesh implementation, and its internals are subject to frequent change.
3048/// As such, storing a [`Mesh`] on disk is highly discouraged.
3049///
3050/// But there are still some valid use cases for serializing a [`Mesh`], namely transferring meshes between processes.
3051/// To support this, you can create a [`SerializedMesh`] from a [`Mesh`] with [`SerializedMesh::from_mesh`],
3052/// and then deserialize it with [`SerializedMesh::deserialize`]. The caveats are:
3053/// - The mesh representation is not valid across different versions of Bevy.
3054/// - This conversion is lossy. Only the following information is preserved:
3055/// - Primitive topology
3056/// - Vertex attributes
3057/// - Indices
3058/// - Custom attributes that were not specified with [`MeshDeserializer::add_custom_vertex_attribute`] will be ignored while deserializing.
3059#[cfg(feature = "serialize")]
3060#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SerializedMesh {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"SerializedMesh", "primitive_topology", &self.primitive_topology,
"attributes", &self.attributes, "indices", &&self.indices)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SerializedMesh {
#[inline]
fn clone(&self) -> Self {
Self {
primitive_topology: ::core::clone::Clone::clone(&self.primitive_topology),
attributes: ::core::clone::Clone::clone(&self.attributes),
indices: ::core::clone::Clone::clone(&self.indices),
}
}
}Clone, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for SerializedMesh {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer,
"SerializedMesh", false as usize + 1 + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"primitive_topology", &self.primitive_topology)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"attributes", &self.attributes)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"indices", &self.indices)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for SerializedMesh {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __field2, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private229::Ok(__Field::__field0),
1u64 => _serde::__private229::Ok(__Field::__field1),
2u64 => _serde::__private229::Ok(__Field::__field2),
_ => _serde::__private229::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"primitive_topology" =>
_serde::__private229::Ok(__Field::__field0),
"attributes" => _serde::__private229::Ok(__Field::__field1),
"indices" => _serde::__private229::Ok(__Field::__field2),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"primitive_topology" =>
_serde::__private229::Ok(__Field::__field0),
b"attributes" =>
_serde::__private229::Ok(__Field::__field1),
b"indices" => _serde::__private229::Ok(__Field::__field2),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<SerializedMesh>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = SerializedMesh;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"struct SerializedMesh")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<PrimitiveTopology>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"struct SerializedMesh with 3 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>>(&mut __seq)? {
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(1usize,
&"struct SerializedMesh with 3 elements")),
};
let __field2 =
match _serde::de::SeqAccess::next_element::<Option<Indices>>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(2usize,
&"struct SerializedMesh with 3 elements")),
};
_serde::__private229::Ok(SerializedMesh {
primitive_topology: __field0,
attributes: __field1,
indices: __field2,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0:
_serde::__private229::Option<PrimitiveTopology> =
_serde::__private229::None;
let mut __field1:
_serde::__private229::Option<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>> = _serde::__private229::None;
let mut __field2:
_serde::__private229::Option<Option<Indices>> =
_serde::__private229::None;
while let _serde::__private229::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private229::Option::is_some(&__field0) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("primitive_topology"));
}
__field0 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<PrimitiveTopology>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private229::Option::is_some(&__field1) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("attributes"));
}
__field1 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>>(&mut __map)?);
}
__Field::__field2 => {
if _serde::__private229::Option::is_some(&__field2) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("indices"));
}
__field2 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Option<Indices>>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private229::Some(__field0) => __field0,
_serde::__private229::None =>
_serde::__private229::de::missing_field("primitive_topology")?,
};
let __field1 =
match __field1 {
_serde::__private229::Some(__field1) => __field1,
_serde::__private229::None =>
_serde::__private229::de::missing_field("attributes")?,
};
let __field2 =
match __field2 {
_serde::__private229::Some(__field2) => __field2,
_serde::__private229::None =>
_serde::__private229::de::missing_field("indices")?,
};
_serde::__private229::Ok(SerializedMesh {
primitive_topology: __field0,
attributes: __field1,
indices: __field2,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] =
&["primitive_topology", "attributes", "indices"];
_serde::Deserializer::deserialize_struct(__deserializer,
"SerializedMesh", FIELDS,
__Visitor {
marker: _serde::__private229::PhantomData::<SerializedMesh>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};Deserialize)]
3061pub struct SerializedMesh {
3062 primitive_topology: PrimitiveTopology,
3063 attributes: Vec<(MeshVertexAttributeId, SerializedMeshAttributeData)>,
3064 indices: Option<Indices>,
3065}
30663067#[cfg(feature = "serialize")]
3068impl SerializedMesh {
3069/// Create a [`SerializedMesh`] from a [`Mesh`]. See the documentation for [`SerializedMesh`] for caveats.
3070pub fn from_mesh(mut mesh: Mesh) -> Self {
3071Self {
3072 primitive_topology: mesh.primitive_topology,
3073 attributes: mesh3074 .attributes
3075 .replace(None)
3076 .expect(MESH_EXTRACTED_ERROR)
3077 .unwrap()
3078 .into_iter()
3079 .map(|(id, data)| {
3080 (
3081id,
3082SerializedMeshAttributeData::from_mesh_attribute_data(data),
3083 )
3084 })
3085 .collect(),
3086 indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),
3087 }
3088 }
30893090/// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
3091 ///
3092 /// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
3093pub fn into_mesh(self) -> Mesh {
3094MeshDeserializer::default().deserialize(self)
3095 }
3096}
30973098/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
3099#[cfg(feature = "serialize")]
3100pub struct MeshDeserializer {
3101 custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
3102}
31033104#[cfg(feature = "serialize")]
3105impl Defaultfor MeshDeserializer {
3106fn default() -> Self {
3107// Written like this so that the compiler can validate that we use all the built-in attributes.
3108 // If you just added a new attribute and got a compile error, please add it to this list :)
3109const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
3110Mesh::ATTRIBUTE_POSITION,
3111Mesh::ATTRIBUTE_NORMAL,
3112Mesh::ATTRIBUTE_UV_0,
3113Mesh::ATTRIBUTE_UV_1,
3114Mesh::ATTRIBUTE_TANGENT,
3115Mesh::ATTRIBUTE_COLOR,
3116Mesh::ATTRIBUTE_JOINT_WEIGHT,
3117Mesh::ATTRIBUTE_JOINT_INDEX,
3118 ];
3119Self {
3120 custom_vertex_attributes: BUILTINS3121 .into_iter()
3122 .map(|attribute| (attribute.name.into(), attribute))
3123 .collect(),
3124 }
3125 }
3126}
31273128#[cfg(feature = "serialize")]
3129impl MeshDeserializer {
3130/// Create a new [`MeshDeserializer`].
3131pub fn new() -> Self {
3132Self::default()
3133 }
31343135/// Register a custom vertex attribute to the deserializer. Custom vertex attributes that were not added with this method will be ignored while deserializing.
3136pub fn add_custom_vertex_attribute(
3137&mut self,
3138 name: &str,
3139 attribute: MeshVertexAttribute,
3140 ) -> &mut Self {
3141self.custom_vertex_attributes.insert(name.into(), attribute);
3142self3143 }
31443145/// Deserialize a [`SerializedMesh`] into a [`Mesh`].
3146 ///
3147 /// See the documentation for [`SerializedMesh`] for caveats.
3148pub fn deserialize(&self, serialized_mesh: SerializedMesh) -> Mesh {
3149Mesh {
3150 attributes: MeshExtractableData::Data(
3151serialized_mesh3152 .attributes
3153 .into_iter()
3154 .filter_map(|(id, data)| {
3155let attribute = data.attribute.clone();
3156let Some(data) =
3157data.try_into_mesh_attribute_data(&self.custom_vertex_attributes)
3158else {
3159{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event src/mesh.rs:3159",
"bevy_mesh::mesh", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("src/mesh.rs"),
::tracing_core::__macro_support::Option::Some(3159u32),
::tracing_core::__macro_support::Option::Some("bevy_mesh::mesh"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Deserialized mesh contains custom vertex attribute {0:?} that was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring.",
attribute) as &dyn ::tracing::field::Value))])
});
} else { ; }
};warn!(
3160"Deserialized mesh contains custom vertex attribute {attribute:?} that \
3161 was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring."
3162);
3163return None;
3164 };
3165Some((id, data))
3166 })
3167 .collect()),
3168 indices: serialized_mesh.indices.into(),
3169 ..Mesh::new(serialized_mesh.primitive_topology, RenderAssetUsages::default())
3170 }
3171 }
3172}
31733174/// Error that can occur when compressing/quantizing mesh vertex attributes.
3175#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for MeshAttributeCompressionError { }
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for MeshAttributeCompressionError {
fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
#[allow(unused_variables, deprecated, clippy ::
used_underscore_binding)]
match self {
MeshAttributeCompressionError::MissingAttribute(_0) =>
match (_0,) {
(__field0,) =>
__formatter.write_fmt(format_args!("Vertex attribute {0:?} doesn\'t exist",
__field0)),
},
MeshAttributeCompressionError::EmptyAttribute(_0) =>
match (_0,) {
(__field0,) =>
__formatter.write_fmt(format_args!("Vertex attribute {0:?} must not be empty",
__field0)),
},
MeshAttributeCompressionError::UnsupportedAttributeForCompression {
attr, expected } =>
match (attr, expected) {
(__field_attr, __field_expected) =>
__formatter.write_fmt(format_args!("Vertex attribute {0:?} must have format {1:?} before compressing/quantizing",
__field_attr, __field_expected)),
},
MeshAttributeCompressionError::UnsupportedAttributeForQuantizing {
attr } =>
match (attr,) {
(__field_attr,) =>
__formatter.write_fmt(format_args!("Vertex attribute {0:?} must have format `Float32`, `Float32x2` or `Float32x4` before quantizing",
__field_attr)),
},
}
}
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshAttributeCompressionError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::MissingAttribute(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MissingAttribute", &__self_0),
Self::EmptyAttribute(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"EmptyAttribute", &__self_0),
Self::UnsupportedAttributeForCompression {
attr: __self_0, expected: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"UnsupportedAttributeForCompression", "attr", __self_0,
"expected", &__self_1),
Self::UnsupportedAttributeForQuantizing { attr: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"UnsupportedAttributeForQuantizing", "attr", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshAttributeCompressionError {
#[inline]
fn clone(&self) -> Self {
match self {
Self::MissingAttribute(__self_0) =>
Self::MissingAttribute(::core::clone::Clone::clone(__self_0)),
Self::EmptyAttribute(__self_0) =>
Self::EmptyAttribute(::core::clone::Clone::clone(__self_0)),
Self::UnsupportedAttributeForCompression {
attr: __self_0, expected: __self_1 } =>
Self::UnsupportedAttributeForCompression {
attr: ::core::clone::Clone::clone(__self_0),
expected: ::core::clone::Clone::clone(__self_1),
},
Self::UnsupportedAttributeForQuantizing { attr: __self_0 } =>
Self::UnsupportedAttributeForQuantizing {
attr: ::core::clone::Clone::clone(__self_0),
},
}
}
}Clone)]
3176pub enum MeshAttributeCompressionError {
3177#[error("Vertex attribute {0:?} doesn't exist")]
3178MissingAttribute(MeshVertexAttributeId),
3179#[error("Vertex attribute {0:?} must not be empty")]
3180EmptyAttribute(MeshVertexAttribute),
3181#[error(
3182"Vertex attribute {attr:?} must have format {expected:?} before compressing/quantizing"
3183)]
3184UnsupportedAttributeForCompression {
3185 attr: MeshVertexAttribute,
3186 expected: VertexFormat,
3187 },
3188#[error("Vertex attribute {attr:?} must have format `Float32`, `Float32x2` or `Float32x4` before quantizing")]
3189UnsupportedAttributeForQuantizing { attr: MeshVertexAttribute },
3190}
31913192/// Error that can occur when calling [`Mesh::merge_duplicate_vertices`]
3193#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for MeshMergeDuplicateVerticesError {
fn source(&self)
->
::core::option::Option<&(dyn ::thiserror::__private21::Error +
'static)> {
use ::thiserror::__private21::AsDynError as _;
#[allow(deprecated)]
match self {
MeshMergeDuplicateVerticesError::IndicesAlreadySet { .. } =>
::core::option::Option::None,
MeshMergeDuplicateVerticesError::MeshAccessError { 0: source, .. }
=> ::core::option::Option::Some(source.as_dyn_error()),
}
}
}
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for MeshMergeDuplicateVerticesError {
fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
use ::thiserror::__private21::AsDisplay as _;
#[allow(unused_variables, deprecated, clippy ::
used_underscore_binding)]
match self {
MeshMergeDuplicateVerticesError::IndicesAlreadySet {} =>
__formatter.write_str("Index attribute already set."),
MeshMergeDuplicateVerticesError::MeshAccessError(_0) =>
match (_0.as_display(),) {
(__display0,) =>
__formatter.write_fmt(format_args!("Mesh access error: {0}",
__display0)),
},
}
}
}
MeshMergeDuplicateVerticesError
#[allow(clippy :: redundant_field_names)]
fn from(source: MeshAccessError) -> Self {
MeshMergeDuplicateVerticesError::MeshAccessError { 0: source }
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshMergeDuplicateVerticesError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::IndicesAlreadySet =>
::core::fmt::Formatter::write_str(f, "IndicesAlreadySet"),
Self::MeshAccessError(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MeshAccessError", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshMergeDuplicateVerticesError {
#[inline]
fn clone(&self) -> Self {
match self {
Self::IndicesAlreadySet => Self::IndicesAlreadySet,
Self::MeshAccessError(__self_0) =>
Self::MeshAccessError(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
3194pub enum MeshMergeDuplicateVerticesError {
3195#[error("Index attribute already set.")]
3196IndicesAlreadySet,
3197#[error("Mesh access error: {0}")]
3198MeshAccessError(#[from] MeshAccessError),
3199}
32003201/// Error that can occur when calling [`Mesh::merge`].
3202#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for MeshMergeError {
fn source(&self)
->
::core::option::Option<&(dyn ::thiserror::__private21::Error +
'static)> {
use ::thiserror::__private21::AsDynError as _;
#[allow(deprecated)]
match self {
MeshMergeError::IncompatibleVertexAttributes { .. } =>
::core::option::Option::None,
MeshMergeError::IncompatiblePrimitiveTopology { .. } =>
::core::option::Option::None,
MeshMergeError::MeshAccessError { 0: source, .. } =>
::core::option::Option::Some(source.as_dyn_error()),
}
}
}
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for MeshMergeError {
fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
use ::thiserror::__private21::AsDisplay as _;
#[allow(unused_variables, deprecated, clippy ::
used_underscore_binding)]
match self {
MeshMergeError::IncompatibleVertexAttributes {
self_attribute, other_attribute } =>
__formatter.write_fmt(format_args!("Incompatible vertex attribute types: {0} and {1}",
self_attribute.name,
other_attribute.map(|a| a.name).unwrap_or("None"))),
MeshMergeError::IncompatiblePrimitiveTopology {
self_primitive_topology, other_primitive_topology } =>
__formatter.write_fmt(format_args!("Incompatible primitive topologies: {0:?} and {1:?}",
self_primitive_topology, other_primitive_topology)),
MeshMergeError::MeshAccessError(_0) =>
match (_0.as_display(),) {
(__display0,) =>
__formatter.write_fmt(format_args!("Mesh access error: {0}",
__display0)),
},
}
}
}
MeshMergeError
#[allow(clippy :: redundant_field_names)]
fn from(source: MeshAccessError) -> Self {
MeshMergeError::MeshAccessError { 0: source }
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshMergeError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::IncompatibleVertexAttributes {
self_attribute: __self_0, other_attribute: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"IncompatibleVertexAttributes", "self_attribute", __self_0,
"other_attribute", &__self_1),
Self::IncompatiblePrimitiveTopology {
self_primitive_topology: __self_0,
other_primitive_topology: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"IncompatiblePrimitiveTopology", "self_primitive_topology",
__self_0, "other_primitive_topology", &__self_1),
Self::MeshAccessError(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MeshAccessError", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshMergeError {
#[inline]
fn clone(&self) -> Self {
match self {
Self::IncompatibleVertexAttributes {
self_attribute: __self_0, other_attribute: __self_1 } =>
Self::IncompatibleVertexAttributes {
self_attribute: ::core::clone::Clone::clone(__self_0),
other_attribute: ::core::clone::Clone::clone(__self_1),
},
Self::IncompatiblePrimitiveTopology {
self_primitive_topology: __self_0,
other_primitive_topology: __self_1 } =>
Self::IncompatiblePrimitiveTopology {
self_primitive_topology: ::core::clone::Clone::clone(__self_0),
other_primitive_topology: ::core::clone::Clone::clone(__self_1),
},
Self::MeshAccessError(__self_0) =>
Self::MeshAccessError(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
3203pub enum MeshMergeError {
3204#[error("Incompatible vertex attribute types: {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
3205IncompatibleVertexAttributes {
3206 self_attribute: MeshVertexAttribute,
3207 other_attribute: Option<MeshVertexAttribute>,
3208 },
3209#[error(
3210"Incompatible primitive topologies: {:?} and {:?}",
3211 self_primitive_topology,
3212 other_primitive_topology
3213 )]
3214IncompatiblePrimitiveTopology {
3215 self_primitive_topology: PrimitiveTopology,
3216 other_primitive_topology: PrimitiveTopology,
3217 },
3218#[error("Mesh access error: {0}")]
3219MeshAccessError(#[from] MeshAccessError),
3220}
32213222#[cfg(test)]
3223mod tests {
3224use super::Mesh;
3225#[cfg(feature = "serialize")]
3226use super::SerializedMesh;
3227use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
3228use crate::{
3229 AttributeQuantization, MeshAttributeCompressionFlags, MeshVertexAttribute,
3230 PrimitiveTopology,
3231 };
3232use bevy_asset::RenderAssetUsages;
3233use bevy_math::{Vec2, Vec3, Vec3A, Vec4};
3234use bevy_shape::{Aabb2d, Aabb3d, Triangle3d};
3235use bevy_transform::components::Transform;
32363237#[test]
3238 #[should_panic]
3239fn panic_invalid_format() {
3240let _mesh = Mesh::new(
3241 PrimitiveTopology::TriangleList,
3242 RenderAssetUsages::default(),
3243 )
3244 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
3245 }
32463247#[test]
3248fn transform_mesh() {
3249let mesh = Mesh::new(
3250 PrimitiveTopology::TriangleList,
3251 RenderAssetUsages::default(),
3252 )
3253 .with_inserted_attribute(
3254 Mesh::ATTRIBUTE_POSITION,
3255vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
3256 )
3257 .with_inserted_attribute(
3258 Mesh::ATTRIBUTE_NORMAL,
3259vec![
3260 Vec3::new(-1., -1., 1.).normalize().to_array(),
3261 Vec3::new(1., -1., 1.).normalize().to_array(),
3262 [0., 0., 1.],
3263 ],
3264 )
3265 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
32663267let mesh = mesh.transformed_by(
3268 Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
3269 );
32703271if let Some(VertexAttributeValues::Float32x3(positions)) =
3272 mesh.attribute(Mesh::ATTRIBUTE_POSITION)
3273 {
3274// All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
3275 // and then shifted by `-2.` along each axis
3276assert_eq!(
3277 positions,
3278&vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
3279 );
3280 } else {
3281panic!("Mesh does not have a position attribute");
3282 }
32833284if let Some(VertexAttributeValues::Float32x3(normals)) =
3285 mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
3286 {
3287assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
3288 } else {
3289panic!("Mesh does not have a normal attribute");
3290 }
32913292if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
3293assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
3294 } else {
3295panic!("Mesh does not have a uv attribute");
3296 }
3297 }
32983299#[test]
3300fn point_list_mesh_invert_winding() {
3301let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
3302 .with_inserted_indices(Indices::U32(vec![]));
3303assert!(matches!(
3304 mesh.with_inverted_winding(),
3305Err(MeshWindingInvertError::WrongTopology)
3306 ));
3307 }
33083309#[test]
3310fn line_list_mesh_invert_winding() {
3311let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
3312 .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
3313let mesh = mesh.with_inverted_winding().unwrap();
3314assert_eq!(
3315 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
3316vec![3, 2, 2, 1, 1, 0]
3317 );
3318 }
33193320#[test]
3321fn line_list_mesh_invert_winding_fail() {
3322let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
3323 .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
3324assert!(matches!(
3325 mesh.with_inverted_winding(),
3326Err(MeshWindingInvertError::AbruptIndicesEnd)
3327 ));
3328 }
33293330#[test]
3331fn line_strip_mesh_invert_winding() {
3332let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
3333 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
3334let mesh = mesh.with_inverted_winding().unwrap();
3335assert_eq!(
3336 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
3337vec![3, 2, 1, 0]
3338 );
3339 }
33403341#[test]
3342fn triangle_list_mesh_invert_winding() {
3343let mesh = Mesh::new(
3344 PrimitiveTopology::TriangleList,
3345 RenderAssetUsages::default(),
3346 )
3347 .with_inserted_indices(Indices::U32(vec![
33480, 3, 1, // First triangle
33491, 3, 2, // Second triangle
3350]));
3351let mesh = mesh.with_inverted_winding().unwrap();
3352assert_eq!(
3353 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
3354vec![
33550, 1, 3, // First triangle
33561, 2, 3, // Second triangle
3357]
3358 );
3359 }
33603361#[test]
3362fn triangle_list_mesh_invert_winding_fail() {
3363let mesh = Mesh::new(
3364 PrimitiveTopology::TriangleList,
3365 RenderAssetUsages::default(),
3366 )
3367 .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
3368assert!(matches!(
3369 mesh.with_inverted_winding(),
3370Err(MeshWindingInvertError::AbruptIndicesEnd)
3371 ));
3372 }
33733374#[test]
3375fn triangle_strip_mesh_invert_winding() {
3376let mesh = Mesh::new(
3377 PrimitiveTopology::TriangleStrip,
3378 RenderAssetUsages::default(),
3379 )
3380 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
3381let mesh = mesh.with_inverted_winding().unwrap();
3382assert_eq!(
3383 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
3384vec![3, 2, 1, 0]
3385 );
3386 }
33873388#[test]
3389fn compute_area_weighted_normals() {
3390let mut mesh = Mesh::new(
3391 PrimitiveTopology::TriangleList,
3392 RenderAssetUsages::default(),
3393 );
33943395// z y
3396 // | /
3397 // 3---2
3398 // | / \
3399 // 0-----1--x
34003401mesh.insert_attribute(
3402 Mesh::ATTRIBUTE_POSITION,
3403vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
3404 );
3405 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
3406 mesh.compute_area_weighted_normals();
3407let normals = mesh
3408 .attribute(Mesh::ATTRIBUTE_NORMAL)
3409 .unwrap()
3410 .as_float3()
3411 .unwrap();
3412assert_eq!(4, normals.len());
3413// 0
3414assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
3415// 1
3416assert_eq!([0., 0., 1.], normals[1]);
3417// 2
3418assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
3419// 3
3420assert_eq!([1., 0., 0.], normals[3]);
3421 }
34223423#[test]
3424fn compute_area_weighted_normals_proportionate() {
3425let mut mesh = Mesh::new(
3426 PrimitiveTopology::TriangleList,
3427 RenderAssetUsages::default(),
3428 );
34293430// z y
3431 // | /
3432 // 3---2..
3433 // | / \
3434 // 0-------1---x
34353436mesh.insert_attribute(
3437 Mesh::ATTRIBUTE_POSITION,
3438vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
3439 );
3440 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
3441 mesh.compute_area_weighted_normals();
3442let normals = mesh
3443 .attribute(Mesh::ATTRIBUTE_NORMAL)
3444 .unwrap()
3445 .as_float3()
3446 .unwrap();
3447assert_eq!(4, normals.len());
3448// 0
3449assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
3450// 1
3451assert_eq!([0., 0., 1.], normals[1]);
3452// 2
3453assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
3454// 3
3455assert_eq!([1., 0., 0.], normals[3]);
3456 }
34573458#[test]
3459fn compute_angle_weighted_normals() {
3460// CuboidMeshBuilder duplicates vertices (even though it is indexed)
34613462 // 5---------4
3463 // /| /|
3464 // 1-+-------0 |
3465 // | 6-------|-7
3466 // |/ |/
3467 // 2---------3
3468let verts = vec![
3469 [1.0, 1.0, 1.0],
3470 [-1.0, 1.0, 1.0],
3471 [-1.0, -1.0, 1.0],
3472 [1.0, -1.0, 1.0],
3473 [1.0, 1.0, -1.0],
3474 [-1.0, 1.0, -1.0],
3475 [-1.0, -1.0, -1.0],
3476 [1.0, -1.0, -1.0],
3477 ];
34783479let indices = Indices::U16(vec![
34800, 1, 2, 2, 3, 0, // front
34815, 4, 7, 7, 6, 5, // back
34821, 5, 6, 6, 2, 1, // left
34834, 0, 3, 3, 7, 4, // right
34844, 5, 1, 1, 0, 4, // top
34853, 2, 6, 6, 7, 3, // bottom
3486]);
3487let mut mesh = Mesh::new(
3488 PrimitiveTopology::TriangleList,
3489 RenderAssetUsages::default(),
3490 );
3491 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, verts);
3492 mesh.insert_indices(indices);
3493 mesh.compute_smooth_normals();
34943495let normals = mesh
3496 .attribute(Mesh::ATTRIBUTE_NORMAL)
3497 .unwrap()
3498 .as_float3()
3499 .unwrap();
35003501for new in normals.iter().copied().flatten() {
3502// std impl is unstable
3503const FRAC_1_SQRT_3: f32 = 0.57735026;
3504const MIN: f32 = FRAC_1_SQRT_3 - f32::EPSILON;
3505const MAX: f32 = FRAC_1_SQRT_3 + f32::EPSILON;
3506assert!(new.abs() >= MIN, "{new} < {MIN}");
3507assert!(new.abs() <= MAX, "{new} > {MAX}");
3508 }
3509 }
35103511#[test]
3512fn triangles_from_triangle_list() {
3513let mut mesh = Mesh::new(
3514 PrimitiveTopology::TriangleList,
3515 RenderAssetUsages::default(),
3516 );
3517 mesh.insert_attribute(
3518 Mesh::ATTRIBUTE_POSITION,
3519vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
3520 );
3521 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
3522assert_eq!(
3523vec![
3524 Triangle3d {
3525 vertices: [
3526 Vec3::new(0., 0., 0.),
3527 Vec3::new(1., 0., 0.),
3528 Vec3::new(1., 1., 0.),
3529 ]
3530 },
3531 Triangle3d {
3532 vertices: [
3533 Vec3::new(1., 1., 0.),
3534 Vec3::new(0., 1., 0.),
3535 Vec3::new(0., 0., 0.),
3536 ]
3537 }
3538 ],
3539 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3540 );
3541 }
35423543#[test]
3544fn triangles_from_triangle_strip() {
3545let mut mesh = Mesh::new(
3546 PrimitiveTopology::TriangleStrip,
3547 RenderAssetUsages::default(),
3548 );
3549// Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
3550 //
3551 // 4 - 5
3552 // | \ |
3553 // 2 - 3
3554 // | \ |
3555 // 0 - 1
3556let positions: Vec<Vec3> = [
3557 [0., 0., 0.],
3558 [1., 0., 0.],
3559 [0., 1., 0.],
3560 [1., 1., 0.],
3561 [0., 2., 0.],
3562 [1., 2., 0.],
3563 ]
3564 .into_iter()
3565 .map(Vec3::from_array)
3566 .collect();
3567 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
3568 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
3569assert_eq!(
3570vec![
3571 Triangle3d {
3572 vertices: [positions[0], positions[1], positions[2]]
3573 },
3574 Triangle3d {
3575 vertices: [positions[2], positions[1], positions[3]]
3576 },
3577 Triangle3d {
3578 vertices: [positions[2], positions[3], positions[4]]
3579 },
3580 Triangle3d {
3581 vertices: [positions[4], positions[3], positions[5]]
3582 },
3583 ],
3584 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3585 );
3586 }
35873588#[test]
3589fn take_gpu_data_calculates_aabb() {
3590let mut mesh = Mesh::new(
3591 PrimitiveTopology::TriangleList,
3592 RenderAssetUsages::default(),
3593 );
3594 mesh.insert_attribute(
3595 Mesh::ATTRIBUTE_POSITION,
3596vec![
3597 [-0.5, 0., 0.],
3598 [-1., 0., 0.],
3599 [-1., -1., 0.],
3600 [-0.5, -1., 0.],
3601 ],
3602 );
3603 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
3604 mesh = mesh.take_gpu_data().unwrap();
3605assert_eq!(
3606 mesh.final_aabb,
3607Some(Aabb3d::from_min_max([-1., -1., 0.], [-0.5, 0., 0.]))
3608 );
3609 }
36103611#[cfg(feature = "serialize")]
3612 #[test]
3613fn serialize_deserialize_mesh() {
3614let mut mesh = Mesh::new(
3615 PrimitiveTopology::TriangleList,
3616 RenderAssetUsages::default(),
3617 );
36183619 mesh.insert_attribute(
3620 Mesh::ATTRIBUTE_POSITION,
3621vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
3622 );
3623 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
36243625let serialized_mesh = SerializedMesh::from_mesh(mesh.clone());
3626let serialized_string = serde_json::to_string(&serialized_mesh).unwrap();
3627let serialized_mesh_from_string: SerializedMesh =
3628 serde_json::from_str(&serialized_string).unwrap();
3629let deserialized_mesh = serialized_mesh_from_string.into_mesh();
3630assert_eq!(mesh, deserialized_mesh);
3631 }
36323633#[test]
3634fn merge_duplicate_vertices() {
3635let mut mesh = Mesh::new(
3636 PrimitiveTopology::TriangleList,
3637 RenderAssetUsages::default(),
3638 );
3639// Quad made of two triangles.
3640let positions = vec![
3641 [0.0, 0.0, 0.0],
3642 [1.0, 0.0, 0.0],
3643 [1.0, 1.0, 0.0],
3644// This will be deduplicated.
3645[1.0, 1.0, 0.0],
3646 [0.0, 1.0, 0.0],
3647// Position is equal to the first one but UV is different so it won't be deduplicated.
3648[0.0, 0.0, 0.0],
3649 ];
3650let uvs = vec![
3651 [0.0, 0.0],
3652 [1.0, 0.0],
3653 [1.0, 1.0],
3654// This will be deduplicated.
3655[1.0, 1.0],
3656 [0.0, 1.0],
3657// Use different UV here so it won't be deduplicated.
3658[0.0, 0.5],
3659 ];
3660 mesh.insert_attribute(
3661 Mesh::ATTRIBUTE_POSITION,
3662 VertexAttributeValues::Float32x3(positions.clone()),
3663 );
3664 mesh.insert_attribute(
3665 Mesh::ATTRIBUTE_UV_0,
3666 VertexAttributeValues::Float32x2(uvs.clone()),
3667 );
36683669let res = mesh.merge_duplicate_vertices();
3670assert!(res.is_ok());
3671assert_eq!(6, mesh.indices().unwrap().len());
3672// Note we have 5 unique vertices, not 6.
3673assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().len());
3674assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap().len());
36753676// Duplicate back.
3677mesh.duplicate_vertices();
3678assert!(mesh.indices().is_none());
3679let VertexAttributeValues::Float32x3(new_positions) =
3680 mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap()
3681else {
3682panic!("Unexpected attribute type")
3683 };
3684let VertexAttributeValues::Float32x2(new_uvs) =
3685 mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap()
3686else {
3687panic!("Unexpected attribute type")
3688 };
3689assert_eq!(&positions, new_positions);
3690assert_eq!(&uvs, new_uvs);
3691 }
36923693#[test]
3694fn compress_mesh_positions() {
3695let mut mesh = Mesh::new(
3696 PrimitiveTopology::TriangleList,
3697 RenderAssetUsages::default(),
3698 )
3699 .with_inserted_attribute(
3700 Mesh::ATTRIBUTE_POSITION,
3701vec![
3702 [0.0, 1.0, -1.0],
3703 [1.0, -0.5, -1.0],
3704 [-1.0, -0.5, -1.0],
3705 [0.0, -0.5, 1.0],
3706 ],
3707 );
3708 mesh.compress_positions().unwrap();
3709assert_eq!(
3710 mesh.final_aabb,
3711Some(Aabb3d::from_min_max(
3712 Vec3A::new(-1.0, -0.5, -1.0),
3713 Vec3A::new(1.0, 1.0, 1.0)
3714 ))
3715 );
3716assert_eq!(
3717 mesh.attribute_compression,
3718 MeshAttributeCompressionFlags::COMPRESS_POSITION
3719 );
3720assert_eq!(
3721 mesh.attribute(Mesh::ATTRIBUTE_POSITION),
3722Some(&VertexAttributeValues::Snorm16x4(vec![
3723 [0, 32767, -32767, 0],
3724 [32767, -32767, -32767, 0],
3725 [-32767, -32767, -32767, 0],
3726 [0, -32767, 32767, 0],
3727 ]))
3728 );
3729 }
37303731#[test]
3732fn compress_mesh_uvs() {
3733let mut mesh = Mesh::new(
3734 PrimitiveTopology::TriangleList,
3735 RenderAssetUsages::default(),
3736 )
3737 .with_inserted_attribute(
3738 Mesh::ATTRIBUTE_UV_0,
3739vec![[0.126, 0.497], [0.126, 1.0], [0.05, 0.0], [0.0, 0.5]],
3740 )
3741 .with_inserted_attribute(
3742 Mesh::ATTRIBUTE_UV_1,
3743vec![[12.6, 0.497], [0.126, 1.0], [-4.05, 0.0], [1.0, -0.5]],
3744 );
3745 mesh.compress_uv0().unwrap();
3746assert_eq!(
3747 mesh.final_uv_ranges,
3748 [
3749Some(Aabb2d {
3750 min: Vec2::new(0.0, 0.0),
3751 max: Vec2::new(0.126, 1.0)
3752 }),
3753None
3754]
3755 );
3756assert_eq!(
3757 mesh.attribute_compression,
3758 MeshAttributeCompressionFlags::COMPRESS_UV0
3759 );
3760assert_eq!(
3761 mesh.attribute(Mesh::ATTRIBUTE_UV_0),
3762Some(&VertexAttributeValues::Unorm16x2(vec![
3763 [65535, 32571],
3764 [65535, 65535],
3765 [26006, 0],
3766 [0, 32768],
3767 ]))
3768 );
37693770 mesh.compress_uv1().unwrap();
3771assert_eq!(
3772 mesh.final_uv_ranges,
3773 [
3774Some(Aabb2d {
3775 min: Vec2::new(0.0, 0.0),
3776 max: Vec2::new(0.126, 1.0)
3777 }),
3778Some(Aabb2d {
3779 min: Vec2::new(-4.05, -0.5),
3780 max: Vec2::new(12.6, 1.0)
3781 })
3782 ]
3783 );
3784assert_eq!(
3785 mesh.attribute_compression,
3786 MeshAttributeCompressionFlags::COMPRESS_UV0
3787 | MeshAttributeCompressionFlags::COMPRESS_UV1
3788 );
3789assert_eq!(
3790 mesh.attribute(Mesh::ATTRIBUTE_UV_1),
3791Some(&VertexAttributeValues::Unorm16x2(vec![
3792 [65535, 43559],
3793 [16437, 65535],
3794 [0, 21845],
3795 [19877, 0]
3796 ]))
3797 );
3798 }
37993800#[test]
3801fn compress_mesh_normals() {
3802let mut mesh = Mesh::new(
3803 PrimitiveTopology::TriangleList,
3804 RenderAssetUsages::default(),
3805 )
3806 .with_inserted_attribute(
3807 Mesh::ATTRIBUTE_NORMAL,
3808vec![
3809 Vec3::new(0.0, 1.0, -1.0).normalize().to_array(),
3810 Vec3::new(1.0, 0.0, -1.0).normalize().to_array(),
3811 Vec3::new(-1.0, 0.0, -1.0).normalize().to_array(),
3812 [0.0, 0.0, 1.0],
3813 ],
3814 );
3815 mesh.compress_normals().unwrap();
3816assert_eq!(
3817 mesh.attribute_compression,
3818 MeshAttributeCompressionFlags::COMPRESS_NORMAL
3819 );
3820assert_eq!(
3821 mesh.attribute(Mesh::ATTRIBUTE_NORMAL),
3822Some(&VertexAttributeValues::Snorm16x2(vec![
3823 [16384, 32767],
3824 [32767, 16384],
3825 [-32767, 16384],
3826 [0, 0],
3827 ]))
3828 );
3829 }
38303831#[test]
3832fn compress_mesh_tangents() {
3833let mut mesh = Mesh::new(
3834 PrimitiveTopology::TriangleList,
3835 RenderAssetUsages::default(),
3836 )
3837 .with_inserted_attribute(
3838 Mesh::ATTRIBUTE_TANGENT,
3839vec![
3840 Vec3::new(0.0, 1.0, 1.0).normalize().extend(1.0).to_array(),
3841 Vec3::new(1.0, 0.0, 1.0).normalize().extend(-1.0).to_array(),
3842 Vec3::new(-1.0, 0.0, 1.0).normalize().extend(1.0).to_array(),
3843 [1.0, 0.0, 0.0, 1.0],
3844 ],
3845 );
3846 mesh.compress_tangents().unwrap();
3847assert_eq!(
3848 mesh.attribute_compression,
3849 MeshAttributeCompressionFlags::COMPRESS_TANGENT
3850 );
3851assert_eq!(
3852 mesh.attribute(Mesh::ATTRIBUTE_TANGENT),
3853Some(&VertexAttributeValues::Snorm16x2(vec![
3854 [0, 24575],
3855 [16384, -16384],
3856 [-16384, 16384],
3857 [32767, 16384],
3858 ]))
3859 );
3860 }
38613862#[test]
3863fn quantize_mesh_colors() {
3864let mut mesh = Mesh::new(
3865 PrimitiveTopology::TriangleList,
3866 RenderAssetUsages::default(),
3867 )
3868 .with_inserted_attribute(
3869 Mesh::ATTRIBUTE_COLOR,
3870vec![
3871 [0.05, 1.0, 0.15, 1.0],
3872 [0.75, 0.07, 1.0, 1.0],
3873 [0.04, 0.11, 1.0, 1.0],
3874 [1.0, 0.11, 0.13, 1.0],
3875 ],
3876 );
3877let mut mesh_color_f16 = mesh.clone();
38783879 mesh.quantize_colors(AttributeQuantization::Unorm8).unwrap();
3880assert_eq!(
3881 mesh.attribute_compression,
3882 MeshAttributeCompressionFlags::empty()
3883 );
3884assert_eq!(
3885 mesh.attribute(Mesh::ATTRIBUTE_COLOR),
3886Some(&VertexAttributeValues::Unorm8x4(vec![
3887 [13, 255, 38, 255],
3888 [191, 18, 255, 255],
3889 [10, 28, 255, 255],
3890 [255, 28, 33, 255],
3891 ]))
3892 );
38933894 mesh_color_f16
3895 .quantize_colors(AttributeQuantization::Float16)
3896 .unwrap();
3897assert_eq!(
3898 mesh_color_f16.attribute_compression,
3899 MeshAttributeCompressionFlags::empty()
3900 );
3901let VertexAttributeValues::Float16x4(color_f16) =
3902 mesh_color_f16.attribute(Mesh::ATTRIBUTE_COLOR).unwrap()
3903else {
3904panic!("Color attribute is not quantized to Float16x4")
3905 };
3906assert!(color_f16
3907 .iter()
3908 .flatten()
3909 .zip(
3910 [
3911 [0.049987793, 1.0, 0.15002441, 1.0].map(half::f16::from_f32),
3912 [0.75, 0.070007324, 1.0, 1.0].map(half::f16::from_f32),
3913 [0.040008545, 0.10998535, 1.0, 1.0].map(half::f16::from_f32),
3914 [1.0, 0.10998535, 0.13000488, 1.0].map(half::f16::from_f32)
3915 ]
3916 .iter()
3917 .flatten()
3918 )
3919 .all(|(a, b)| approx::relative_eq!(a.to_f32(), b.to_f32())));
3920 }
39213922#[test]
3923fn quantize_mesh_joint_weights() {
3924let mut mesh = Mesh::new(
3925 PrimitiveTopology::TriangleList,
3926 RenderAssetUsages::default(),
3927 )
3928 .with_inserted_attribute(
3929 Mesh::ATTRIBUTE_JOINT_WEIGHT,
3930vec![
3931 [1.0, 0.0, 0.0, 0.0],
3932 [0.0, 1.0, 0.0, 0.0],
3933 [0.0, 0.0, 1.0, 0.0],
3934 [0.0, 0.0, 0.0, 1.0],
3935 [0.1, 0.9, 0.0, 0.0],
3936 [0.1, 0.2, 0.7, 0.0],
3937 [0.1, 0.2, 0.4, 0.3],
3938 ],
3939 );
39403941 mesh.quantize_joint_weights(AttributeQuantization::Unorm16)
3942 .unwrap();
3943assert_eq!(
3944 mesh.attribute_compression,
3945 MeshAttributeCompressionFlags::empty()
3946 );
3947assert_eq!(
3948 mesh.attribute(Mesh::ATTRIBUTE_JOINT_WEIGHT),
3949Some(&VertexAttributeValues::Unorm16x4(vec![
3950 [65535, 0, 0, 0],
3951 [0, 65535, 0, 0],
3952 [0, 0, 65535, 0],
3953 [0, 0, 0, 65535],
3954 [6554, 58982, 0, 0],
3955 [6554, 13107, 45875, 0],
3956 [6554, 13107, 26214, 19661]
3957 ]))
3958 );
3959 }
39603961#[test]
3962fn compress_mesh_indices() {
3963let mut mesh = Mesh::new(
3964 PrimitiveTopology::TriangleList,
3965 RenderAssetUsages::default(),
3966 )
3967 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 0, 3, 1, 0, 2, 3, 1, 3, 2]));
39683969 mesh.compress_indices();
3970assert_eq!(
3971 mesh.attribute_compression,
3972 MeshAttributeCompressionFlags::empty()
3973 );
3974assert_eq!(
3975 mesh.indices(),
3976Some(&Indices::U16(vec![0, 1, 2, 0, 3, 1, 0, 2, 3, 1, 3, 2]))
3977 );
3978 }
39793980#[test]
3981fn quantize_mesh_float32_attributes() {
3982let f4 = MeshVertexAttribute::new("f32x4", 10, wgpu_types::VertexFormat::Float32x4);
3983let f2 = MeshVertexAttribute::new("f32x2", 11, wgpu_types::VertexFormat::Float32x2);
3984let f1 = MeshVertexAttribute::new("f32x1", 12, wgpu_types::VertexFormat::Float32);
3985let mut mesh = Mesh::new(
3986 PrimitiveTopology::TriangleList,
3987 RenderAssetUsages::default(),
3988 )
3989 .with_inserted_attribute(
3990 f4,
3991vec![
3992 [1.0, 0.0, -2.0, 0.0],
3993 [0.0, 5.0, 0.0, 0.0],
3994 [0.0, 0.0, -1.0, 0.0],
3995 [0.0, 0.0, 0.0, 1.0],
3996 [0.1, -0.9, 0.0, 0.0],
3997 [0.1, 0.2, -0.7, 0.0],
3998 [0.1, 0.2, 0.4, 0.3],
3999 ],
4000 )
4001 .with_inserted_attribute(
4002 f2,
4003vec![
4004 [10.0, 0.0],
4005 [0.0, 1.0],
4006 [-2.0, 0.0],
4007 [-0.5, 0.0],
4008 [0.1, 0.9],
4009 [0.1, 0.2],
4010 [0.1, 0.2],
4011 ],
4012 )
4013 .with_inserted_attribute(f1, vec![10.0, 0.0, 2.0, 0.0, 0.1, 0.1, 0.1]);
40144015 mesh.quantize_float32_attribute(f4, AttributeQuantization::Unorm16)
4016 .unwrap();
4017assert_eq!(
4018 mesh.attribute(f4),
4019Some(&VertexAttributeValues::Unorm16x4(vec![
4020 [65535, 0, 0, 0],
4021 [0, 65535, 0, 0],
4022 [0, 0, 0, 0],
4023 [0, 0, 0, 65535],
4024 [6554, 0, 0, 0],
4025 [6554, 13107, 0, 0],
4026 [6554, 13107, 26214, 19661]
4027 ]))
4028 );
40294030 mesh.quantize_float32_attribute(f2, AttributeQuantization::Snorm8)
4031 .unwrap();
4032assert_eq!(
4033 mesh.attribute(f2),
4034Some(&VertexAttributeValues::Snorm8x2(vec![
4035 [127, 0],
4036 [0, 127],
4037 [-127, 0],
4038 [-64, 0],
4039 [13, 114],
4040 [13, 25],
4041 [13, 25]
4042 ]))
4043 );
40444045 mesh.quantize_float32_attribute(f1, AttributeQuantization::Float16)
4046 .unwrap();
4047let VertexAttributeValues::Float16(f16_values) = mesh.attribute(f1).unwrap() else {
4048panic!("Attribute f1 is not quantized to Float16")
4049 };
4050assert!(f16_values
4051 .iter()
4052 .zip([10.0, 0.0, 2.0, 0.0, 0.1, 0.1, 0.1].map(half::f16::from_f32))
4053 .all(|(a, b)| approx::relative_eq!(a.to_f32(), b.to_f32())));
4054 }
40554056#[test]
4057fn get_attributes_mut_test() {
4058let mut mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default());
40594060 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vec![Vec3::new(0., 0., 0.)]);
4061 mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vec![Vec3::new(1., 1., 1.)]);
4062 mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vec![Vec4::new(2., 2., 2., 2.)]);
4063 {
4064let Ok([pos, normal, color]) = mesh.try_disjoint_attributes_mut([
4065&Mesh::ATTRIBUTE_POSITION.id,
4066&Mesh::ATTRIBUTE_NORMAL.id,
4067&Mesh::ATTRIBUTE_COLOR.id,
4068 ]) else {
4069unreachable!("Data shouldn't have been extracted.");
4070 };
4071assert_eq!(pos.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
4072assert_eq!(normal.unwrap().0, &Mesh::ATTRIBUTE_NORMAL);
4073assert_eq!(color.unwrap().0, &Mesh::ATTRIBUTE_COLOR);
4074 }
4075 {
4076let Ok([pos, color, normal]) = mesh.try_disjoint_attributes_mut([
4077&Mesh::ATTRIBUTE_POSITION.id,
4078&Mesh::ATTRIBUTE_COLOR.id,
4079&Mesh::ATTRIBUTE_NORMAL.id,
4080 ]) else {
4081unreachable!("Data shouldn't have been extracted.");
4082 };
4083assert_eq!(pos.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
4084assert_eq!(color.unwrap().0, &Mesh::ATTRIBUTE_COLOR);
4085assert_eq!(normal.unwrap().0, &Mesh::ATTRIBUTE_NORMAL);
4086 }
4087 {
4088let Ok([pos1, pos2, pos3]) = mesh.try_disjoint_attributes_mut([
4089&Mesh::ATTRIBUTE_POSITION.id,
4090&Mesh::ATTRIBUTE_POSITION.id,
4091&Mesh::ATTRIBUTE_POSITION.id,
4092 ]) else {
4093unreachable!("Data shouldn't have been extracted.");
4094 };
4095assert_eq!(pos1.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
4096assert!(pos2.is_none());
4097assert!(pos3.is_none());
4098 }
4099 {
4100let Ok([pos1, pos2, pos3, normal, color]) = mesh.try_disjoint_attributes_mut([
4101&Mesh::ATTRIBUTE_POSITION.id,
4102&Mesh::ATTRIBUTE_POSITION.id,
4103&Mesh::ATTRIBUTE_POSITION.id,
4104&Mesh::ATTRIBUTE_NORMAL.id,
4105&Mesh::ATTRIBUTE_COLOR.id,
4106 ]) else {
4107unreachable!("Data shouldn't have been extracted.");
4108 };
4109assert_eq!(pos1.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
4110assert!(pos2.is_none());
4111assert!(pos3.is_none());
4112assert_eq!(normal.unwrap().0, &Mesh::ATTRIBUTE_NORMAL);
4113assert_eq!(color.unwrap().0, &Mesh::ATTRIBUTE_COLOR);
4114 }
4115 {
4116let Ok([color, uv0, normal, uv1, pos]) = mesh.try_disjoint_attributes_mut([
4117&Mesh::ATTRIBUTE_COLOR.id,
4118&Mesh::ATTRIBUTE_UV_0.id,
4119&Mesh::ATTRIBUTE_NORMAL.id,
4120&Mesh::ATTRIBUTE_UV_1.id,
4121&Mesh::ATTRIBUTE_POSITION.id,
4122 ]) else {
4123unreachable!("Data shouldn't have been extracted.");
4124 };
4125assert_eq!(color.unwrap().0, &Mesh::ATTRIBUTE_COLOR);
4126assert!(uv0.is_none());
4127assert_eq!(normal.unwrap().0, &Mesh::ATTRIBUTE_NORMAL);
4128assert!(uv1.is_none());
4129assert_eq!(pos.unwrap().0, &Mesh::ATTRIBUTE_POSITION);
4130 }
4131 }
4132}