add uniform field attribute

This commit is contained in:
Carter Anderson 2020-02-09 21:41:51 -08:00
parent c1bac8869e
commit 4a12d16307
7 changed files with 80 additions and 7 deletions

View file

@ -13,5 +13,6 @@ proc-macro = true
syn = "1.0"
quote = "1.0"
Inflector = { version = "0.11.4", default-features = false }
darling = "0.10.2"
[dev-dependencies]

View file

@ -1,9 +1,10 @@
extern crate proc_macro;
use darling::FromMeta;
use inflector::Inflector;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields};
#[proc_macro_derive(EntityArchetype)]
pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
@ -29,10 +30,19 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
}
})
}
#[derive(FromMeta, Debug, Default)]
struct UniformAttributeArgs {
#[darling(default)]
pub ignore: Option<bool>,
#[darling(default)]
pub shader_def: Option<String>,
}
#[proc_macro_derive(Uniforms)]
#[proc_macro_derive(Uniforms, attributes(uniform))]
pub fn derive_uniforms(input: TokenStream) -> TokenStream {
const UNIFORM_ATTRIBUTE_NAME: &'static str = "uniform";
let ast = parse_macro_input!(input as DeriveInput);
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
@ -41,19 +51,67 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
_ => panic!("expected a struct with named fields"),
};
let uniform_fields = fields
.iter()
.map(|f| {
(
f,
f.attrs
.iter()
.find(|a| {
a.path.get_ident().as_ref().unwrap().to_string() == UNIFORM_ATTRIBUTE_NAME
})
.map(|a| {
UniformAttributeArgs::from_meta(&a.parse_meta().unwrap())
.unwrap_or_else(|_err| UniformAttributeArgs::default())
}),
)
})
.collect::<Vec<(&Field, Option<UniformAttributeArgs>)>>();
let active_uniform_fields = uniform_fields
.iter()
.filter(|(_field, attrs)| {
attrs.is_none()
|| match attrs.as_ref().unwrap().ignore {
Some(ignore) => !ignore,
None => true,
}
})
.map(|(f, _attr)| *f)
.collect::<Vec<&Field>>();
let shader_defs = uniform_fields
.iter()
.filter(|(_f, attrs)| match attrs {
Some(attrs) => attrs.shader_def.is_some(),
None => false,
})
.map(|(f, attrs)| {
// attrs is guaranteed to be set because we checked in filter
let shader_def = attrs.as_ref().unwrap().shader_def.as_ref().unwrap();
if shader_def.len() == 0 {
f.ident.as_ref().unwrap().to_string()
} else {
shader_def.to_string()
}
})
.collect::<Vec<String>>();
let struct_name = &ast.ident;
let struct_name_screaming_snake = struct_name.to_string().to_screaming_snake_case();
let info_ident = format_ident!("{}_UNIFORM_INFO", struct_name_screaming_snake);
let layout_ident = format_ident!("{}_UNIFORM_LAYOUTS", struct_name_screaming_snake);
let layout_arrays = (0..fields.len()).map(|_| quote!(&[]));
let uniform_name_uniform_info = fields
let layout_arrays = (0..active_uniform_fields.len()).map(|_| quote!(&[]));
let uniform_name_uniform_info = active_uniform_fields
.iter()
.map(|field| format!("{}_{}", struct_name, field.ident.as_ref().unwrap()))
.collect::<Vec<String>>();
let get_uniform_bytes_field_name = fields.iter().map(|field| &field.ident);
let get_uniform_bytes_field_name = active_uniform_fields.iter().map(|field| &field.ident);
let get_uniform_bytes_uniform_name = uniform_name_uniform_info.clone();
let get_uniform_info_uniform_name = uniform_name_uniform_info.clone();
let get_uniform_info_array_refs = (0..fields.len()).map(|i| quote!(&#info_ident[#i]));
let get_uniform_info_array_refs =
(0..active_uniform_fields.len()).map(|i| quote!(&#info_ident[#i]));
TokenStream::from(quote! {
const #info_ident: &[UniformInfo] = &[
@ -92,6 +150,12 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
_ => None,
}
}
fn get_shader_defs(&self) -> Vec<&'static str> {
vec![
#(#shader_defs,)*
]
}
}
})
}

View file

@ -1377,7 +1377,7 @@ pub struct ComponentResourceSet {
impl ComponentResourceSet {
/// Gets the version of the component slice.
pub fn version(&self) -> u64 { unsafe { (*self.version.get()) } }
pub fn version(&self) -> u64 { unsafe { *self.version.get() } }
/// Gets a raw pointer to the start of the component slice.
///

View file

@ -305,6 +305,7 @@ impl WgpuRenderer {
}
// TODO: remove me
#[allow(dead_code)]
fn setup_dynamic_entity_shader_uniforms(
&mut self,
world: &World,

View file

@ -41,6 +41,7 @@ pub trait AsUniforms {
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>;
fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]];
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>>;
fn get_shader_defs(&self) -> Vec<&'static str>;
// TODO: support zero-copy uniforms
// fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>;
}

View file

@ -40,4 +40,8 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld {
_ => None,
}
}
fn get_shader_defs(&self) -> std::vec::Vec<&'static str> {
Vec::new()
}
}

View file

@ -11,4 +11,6 @@ use bevy_derive::Uniforms;
#[derive(Uniforms)]
pub struct StandardMaterial {
pub albedo: Vec4,
// #[uniform(ignore,shader_def="Hi")]
// pub enable_thing: bool,
}