use eframe::egui_wgpu::wgpu; use std::ops::Range; use crate::texture; pub trait Vertex { fn desc<'a>() -> wgpu::VertexBufferLayout<'a>; } #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] pub struct ModelVertex { pub position: [f32; 3], pub tex_coords: [f32; 2], pub normal: [f32; 3], } impl Vertex for ModelVertex { fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { use core::mem; wgpu::VertexBufferLayout { array_stride: mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, attributes: &[ wgpu::VertexAttribute { offset: 0, shader_location: 0, format: wgpu::VertexFormat::Float32x3, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, shader_location: 1, format: wgpu::VertexFormat::Float32x2, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress, shader_location: 2, format: wgpu::VertexFormat::Float32x3, }, ], } } } pub struct Instance { position: glam::Vec3, rotation: glam::Quat, } impl Instance { pub fn new(position: glam::Vec3, rotation: glam::Quat) -> Self { Self { position, rotation } } pub fn to_raw(&self) -> InstanceRaw { InstanceRaw { model: (glam::Mat4::from_translation(self.position) * glam::Mat4::from_quat(self.rotation)) .to_cols_array_2d(), } } } #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct InstanceRaw { #[allow(dead_code)] model: [[f32; 4]; 4], } impl InstanceRaw { pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { use core::mem; wgpu::VertexBufferLayout { array_stride: mem::size_of::() as wgpu::BufferAddress, // We need to switch from using a step mode of Vertex to Instance // This means that our shaders will only change to use the next // instance when the shader starts processing a new instance step_mode: wgpu::VertexStepMode::Instance, attributes: &[ wgpu::VertexAttribute { offset: 0, // While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll // be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later shader_location: 5, format: wgpu::VertexFormat::Float32x4, }, // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot // for each vec4. We don't have to do this in code though. wgpu::VertexAttribute { offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, shader_location: 6, format: wgpu::VertexFormat::Float32x4, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, shader_location: 7, format: wgpu::VertexFormat::Float32x4, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress, shader_location: 8, format: wgpu::VertexFormat::Float32x4, }, ], } } } pub struct Model { pub meshes: Vec, pub materials: Vec, } pub struct Material { pub name: String, pub diffuse_texture: texture::Texture, pub bind_group: wgpu::BindGroup, } pub struct Mesh { pub name: String, pub vertex_buffer: wgpu::Buffer, pub index_buffer: wgpu::Buffer, pub num_elements: u32, pub material: usize, } pub trait DrawModel<'a> { fn draw_mesh(&mut self, mesh: &'a Mesh); fn draw_mesh_instanced(&mut self, mesh: &'a Mesh, instances: Range); } impl<'a, 'b> DrawModel<'b> for wgpu::RenderPass<'a> where 'b: 'a, { fn draw_mesh(&mut self, mesh: &'b Mesh) { self.draw_mesh_instanced(mesh, 0..1); } fn draw_mesh_instanced(&mut self, mesh: &'b Mesh, instances: Range) { self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); self.draw_indexed(0..mesh.num_elements, 0, instances); } }