use crate::types::{VertexBufferLayout, VertexAttribute, VertexFormat};
use bytemuck::{Pod, Zeroable};
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct VertexUv {
pub position: [f32; 2],
pub uv: [f32; 2],
}
impl VertexUv {
pub const fn new(x: f32, y: f32, u: f32, v: f32) -> Self {
Self {
position: [x, y],
uv: [u, v],
}
}
pub fn layout() -> VertexBufferLayout {
VertexBufferLayout {
stride: std::mem::size_of::<Self>() as u32,
attributes: vec![
VertexAttribute {
location: 0,
format: VertexFormat::Float32x2,
offset: 0,
},
VertexAttribute {
location: 1,
format: VertexFormat::Float32x2,
offset: 8,
},
],
}
}
}
pub const FULLSCREEN_QUAD: [VertexUv; 6] = [
VertexUv { position: [-1.0, -1.0], uv: [0.0, 1.0] },
VertexUv { position: [1.0, -1.0], uv: [1.0, 1.0] },
VertexUv { position: [1.0, 1.0], uv: [1.0, 0.0] },
VertexUv { position: [-1.0, -1.0], uv: [0.0, 1.0] },
VertexUv { position: [1.0, 1.0], uv: [1.0, 0.0] },
VertexUv { position: [-1.0, 1.0], uv: [0.0, 0.0] },
];
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct VertexUvTime {
pub position: [f32; 2],
pub uv: [f32; 2],
pub time: f32,
}
impl VertexUvTime {
pub const fn new(x: f32, y: f32, u: f32, v: f32, time: f32) -> Self {
Self {
position: [x, y],
uv: [u, v],
time,
}
}
pub fn layout() -> VertexBufferLayout {
VertexBufferLayout {
stride: std::mem::size_of::<Self>() as u32,
attributes: vec![
VertexAttribute {
location: 0,
format: VertexFormat::Float32x2,
offset: 0,
},
VertexAttribute {
location: 1,
format: VertexFormat::Float32x2,
offset: 8,
},
VertexAttribute {
location: 2,
format: VertexFormat::Float32,
offset: 16,
},
],
}
}
}
pub fn create_fullscreen_quad_with_time(time: f32) -> [VertexUvTime; 6] {
[
VertexUvTime::new(-1.0, -1.0, 0.0, 1.0, time),
VertexUvTime::new(1.0, -1.0, 1.0, 1.0, time),
VertexUvTime::new(1.0, 1.0, 1.0, 0.0, time),
VertexUvTime::new(-1.0, -1.0, 0.0, 1.0, time),
VertexUvTime::new(1.0, 1.0, 1.0, 0.0, time),
VertexUvTime::new(-1.0, 1.0, 0.0, 0.0, time),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vertex_uv_layout() {
let layout = VertexUv::layout();
assert_eq!(layout.stride, 16); assert_eq!(layout.attributes.len(), 2);
assert_eq!(layout.attributes[0].offset, 0);
assert_eq!(layout.attributes[1].offset, 8);
}
#[test]
fn test_vertex_uv_time_layout() {
let layout = VertexUvTime::layout();
assert_eq!(layout.stride, 20); assert_eq!(layout.attributes.len(), 3);
assert_eq!(layout.attributes[0].offset, 0);
assert_eq!(layout.attributes[1].offset, 8);
assert_eq!(layout.attributes[2].offset, 16);
}
#[test]
fn test_fullscreen_quad_coverage() {
let min_x = FULLSCREEN_QUAD.iter().map(|v| v.position[0]).fold(f32::INFINITY, f32::min);
let max_x = FULLSCREEN_QUAD.iter().map(|v| v.position[0]).fold(f32::NEG_INFINITY, f32::max);
let min_y = FULLSCREEN_QUAD.iter().map(|v| v.position[1]).fold(f32::INFINITY, f32::min);
let max_y = FULLSCREEN_QUAD.iter().map(|v| v.position[1]).fold(f32::NEG_INFINITY, f32::max);
assert_eq!(min_x, -1.0);
assert_eq!(max_x, 1.0);
assert_eq!(min_y, -1.0);
assert_eq!(max_y, 1.0);
}
#[test]
fn test_create_fullscreen_quad_with_time() {
let time = 1.5;
let quad = create_fullscreen_quad_with_time(time);
assert_eq!(quad.len(), 6);
for v in &quad {
assert_eq!(v.time, time);
}
}
}