1use wde_logger::prelude::*;
2
3use bevy::{
4 asset::{AssetLoader, LoadContext, io::Reader},
5 ecs::system::{
6 SystemParamItem,
7 lifetimeless::{SRes, SResMut}
8 },
9 prelude::*
10};
11use serde::{Deserialize, Serialize};
12use std::{
13 fs::File,
14 io::{BufReader, Error}
15};
16use thiserror::Error;
17use tobj::LoadError;
18use wde_wgpu::{
19 buffer::{Buffer, BufferUsage},
20 vertex::Vertex
21};
22
23use crate::{
24 assets::{GpuBuffer, RenderAssets, SRenderData},
25 core::RenderInstance,
26 utils::{SsboMesh, ssbo_mesh::SsboMeshDescriptor}
27};
28
29use super::asset::{PrepareAssetError, RenderAsset};
30
31#[derive(Component, Reflect, Default)]
33pub struct Mesh3d(pub Handle<Mesh>);
34
35#[derive(Clone, Debug)]
36pub struct MeshBbox {
37 pub min: Vec3,
38 pub max: Vec3
39}
40#[derive(Asset, TypePath, Clone, Debug)]
45pub struct Mesh {
46 pub label: String,
47
48 pub vertices: Vec<Vertex>,
49 pub indices: Vec<u32>,
50 pub bbox: MeshBbox,
51
52 pub use_ssbo: bool
54}
55
56pub struct GpuMesh {
59 pub label: String,
60
61 pub ssbo_first_vertex: u32,
63 pub ssbo_first_index: u32,
65 pub use_ssbo: bool,
66
67 pub vertex_buffer: Option<Buffer>,
69 pub index_buffer: Option<Buffer>,
71
72 pub index_count: u32,
73 pub bounding_box: MeshBbox
74}
75impl RenderAsset for GpuMesh {
76 type SourceAsset = Mesh;
77 type Params = (
78 SRes<RenderInstance>,
79 SResMut<SsboMeshDescriptor>,
80 SRenderData<SsboMesh>,
81 SRes<RenderAssets<GpuBuffer>>
82 );
83
84 fn prepare(
85 asset: Self::SourceAsset,
86 (render_instance, ssbo_descriptor, ssbo_mesh, gpu_buffers): &mut SystemParamItem<
87 Self::Params
88 >
89 ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
90 trace!(asset.label, "Preparing GPU mesh asset.");
91
92 let ssbo = match ssbo_mesh.iter().next() {
94 Some((_, ssbo)) => ssbo,
95 None => return Err(PrepareAssetError::RetryNextUpdate(asset))
96 };
97
98 let (ssbo_vertex_buffer, ssbo_index_buffer) = match (
100 gpu_buffers.get(&ssbo.get_buffer(SsboMesh::VERTEX_BUFFER_ID).unwrap()),
101 gpu_buffers.get(&ssbo.get_buffer(SsboMesh::INDEX_BUFFER_ID).unwrap())
102 ) {
103 (Some(vb), Some(ib)) => (vb, ib),
104 _ => return Err(PrepareAssetError::RetryNextUpdate(asset))
105 };
106
107 let usage_vertex = if asset.use_ssbo {
109 BufferUsage::COPY_SRC
110 } else {
111 BufferUsage::VERTEX
112 };
113 let usage_index = if asset.use_ssbo {
114 BufferUsage::COPY_SRC
115 } else {
116 BufferUsage::INDEX
117 };
118
119 let render_instance = render_instance.0.read().unwrap();
121 let vertex_buffer = Buffer::new(
122 &render_instance,
123 format!("{}-vertex-staging", asset.label).as_str(),
124 std::mem::size_of::<Vertex>() * asset.vertices.len(),
125 usage_vertex,
126 Some(bytemuck::cast_slice(&asset.vertices))
127 );
128 let index_buffer = Buffer::new(
129 &render_instance,
130 format!("{}-indices-staging", asset.label).as_str(),
131 std::mem::size_of::<u32>() * asset.indices.len(),
132 usage_index,
133 Some(bytemuck::cast_slice(&asset.indices))
134 );
135
136 if !asset.use_ssbo {
138 return Ok(GpuMesh {
139 label: asset.label,
140 ssbo_first_vertex: 0,
141 ssbo_first_index: 0,
142 index_count: asset.indices.len() as u32,
143 bounding_box: asset.bbox,
144 use_ssbo: asset.use_ssbo,
145 vertex_buffer: Some(vertex_buffer),
146 index_buffer: Some(index_buffer)
147 });
148 }
149
150 let first_vertex = ssbo_descriptor.vertex_buffer_offset;
152 let first_index = ssbo_descriptor.index_buffer_offset;
153 let vertices_count = asset.vertices.len() as u32;
154 let indices_count = asset.indices.len() as u32;
155
156 let vertices_offset_bytes = (first_vertex as u64) * (std::mem::size_of::<Vertex>() as u64);
158 let indices_offset_bytes = (first_index as u64) * (std::mem::size_of::<u32>() as u64);
159 let vertices_size_bytes = (vertices_count as u64) * (std::mem::size_of::<Vertex>() as u64);
160 let indices_size_bytes = (indices_count as u64) * (std::mem::size_of::<u32>() as u64);
161
162 ssbo_vertex_buffer.buffer.copy_from_buffer_offset(
163 &render_instance,
164 &vertex_buffer,
165 0,
166 vertices_offset_bytes,
167 vertices_size_bytes
168 );
169 ssbo_descriptor.vertex_buffer_offset += vertices_count;
170
171 ssbo_index_buffer.buffer.copy_from_buffer_offset(
172 &render_instance,
173 &index_buffer,
174 0,
175 indices_offset_bytes,
176 indices_size_bytes
177 );
178 ssbo_descriptor.index_buffer_offset += indices_count;
179
180 Ok(GpuMesh {
181 label: asset.label,
182 ssbo_first_vertex: first_vertex,
183 ssbo_first_index: first_index,
184 index_count: indices_count,
185 bounding_box: asset.bbox,
186 use_ssbo: asset.use_ssbo,
187 vertex_buffer: None,
188 index_buffer: None
189 })
190 }
191
192 fn label(&self) -> &str {
193 &self.label
194 }
195}
196
197#[derive(Serialize, Deserialize)]
199pub struct MeshLoaderSettings {
200 pub label: String,
201 pub use_ssbo: bool
203}
204impl Default for MeshLoaderSettings {
205 fn default() -> Self {
206 Self {
207 label: "Unknown Mesh".to_string(),
208 use_ssbo: true
209 }
210 }
211}
212
213#[derive(Debug, Error)]
214pub(crate) enum MeshLoaderError {
215 #[error("Could not load mesh: {0}")]
216 Io(#[from] std::io::Error)
217}
218#[derive(Default, TypePath)]
219pub(crate) struct MeshLoader;
220impl AssetLoader for MeshLoader {
221 type Asset = Mesh;
222 type Settings = MeshLoaderSettings;
223 type Error = MeshLoaderError;
224
225 async fn load(
226 &self,
227 reader: &mut dyn Reader,
228 settings: &Self::Settings,
229 load_context: &mut LoadContext<'_>
230 ) -> Result<Self::Asset, Self::Error> {
231 info!("Loading mesh {}.", load_context.path());
232
233 let label = if settings.label.is_empty() {
235 load_context.path().to_string()
236 } else {
237 settings.label.clone()
238 };
239
240 let mut bytes = Vec::new();
242 reader.read_to_end(&mut bytes).await?;
243
244 let load_res = match tobj::load_obj_buf(
246 &mut BufReader::new(bytes.as_slice()),
247 &tobj::LoadOptions {
248 single_index: true,
249 ..Default::default()
250 },
251 |p| {
252 let f = match File::open(p.file_name().unwrap().to_str().unwrap()) {
253 Ok(f) => f,
254 Err(_) => return Err(LoadError::OpenFileFailed)
255 };
256 tobj::load_mtl_buf(&mut BufReader::new(f))
257 }
258 ) {
259 Ok(res) => res,
260 Err(e) => return Err(MeshLoaderError::Io(Error::other(e.to_string())))
261 };
262 let models = load_res.0;
263
264 let mut vertices: Vec<Vertex> = Vec::new();
266 let mut indices: Vec<u32> = Vec::new();
267 let mut bounding_box = MeshBbox {
268 min: Vec3::new(f32::MAX, f32::MAX, f32::MAX),
269 max: Vec3::new(f32::MIN, f32::MIN, f32::MIN)
270 };
271 for m in models.iter() {
272 let mesh = &m.mesh;
273 if mesh.positions.len() % 3 != 0 {
274 return Err(MeshLoaderError::Io(std::io::Error::other(
275 "Mesh positions are not divisible by 3."
276 )));
277 }
278
279 vertices.reserve(mesh.positions.len() / 3);
281
282 for vtx in 0..mesh.positions.len() / 3 {
284 let x = mesh.positions[3 * vtx];
285 let y = mesh.positions[3 * vtx + 1];
286 let z = mesh.positions[3 * vtx + 2];
287
288 let mut nx = 0.0;
290 let mut ny = 0.0;
291 let mut nz = 0.0;
292 if mesh.normals.len() >= 3 * vtx + 2 {
293 nx = mesh.normals[3 * vtx];
294 ny = mesh.normals[3 * vtx + 1];
295 nz = mesh.normals[3 * vtx + 2];
296 }
297
298 let mut u = 0.0;
300 let mut v = 0.0;
301 if mesh.texcoords.len() > 2 * vtx {
302 u = mesh.texcoords[2 * vtx];
303 v = mesh.texcoords[2 * vtx + 1];
304 }
305
306 vertices.push(Vertex {
308 position: [x, y, z],
309 normal: [nx, ny, nz],
310 uv: [u, v],
311 tangent: [0.0, 0.0, 0.0, 0.0]
312 });
313
314 bounding_box.min.x = bounding_box.min.x.min(x);
316 bounding_box.min.y = bounding_box.min.y.min(y);
317 bounding_box.min.z = bounding_box.min.z.min(z);
318 bounding_box.max.x = bounding_box.max.x.max(x);
319 bounding_box.max.y = bounding_box.max.y.max(y);
320 bounding_box.max.z = bounding_box.max.z.max(z);
321 }
322
323 indices.extend_from_slice(&mesh.indices);
325 }
326 Ok(Mesh {
327 label,
328 vertices,
329 indices,
330 bbox: bounding_box,
331 use_ssbo: settings.use_ssbo
332 })
333 }
334
335 fn extensions(&self) -> &[&str] {
336 &["obj", "fbx"]
337 }
338}