use bytemuck::{Pod, Zeroable};
pub trait Vertex: Pod {
fn layout() -> wgpu::VertexBufferLayout<'static>;
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct PositionColorVertex {
pub position: [f32; 3],
pub color: [f32; 3],
}
impl PositionColorVertex {
#[must_use]
pub const fn new(position: [f32; 3], color: [f32; 3]) -> Self {
Self { position, color }
}
}
impl Vertex for PositionColorVertex {
fn layout() -> wgpu::VertexBufferLayout<'static> {
const ATTRIBUTES: &[wgpu::VertexAttribute] = &[
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: std::mem::size_of::<[f32; 3]>() as u64,
shader_location: 1,
},
];
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<PositionColorVertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: ATTRIBUTES,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct PositionColorTexVertex {
pub position: [f32; 3],
pub color: [f32; 3],
pub tex_coords: [f32; 2],
}
impl PositionColorTexVertex {
#[must_use]
pub const fn new(position: [f32; 3], color: [f32; 3], tex_coords: [f32; 2]) -> Self {
Self {
position,
color,
tex_coords,
}
}
}
impl Vertex for PositionColorTexVertex {
fn layout() -> wgpu::VertexBufferLayout<'static> {
const ATTRIBUTES: &[wgpu::VertexAttribute] = &[
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: std::mem::size_of::<[f32; 3]>() as u64,
shader_location: 1,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: (std::mem::size_of::<[f32; 3]>() * 2) as u64,
shader_location: 2,
},
];
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<PositionColorTexVertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: ATTRIBUTES,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_position_color_vertex_new() {
let vertex = PositionColorVertex::new([1.0, 2.0, 3.0], [0.5, 0.6, 0.7]);
assert_eq!(vertex.position, [1.0, 2.0, 3.0]);
assert_eq!(vertex.color, [0.5, 0.6, 0.7]);
}
#[test]
fn test_position_color_vertex_layout() {
let layout = PositionColorVertex::layout();
assert_eq!(
layout.array_stride,
std::mem::size_of::<PositionColorVertex>() as u64
);
assert_eq!(layout.step_mode, wgpu::VertexStepMode::Vertex);
assert_eq!(layout.attributes.len(), 2);
assert_eq!(layout.attributes[0].shader_location, 0);
assert_eq!(layout.attributes[0].format, wgpu::VertexFormat::Float32x3);
assert_eq!(layout.attributes[0].offset, 0);
assert_eq!(layout.attributes[1].shader_location, 1);
assert_eq!(layout.attributes[1].format, wgpu::VertexFormat::Float32x3);
assert_eq!(
layout.attributes[1].offset,
std::mem::size_of::<[f32; 3]>() as u64
);
}
#[test]
fn test_position_color_tex_vertex_new() {
let vertex = PositionColorTexVertex::new([1.0, 2.0, 3.0], [0.5, 0.6, 0.7], [0.0, 1.0]);
assert_eq!(vertex.position, [1.0, 2.0, 3.0]);
assert_eq!(vertex.color, [0.5, 0.6, 0.7]);
assert_eq!(vertex.tex_coords, [0.0, 1.0]);
}
#[test]
fn test_position_color_tex_vertex_layout() {
let layout = PositionColorTexVertex::layout();
assert_eq!(
layout.array_stride,
std::mem::size_of::<PositionColorTexVertex>() as u64
);
assert_eq!(layout.attributes.len(), 3);
assert_eq!(layout.attributes[2].shader_location, 2);
assert_eq!(layout.attributes[2].format, wgpu::VertexFormat::Float32x2);
}
#[test]
fn test_vertex_size_alignment() {
assert_eq!(std::mem::size_of::<PositionColorVertex>(), 24); assert_eq!(std::mem::size_of::<PositionColorTexVertex>(), 32); }
#[test]
fn test_vertex_is_pod() {
let vertex = PositionColorVertex::new([1.0, 0.0, 0.0], [1.0, 1.0, 1.0]);
let bytes: &[u8] = bytemuck::bytes_of(&vertex);
assert_eq!(bytes.len(), 24);
}
}