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
93impl Mesh {
94 pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>) -> Self {
95 Self { vertices, indices }
96 }
97
98 fn validate(&self) {
102 if self.vertices.is_empty() {
103 tracing::warn!("Mesh::new(): no vertices — did you forget to pass them?");
104 }
105 if self.indices.is_empty() {
106 tracing::warn!("Mesh::new(): no indices — did you forget to pass them?");
107 }
108 }
109
110 pub fn build(self) -> Self {
112 self.validate();
113 self
114 }
115
116 pub fn build_asset(self, name: &str, assets: &mut Assets<Self>) -> Handle<Self> {
119 self.validate();
120 assets.insert(name, self)
121 }
122}
123
124pub struct GPUMesh {
129 pub vertex_buffer: Buffer,
130 pub index_buffer: Buffer,
131 pub index_count: u32,
132}
133
134impl Asset<WGPUBackend> for GPUMesh {
135 type Source = Mesh;
136 type Deps<'a> = ();
137
138 fn upload<'a>(source: &Mesh, backend: &WGPUBackend, _deps: &()) -> Option<Self> {
139 let vertex_buffer = BufferBuilder::new()
140 .label("Mesh Vertex Buffer")
141 .usage(BufferUsages::VERTEX)
142 .data(bytemuck::cast_slice(source.vertices.as_slice()))
143 .build(backend);
144 let index_buffer = BufferBuilder::new()
145 .label("Mesh Index Buffer")
146 .usage(BufferUsages::INDEX)
147 .data(bytemuck::cast_slice(&source.indices))
148 .build(backend);
149 Some(Self {
150 vertex_buffer,
151 index_buffer,
152 index_count: source.indices.len() as u32,
153 })
154 }
155}
156
157crate::wgpu::plugin_macros::asset_plugin! {
158 MeshPlugin, GPUMesh
163}