1use crate::{
2 assets::{handle::Handle, storage::Assets, upload::{Asset, AssetSource}},
3 wgpu::{
4 backend::WGPUBackend,
5 buffer::Buffer,
6 buffers::BufferBuilder,
7 flags::BufferUsages,
8 vertex_format::{VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode},
9 },
10};
11
12#[repr(C)]
21#[derive(Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
22pub struct Vertex {
23 pub position: glam::Vec3,
24 pub tex_coords: glam::Vec2,
25 pub normal: glam::Vec3,
26 pub tangent: glam::Vec4,
27}
28
29impl Vertex {
30 pub fn new(
31 position: glam::Vec3,
32 tex_coords: glam::Vec2,
33 normal: glam::Vec3,
34 tangent: glam::Vec4,
35 ) -> Self {
36 Self {
37 position,
38 tex_coords,
39 normal,
40 tangent,
41 }
42 }
43
44 pub fn layout() -> VertexBufferLayout {
45 VertexBufferLayout {
46 array_stride: std::mem::size_of::<Vertex>() as u64,
47 step_mode: VertexStepMode::Vertex,
48 attributes: vec![
49 VertexAttribute { format: VertexFormat::Float32x3, offset: 0, shader_location: 0 }, VertexAttribute { format: VertexFormat::Float32x2, offset: 12, shader_location: 1 }, VertexAttribute { format: VertexFormat::Float32x3, offset: 20, shader_location: 2 }, VertexAttribute { format: VertexFormat::Float32x4, offset: 32, shader_location: 3 }, ],
54 }
55 }
56}
57
58#[repr(C)]
61#[derive(Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
62pub struct InstanceVertex {
63 pub model: glam::Mat4,
64}
65
66impl InstanceVertex {
67 pub fn new(model: glam::Mat4) -> Self {
68 Self { model }
69 }
70
71 pub fn layout() -> VertexBufferLayout {
72 VertexBufferLayout {
73 array_stride: std::mem::size_of::<InstanceVertex>() as u64,
74 step_mode: VertexStepMode::Instance,
75 attributes: vec![
76 VertexAttribute { format: VertexFormat::Float32x4, offset: 0, shader_location: 4 }, VertexAttribute { format: VertexFormat::Float32x4, offset: 16, shader_location: 5 }, VertexAttribute { format: VertexFormat::Float32x4, offset: 32, shader_location: 6 }, VertexAttribute { format: VertexFormat::Float32x4, offset: 48, shader_location: 7 }, ],
81 }
82 }
83}
84
85pub struct Mesh {
89 vertices: Vec<Vertex>,
90 indices: Vec<u32>,
91}
92
93pub struct MeshBuilder {
97 vertices: Vec<Vertex>,
98 indices: Vec<u32>,
99}
100
101impl MeshBuilder {
102 pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
103 Self { vertices, indices }
104 }
105
106 fn validate(&self) {
110 if self.vertices.is_empty() {
111 tracing::warn!("MeshBuilder::new(): no vertices — did you forget to pass them?");
112 }
113 if self.indices.is_empty() {
114 tracing::warn!("MeshBuilder::new(): no indices — did you forget to pass them?");
115 }
116 }
117
118 pub fn build(self) -> Mesh {
120 self.validate();
121 Mesh { vertices: self.vertices, indices: self.indices }
122 }
123
124 pub fn build_asset(self, name: &str, assets: &mut Assets<Mesh>) -> Handle<Mesh> {
127 let mesh = self.build();
128 assets.insert(name, mesh)
129 }
130
131 pub fn from_file(path: &str) -> Result<Self, super::gltf_loader::ModelLoadError> {
133 let model = super::gltf_loader::load_gltf(path)?;
134 let (_, mesh) = model.static_meshes.into_iter().next()
135 .ok_or_else(|| super::gltf_loader::ModelLoadError::MissingData("no static mesh in file".to_string()))?;
136 Ok(Self { vertices: mesh.vertices, indices: mesh.indices })
137 }
138}
139
140pub struct GPUMesh {
145 pub vertex_buffer: Buffer,
146 pub index_buffer: Buffer,
147 pub index_count: u32,
148}
149
150impl AssetSource for Mesh {
151 type Processed = GPUMesh;
152}
153
154impl Asset<WGPUBackend> for Mesh {
155 type Deps<'a> = ();
156
157 fn upload<'a>(&self, backend: &WGPUBackend, _deps: &()) -> Option<GPUMesh> {
158 let vertex_buffer = BufferBuilder::with_data(bytemuck::cast_slice(self.vertices.as_slice()))
159 .with_label("Mesh Vertex Buffer")
160 .with_usage(BufferUsages::VERTEX)
161 .build(backend);
162 let index_buffer = BufferBuilder::with_data(bytemuck::cast_slice(&self.indices))
163 .with_label("Mesh Index Buffer")
164 .with_usage(BufferUsages::INDEX)
165 .build(backend);
166 Some(GPUMesh {
167 vertex_buffer,
168 index_buffer,
169 index_count: self.indices.len() as u32,
170 })
171 }
172}
173
174crate::wgpu::plugin_macros::asset_plugin! {
175 MeshPlugin, Mesh
179}