use wgpu::{self, util::DeviceExt}; use super::BufferObject; pub struct VertexBuffer { /// Vertices to draw. /// /// This can be set to None if each instance /// only needs one vertex. Note that the shader /// must be prepared for this! vertices: Option, /// Vertex indices. This will be None if we're /// drawing vertices directly, without indices. indices: Option, pub instances: wgpu::Buffer, pub layout: Box<[wgpu::VertexBufferLayout<'static>]>, } impl VertexBuffer { pub fn new( label: &str, device: &wgpu::Device, vertices: Option<&[VertexType]>, indices: Option<&[u16]>, length: u64, ) -> Self where VertexType: BufferObject, InstanceType: BufferObject, { let vertices = if let Some(vertices) = vertices { Some( device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some(&format!("[{}] vertex buffer", label)), contents: bytemuck::cast_slice(vertices), usage: wgpu::BufferUsages::VERTEX, }), ) } else { None }; let indices = if let Some(indices) = indices { if vertices.is_none() { unreachable!("Bad code! You cannot draw indexed vertices if vertices is None!") } Some( device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some(&format!("[{}] index buffer", label)), contents: bytemuck::cast_slice(indices), usage: wgpu::BufferUsages::INDEX, }), ) } else { None }; let instances = device.create_buffer(&wgpu::BufferDescriptor { label: Some(&format!("[{}] instance buffer", label)), usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, size: InstanceType::SIZE * length, mapped_at_creation: false, }); let mut layout = Vec::new(); if vertices.is_some() { layout.push(VertexType::layout()); } layout.push(InstanceType::layout()); Self { vertices, indices, instances, layout: layout.into(), } } /// Set the buffers defined here as buffers in a RenderPass. pub fn set_in_pass<'a, 'b: 'a>(&'b self, render_pass: &'a mut wgpu::RenderPass<'b>) { // TODO: why do these lifetimes work? let mut v_slot = 0u32; if let Some(vertices) = &self.vertices { render_pass.set_vertex_buffer(v_slot, vertices.slice(..)); v_slot += 1; } render_pass.set_vertex_buffer(v_slot, self.instances.slice(..)); //v_slot += 1; if let Some(indices) = &self.indices { render_pass.set_index_buffer(indices.slice(..), wgpu::IndexFormat::Uint16); } } }