1use crate::{
2 assets::{handle::Handle, storage::Assets, upload::Asset},
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
132pub struct GPUMesh {
137 pub vertex_buffer: Buffer,
138 pub index_buffer: Buffer,
139 pub index_count: u32,
140}
141
142impl Asset<WGPUBackend> for GPUMesh {
143 type Source = Mesh;
144 type Deps<'a> = ();
145
146 fn upload<'a>(source: &Mesh, backend: &WGPUBackend, _deps: &()) -> Option<Self> {
147 let vertex_buffer = BufferBuilder::with_data(bytemuck::cast_slice(source.vertices.as_slice()))
148 .label("Mesh Vertex Buffer")
149 .usage(BufferUsages::VERTEX)
150 .build(backend);
151 let index_buffer = BufferBuilder::with_data(bytemuck::cast_slice(&source.indices))
152 .label("Mesh Index Buffer")
153 .usage(BufferUsages::INDEX)
154 .build(backend);
155 Some(Self {
156 vertex_buffer,
157 index_buffer,
158 index_count: source.indices.len() as u32,
159 })
160 }
161}
162
163crate::wgpu::plugin_macros::asset_plugin! {
164 MeshPlugin, GPUMesh
169}