derive struct as uniform
This commit is contained in:
parent
736faa3f46
commit
05dbf31fd1
@ -1,5 +1,8 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
mod modules;
|
||||||
|
|
||||||
|
use modules::{get_modules, get_path};
|
||||||
use darling::FromMeta;
|
use darling::FromMeta;
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
@ -12,112 +15,6 @@ struct EntityArchetypeAttributeArgs {
|
|||||||
pub tag: Option<bool>,
|
pub tag: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromMeta, Debug)]
|
|
||||||
struct ModuleAttributeArgs {
|
|
||||||
#[darling(default)]
|
|
||||||
pub bevy_render: Option<String>,
|
|
||||||
#[darling(default)]
|
|
||||||
pub bevy_asset: Option<String>,
|
|
||||||
#[darling(default)]
|
|
||||||
pub bevy_core: Option<String>,
|
|
||||||
#[darling(default)]
|
|
||||||
pub bevy_app: Option<String>,
|
|
||||||
#[darling(default)]
|
|
||||||
pub legion: Option<String>,
|
|
||||||
|
|
||||||
/// If true, it will use the meta "bevy" crate for dependencies by default (ex: bevy:app). If this is set to false, the individual bevy crates
|
|
||||||
/// will be used (ex: "bevy_app"). Defaults to "true"
|
|
||||||
#[darling(default)]
|
|
||||||
pub meta: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Modules {
|
|
||||||
pub bevy_render: String,
|
|
||||||
pub bevy_asset: String,
|
|
||||||
pub bevy_core: String,
|
|
||||||
pub bevy_app: String,
|
|
||||||
pub legion: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Modules {
|
|
||||||
pub fn meta() -> Modules {
|
|
||||||
Modules {
|
|
||||||
bevy_asset: "bevy::asset".to_string(),
|
|
||||||
bevy_render: "bevy::render".to_string(),
|
|
||||||
bevy_core: "bevy::core".to_string(),
|
|
||||||
bevy_app: "bevy::app".to_string(),
|
|
||||||
legion: "bevy".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn external() -> Modules {
|
|
||||||
Modules {
|
|
||||||
bevy_asset: "bevy_asset".to_string(),
|
|
||||||
bevy_render: "bevy_render".to_string(),
|
|
||||||
bevy_core: "bevy_core".to_string(),
|
|
||||||
bevy_app: "bevy_app".to_string(),
|
|
||||||
legion: "legion".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ModuleAttributeArgs {
|
|
||||||
fn default() -> Self {
|
|
||||||
ModuleAttributeArgs {
|
|
||||||
bevy_asset: None,
|
|
||||||
bevy_render: None,
|
|
||||||
bevy_core: None,
|
|
||||||
bevy_app: None,
|
|
||||||
legion: None,
|
|
||||||
meta: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static MODULE_ATTRIBUTE_NAME: &'static str = "module";
|
|
||||||
|
|
||||||
fn get_modules(ast: &DeriveInput) -> Modules {
|
|
||||||
let module_attribute_args = ast
|
|
||||||
.attrs
|
|
||||||
.iter()
|
|
||||||
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == MODULE_ATTRIBUTE_NAME)
|
|
||||||
.map(|a| {
|
|
||||||
ModuleAttributeArgs::from_meta(&a.parse_meta().unwrap())
|
|
||||||
.unwrap_or_else(|_err| ModuleAttributeArgs::default())
|
|
||||||
});
|
|
||||||
if let Some(module_attribute_args) = module_attribute_args {
|
|
||||||
let mut modules = if module_attribute_args.meta {
|
|
||||||
Modules::meta()
|
|
||||||
} else {
|
|
||||||
Modules::external()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(path) = module_attribute_args.bevy_asset {
|
|
||||||
modules.bevy_asset = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(path) = module_attribute_args.bevy_render {
|
|
||||||
modules.bevy_render = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(path) = module_attribute_args.bevy_core {
|
|
||||||
modules.bevy_core = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(path) = module_attribute_args.bevy_app {
|
|
||||||
modules.bevy_app = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
modules
|
|
||||||
} else {
|
|
||||||
Modules::meta()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_path(path_str: &str) -> Path {
|
|
||||||
syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_derive(Resource)]
|
#[proc_macro_derive(Resource)]
|
||||||
pub fn derive_resource(input: TokenStream) -> TokenStream {
|
pub fn derive_resource(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
@ -153,6 +50,78 @@ pub fn derive_resource(input: TokenStream) -> TokenStream {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(Uniform, attributes(uniform, module))]
|
||||||
|
pub fn derive_uniform(input: TokenStream) -> TokenStream {
|
||||||
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
|
let modules = get_modules(&ast);
|
||||||
|
let bevy_asset_path = get_path(&modules.bevy_asset);
|
||||||
|
let bevy_core_path = get_path(&modules.bevy_core);
|
||||||
|
let bevy_render_path = get_path(&modules.bevy_render);
|
||||||
|
|
||||||
|
let generics = ast.generics;
|
||||||
|
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
|
let struct_name = &ast.ident;
|
||||||
|
let struct_name_string = struct_name.to_string();
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
impl #impl_generics #bevy_render_path::shader::AsUniforms for #struct_name#ty_generics {
|
||||||
|
fn get_field_infos() -> &'static [#bevy_render_path::shader::FieldInfo] {
|
||||||
|
static FIELD_INFOS: &[#bevy_render_path::shader::FieldInfo] = &[
|
||||||
|
#bevy_render_path::shader::FieldInfo {
|
||||||
|
name: #struct_name_string,
|
||||||
|
uniform_name: #struct_name_string,
|
||||||
|
texture_name: #struct_name_string,
|
||||||
|
sampler_name: #struct_name_string,
|
||||||
|
is_instanceable: false,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
&FIELD_INFOS
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
|
||||||
|
use #bevy_render_path::shader::AsFieldBindType;
|
||||||
|
match name {
|
||||||
|
#struct_name_string => self.get_bind_type(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_uniform_bytes(&self, name: &str) -> Option<Vec<u8>> {
|
||||||
|
use #bevy_core_path::bytes::GetBytes;
|
||||||
|
match name {
|
||||||
|
#struct_name_string => Some(self.get_bytes()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]> {
|
||||||
|
use #bevy_core_path::bytes::GetBytes;
|
||||||
|
match name {
|
||||||
|
#struct_name_string => self.get_bytes_ref(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_uniform_texture(&self, name: &str) -> Option<#bevy_asset_path::Handle<#bevy_render_path::texture::Texture>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: move this to field_info and add has_shader_def(&self, &str) -> bool
|
||||||
|
// TODO: this will be very allocation heavy. find a way to either make this allocation free
|
||||||
|
// or alternatively only run it when the shader_defs have changed
|
||||||
|
fn get_shader_defs(&self) -> Option<Vec<String>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_vertex_buffer_descriptor() -> Option<&'static #bevy_render_path::pipeline::VertexBufferDescriptor> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(EntityArchetype, attributes(tag, module))]
|
#[proc_macro_derive(EntityArchetype, attributes(tag, module))]
|
||||||
pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
|
pub fn derive_entity_archetype(input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
@ -449,7 +418,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
|||||||
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
|
fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> {
|
||||||
use #bevy_render_path::shader::AsFieldBindType;
|
use #bevy_render_path::shader::AsFieldBindType;
|
||||||
match name {
|
match name {
|
||||||
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_field_bind_type(),)*
|
#(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)*
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
109
crates/bevy_derive/src/modules.rs
Normal file
109
crates/bevy_derive/src/modules.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
use darling::FromMeta;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use syn::{DeriveInput, Path};
|
||||||
|
|
||||||
|
#[derive(FromMeta, Debug)]
|
||||||
|
pub struct ModuleAttributeArgs {
|
||||||
|
#[darling(default)]
|
||||||
|
pub bevy_render: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
|
pub bevy_asset: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
|
pub bevy_core: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
|
pub bevy_app: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
|
pub legion: Option<String>,
|
||||||
|
|
||||||
|
/// If true, it will use the meta "bevy" crate for dependencies by default (ex: bevy:app). If this is set to false, the individual bevy crates
|
||||||
|
/// will be used (ex: "bevy_app"). Defaults to "true"
|
||||||
|
#[darling(default)]
|
||||||
|
pub meta: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Modules {
|
||||||
|
pub bevy_render: String,
|
||||||
|
pub bevy_asset: String,
|
||||||
|
pub bevy_core: String,
|
||||||
|
pub bevy_app: String,
|
||||||
|
pub legion: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Modules {
|
||||||
|
pub fn meta() -> Modules {
|
||||||
|
Modules {
|
||||||
|
bevy_asset: "bevy::asset".to_string(),
|
||||||
|
bevy_render: "bevy::render".to_string(),
|
||||||
|
bevy_core: "bevy::core".to_string(),
|
||||||
|
bevy_app: "bevy::app".to_string(),
|
||||||
|
legion: "bevy".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn external() -> Modules {
|
||||||
|
Modules {
|
||||||
|
bevy_asset: "bevy_asset".to_string(),
|
||||||
|
bevy_render: "bevy_render".to_string(),
|
||||||
|
bevy_core: "bevy_core".to_string(),
|
||||||
|
bevy_app: "bevy_app".to_string(),
|
||||||
|
legion: "legion".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ModuleAttributeArgs {
|
||||||
|
fn default() -> Self {
|
||||||
|
ModuleAttributeArgs {
|
||||||
|
bevy_asset: None,
|
||||||
|
bevy_render: None,
|
||||||
|
bevy_core: None,
|
||||||
|
bevy_app: None,
|
||||||
|
legion: None,
|
||||||
|
meta: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static MODULE_ATTRIBUTE_NAME: &'static str = "module";
|
||||||
|
|
||||||
|
pub fn get_modules(ast: &DeriveInput) -> Modules {
|
||||||
|
let module_attribute_args = ast
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.path.get_ident().as_ref().unwrap().to_string() == MODULE_ATTRIBUTE_NAME)
|
||||||
|
.map(|a| {
|
||||||
|
ModuleAttributeArgs::from_meta(&a.parse_meta().unwrap())
|
||||||
|
.unwrap_or_else(|_err| ModuleAttributeArgs::default())
|
||||||
|
});
|
||||||
|
if let Some(module_attribute_args) = module_attribute_args {
|
||||||
|
let mut modules = if module_attribute_args.meta {
|
||||||
|
Modules::meta()
|
||||||
|
} else {
|
||||||
|
Modules::external()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(path) = module_attribute_args.bevy_asset {
|
||||||
|
modules.bevy_asset = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = module_attribute_args.bevy_render {
|
||||||
|
modules.bevy_render = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = module_attribute_args.bevy_core {
|
||||||
|
modules.bevy_core = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = module_attribute_args.bevy_app {
|
||||||
|
modules.bevy_app = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
modules
|
||||||
|
} else {
|
||||||
|
Modules::meta()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_path(path_str: &str) -> Path {
|
||||||
|
syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap()
|
||||||
|
}
|
||||||
@ -82,20 +82,20 @@ pub struct FieldInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsFieldBindType {
|
pub trait AsFieldBindType {
|
||||||
fn get_field_bind_type(&self) -> Option<FieldBindType>;
|
fn get_bind_type(&self) -> Option<FieldBindType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsFieldBindType for ColorSource {
|
impl AsFieldBindType for ColorSource {
|
||||||
fn get_field_bind_type(&self) -> Option<FieldBindType> {
|
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||||
match *self {
|
match *self {
|
||||||
ColorSource::Texture(_) => Some(FieldBindType::Texture),
|
ColorSource::Texture(_) => Some(FieldBindType::Texture),
|
||||||
ColorSource::Color(color) => color.get_field_bind_type(),
|
ColorSource::Color(color) => color.get_bind_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsFieldBindType for Option<Handle<Texture>> {
|
impl AsFieldBindType for Option<Handle<Texture>> {
|
||||||
fn get_field_bind_type(&self) -> Option<FieldBindType> {
|
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||||
match *self {
|
match *self {
|
||||||
Some(_) => Some(FieldBindType::Texture),
|
Some(_) => Some(FieldBindType::Texture),
|
||||||
None => None,
|
None => None,
|
||||||
@ -104,7 +104,7 @@ impl AsFieldBindType for Option<Handle<Texture>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsFieldBindType for Handle<Texture> {
|
impl AsFieldBindType for Handle<Texture> {
|
||||||
fn get_field_bind_type(&self) -> Option<FieldBindType> {
|
fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||||
Some(FieldBindType::Texture)
|
Some(FieldBindType::Texture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ where
|
|||||||
T: GetBytes,
|
T: GetBytes,
|
||||||
{
|
{
|
||||||
// TODO: this breaks if get_bytes_ref() isn't supported for a datatype
|
// TODO: this breaks if get_bytes_ref() isn't supported for a datatype
|
||||||
default fn get_field_bind_type(&self) -> Option<FieldBindType> {
|
default fn get_bind_type(&self) -> Option<FieldBindType> {
|
||||||
Some(FieldBindType::Uniform {
|
Some(FieldBindType::Uniform {
|
||||||
size: self.get_bytes_ref().unwrap().len(),
|
size: self.get_bytes_ref().unwrap().len(),
|
||||||
})
|
})
|
||||||
|
|||||||
@ -65,7 +65,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld {
|
|||||||
}
|
}
|
||||||
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType> {
|
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType> {
|
||||||
match name {
|
match name {
|
||||||
"object" => self.0.get_field_bind_type(),
|
"object" => self.0.get_bind_type(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use glam::Vec2;
|
use bevy_core::bytes::GetBytes;
|
||||||
|
use bevy_derive::Uniform;
|
||||||
use bevy_render::Color;
|
use bevy_render::Color;
|
||||||
use bevy_derive::Uniforms;
|
use glam::Vec2;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default, Clone, Copy, Debug, Uniforms, AsBytes)]
|
#[derive(Default, Clone, Copy, Debug, Uniform, AsBytes)]
|
||||||
#[module(meta = "false")]
|
#[module(meta = "false")]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
@ -11,3 +12,8 @@ pub struct Rect {
|
|||||||
pub color: Color,
|
pub color: Color,
|
||||||
pub z_index: f32,
|
pub z_index: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetBytes for Rect {
|
||||||
|
fn get_bytes(&self) -> Vec<u8> { self.as_bytes().to_vec() }
|
||||||
|
fn get_bytes_ref(&self) -> Option<&[u8]> { Some(self.as_bytes()) }
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user