canvas/src/renderer/utils.rs
2022-11-01 19:09:04 +01:00

167 lines
5.9 KiB
Rust

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
//--Internal imports--------------------------------------------------------------------------------
//--External imports--------------------------------------------------------------------------------
use std::marker::PhantomData;
use super::WgpuRenderer;
//--Bind group layouts------------------------------------------------------------------------------
/// Creates the layout bind_group used by all matrixes of the renderer
pub fn new_matrix_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
],
label: Some("matrix_bind_group_layout"),
})
}
/// Crates the layout bind group used by all textures of the renderer
pub fn new_texture_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
// This should match the filterable field of the
// corresponding Texture entry above.
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("texture_bind_group_layout"),
})
}
//--TextureVertex struct----------------------------------------------------------------------------
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct ColorVertex {
pub position: [f32; 2],
pub color: [f32; 3],
}
impl ColorVertex {
const ATTRIBS: [wgpu::VertexAttribute; 2] =
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3];
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<ColorVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &Self::ATTRIBS,
}
}
}
//--Mesh struct-------------------------------------------------------------------------------------
/// Handles the buffers to be used to draw a Mesh
///
/// The mesh consist of an array of vertices, and its ccorresponding indices.
///
/// A vertex can be any type that can be converted to a byte array using the bytemuck crate.
/// Generaly, adding `#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]` to a struct
/// is enough for that.
///
/// An index is a standard u16
///
/// A mesh can be used with, and only with, the renderer for wich it was created
pub struct Mesh<V, const V_NB: usize, const I_NB: usize>
where
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable,
{
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
vertex_type: PhantomData<V>,
}
impl <V, const V_NB: usize, const I_NB: usize> Mesh<V, V_NB, I_NB>
where
V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable + std::fmt::Debug
{
/// Creates a new mesh using the [Device] from the renderer to be used
pub fn new(device: &wgpu::Device) -> Self {
use std::mem::size_of;
use wgpu_types::BufferUsages as Usages;
let vertex_buffer = device.create_buffer(
&wgpu_types::BufferDescriptor {
label: Some("Vertex Buffer"),
size: (V_NB * size_of::<V>()) as u64,
usage: Usages::VERTEX | Usages::COPY_DST,
mapped_at_creation: false,
}
);
let index_buffer = device.create_buffer( &wgpu_types::BufferDescriptor {
label: Some("Index Buffer"),
size: (I_NB * size_of::<u16>()) as u64,
usage: Usages::INDEX | Usages::COPY_DST,
mapped_at_creation: false,
}
);
Self {
vertex_buffer,
index_buffer,
vertex_type: PhantomData::default(),
}
}
/// Updates the vertices of the [Mesh]. The modification will be applied before the next
/// rendering of the [Mesh]. The function will fail if the given slice has more elements than
/// specified at the [Mesh] creation
pub fn set_vertices(&mut self, renderer: &WgpuRenderer, vertices: &[V]) {
renderer.queue.write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(vertices));
}
/// Updates the indices of the [Mesh]. The modification will be applied before the next
/// rendering of the [Mesh]. The function will fail if the given slice has more elements than
/// specified at the [Mesh] creation
pub fn set_indices(&mut self, renderer: &WgpuRenderer, indices: &[u16]) {
renderer.queue.write_buffer(&self.index_buffer, 0, bytemuck::cast_slice(indices));
}
/// Returns a [BufferSlice] containing the vertices, to be used in a render pass
pub fn get_vertex_buffer_slice(&self) -> wgpu::BufferSlice {
self.vertex_buffer.slice(..)
}
/// Returns a [BufferSlice] containing the indices, to be used in a render pass
pub fn get_index_buffer_slice(&self) -> wgpu::BufferSlice {
self.index_buffer.slice(..)
}
}