use std::alloc::Layout; use std::borrow::Cow; use std::marker::PhantomData; use seq_macro::seq; use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; use crate::mesh::VertexAttrType; pub trait VertexAttrValue: IntoBytes + FromBytes + KnownLayout + Immutable + 'static { fn ty() -> VertexAttrType; } impl VertexAttrValue for f32 { fn ty() -> VertexAttrType { VertexAttrType::Float32 } } impl VertexAttrValue for [f32; LEN] { fn ty() -> VertexAttrType { VertexAttrType::Float32Array { length: LEN } } } #[derive(Debug)] pub struct NamedVertexAttr<'name, Value: VertexAttrValue> { pub name: &'name str, pub value: Value, } #[derive(Debug, Clone)] #[non_exhaustive] pub struct VertexAttrProperties { pub name: Cow<'static, str>, pub ty: VertexAttrType, pub layout: Layout, pub byte_offset: usize, } #[derive(Debug)] pub struct VertexAttrInfo { pub name: Cow<'static, str>, pub ty: VertexAttrType, } #[derive(Debug, Clone, Default)] pub struct VertexBuffer { buf: Vec, vertex_size: usize, vertex_attr_props: Vec, } impl VertexBuffer { pub fn with_capacity(vertex_attrs: &[VertexAttrInfo], capacity: usize) -> Self { let mut vertex_attr_props = vertex_attrs .iter() .map(|VertexAttrInfo { name, ty }| VertexAttrProperties { name: name.clone(), ty: ty.clone(), layout: ty.layout(), byte_offset: 0, }) .collect::>(); let mut vertex_layout = Layout::new::<()>(); for VertexAttrProperties { name: _, ty: _, layout: vertex_attr_layout, byte_offset: vertex_attr_byte_offset, } in &mut vertex_attr_props { let (new_struct_layout, byte_offset) = vertex_layout.extend(*vertex_attr_layout).unwrap(); *vertex_attr_byte_offset = byte_offset; vertex_layout = new_struct_layout; } let vertex_layout = vertex_layout.pad_to_align(); Self { buf: Vec::with_capacity(vertex_layout.size() * capacity), vertex_size: vertex_layout.size(), vertex_attr_props, } } pub fn push<'name, VertexAttrs: NamedVertexAttrs<'name>>( &mut self, vertex: VertexAttrs, ) { assert_eq!( self.vertex_attr_props.len(), vertex.vertex_attr_cnt(), "Vertex has incorrect amount of attributes" ); if self.buf.spare_capacity_mut().len() < self.vertex_size { self.buf.reserve_exact(self.vertex_size * (self.len() / 2)); } let spare_capacity = self.buf.spare_capacity_mut(); let vertex_attrs = vertex.vertex_attrs(); for (vertex_attr_name, vertex_attr_bytes, vertex_attr_ty) in vertex_attrs { let vertex_attr_props = self .vertex_attr_props .iter() .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name) .unwrap(); assert_eq!(vertex_attr_ty, vertex_attr_props.ty); let start_offset = vertex_attr_props.byte_offset; let end_offset = start_offset + vertex_attr_props.layout.size(); spare_capacity[start_offset..end_offset] .write_copy_of_slice(vertex_attr_bytes); } unsafe { self.buf.set_len(self.buf.len() + self.vertex_size); } } pub fn vertex_attr_props(&self) -> &[VertexAttrProperties] { &self.vertex_attr_props } pub fn len(&self) -> usize { assert_eq!(self.buf.len() % self.vertex_size, 0, "Invalid length"); self.buf.len() / self.vertex_size } pub fn vertex_size(&self) -> usize { self.vertex_size } pub fn as_bytes(&self) -> &[u8] { &self.buf } pub fn iter( &self, vertex_attr_name: &str, ) -> Iter<'_, VertexAttr> { let vertex_attr_props = self .vertex_attr_props .iter() .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name) .unwrap(); assert_eq!(VertexAttr::ty(), vertex_attr_props.ty); Iter { buf: self, vertex_attr_props, curr_index: 0, _pd: PhantomData, } } } pub struct Iter<'a, VertexAttr: VertexAttrValue> { buf: &'a VertexBuffer, vertex_attr_props: &'a VertexAttrProperties, curr_index: usize, _pd: PhantomData, } impl<'a, VertexAttr: VertexAttrValue> Iterator for Iter<'a, VertexAttr> { type Item = &'a VertexAttr; fn next(&mut self) -> Option { let start_offset = (self.buf.vertex_size * self.curr_index) + self.vertex_attr_props.byte_offset; let end_offset = start_offset + self.vertex_attr_props.layout.size(); let bytes = self.buf.buf.get(start_offset..end_offset)?; self.curr_index += 1; Some(VertexAttr::ref_from_bytes(bytes).unwrap()) } } pub trait NamedVertexAttrs<'name> { fn vertex_attr_cnt(&self) -> usize; fn vertex_attrs(&self) -> impl Iterator; } macro_rules! impl_named_vertex_attrs { ($cnt: tt) => { seq!(I in 0..$cnt { impl<'name, #(VertexAttr~I: VertexAttrValue,)*> NamedVertexAttrs<'name> for (#(NamedVertexAttr<'name, VertexAttr~I>,)*) { fn vertex_attr_cnt(&self) -> usize { $cnt } fn vertex_attrs(&self) -> impl Iterator { [#( (self.I.name, self.I.value.as_bytes(), VertexAttr~I::ty()), )*].into_iter() } } }); }; } seq!(I in 0..16 { impl_named_vertex_attrs!(I); });