Skip to main content

pebble/wgpu/
mesh.rs

1use crate::{
2    app::App,
3    assets::{plugin::AssetPlugin, upload::Asset},
4    ecs::plugin::Plugin,
5    wgpu::backend::WGPUBackend,
6};
7
8#[repr(C)]
9#[derive(Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
10pub struct Vertex {
11    pub position: glam::Vec3,
12    pub tex_coords: glam::Vec2,
13    pub normal: glam::Vec3,
14    pub tangent: glam::Vec4,
15}
16
17impl Vertex {
18    pub fn new(position: glam::Vec3, tex_coords: glam::Vec2, normal: glam::Vec3, tangent: glam::Vec4) -> Self {
19        Self { position, tex_coords, normal, tangent }
20    }
21
22    pub fn layout() -> wgpu::VertexBufferLayout<'static> {
23        const ATTRS: &[wgpu::VertexAttribute] = &wgpu::vertex_attr_array![
24            0 => Float32x3,  // position
25            1 => Float32x2,  // tex_coords
26            2 => Float32x3,  // normal
27            3 => Float32x4,  // tangent
28        ];
29        wgpu::VertexBufferLayout {
30            array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
31            step_mode: wgpu::VertexStepMode::Vertex,
32            attributes: ATTRS,
33        }
34    }
35}
36
37/// Per-instance vertex data. Carries a model matrix as four `Vec4` columns,
38/// passed as vertex attributes with `step_mode: Instance`.
39#[repr(C)]
40#[derive(Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
41pub struct InstanceVertex {
42    pub model: glam::Mat4,
43}
44
45impl InstanceVertex {
46    pub fn new(model: glam::Mat4) -> Self {
47        Self { model }
48    }
49
50    pub fn layout() -> wgpu::VertexBufferLayout<'static> {
51        const ATTRS: &[wgpu::VertexAttribute] = &wgpu::vertex_attr_array![
52            4 => Float32x4,  // model col 0
53            5 => Float32x4,  // model col 1
54            6 => Float32x4,  // model col 2
55            7 => Float32x4,  // model col 3
56        ];
57        wgpu::VertexBufferLayout {
58            array_stride: std::mem::size_of::<InstanceVertex>() as wgpu::BufferAddress,
59            step_mode: wgpu::VertexStepMode::Instance,
60            attributes: ATTRS,
61        }
62    }
63}
64
65pub struct MeshDescriptor {
66    pub vertices: Vec<Vertex>,
67    pub indices: Vec<u32>,
68}
69
70pub struct GPUMesh {
71    pub vertex_buffer: wgpu::Buffer,
72    pub index_buffer: wgpu::Buffer,
73    pub index_count: u32,
74}
75
76impl Asset<WGPUBackend> for GPUMesh {
77    type Source = MeshDescriptor;
78    type Deps<'a> = ();
79
80    fn upload<'a>(source: &MeshDescriptor, backend: &WGPUBackend, _deps: &()) -> Option<Self> {
81        use wgpu::util::DeviceExt;
82        let vertex_buffer = backend
83            .device
84            .create_buffer_init(&wgpu::util::BufferInitDescriptor {
85                label: Some("Mesh Vertex Buffer"),
86                contents: bytemuck::cast_slice(source.vertices.as_slice()),
87                usage: wgpu::BufferUsages::VERTEX,
88            });
89        let index_buffer = backend
90            .device
91            .create_buffer_init(&wgpu::util::BufferInitDescriptor {
92                label: Some("Mesh Index Buffer"),
93                contents: bytemuck::cast_slice(&source.indices),
94                usage: wgpu::BufferUsages::INDEX,
95            });
96        Some(Self {
97            vertex_buffer,
98            index_buffer,
99            index_count: source.indices.len() as u32,
100        })
101    }
102}
103
104#[derive(Default)]
105pub struct MeshPlugin;
106impl MeshPlugin {
107    pub fn new() -> Self {
108        Self
109    }
110}
111impl Plugin for MeshPlugin {
112    fn build(&self, app: &mut App) {
113        app.add_plugin(AssetPlugin::<WGPUBackend, GPUMesh>::new());
114    }
115}