From 5b48de96db57ca2b1ad7857e9cd5d9ae921afa50 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 9 Feb 2020 18:04:18 -0800 Subject: [PATCH] Add Uniforms proc macro --- bevy_derive/Cargo.toml | 1 + bevy_derive/src/lib.rs | 80 +++++++++++++++++-- src/render/render_graph_2/mod.rs | 2 + .../pipelines/forward/forward.frag | 2 +- .../pipelines/forward/forward.vert | 2 +- .../render_graph_2/pipelines/forward/mod.rs | 2 +- .../pipelines/forward_flat/forward_flat.frag | 2 +- .../pipelines/forward_flat/forward_flat.vert | 2 +- .../pipelines/forward_flat/mod.rs | 2 +- src/render/render_graph_2/renderable.rs | 6 ++ .../render_graph_2/standard_material.rs | 66 +-------------- 11 files changed, 92 insertions(+), 75 deletions(-) create mode 100644 src/render/render_graph_2/renderable.rs diff --git a/bevy_derive/Cargo.toml b/bevy_derive/Cargo.toml index efa36b6681..2ef015a6c7 100644 --- a/bevy_derive/Cargo.toml +++ b/bevy_derive/Cargo.toml @@ -12,5 +12,6 @@ proc-macro = true syn = "1.0" quote = "1.0" +Inflector = { version = "0.11.4", default-features = false } [dev-dependencies] \ No newline at end of file diff --git a/bevy_derive/src/lib.rs b/bevy_derive/src/lib.rs index 25687d8c3d..645d2727f7 100644 --- a/bevy_derive/src/lib.rs +++ b/bevy_derive/src/lib.rs @@ -1,14 +1,18 @@ extern crate proc_macro; +use inflector::Inflector; use proc_macro::TokenStream; -use syn::{parse_macro_input, DeriveInput, Data, DataStruct, Fields}; -use quote::quote; +use quote::{format_ident, quote}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; #[proc_macro_derive(EntityArchetype)] pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let fields = match &ast.data { - Data::Struct(DataStruct { fields: Fields::Named(fields), .. }) => &fields.named, + Data::Struct(DataStruct { + fields: Fields::Named(fields), + .. + }) => &fields.named, _ => panic!("expected a struct with named fields"), }; @@ -19,8 +23,74 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { impl EntityArchetype for #struct_name { fn insert(self, world: &mut World) -> Entity { *world.insert((), vec![( - #(self.#field_name),* - ,)]).first().unwrap() + #(self.#field_name,)* + )]).first().unwrap() + } + } + }) +} + +#[proc_macro_derive(Uniforms)] +pub fn derive_uniforms(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let fields = match &ast.data { + Data::Struct(DataStruct { + fields: Fields::Named(fields), + .. + }) => &fields.named, + _ => panic!("expected a struct with named fields"), + }; + + 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 + .iter() + .map(|field| format!("{}_{}", struct_name, field.ident.as_ref().unwrap())) + .collect::>(); + let get_uniform_bytes_field_name = 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])); + + TokenStream::from(quote! { + const #info_ident: &[UniformInfo] = &[ + #(UniformInfo { + name: #uniform_name_uniform_info, + bind_type: BindType::Uniform { + dynamic: false, + // TODO: fill this in with properties + properties: Vec::new(), + }, + },)* + ]; + + const #layout_ident: &[&[UniformPropertyType]] = &[ + #(#layout_arrays,)* + ]; + + impl AsUniforms for #struct_name { + fn get_uniform_infos(&self) -> &[UniformInfo] { + #info_ident + } + + fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] { + #layout_ident + } + + fn get_uniform_bytes(&self, name: &str) -> Option> { + match name { + #(#get_uniform_bytes_uniform_name => Some(self.#get_uniform_bytes_field_name.get_bytes()),)* + _ => None, + } + } + fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo> { + match name { + #(#get_uniform_info_uniform_name => Some(#get_uniform_info_array_refs),)* + _ => None, + } } } }) diff --git a/src/render/render_graph_2/mod.rs b/src/render/render_graph_2/mod.rs index 79ba57cb4b..5a4b5b0f1b 100644 --- a/src/render/render_graph_2/mod.rs +++ b/src/render/render_graph_2/mod.rs @@ -14,6 +14,7 @@ pub mod resource_provider; pub mod resource_providers; mod standard_material; mod uniform; +mod renderable; pub use draw_target::*; pub use pass::*; @@ -25,3 +26,4 @@ pub use resource::*; pub use resource_provider::*; pub use standard_material::*; pub use uniform::*; +pub use renderable::*; diff --git a/src/render/render_graph_2/pipelines/forward/forward.frag b/src/render/render_graph_2/pipelines/forward/forward.frag index 8d454a3fb7..05e2ecd7c6 100644 --- a/src/render/render_graph_2/pipelines/forward/forward.frag +++ b/src/render/render_graph_2/pipelines/forward/forward.frag @@ -23,7 +23,7 @@ layout(set = 0, binding = 1) uniform Lights { Light SceneLights[MAX_LIGHTS]; }; -layout(set = 1, binding = 1) uniform StandardMaterial { +layout(set = 1, binding = 1) uniform StandardMaterial_albedo { vec4 Albedo; }; diff --git a/src/render/render_graph_2/pipelines/forward/forward.vert b/src/render/render_graph_2/pipelines/forward/forward.vert index ce7c3c08f3..88f247a461 100644 --- a/src/render/render_graph_2/pipelines/forward/forward.vert +++ b/src/render/render_graph_2/pipelines/forward/forward.vert @@ -16,7 +16,7 @@ layout(set = 1, binding = 0) uniform Object { mat4 Model; }; -layout(set = 1, binding = 1) uniform StandardMaterial { +layout(set = 1, binding = 1) uniform StandardMaterial_albedo { vec4 Albedo; }; diff --git a/src/render/render_graph_2/pipelines/forward/mod.rs b/src/render/render_graph_2/pipelines/forward/mod.rs index f595ee273f..346c61497b 100644 --- a/src/render/render_graph_2/pipelines/forward/mod.rs +++ b/src/render/render_graph_2/pipelines/forward/mod.rs @@ -68,7 +68,7 @@ impl ForwardPipelineBuilder for RenderGraphBuilder { }, }, Binding { - name: "StandardMaterial".to_string(), + name: "StandardMaterial_albedo".to_string(), bind_type: BindType::Uniform { dynamic: true, properties: vec![UniformProperty { diff --git a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag index 55f30d1328..6bb8549240 100644 --- a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag +++ b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag @@ -10,7 +10,7 @@ layout(set = 0, binding = 0) uniform Camera { mat4 ViewProj; }; -layout(set = 1, binding = 1) uniform StandardMaterial { +layout(set = 1, binding = 1) uniform StandardMaterial_albedo { vec4 Albedo; }; diff --git a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert index 4bb8e07c84..36a2625728 100644 --- a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert +++ b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert @@ -16,7 +16,7 @@ layout(set = 1, binding = 0) uniform Object { mat4 Model; }; -layout(set = 1, binding = 1) uniform StandardMaterial { +layout(set = 1, binding = 1) uniform StandardMaterial_albedo { vec4 Albedo; }; diff --git a/src/render/render_graph_2/pipelines/forward_flat/mod.rs b/src/render/render_graph_2/pipelines/forward_flat/mod.rs index 7300797abf..8c60659c14 100644 --- a/src/render/render_graph_2/pipelines/forward_flat/mod.rs +++ b/src/render/render_graph_2/pipelines/forward_flat/mod.rs @@ -43,7 +43,7 @@ impl ForwardFlatPipelineBuilder for RenderGraphBuilder { }, }, Binding { - name: "StandardMaterial".to_string(), + name: "StandardMaterial_albedo".to_string(), bind_type: BindType::Uniform { dynamic: true, properties: vec![UniformProperty { diff --git a/src/render/render_graph_2/renderable.rs b/src/render/render_graph_2/renderable.rs new file mode 100644 index 0000000000..207a918e72 --- /dev/null +++ b/src/render/render_graph_2/renderable.rs @@ -0,0 +1,6 @@ +use crate::{asset::Handle, render::Shader}; + +pub struct Renderable { + pub render: bool, + pub shaders: Vec>, +} diff --git a/src/render/render_graph_2/standard_material.rs b/src/render/render_graph_2/standard_material.rs index cbd9e938f7..4c6d8de093 100644 --- a/src/render/render_graph_2/standard_material.rs +++ b/src/render/render_graph_2/standard_material.rs @@ -6,63 +6,14 @@ use crate::{ }, }; +use bevy_derive::Uniforms; use zerocopy::AsBytes; +#[derive(Uniforms)] pub struct StandardMaterial { pub albedo: Vec4, } -// create this from a derive macro -const STANDARD_MATERIAL_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo { - name: "StandardMaterial", - bind_type: BindType::Uniform { - dynamic: false, - // TODO: fill this in with properties - properties: Vec::new(), - }, -}]; - -// these are separate from BindType::Uniform{properties} because they need to be const -const STANDARD_MATERIAL_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]]; - -// const -impl AsUniforms for StandardMaterial { - fn get_uniform_infos(&self) -> &[UniformInfo] { - STANDARD_MATERIAL_UNIFORM_INFO - } - - fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]] { - STANDARD_MATERIAL_UNIFORM_LAYOUTS - } - - fn get_uniform_bytes(&self, name: &str) -> Option> { - match name { - "StandardMaterial" => Some(self.albedo.get_bytes()), - _ => None, - } - } - fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo> { - match name { - "StandardMaterial" => Some(&STANDARD_MATERIAL_UNIFORM_INFO[0]), - _ => None, - } - } - - // fn iter_properties(&self) -> std::slice::Iter<&'static str> { - // STANDARD_MATERIAL_PROPERTIES.iter() - // } - // fn get_property(&self, name: &str) -> Option { - // match name { - // "albedo" => Some(match self.albedo { - // Albedo::Color(color) => ShaderValue::Vec4(color), - // Albedo::Texture(ref texture) => ShaderValue::Texture(texture) - // }), - // _ => None, - // } - // } -} - -// create this from a derive macro const LOCAL_TO_WORLD_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo { name: "Object", bind_type: BindType::Uniform { @@ -75,7 +26,6 @@ const LOCAL_TO_WORLD_UNIFORM_INFO: &[UniformInfo] = &[UniformInfo { // these are separate from BindType::Uniform{properties} because they need to be const const LOCAL_TO_WORLD_UNIFORM_LAYOUTS: &[&[UniformPropertyType]] = &[&[]]; -// const ST impl AsUniforms for bevy_transform::prelude::LocalToWorld { fn get_uniform_infos(&self) -> &[UniformInfo] { LOCAL_TO_WORLD_UNIFORM_INFO @@ -97,16 +47,4 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { _ => None, } } - // fn iter_properties(&self) -> std::slice::Iter<&'static str> { - // STANDARD_MATERIAL_PROPERTIES.iter() - // } - // fn get_property(&self, name: &str) -> Option { - // match name { - // "albedo" => Some(match self.albedo { - // Albedo::Color(color) => ShaderValue::Vec4(color), - // Albedo::Texture(ref texture) => ShaderValue::Texture(texture) - // }), - // _ => None, - // } - // } }