1pub mod allocator;
2#[cfg(feature = "morph")]
3pub mod morph;
4
5#[cfg(feature = "morph")]
6use crate::GpuResourceAppExt;
7use crate::{
8 render_asset::{AssetExtractionError, PrepareAssetError, RenderAsset, RenderAssetPlugin},
9 renderer::{RenderDevice, RenderQueue},
10 texture::GpuImage,
11 RenderApp,
12};
13use allocator::MeshAllocatorPlugin;
14use bevy_app::{App, Plugin};
15use bevy_asset::{AssetId, RenderAssetUsages};
16use bevy_camera::primitives::MeshAabb;
17use bevy_ecs::{
18 prelude::*,
19 system::{
20 lifetimeless::{SRes, SResMut},
21 SystemParamItem,
22 },
23};
24pub use bevy_mesh::*;
25use glam::Vec3;
26use wgpu::IndexFormat;
27
28#[cfg(feature = "morph")]
29use crate::mesh::morph::RenderMorphTargetAllocator;
30
31pub struct MeshRenderAssetPlugin;
34
35impl Plugin for MeshRenderAssetPlugin {
36 fn build(&self, app: &mut App) {
37 app
38 .add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
40 .add_plugins(MeshAllocatorPlugin);
41
42 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
43 return;
44 };
45
46 render_app.init_resource::<MeshVertexBufferLayouts>();
47 }
48
49 fn finish(&self, app: &mut App) {
50 let Some(_render_app) = app.get_sub_app_mut(RenderApp) else {
51 return;
52 };
53
54 #[cfg(feature = "morph")]
55 _render_app.init_gpu_resource::<RenderMorphTargetAllocator>();
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct RenderMesh {
62 pub vertex_count: u32,
64
65 pub aabb_center: Vec3,
67
68 pub buffer_info: RenderMeshBufferInfo,
71
72 pub key_bits: BaseMeshPipelineKey,
74
75 pub layout: MeshVertexBufferLayoutRef,
80}
81
82impl RenderMesh {
83 #[inline]
86 pub fn primitive_topology(&self) -> PrimitiveTopology {
87 self.key_bits.primitive_topology()
88 }
89
90 #[inline]
92 pub fn indexed(&self) -> bool {
93 matches!(self.buffer_info, RenderMeshBufferInfo::Indexed { .. })
94 }
95
96 #[inline]
97 pub fn index_format(&self) -> Option<IndexFormat> {
98 match self.buffer_info {
99 RenderMeshBufferInfo::Indexed { index_format, .. } => Some(index_format),
100 RenderMeshBufferInfo::NonIndexed => None,
101 }
102 }
103
104 #[inline]
105 pub fn has_morph_targets(&self) -> bool {
106 self.key_bits.contains(BaseMeshPipelineKey::MORPH_TARGETS)
107 }
108}
109
110#[derive(Debug, Clone)]
112pub enum RenderMeshBufferInfo {
113 Indexed {
114 count: u32,
115 index_format: IndexFormat,
116 },
117 NonIndexed,
118}
119
120impl RenderAsset for RenderMesh {
121 type SourceAsset = Mesh;
122
123 #[cfg(not(feature = "morph"))]
124 type Param = (
125 SRes<RenderDevice>,
126 SRes<RenderQueue>,
127 SResMut<MeshVertexBufferLayouts>,
128 (),
129 );
130 #[cfg(feature = "morph")]
131 type Param = (
132 SRes<RenderDevice>,
133 SRes<RenderQueue>,
134 SResMut<MeshVertexBufferLayouts>,
135 SResMut<RenderMorphTargetAllocator>,
136 );
137
138 #[inline]
139 fn asset_usage(mesh: &Self::SourceAsset) -> RenderAssetUsages {
140 mesh.asset_usage
141 }
142
143 fn take_gpu_data(
144 source: &mut Self::SourceAsset,
145 _previous_gpu_asset: Option<&Self>,
146 ) -> Result<Self::SourceAsset, AssetExtractionError> {
147 source
148 .take_gpu_data()
149 .map_err(|_| AssetExtractionError::AlreadyExtracted)
150 }
151
152 fn byte_len(mesh: &Self::SourceAsset) -> Option<usize> {
153 let mut vertex_size = 0;
154 for attribute_data in mesh.attributes() {
155 let vertex_format = attribute_data.0.format;
156 vertex_size += vertex_format.size() as usize;
157 }
158
159 let vertex_count = mesh.count_vertices();
160 let index_bytes = mesh.get_index_buffer_bytes().map(<[_]>::len).unwrap_or(0);
161 Some(vertex_size * vertex_count + index_bytes)
162 }
163
164 fn prepare_asset(
166 mesh: Self::SourceAsset,
167 _mesh_id: AssetId<Self::SourceAsset>,
168 (
169 _render_device,
170 _render_queue,
171 mesh_vertex_buffer_layouts,
172 _render_morph_targets_allocator,
173 ): &mut SystemParamItem<Self::Param>,
174 _: Option<&Self>,
175 ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
176 let (buffer_info, index_format) = match mesh.indices() {
177 Some(indices) => (
178 RenderMeshBufferInfo::Indexed {
179 count: indices.len() as u32,
180 index_format: indices.into(),
181 },
182 Some(indices.into()),
183 ),
184 None => (RenderMeshBufferInfo::NonIndexed, None),
185 };
186
187 let mesh_vertex_buffer_layout =
188 mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
189
190 let key_bits = BaseMeshPipelineKey::from_primitive_topology_and_strip_index(
191 mesh.primitive_topology(),
192 index_format,
193 );
194 #[cfg(feature = "morph")]
195 let key_bits = if mesh.morph_targets().is_some() {
196 key_bits | BaseMeshPipelineKey::MORPH_TARGETS
197 } else {
198 key_bits
199 };
200
201 #[cfg(feature = "morph")]
203 if let Some(morph_targets) = mesh.morph_targets() {
204 _render_morph_targets_allocator.allocate(
205 _render_device,
206 _render_queue,
207 _mesh_id,
208 morph_targets,
209 mesh.count_vertices(),
210 );
211 }
212
213 Ok(RenderMesh {
214 vertex_count: mesh.count_vertices() as u32,
215 aabb_center: match mesh.compute_aabb() {
216 Some(aabb) => aabb.center.into(),
217 None => Vec3::ZERO,
218 },
219 buffer_info,
220 key_bits,
221 layout: mesh_vertex_buffer_layout,
222 })
223 }
224
225 fn unload_asset(
226 _mesh_id: AssetId<Self::SourceAsset>,
227 (_, _, _, _render_morph_targets_allocator): &mut SystemParamItem<Self::Param>,
228 ) {
229 #[cfg(feature = "morph")]
231 _render_morph_targets_allocator.free(_mesh_id);
232 }
233}