Skip to main content

bevy_mesh/
components.rs

1use crate::mesh::Mesh;
2use bevy_asset::{AsAssetId, AssetEvent, AssetId, Handle};
3use bevy_derive::{Deref, DerefMut};
4use bevy_ecs::{
5    change_detection::DetectChangesMut, component::Component, message::MessageReader,
6    reflect::ReflectComponent, system::Query, template::FromTemplate,
7};
8use bevy_platform::{collections::HashSet, hash::FixedHasher};
9use bevy_reflect::{std_traits::ReflectDefault, Reflect};
10use bevy_transform::components::Transform;
11use core::any::TypeId;
12use derive_more::derive::From;
13
14/// A component for 2D meshes. Requires a [`MeshMaterial2d`] to be rendered, commonly using a [`ColorMaterial`].
15///
16/// [`MeshMaterial2d`]: <https://docs.rs/bevy/latest/bevy/prelude/struct.MeshMaterial2d.html>
17/// [`ColorMaterial`]: <https://docs.rs/bevy/latest/bevy/prelude/struct.ColorMaterial.html>
18///
19/// # Example
20///
21/// ```ignore
22/// # use bevy_sprite::{ColorMaterial, MeshMaterial2d};
23/// # use bevy_ecs::prelude::*;
24/// # use bevy_mesh::{Mesh, Mesh2d};
25/// # use bevy_color::palettes::basic::RED;
26/// # use bevy_asset::Assets;
27/// # use bevy_shape::Circle;
28/// #
29/// // Spawn an entity with a mesh using `ColorMaterial`.
30/// fn setup(
31///     mut commands: Commands,
32///     mut meshes: ResMut<Assets<Mesh>>,
33///     mut materials: ResMut<Assets<ColorMaterial>>,
34/// ) {
35///     commands.spawn((
36///         Mesh2d(meshes.add(Circle::new(50.0))),
37///         MeshMaterial2d(materials.add(ColorMaterial::from_color(RED))),
38///     ));
39/// }
40/// ```
41#[derive(
42    Component, FromTemplate, Clone, Debug, Default, Deref, DerefMut, Reflect, PartialEq, Eq, From,
43)]
44#[reflect(Component, Default, Clone, PartialEq)]
45#[require(Transform)]
46pub struct Mesh2d(pub Handle<Mesh>);
47
48impl From<Mesh2d> for AssetId<Mesh> {
49    fn from(mesh: Mesh2d) -> Self {
50        mesh.id()
51    }
52}
53
54impl From<&Mesh2d> for AssetId<Mesh> {
55    fn from(mesh: &Mesh2d) -> Self {
56        mesh.id()
57    }
58}
59
60impl AsAssetId for Mesh2d {
61    type Asset = Mesh;
62
63    fn as_asset_id(&self) -> AssetId<Self::Asset> {
64        self.id()
65    }
66}
67
68/// A component for 3D meshes. Requires a [`MeshMaterial3d`] to be rendered, commonly using a [`StandardMaterial`].
69///
70/// [`MeshMaterial3d`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.MeshMaterial3d.html>
71/// [`StandardMaterial`]: <https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html>
72///
73/// # Example
74///
75/// ```ignore
76/// # use bevy_pbr::{Material, MeshMaterial3d, StandardMaterial};
77/// # use bevy_ecs::prelude::*;
78/// # use bevy_mesh::{Mesh, Mesh3d};
79/// # use bevy_color::palettes::basic::RED;
80/// # use bevy_asset::Assets;
81/// # use bevy_shape::Capsule3d;
82/// #
83/// // Spawn an entity with a mesh using `StandardMaterial`.
84/// fn setup(
85///     mut commands: Commands,
86///     mut meshes: ResMut<Assets<Mesh>>,
87///     mut materials: ResMut<Assets<StandardMaterial>>,
88/// ) {
89///     commands.spawn((
90///         Mesh3d(meshes.add(Capsule3d::default())),
91///         MeshMaterial3d(materials.add(StandardMaterial {
92///             base_color: RED.into(),
93///             ..Default::default()
94///         })),
95///     ));
96/// }
97/// ```
98#[derive(
99    Component, FromTemplate, Clone, Debug, Default, Deref, DerefMut, Reflect, PartialEq, Eq, From,
100)]
101#[reflect(Component, Default, Clone, PartialEq)]
102#[require(Transform)]
103pub struct Mesh3d(pub Handle<Mesh>);
104
105impl From<Mesh3d> for AssetId<Mesh> {
106    fn from(mesh: Mesh3d) -> Self {
107        mesh.id()
108    }
109}
110
111impl From<&Mesh3d> for AssetId<Mesh> {
112    fn from(mesh: &Mesh3d) -> Self {
113        mesh.id()
114    }
115}
116
117impl AsAssetId for Mesh3d {
118    type Asset = Mesh;
119
120    fn as_asset_id(&self) -> AssetId<Self::Asset> {
121        self.id()
122    }
123}
124
125/// A system that marks a [`Mesh2d`] as changed if the associated [`Mesh2d`]
126/// asset has changed.
127///
128/// This is needed because the system that extracts meshes, `extract_2d_meshes`,
129/// write some metadata about the mesh into the GPU structures that they build
130/// that needs to be kept up to date if the contents of the mesh change.
131pub fn mark_2d_meshes_as_changed_if_their_assets_changed(
132    mut meshes_2d: Query<&mut Mesh2d>,
133    mut mesh_asset_events: MessageReader<AssetEvent<Mesh>>,
134) {
135    let mut changed_meshes: HashSet<AssetId<Mesh>, FixedHasher> = HashSet::default();
136    for mesh_asset_event in mesh_asset_events.read() {
137        if let AssetEvent::Modified { id } = mesh_asset_event {
138            changed_meshes.insert(*id);
139        }
140    }
141
142    if changed_meshes.is_empty() {
143        return;
144    }
145
146    for mut mesh_2d in &mut meshes_2d {
147        if changed_meshes.contains(&mesh_2d.0.id()) {
148            mesh_2d.set_changed();
149        }
150    }
151}
152
153/// A system that marks a [`Mesh3d`] as changed if the associated [`Mesh`] asset
154/// has changed.
155///
156/// This is needed because the systems that extract meshes, such as
157/// `extract_meshes_for_gpu_building`, write some metadata about the mesh (like
158/// the location within each slab) into the GPU structures that they build that
159/// needs to be kept up to date if the contents of the mesh change.
160pub fn mark_3d_meshes_as_changed_if_their_assets_changed(
161    mut meshes_3d: Query<&mut Mesh3d>,
162    mut mesh_asset_events: MessageReader<AssetEvent<Mesh>>,
163) {
164    let mut changed_meshes: HashSet<AssetId<Mesh>, FixedHasher> = HashSet::default();
165    for mesh_asset_event in mesh_asset_events.read() {
166        if let AssetEvent::Modified { id } = mesh_asset_event {
167            changed_meshes.insert(*id);
168        }
169    }
170
171    if changed_meshes.is_empty() {
172        return;
173    }
174
175    meshes_3d.par_iter_mut().for_each(|mut mesh_3d| {
176        if changed_meshes.contains(&mesh_3d.0.id()) {
177            mesh_3d.set_changed();
178        }
179    });
180}
181
182/// A component that stores an arbitrary index used to identify the mesh
183/// instance when rendering.
184///
185/// You can fetch the value of the tag in the shader using the `tag` field on
186/// `bevy_pbr::mesh_bindings::mesh`.
187///
188/// When using a `GpuComponentArrayBuffer`, the tag represents the index of the
189/// mesh instance data in the buffer. In this case, Bevy automatically manages
190/// the tag, keeping it up to date as component data are extracted to and
191/// removed from the buffer. If you aren't using a `GpuComponentArrayBuffer`,
192/// the tag is free for you to use for whatever purpose you wish.
193///
194/// You may optionally supply a [`TypeId`] to accompany the mesh tag. Bevy
195/// ignores this type and treats it only as an opaque marker. It's not stored
196/// except in debug mode. Its only purpose is to provide diagnostics so that
197/// `GpuComponentArrayBuffer` can emit warnings if it overwrites a mesh tag.
198/// Examples of misuse that `GpuComponentArrayBuffer` can detect are cases in
199/// which you were using a [`MeshTag`] for application-specific purposes in
200/// addition to storing a component backed by a `GpuComponentArrayBuffer` on
201/// your mesh and cases in which you attempted to store multiple components
202/// backed by `GpuComponentArrayBuffer`s on the same mesh.
203#[derive(Component, Clone, Debug, Default, Deref, DerefMut, Reflect, PartialEq, Eq)]
204#[reflect(Component, Default, Clone, PartialEq)]
205pub struct MeshTag {
206    /// The value made available to the shader.
207    #[deref]
208    pub value: u32,
209
210    /// The optional opaque type ID.
211    ///
212    /// See the documentation of [`MeshTag`] for more information.
213    ///
214    /// This field is only present in debug mode.
215    #[cfg(debug_assertions)]
216    type_id: Option<TypeId>,
217}
218
219impl MeshTag {
220    /// Creates a new [`MeshTag`] with the given value.
221    ///
222    /// No type ID is specified.
223    pub const fn new(value: u32) -> MeshTag {
224        MeshTag {
225            value,
226            #[cfg(debug_assertions)]
227            type_id: None,
228        }
229    }
230
231    /// Creates a new [`MeshTag`] with the given value and type.
232    ///
233    /// In debug mode, the type is stored on the [`MeshTag`] component and used
234    /// for detecting accidental tag overwriting.
235    pub fn with_type<T>(value: u32) -> MeshTag
236    where
237        T: 'static + Sized,
238    {
239        MeshTag::with_type_id(value, TypeId::of::<T>())
240    }
241
242    /// Creates a new [`MeshTag`] with the given value and type ID.
243    ///
244    /// This is the equivalent of [`Self::with_type`], except that the type ID
245    /// can be supplied dynamically.
246    ///
247    /// In debug mode, the type ID is stored on the [`MeshTag`] component and
248    /// used for detecting accidental tag overwriting.
249    pub fn with_type_id(value: u32, _type_id: TypeId) -> MeshTag {
250        MeshTag {
251            value,
252            #[cfg(debug_assertions)]
253            type_id: Some(_type_id),
254        }
255    }
256
257    /// Returns true if the type ID is present and equal to the ID of the given
258    /// type.
259    ///
260    /// `GpuComponentArrayBuffer` uses this to emit diagnostics if the component
261    /// array buffer logic overwrites a tag that might have been used for
262    /// application-specific purposes or for storing other components backed by
263    /// array buffers.
264    ///
265    /// In debug mode, this always returns true.
266    pub fn type_is<T>(&self) -> bool
267    where
268        T: 'static + Sized,
269    {
270        self.type_id_is(TypeId::of::<T>())
271    }
272
273    /// Returns true if the type ID is present and equal to the given type ID.
274    ///
275    /// This is the equivalent of [`Self::type_is`], except that the type ID can
276    /// be supplied dynamically.
277    ///
278    /// In debug mode, this always returns true.
279    #[cfg(debug_assertions)]
280    pub fn type_id_is(&self, type_id: TypeId) -> bool {
281        self.type_id == Some(type_id)
282    }
283
284    /// Returns true if the type ID is present and equal to the given type ID.
285    ///
286    /// This is the equivalent of [`Self::type_is`], except that the type ID can
287    /// be supplied dynamically.
288    ///
289    /// In debug mode, this always returns true.
290    #[cfg(not(debug_assertions))]
291    pub fn type_id_is(&self, _: TypeId) -> bool {
292        true
293    }
294}