1pub mod allocator;
2#[cfg(feature = "morph")]
3pub mod morph;
4
5use crate::{
6 mesh::allocator::{ElementClass, MeshAllocationKey, MeshAllocator, MeshSlabId},
7 render_asset::{
8 prepare_assets, AssetExtractionError, PrepareAssetError, RenderAsset, RenderAssetPlugin,
9 },
10 render_resource::Buffer,
11 renderer::{RenderDevice, RenderQueue},
12 texture::GpuImage,
13 Render, RenderApp, RenderSystems,
14};
15use allocator::MeshAllocatorPlugin;
16use bevy_app::{App, Plugin};
17use bevy_asset::{AssetId, Assets, Handle, RenderAssetUsages};
18use bevy_camera::primitives::MeshAabb;
19use bevy_ecs::{
20 prelude::*,
21 system::{
22 lifetimeless::{SRes, SResMut},
23 SystemParamItem,
24 },
25};
26use bevy_encase_derive::ShaderType;
27pub use bevy_mesh::*;
28use bevy_shader::load_shader_library;
29use bytemuck::{Pod, Zeroable};
30use glam::{Vec3, Vec4};
31use wgpu::IndexFormat;
32
33#[cfg(feature = "morph")]
34use crate::mesh::morph::RenderMorphTargetAllocator;
35
36pub struct MeshRenderAssetPlugin;
39
40impl Plugin for MeshRenderAssetPlugin {
41 fn build(&self, app: &mut App) {
42 load_shader_library!(app, "metadata_types.wesl");
43
44 app
45 .add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
47 .add_plugins(MeshAllocatorPlugin);
48
49 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
50 return;
51 };
52
53 render_app
54 .init_resource::<MeshVertexBufferLayouts>()
55 .add_systems(
56 Render,
57 prepare_mesh_metadata_fallback_buffer
58 .in_set(RenderSystems::PrepareAssets)
59 .after(prepare_assets::<RenderMesh>),
60 );
61 }
62
63 fn finish(&self, app: &mut App) {
64 let mut mesh_assets = app.world_mut().resource_mut::<Assets<Mesh>>();
65 let handle = mesh_assets.add({
66 let mut mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::all())
67 .with_inserted_attribute(
68 Mesh::ATTRIBUTE_POSITION,
69 VertexAttributeValues::Float32x3(vec![[0.0; 3]]),
70 )
71 .with_inserted_indices(Indices::U16(vec![0]));
72 mesh.compress_positions().unwrap();
73 mesh
74 });
75
76 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
77 return;
78 };
79
80 render_app.insert_resource(MeshMetadataFallbackMesh(handle));
81
82 #[cfg(feature = "morph")]
83 crate::GpuResourceAppExt::init_gpu_resource::<RenderMorphTargetAllocator>(render_app);
84 }
85}
86
87#[derive(Resource)]
88pub struct MeshMetadataFallbackMesh(pub Handle<Mesh>);
89
90#[derive(Resource)]
93pub struct MeshMetadataFallbackBuffer {
94 pub slab_id: MeshSlabId,
95 pub buffer: Buffer,
96}
97
98pub fn prepare_mesh_metadata_fallback_buffer(
99 mut commands: Commands,
100 mesh_allocator: Res<MeshAllocator>,
101 metadata_fallback_mesh: Res<MeshMetadataFallbackMesh>,
102) {
103 let slab_id = mesh_allocator
104 .key_to_slab
105 .get(&MeshAllocationKey::new(
106 metadata_fallback_mesh.0.id(),
107 ElementClass::Metadata,
108 ))
109 .cloned()
110 .unwrap();
111 let buffer = mesh_allocator.buffer_for_slab(slab_id).unwrap().clone();
112 commands.insert_resource(MeshMetadataFallbackBuffer { slab_id, buffer });
113}
114
115#[derive(Default, Pod, Zeroable, Clone, Copy, Debug, ShaderType)]
118#[repr(C)]
119pub struct MeshMetadata {
120 pub aabb_center: Vec3,
122 pub pad1: u32,
123 pub aabb_half_extents: Vec3,
125 pub pad2: u32,
126 pub uv_channels_min_and_extents: [Vec4; 2],
128}
129
130#[derive(Debug, Clone)]
132pub struct RenderMesh {
133 pub vertex_count: u32,
135
136 pub aabb_center: Vec3,
138
139 pub buffer_info: RenderMeshBufferInfo,
142
143 pub key_bits: BaseMeshPipelineKey,
145
146 pub layout: MeshVertexBufferLayoutRef,
151}
152
153impl RenderMesh {
154 #[inline]
157 pub fn primitive_topology(&self) -> PrimitiveTopology {
158 self.key_bits.primitive_topology()
159 }
160
161 #[inline]
163 pub fn indexed(&self) -> bool {
164 matches!(self.buffer_info, RenderMeshBufferInfo::Indexed { .. })
165 }
166
167 #[inline]
168 pub fn index_format(&self) -> Option<IndexFormat> {
169 match self.buffer_info {
170 RenderMeshBufferInfo::Indexed { index_format, .. } => Some(index_format),
171 RenderMeshBufferInfo::NonIndexed => None,
172 }
173 }
174
175 #[inline]
176 pub fn has_morph_targets(&self) -> bool {
177 self.key_bits.contains(BaseMeshPipelineKey::MORPH_TARGETS)
178 }
179}
180
181#[derive(Debug, Clone)]
183pub enum RenderMeshBufferInfo {
184 Indexed {
185 count: u32,
186 index_format: IndexFormat,
187 },
188 NonIndexed,
189}
190
191impl RenderAsset for RenderMesh {
192 type SourceAsset = Mesh;
193
194 #[cfg(not(feature = "morph"))]
195 type Param = (
196 SRes<RenderDevice>,
197 SRes<RenderQueue>,
198 SResMut<MeshVertexBufferLayouts>,
199 (),
200 );
201 #[cfg(feature = "morph")]
202 type Param = (
203 SRes<RenderDevice>,
204 SRes<RenderQueue>,
205 SResMut<MeshVertexBufferLayouts>,
206 SResMut<RenderMorphTargetAllocator>,
207 );
208
209 #[inline]
210 fn asset_usage(mesh: &Self::SourceAsset) -> RenderAssetUsages {
211 mesh.asset_usage
212 }
213
214 fn take_gpu_data(
215 source: &mut Self::SourceAsset,
216 _previous_gpu_asset: Option<&Self>,
217 ) -> Result<Self::SourceAsset, AssetExtractionError> {
218 source
219 .take_gpu_data()
220 .map_err(|_| AssetExtractionError::AlreadyExtracted)
221 }
222
223 fn byte_len(mesh: &Self::SourceAsset) -> Option<usize> {
224 let mut vertex_size = 0;
225 for attribute_data in mesh.attributes() {
226 let vertex_format = attribute_data.0.format;
227 vertex_size += vertex_format.size() as usize;
228 }
229
230 let vertex_count = mesh.count_vertices();
231 let index_bytes = mesh.get_index_buffer_bytes().map(<[_]>::len).unwrap_or(0);
232 Some(vertex_size * vertex_count + index_bytes)
233 }
234
235 fn prepare_asset(
237 mesh: Self::SourceAsset,
238 _mesh_id: AssetId<Self::SourceAsset>,
239 (
240 _render_device,
241 _render_queue,
242 mesh_vertex_buffer_layouts,
243 _render_morph_targets_allocator,
244 ): &mut SystemParamItem<Self::Param>,
245 _: Option<&Self>,
246 ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
247 let (buffer_info, index_format) = match mesh.indices() {
248 Some(indices) => (
249 RenderMeshBufferInfo::Indexed {
250 count: indices.len() as u32,
251 index_format: indices.into(),
252 },
253 Some(indices.into()),
254 ),
255 None => (RenderMeshBufferInfo::NonIndexed, None),
256 };
257
258 let mesh_vertex_buffer_layout =
259 mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
260
261 let key_bits = BaseMeshPipelineKey::from_primitive_topology_and_strip_index(
262 mesh.primitive_topology(),
263 index_format,
264 );
265 #[cfg(feature = "morph")]
266 let key_bits = if mesh.morph_targets().is_some() {
267 key_bits | BaseMeshPipelineKey::MORPH_TARGETS
268 } else {
269 key_bits
270 };
271
272 #[cfg(feature = "morph")]
274 if let Some(morph_targets) = mesh.morph_targets() {
275 _render_morph_targets_allocator.allocate(
276 _render_device,
277 _render_queue,
278 _mesh_id,
279 morph_targets,
280 mesh.count_vertices(),
281 );
282 }
283
284 Ok(RenderMesh {
285 vertex_count: mesh.count_vertices() as u32,
286 aabb_center: match mesh.get_aabb() {
287 Some(aabb) => aabb.center.into(),
288 None => Vec3::ZERO,
289 },
290 buffer_info,
291 key_bits,
292 layout: mesh_vertex_buffer_layout,
293 })
294 }
295
296 fn unload_asset(
297 _mesh_id: AssetId<Self::SourceAsset>,
298 (_, _, _, _render_morph_targets_allocator): &mut SystemParamItem<Self::Param>,
299 ) {
300 #[cfg(feature = "morph")]
302 _render_morph_targets_allocator.free(_mesh_id);
303 }
304}