1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5
6#[proc_macro_derive(VertexLayout)]
7pub fn vertex_layout(item: TokenStream) -> TokenStream {
8 let ast: syn::DeriveInput = syn::parse(item).unwrap();
11
12 let name = &ast.ident;
13
14 let vertex_step_mode = quote! { ::agpu::wgpu::VertexStepMode::Vertex };
15
16 let vertex_attrs = match attrs_from_fields(&ast) {
18 Ok(value) => value,
19 Err(value) => return value,
20 };
21
22 let gen = quote! {
23 impl ::agpu::buffer::VertexLayout for #name {
25 fn vertex_buffer_layout<const L: u32>() -> ::agpu::wgpu::VertexBufferLayout<'static> {
27 use ::agpu::VertexFormatType;
28 ::agpu::wgpu::VertexBufferLayout {
29 array_stride: ::std::mem::size_of::<Self>() as ::agpu::wgpu::BufferAddress,
30 step_mode: #vertex_step_mode,
31 attributes: &[
32 #vertex_attrs
33 ],
34 }
35 }
36 }
37 };
38
39 gen.into()
40}
41
42#[proc_macro_derive(VertexLayoutInstance)]
43pub fn vertex_layout_instance(item: TokenStream) -> TokenStream {
44 let ast: syn::DeriveInput = syn::parse(item).unwrap();
47
48 let name = &ast.ident;
49
50 let vertex_step_mode = quote! { ::agpu::wgpu::VertexStepMode::Instance };
51
52 let vertex_attrs = match attrs_from_fields(&ast) {
54 Ok(value) => value,
55 Err(value) => return value,
56 };
57
58 let gen = quote! {
59 impl ::agpu::buffer::VertexLayout for #name {
61 fn vertex_buffer_layout<const L: u32>() -> ::agpu::wgpu::VertexBufferLayout<'static> {
63 use ::agpu::VertexFormatType;
64 ::agpu::wgpu::VertexBufferLayout {
65 array_stride: ::std::mem::size_of::<Self>() as ::agpu::wgpu::BufferAddress,
66 step_mode: #vertex_step_mode,
67 attributes: &[
68 #vertex_attrs
69 ],
70 }
71 }
72 }
73 };
74
75 gen.into()
76}
77
78fn attrs_from_fields(ast: &syn::DeriveInput) -> Result<quote::__private::TokenStream, TokenStream> {
79 let mut vertex_attrs = quote! {};
80 let fields = match &ast.data {
81 syn::Data::Struct(data) => &data.fields,
82 _ => return Err(quote! { compile_error!("Vertex buffer must be struct")}.into()),
84 };
85 let mut offset = quote! { 0 };
86 for (i, field) in fields.iter().enumerate() {
87 let ty = &field.ty;
88
89 vertex_attrs.extend(quote! {
97 ::agpu::wgpu::VertexAttribute {
98 offset: #offset,
99 shader_location: L + #i as u32,
100 format: <#ty>::VERTEX_FORMAT_TYPE,
101 },
102 });
103
104 offset.extend(quote! {+ ::std::mem::size_of::<#ty>() as u64});
106 }
107 Ok(vertex_attrs)
108}
109
110