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], pub color: [f32; 4], pub tangent: [f32; 4], } 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, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, shader_location: 3, format: wgpu::VertexFormat::Float32x4, }, wgpu::VertexAttribute { offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress, shader_location: 4, format: wgpu::VertexFormat::Float32x4, }, ], } } } 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) * glam::Mat4::from_scale(glam::Vec3::splat(128.0))) .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, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AlphaMode { Opaque, Mask, Blend, } impl AlphaMode { pub fn as_str(self) -> &'static str { match self { Self::Opaque => "OPAQUE", Self::Mask => "MASK", Self::Blend => "BLEND", } } pub fn shader_value(self) -> f32 { match self { Self::Opaque => 0.0, Self::Mask => 1.0, Self::Blend => 2.0, } } } pub struct Material { pub name: String, pub alpha_mode: AlphaMode, pub alpha_cutoff: f32, pub base_color_factor: [f32; 4], pub double_sided: bool, pub base_color_texture: texture::Texture, pub metallic_roughness_texture: texture::Texture, pub normal_texture: texture::Texture, pub occlusion_texture: texture::Texture, pub emissive_texture: texture::Texture, pub params_buffer: wgpu::Buffer, 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 center: [f32; 3], } 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); } }