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