use crate::format::Format;
#[deprecated(
since = "0.33.0",
note = "derive `Vertex` instead and use field-level attributes to specify format"
)]
#[macro_export]
macro_rules! impl_vertex {
($out:ty $(, $member:ident)*) => (
#[allow(unsafe_code)]
unsafe impl $crate::pipeline::graphics::vertex_input::Vertex for $out {
#[inline(always)]
#[allow(deprecated)]
fn per_vertex() -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
#[allow(unused_imports)]
use std::collections::HashMap;
use $crate::format::Format;
use $crate::pipeline::graphics::vertex_input::VertexMember;
use $crate::pipeline::graphics::vertex_input::{VertexInputRate, VertexMemberInfo};
let mut members = HashMap::default();
$(
{
let dummy = <$out>::default();
#[inline] fn f<T: VertexMember>(_: &T) -> Format { T::format() }
let format = f(&dummy.$member);
let field_size = {
let p = unsafe {
core::ptr::addr_of!((*(&dummy as *const _ as *const $out)).$member)
};
const fn size_of_raw<T>(_: *const T) -> usize {
core::mem::size_of::<T>()
}
size_of_raw(p)
} as u32;
let format_size = format.block_size() as u32;
let num_elements = field_size / format_size;
let remainder = field_size % format_size;
assert!(remainder == 0, "struct field `{}` size does not fit multiple of format size", stringify!($member));
let dummy_ptr = (&dummy) as *const _;
let member_ptr = (&dummy.$member) as *const _;
members.insert(stringify!($member).to_string(), VertexMemberInfo {
offset: member_ptr as usize - dummy_ptr as usize,
format,
num_elements,
});
}
)*
$crate::pipeline::graphics::vertex_input::VertexBufferDescription {
members,
stride: std::mem::size_of::<$out>() as u32,
input_rate: VertexInputRate::Vertex,
}
}
#[inline(always)]
#[allow(deprecated)]
fn per_instance() -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
<$out as $crate::pipeline::graphics::vertex_input::Vertex>::per_vertex().per_instance()
}
#[inline(always)]
#[allow(deprecated)]
fn per_instance_with_divisor(divisor: u32) -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
<$out as $crate::pipeline::graphics::vertex_input::Vertex>::per_vertex().per_instance_with_divisor(divisor)
}
}
)
}
#[deprecated(
since = "0.33.0",
note = "derive `Vertex` instead and use field-level attributes to specify format"
)]
pub unsafe trait VertexMember {
fn format() -> Format;
}
#[macro_export]
macro_rules! impl_vertex_member {
($out:ty, $format:ident) => {
#[allow(deprecated)]
unsafe impl VertexMember for $out {
#[inline]
fn format() -> Format {
Format::$format
}
}
};
}
impl_vertex_member!(i8, R8_SINT);
impl_vertex_member!(u8, R8_UINT);
impl_vertex_member!(i16, R16_SINT);
impl_vertex_member!(u16, R16_UINT);
impl_vertex_member!(i32, R32_SINT);
impl_vertex_member!(u32, R32_UINT);
impl_vertex_member!(f32, R32_SFLOAT);
impl_vertex_member!(f64, R64_SFLOAT);
impl_vertex_member!([i8; 2], R8G8_SINT);
impl_vertex_member!([u8; 2], R8G8_UINT);
impl_vertex_member!([i16; 2], R16G16_SINT);
impl_vertex_member!([u16; 2], R16G16_UINT);
impl_vertex_member!([i32; 2], R32G32_SINT);
impl_vertex_member!([u32; 2], R32G32_UINT);
impl_vertex_member!([f32; 2], R32G32_SFLOAT);
impl_vertex_member!([f64; 2], R64G64_SFLOAT);
impl_vertex_member!([i8; 3], R8G8B8_SINT);
impl_vertex_member!([u8; 3], R8G8B8_UINT);
impl_vertex_member!([i16; 3], R16G16B16_SINT);
impl_vertex_member!([u16; 3], R16G16B16_UINT);
impl_vertex_member!([i32; 3], R32G32B32_SINT);
impl_vertex_member!([u32; 3], R32G32B32_UINT);
impl_vertex_member!([f32; 3], R32G32B32_SFLOAT);
impl_vertex_member!([f64; 3], R64G64B64_SFLOAT);
impl_vertex_member!([i8; 4], R8G8B8A8_SINT);
impl_vertex_member!([u8; 4], R8G8B8A8_UINT);
impl_vertex_member!([i16; 4], R16G16B16A16_SINT);
impl_vertex_member!([u16; 4], R16G16B16A16_UINT);
impl_vertex_member!([i32; 4], R32G32B32A32_SINT);
impl_vertex_member!([u32; 4], R32G32B32A32_UINT);
impl_vertex_member!([f32; 4], R32G32B32A32_SFLOAT);
impl_vertex_member!([f64; 4], R64G64B64A64_SFLOAT);
impl_vertex_member!([f32; 9], R32G32B32_SFLOAT);
impl_vertex_member!([f32; 16], R32G32B32A32_SFLOAT);
#[allow(deprecated)]
unsafe impl<T> VertexMember for [T; 1]
where
T: VertexMember,
{
fn format() -> Format {
<T as VertexMember>::format()
}
}
#[cfg(test)]
mod tests {
use crate::format::Format;
#[allow(deprecated)]
use crate::pipeline::graphics::vertex_input::Vertex;
use bytemuck::{Pod, Zeroable};
#[test]
#[allow(deprecated)]
fn impl_vertex() {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct TestVertex {
matrix: [f32; 16],
vector: [f32; 4],
scalar: u16,
_padding: u16,
}
impl_vertex!(TestVertex, scalar, vector, matrix);
let info = TestVertex::per_vertex();
let matrix = info.members.get("matrix").unwrap();
let vector = info.members.get("vector").unwrap();
let scalar = info.members.get("scalar").unwrap();
assert_eq!(matrix.format, Format::R32G32B32A32_SFLOAT);
assert_eq!(matrix.offset, 0);
assert_eq!(matrix.num_elements, 4);
assert_eq!(vector.format, Format::R32G32B32A32_SFLOAT);
assert_eq!(vector.offset, 16 * 4);
assert_eq!(vector.num_elements, 1);
assert_eq!(scalar.format, Format::R16_UINT);
assert_eq!(scalar.offset, 16 * 5);
assert_eq!(scalar.num_elements, 1);
}
}