shader_defs: new leaner shader defs. they are now separate from uniforms
This commit is contained in:
parent
fd8f87400d
commit
62c434274f
@ -8,6 +8,7 @@ mod modules;
|
||||
mod render_resources;
|
||||
mod render_resource;
|
||||
mod resource;
|
||||
mod shader_defs;
|
||||
mod uniforms;
|
||||
mod as_vertex_buffer_descriptor;
|
||||
|
||||
@ -43,6 +44,11 @@ pub fn derive_render_resource(input: TokenStream) -> TokenStream {
|
||||
render_resource::derive_render_resource(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ShaderDefs, attributes(shader_def, module))]
|
||||
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
|
||||
shader_defs::derive_shader_defs(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AsVertexBufferDescriptor, attributes(vertex, module))]
|
||||
pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
|
||||
as_vertex_buffer_descriptor::derive_as_vertex_buffer_descriptor(input)
|
||||
|
||||
71
crates/bevy_derive/src/shader_defs.rs
Normal file
71
crates/bevy_derive/src/shader_defs.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use crate::modules::{get_modules, get_path};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
use inflector::Inflector;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Path};
|
||||
|
||||
static SHADER_DEF_ATTRIBUTE_NAME: &'static str = "shader_def";
|
||||
|
||||
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let modules = get_modules(&ast);
|
||||
let bevy_render_path: Path = get_path(&modules.bevy_render);
|
||||
|
||||
let fields = match &ast.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(fields),
|
||||
..
|
||||
}) => &fields.named,
|
||||
_ => panic!("expected a struct with named fields"),
|
||||
};
|
||||
|
||||
let shader_def_idents = fields
|
||||
.iter()
|
||||
.filter(|f| {
|
||||
f.attrs
|
||||
.iter()
|
||||
.find(|a| {
|
||||
a.path.get_ident().as_ref().unwrap().to_string() == SHADER_DEF_ATTRIBUTE_NAME
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.map(|f| f.ident.as_ref().unwrap())
|
||||
.collect::<Vec<&Ident>>();
|
||||
let struct_name = &ast.ident;
|
||||
let struct_name_pascal_case = ast.ident.to_string().to_pascal_case();
|
||||
let shader_defs = shader_def_idents
|
||||
.iter()
|
||||
.map(|i| format!("{}_{}", struct_name_pascal_case, i.to_string()).to_uppercase());
|
||||
|
||||
let shader_defs_len = shader_defs.len();
|
||||
let shader_def_indices = 0..shader_defs_len;
|
||||
|
||||
let generics = ast.generics;
|
||||
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
|
||||
|
||||
|
||||
TokenStream::from(quote! {
|
||||
impl #impl_generics #bevy_render_path::shader::ShaderDefs for #struct_name#ty_generics {
|
||||
fn shader_defs_len(&self) -> usize {
|
||||
#shader_defs_len
|
||||
}
|
||||
|
||||
fn get_shader_def(&self, index: usize) -> Option<&str> {
|
||||
use #bevy_render_path::shader::ShaderDef;
|
||||
match index {
|
||||
#(#shader_def_indices => if self.#shader_def_idents.is_defined() {
|
||||
Some(#shader_defs)
|
||||
} else {
|
||||
None
|
||||
},)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn iter_shader_defs(&self) -> #bevy_render_path::shader::ShaderDefIterator {
|
||||
#bevy_render_path::shader::ShaderDefIterator::new(self)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -138,15 +138,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
|
||||
// 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>> {
|
||||
use #bevy_render_path::shader::ShaderDefSuffixProvider;
|
||||
let mut potential_shader_defs: Vec<(&'static str, Option<&'static str>)> = vec![
|
||||
#((#shader_def_field_names_screaming_snake, self.#shader_def_field_names.get_shader_def()),)*
|
||||
];
|
||||
|
||||
Some(potential_shader_defs.drain(..)
|
||||
.filter(|(f, shader_def)| shader_def.is_some())
|
||||
.map(|(f, shader_def)| format!("{}_{}{}", #struct_name_uppercase, f, shader_def.unwrap()))
|
||||
.collect::<Vec<String>>())
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use bevy_asset::{self, Handle};
|
||||
use bevy_render::{render_resource::RenderResources, shader::Uniforms, texture::Texture, Color};
|
||||
use bevy_render::{render_resource::RenderResources, shader::ShaderDefs, texture::Texture, Color};
|
||||
|
||||
#[derive(Uniforms, RenderResources)]
|
||||
#[derive(RenderResources, ShaderDefs)]
|
||||
pub struct StandardMaterial {
|
||||
pub albedo: Color,
|
||||
#[uniform(shader_def)]
|
||||
#[shader_def]
|
||||
pub albedo_texture: Option<Handle<Texture>>,
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
mod shader;
|
||||
mod shader_defs;
|
||||
mod shader_reflect;
|
||||
mod uniform;
|
||||
pub mod uniforms;
|
||||
|
||||
pub use shader::*;
|
||||
pub use shader_defs::*;
|
||||
pub use shader_reflect::*;
|
||||
pub use uniform::*;
|
||||
92
crates/bevy_render/src/shader/shader_defs.rs
Normal file
92
crates/bevy_render/src/shader/shader_defs.rs
Normal file
@ -0,0 +1,92 @@
|
||||
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use crate::{Renderable, texture::Texture};
|
||||
use legion::prelude::{Res, Com, ComMut};
|
||||
|
||||
pub use bevy_derive::ShaderDefs;
|
||||
|
||||
pub trait ShaderDef {
|
||||
fn is_defined(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait ShaderDefs {
|
||||
fn shader_defs_len(&self) -> usize;
|
||||
fn get_shader_def(&self, index: usize) -> Option<&str>;
|
||||
fn iter_shader_defs(&self) -> ShaderDefIterator;
|
||||
}
|
||||
|
||||
|
||||
pub struct ShaderDefIterator<'a> {
|
||||
shader_defs: &'a dyn ShaderDefs,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> ShaderDefIterator<'a> {
|
||||
pub fn new(shader_defs: &'a dyn ShaderDefs) -> Self {
|
||||
Self {
|
||||
shader_defs,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> Iterator for ShaderDefIterator<'a> {
|
||||
type Item = &'a str;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
if self.index == self.shader_defs.shader_defs_len() {
|
||||
return None;
|
||||
}
|
||||
let shader_def = self
|
||||
.shader_defs
|
||||
.get_shader_def(self.index);
|
||||
self.index += 1;
|
||||
if shader_def.is_some() {
|
||||
return shader_def;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShaderDef for bool {
|
||||
fn is_defined(&self) -> bool {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl ShaderDef for Option<Handle<Texture>> {
|
||||
fn is_defined(&self) -> bool {
|
||||
self.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shader_def_system<T>(shader_defs: Com<T>, mut renderable: ComMut<Renderable>)
|
||||
where
|
||||
T: ShaderDefs + Send + Sync + 'static,
|
||||
{
|
||||
for shader_def in shader_defs.iter_shader_defs() {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
.shader_defs
|
||||
.insert(shader_def.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn asset_shader_def_system<T>(
|
||||
assets: Res<Assets<T>>,
|
||||
asset_handle: Com<Handle<T>>,
|
||||
mut renderable: ComMut<Renderable>,
|
||||
) where
|
||||
T: ShaderDefs + Send + Sync + 'static,
|
||||
{
|
||||
let shader_defs = assets.get(&asset_handle).unwrap();
|
||||
for shader_def in shader_defs.iter_shader_defs() {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
.shader_defs
|
||||
.insert(shader_def.to_string());
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
use crate::{pipeline::BindType, texture::Texture, Renderable};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use legion::prelude::*;
|
||||
use crate::{pipeline::BindType, texture::Texture};
|
||||
use bevy_asset::Handle;
|
||||
|
||||
pub use bevy_derive::{Uniform, Uniforms};
|
||||
|
||||
@ -13,42 +12,6 @@ pub trait Uniforms: Send + Sync + 'static {
|
||||
fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType>;
|
||||
}
|
||||
|
||||
pub fn shader_def_system<T>(uniforms: Com<T>, mut renderable: ComMut<Renderable>)
|
||||
where
|
||||
T: Uniforms + Send + Sync + 'static,
|
||||
{
|
||||
if let Some(shader_defs) = uniforms.get_shader_defs() {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
.shader_defs
|
||||
.extend(shader_defs)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn asset_shader_def_system<T>(
|
||||
assets: Res<Assets<T>>,
|
||||
asset_handle: Com<Handle<T>>,
|
||||
mut renderable: ComMut<Renderable>,
|
||||
) where
|
||||
T: Uniforms + Send + Sync + 'static,
|
||||
{
|
||||
if !renderable.is_visible || renderable.is_instanced {
|
||||
return;
|
||||
}
|
||||
|
||||
let uniforms = assets.get(&asset_handle).unwrap();
|
||||
if let Some(shader_defs) = uniforms.get_shader_defs() {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.shader_specialization
|
||||
.shader_defs
|
||||
.extend(shader_defs)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ShaderDefSuffixProvider {
|
||||
fn get_shader_def(&self) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use bevy_asset::{self, Handle};
|
||||
use bevy_render::{texture::Texture, Color, render_resource::RenderResources, shader::Uniforms};
|
||||
use bevy_render::{render_resource::RenderResources, shader::ShaderDefs, texture::Texture, Color};
|
||||
|
||||
#[derive(Uniforms, RenderResources)]
|
||||
#[derive(RenderResources, ShaderDefs)]
|
||||
pub struct ColorMaterial {
|
||||
pub color: Color,
|
||||
#[uniform(shader_def)]
|
||||
#[shader_def]
|
||||
pub texture: Option<Handle<Texture>>,
|
||||
}
|
||||
|
||||
|
||||
@ -1,26 +1,27 @@
|
||||
use crate::Rect;
|
||||
use bevy_asset::Handle;
|
||||
use bevy_render::{texture::Texture, render_resource::{RenderResources, RenderResource}, shader::{Uniforms, Uniform}};
|
||||
use bevy_core::bytes::Bytes;
|
||||
use bevy_render::{
|
||||
render_resource::{RenderResource, RenderResources},
|
||||
texture::Texture,
|
||||
};
|
||||
use glam::{Vec2, Vec3};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Uniforms, RenderResources)]
|
||||
#[derive(RenderResources)]
|
||||
pub struct TextureAtlas {
|
||||
pub texture: Handle<Texture>,
|
||||
// TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer
|
||||
pub dimensions: Vec2,
|
||||
#[uniform(buffer)]
|
||||
#[render_resources(buffer)]
|
||||
pub textures: Vec<Rect>,
|
||||
#[uniform(ignore)]
|
||||
#[render_resources(ignore)]
|
||||
pub texture_handles: Option<HashMap<Handle<Texture>, usize>>,
|
||||
}
|
||||
|
||||
// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
|
||||
// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
|
||||
#[derive(Uniform, Bytes, RenderResources, RenderResource, Default)]
|
||||
#[derive(Bytes, RenderResources, RenderResource, Default)]
|
||||
#[render_resources(from_self)]
|
||||
pub struct TextureAtlasSprite {
|
||||
pub position: Vec3,
|
||||
|
||||
@ -8,7 +8,7 @@ fn main() {
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Uniforms, RenderResources, Default)]
|
||||
#[derive(RenderResources, Default)]
|
||||
struct MyMaterial {
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
@ -12,11 +12,11 @@ fn main() {
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Uniforms, RenderResources, Default)]
|
||||
#[derive(RenderResources, ShaderDefs, Default)]
|
||||
struct MyMaterial {
|
||||
pub color: Color,
|
||||
#[uniform(ignore, shader_def)]
|
||||
#[render_resources(ignore)]
|
||||
#[shader_def]
|
||||
pub always_red: bool,
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
pub use crate::{
|
||||
app::{
|
||||
schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, EntityArchetype,
|
||||
EventReader, Events, FromResources, System, DynamicAppPlugin
|
||||
schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, DynamicAppPlugin,
|
||||
EntityArchetype, EventReader, Events, FromResources, System,
|
||||
},
|
||||
asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle},
|
||||
core::{
|
||||
@ -25,8 +25,10 @@ pub use crate::{
|
||||
},
|
||||
RenderGraph,
|
||||
},
|
||||
shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages, Uniforms},
|
||||
render_resource::RenderResources,
|
||||
shader::{
|
||||
Shader, ShaderDefSuffixProvider, ShaderDefs, ShaderStage, ShaderStages, Uniforms,
|
||||
},
|
||||
texture::Texture,
|
||||
Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user