use wgpu::util::DeviceExt;
use engvis_core::Mesh;
use glam::{Affine3A, Mat4};
pub struct MeshBuffer {
pub vertex_buffer: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
pub edge_endpoint_buffer: wgpu::Buffer,
pub index_count: u32,
pub edge_instance_count: u32,
pub vertex_count: u32,
}
pub struct MeshRenderer {
pub mesh_buffers: Vec<MeshBuffer>,
pub material_bind_groups: Vec<wgpu::BindGroup>,
pub material_uniform_buffers: Vec<wgpu::Buffer>,
pub object_bind_group_layout: wgpu::BindGroupLayout,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct ObjectUniforms {
pub model: [[f32; 4]; 4],
pub normal_matrix: [[f32; 4]; 4],
}
impl MeshRenderer {
pub fn new(device: &wgpu::Device) -> Self {
let object_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Object Bind Group Layout"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
});
Self {
mesh_buffers: Vec::new(),
material_bind_groups: Vec::new(),
material_uniform_buffers: Vec::new(),
object_bind_group_layout,
}
}
pub fn upload_mesh(&mut self, device: &wgpu::Device, mesh: &Mesh) -> usize {
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("Mesh '{}' Vertex Buffer", mesh.name)),
contents: bytemuck::cast_slice(&mesh.vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("Mesh '{}' Index Buffer", mesh.name)),
contents: bytemuck::cast_slice(&mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
let edge_indices = mesh.extract_edge_indices();
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
struct EdgeEndpoints {
pos_a: [f32; 3],
pos_b: [f32; 3],
}
let edge_count = edge_indices.len() / 2;
let mut edge_endpoints: Vec<EdgeEndpoints> = Vec::with_capacity(edge_count);
for i in 0..edge_count {
let i0 = edge_indices[i * 2] as usize;
let i1 = edge_indices[i * 2 + 1] as usize;
edge_endpoints.push(EdgeEndpoints {
pos_a: mesh.vertices[i0].position,
pos_b: mesh.vertices[i1].position,
});
}
let edge_endpoint_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("Mesh '{}' Edge Endpoint Buffer", mesh.name)),
contents: bytemuck::cast_slice(&edge_endpoints),
usage: wgpu::BufferUsages::VERTEX,
});
let index = self.mesh_buffers.len();
self.mesh_buffers.push(MeshBuffer {
vertex_buffer,
index_buffer,
edge_endpoint_buffer,
index_count: mesh.indices.len() as u32,
edge_instance_count: edge_count as u32,
vertex_count: mesh.vertices.len() as u32,
});
index
}
pub fn create_object_bind_group(
&self,
device: &wgpu::Device,
transform: Affine3A,
) -> (wgpu::Buffer, wgpu::BindGroup) {
let model_mat = Mat4::from(transform);
let normal_mat = model_mat.inverse().transpose();
let uniforms = ObjectUniforms {
model: model_mat.to_cols_array_2d(),
normal_matrix: normal_mat.to_cols_array_2d(),
};
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Object Uniform Buffer"),
contents: bytemuck::cast_slice(&[uniforms]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Object Bind Group"),
layout: &self.object_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
}],
});
(buffer, bind_group)
}
}