diff --git a/Cargo.toml b/Cargo.toml index 1d73f60..78020e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,6 @@ resolver = "2" members = [ "crates/rusteroids", "crates/wgpu_utils", + "crates/wgpu_utils/internals", "crates/wgpu_utils/vertex_attribute_derive", ] \ No newline at end of file diff --git a/crates/rusteroids/src/mesh.rs b/crates/rusteroids/src/mesh.rs index d70c977..7d3143d 100644 --- a/crates/rusteroids/src/mesh.rs +++ b/crates/rusteroids/src/mesh.rs @@ -2,8 +2,8 @@ use std::ops::Range; use glam::Mat4; use wgpu::util::DeviceExt; -use wgpu::{Queue, RenderPass, VertexAttribute}; -use wgpu_utils::VertexAttributeArray; +use wgpu::{Queue, RenderPass}; +use wgpu_utils::{format_of, VertexAttributeArray}; use crate::utils::{common_layout_descriptor, Bindable, UniformBuffer}; #[repr(C)] @@ -13,10 +13,6 @@ pub struct Vertex { pub color: [f32; 3], } -impl Vertex { - const ATTR: [VertexAttribute; 2] = wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3]; -} - pub struct Geometry { vertex_buffer: Option, model_uniform: Option, diff --git a/crates/wgpu_utils/Cargo.toml b/crates/wgpu_utils/Cargo.toml index a11b1eb..4a80dcf 100644 --- a/crates/wgpu_utils/Cargo.toml +++ b/crates/wgpu_utils/Cargo.toml @@ -5,4 +5,5 @@ edition = "2021" [dependencies] vertex_attribute_derive = { path = "vertex_attribute_derive" } -wgpu = "22.0" \ No newline at end of file +wgpu = "22.0" +internals = { path = "internals"} \ No newline at end of file diff --git a/crates/wgpu_utils/internals/Cargo.toml b/crates/wgpu_utils/internals/Cargo.toml new file mode 100644 index 0000000..adfcacb --- /dev/null +++ b/crates/wgpu_utils/internals/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "internals" +version = "0.1.0" +edition = "2021" + +[dependencies] +wgpu = "22.0" \ No newline at end of file diff --git a/crates/wgpu_utils/internals/src/lib.rs b/crates/wgpu_utils/internals/src/lib.rs new file mode 100644 index 0000000..b57a4ca --- /dev/null +++ b/crates/wgpu_utils/internals/src/lib.rs @@ -0,0 +1,39 @@ +pub trait ConstFormat { + const FORMAT: wgpu::VertexFormat; +} + +pub const fn format_of() -> wgpu::VertexFormat { + T::FORMAT +} +/// Defines the default VertexFormat of a particular type. +/// By defining it using +/// `````` +/// const_format_of!(MyVec3 => VertexFormat::Float32x3) +/// ``` +/// +/// You can then use its format with the following call +/// ``` +/// let vertex_format: wgpu::VertexFormat = format_of::(); +/// ``` +/// +/// And use this in conjunction with VertexAttributeArray macro +/// ``` +/// #[derive(VertexAttributeArray)] +/// struct MyVertexBuffer{ +/// pos: MyVec3, +/// } +macro_rules! const_format_of { + ($T:ty => $format:expr) => { + impl ConstFormat for $T { + const FORMAT: wgpu::VertexFormat = $format; + } + }; +} + +const_format_of!(f32 => wgpu::VertexFormat::Float32); +const_format_of!([f32; 2] => wgpu::VertexFormat::Float32x2); +const_format_of!([f32; 3] => wgpu::VertexFormat::Float32x3); +const_format_of!([f32; 4] => wgpu::VertexFormat::Float32x4); +const_format_of!(u32 => wgpu::VertexFormat::Uint32); +const_format_of!([u32; 2] => wgpu::VertexFormat::Uint32x2); +const_format_of!([u32; 3] => wgpu::VertexFormat::Uint32x3); diff --git a/crates/wgpu_utils/src/lib.rs b/crates/wgpu_utils/src/lib.rs index bcc3cce..de3aa4b 100644 --- a/crates/wgpu_utils/src/lib.rs +++ b/crates/wgpu_utils/src/lib.rs @@ -1,3 +1,4 @@ +pub use internals::format_of; pub use vertex_attribute_derive::VertexAttributeArray; pub trait VertexAttributeArray { diff --git a/crates/wgpu_utils/vertex_attribute_derive/Cargo.toml b/crates/wgpu_utils/vertex_attribute_derive/Cargo.toml index c0d0d9a..5bb6c30 100644 --- a/crates/wgpu_utils/vertex_attribute_derive/Cargo.toml +++ b/crates/wgpu_utils/vertex_attribute_derive/Cargo.toml @@ -9,4 +9,5 @@ proc-macro = true [dependencies] quote = "1.0.37" syn = "2.0.79" -wgpu = "22.0" \ No newline at end of file +wgpu = "22.0" +internals = { path = "../internals" } \ No newline at end of file diff --git a/crates/wgpu_utils/vertex_attribute_derive/src/lib.rs b/crates/wgpu_utils/vertex_attribute_derive/src/lib.rs index b754da7..7ee1288 100644 --- a/crates/wgpu_utils/vertex_attribute_derive/src/lib.rs +++ b/crates/wgpu_utils/vertex_attribute_derive/src/lib.rs @@ -1,6 +1,7 @@ +use internals::format_of; use proc_macro::TokenStream; use quote::quote; - +use syn::{Data, Fields}; /// Ensures the struct is capable of generating a VertexBufferLayout /// by calling desc. Requires the existing of a ```const ATTR: [wgpu::VertexAttribute; N]``` /// @@ -30,13 +31,42 @@ pub fn vertex_attribute_derive(input: TokenStream) -> TokenStream { fn impl_vertex_attribute(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; + let fields = match &ast.data { + Data::Struct(data) => { + if let Fields::Named(named_fields) = &data.fields { + named_fields.named.clone() + } else { + panic!("#[derive(VertexAttributeArray)] is only supported on structs with named fields"); + } + } + // TODO: Add enums + _ => panic!("#[derive(VertexAttributeArray)] is only supported on structs"), + }; + + // Generate the vertex attributes + let field_types = fields.iter().enumerate().map(|(i, f)| { + let ty = &f.ty; + quote! { + wgpu::VertexAttribute { + format: format_of::<#ty>(), + offset: size_of::<#ty>() as u64, + shader_location: #i as u32, + } + } + }); + + let attrs_array_len = field_types.len(); + let gen = quote! { impl VertexAttributeArray for #name { fn desc() -> wgpu::VertexBufferLayout<'static> { + static attr: [wgpu::VertexAttribute; #attrs_array_len] = [ + #(#field_types),* + ]; wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, - attributes: &Self::ATTR, + attributes: &attr, } } }