1#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2
3extern crate alloc;
4extern crate core;
5
6mod components;
7mod conversions;
8mod index;
9mod mesh;
10#[cfg(feature = "bevy_mikktspace")]
11mod mikktspace;
12#[cfg(feature = "morph")]
13pub mod morph;
14pub mod primitives;
15pub mod skinning;
16mod vertex;
17use bevy_app::{App, Plugin, PostUpdate};
18use bevy_asset::{AssetApp, AssetEventSystems};
19use bevy_ecs::schedule::IntoScheduleConfigs;
20use bitflags::bitflags;
21pub use components::*;
22pub use index::*;
23pub use mesh::*;
24#[cfg(feature = "bevy_mikktspace")]
25pub use mikktspace::*;
26pub use primitives::*;
27pub use vertex::*;
28pub use wgpu_types::VertexFormat;
29
30pub mod prelude {
34 #[cfg(feature = "morph")]
35 pub use crate::morph::MorphWeights;
36 #[doc(hidden)]
37 pub use crate::{primitives::MeshBuilder, primitives::Meshable, Mesh, Mesh2d, Mesh3d};
38}
39
40bitflags! {
41 #[derive(Clone, Debug)]
46 pub struct BaseMeshPipelineKey: u64 {
47 const MORPH_TARGETS = 1 << Self::MORPH_TARGETS_SHIFT_BITS;
48
49 const PRIMITIVE_TOPOLOGY_RESERVED_BITS = Self::PRIMITIVE_TOPOLOGY_MASK_BITS << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
50
51 const STRIP_INDEX_FORMAT_RESERVED_BITS = Self::STRIP_INDEX_FORMAT_MASK_BITS << Self::STRIP_INDEX_FORMAT_SHIFT_BITS;
52 const STRIP_INDEX_FORMAT_NONE = 0 << Self::STRIP_INDEX_FORMAT_SHIFT_BITS;
53 const STRIP_INDEX_FORMAT_U32 = 1 << Self::STRIP_INDEX_FORMAT_SHIFT_BITS;
54 const STRIP_INDEX_FORMAT_U16 = 2 << Self::STRIP_INDEX_FORMAT_SHIFT_BITS;
55 }
56}
57
58#[derive(Default)]
60pub struct MeshPlugin;
61
62impl Plugin for MeshPlugin {
63 fn build(&self, app: &mut App) {
64 app.init_asset::<Mesh>()
65 .init_asset::<skinning::SkinnedMeshInverseBindposes>()
66 .register_asset_reflect::<Mesh>()
67 .add_systems(
68 PostUpdate,
69 mark_3d_meshes_as_changed_if_their_assets_changed.after(AssetEventSystems),
70 );
71 }
72}
73
74impl BaseMeshPipelineKey {
75 pub const MORPH_TARGETS_SHIFT_BITS: u64 = (u64::BITS - 1) as u64;
76
77 pub const PRIMITIVE_TOPOLOGY_MASK_BITS: u64 = 0b111;
78 pub const PRIMITIVE_TOPOLOGY_SHIFT_BITS: u64 =
79 Self::MORPH_TARGETS_SHIFT_BITS - Self::PRIMITIVE_TOPOLOGY_MASK_BITS.count_ones() as u64;
80
81 pub const STRIP_INDEX_FORMAT_MASK_BITS: u64 = 0b11;
82 pub const STRIP_INDEX_FORMAT_SHIFT_BITS: u64 = Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS
83 - Self::STRIP_INDEX_FORMAT_MASK_BITS.count_ones() as u64;
84
85 pub fn from_primitive_topology_and_strip_index(
89 primitive_topology: PrimitiveTopology,
90 strip_index_format: Option<wgpu_types::IndexFormat>,
91 ) -> Self {
92 let index_bits = if primitive_topology.is_strip() {
93 match strip_index_format {
94 None => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE,
95 Some(index_format) => match index_format {
96 wgpu_types::IndexFormat::Uint16 => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U16,
97 wgpu_types::IndexFormat::Uint32 => BaseMeshPipelineKey::STRIP_INDEX_FORMAT_U32,
98 },
99 }
100 } else {
101 BaseMeshPipelineKey::STRIP_INDEX_FORMAT_NONE
102 }
103 .bits();
104 let primitive_topology_bits = ((primitive_topology as u64)
105 & Self::PRIMITIVE_TOPOLOGY_MASK_BITS)
106 << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
107 Self::from_bits_retain(primitive_topology_bits | index_bits)
108 }
109
110 pub fn primitive_topology(&self) -> PrimitiveTopology {
111 let primitive_topology_bits = (self.bits() >> Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
112 & Self::PRIMITIVE_TOPOLOGY_MASK_BITS;
113 match primitive_topology_bits {
114 x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
115 x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
116 x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
117 x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
118 x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
119 _ => PrimitiveTopology::default(),
120 }
121 }
122}