From 0de1e3aa19203f8743952ed750cbb162adb37b5e Mon Sep 17 00:00:00 2001 From: Torstein Grindvik Date: Sat, 28 Jan 2023 18:31:10 +0100 Subject: [PATCH 1/3] Allow deriving extracting components for simple cases Signed-off-by: Torstein Grindvik --- .../src/core_2d/camera_2d.rs | 15 ++---- .../src/core_3d/camera_3d.rs | 15 ++---- crates/bevy_core_pipeline/src/fxaa/mod.rs | 15 ++---- .../bevy_core_pipeline/src/tonemapping/mod.rs | 14 +----- crates/bevy_pbr/src/wireframe.rs | 14 ++---- .../macros/src/extract_component.rs | 48 +++++++++++++++++++ crates/bevy_render/macros/src/lib.rs | 6 +++ crates/bevy_render/src/extract_component.rs | 2 + crates/bevy_ui/src/camera_config.rs | 14 +----- 9 files changed, 73 insertions(+), 70 deletions(-) create mode 100644 crates/bevy_render/macros/src/extract_component.rs diff --git a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs index dce52de82b375..0eb793228b9fa 100644 --- a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs +++ b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs @@ -1,5 +1,5 @@ use crate::{clear_color::ClearColorConfig, tonemapping::Tonemapping}; -use bevy_ecs::{prelude::*, query::QueryItem}; +use bevy_ecs::prelude::*; use bevy_reflect::Reflect; use bevy_render::{ camera::{Camera, CameraProjection, CameraRenderGraph, OrthographicProjection}, @@ -9,22 +9,13 @@ use bevy_render::{ }; use bevy_transform::prelude::{GlobalTransform, Transform}; -#[derive(Component, Default, Reflect, Clone)] +#[derive(Component, Default, Reflect, Clone, ExtractComponent)] +#[extract_component_filter(With)] #[reflect(Component)] pub struct Camera2d { pub clear_color: ClearColorConfig, } -impl ExtractComponent for Camera2d { - type Query = &'static Self; - type Filter = With; - type Out = Self; - - fn extract_component(item: QueryItem<'_, Self::Query>) -> Option { - Some(item.clone()) - } -} - #[derive(Bundle)] pub struct Camera2dBundle { pub camera: Camera, diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index d722f411a21d6..045ac906f7c7e 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -1,5 +1,5 @@ use crate::{clear_color::ClearColorConfig, tonemapping::Tonemapping}; -use bevy_ecs::{prelude::*, query::QueryItem}; +use bevy_ecs::prelude::*; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; use bevy_render::{ camera::{Camera, CameraRenderGraph, Projection}, @@ -12,7 +12,8 @@ use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; /// Configuration for the "main 3d render graph". -#[derive(Component, Reflect, Clone, Default)] +#[derive(Component, Reflect, Clone, Default, ExtractComponent)] +#[extract_component_filter(With)] #[reflect(Component)] pub struct Camera3d { /// The clear color operation to perform for the main 3d pass. @@ -47,16 +48,6 @@ impl From for LoadOp { } } -impl ExtractComponent for Camera3d { - type Query = &'static Self; - type Filter = With; - type Out = Self; - - fn extract_component(item: QueryItem<'_, Self::Query>) -> Option { - Some(item.clone()) - } -} - #[derive(Bundle)] pub struct Camera3dBundle { pub camera: Camera, diff --git a/crates/bevy_core_pipeline/src/fxaa/mod.rs b/crates/bevy_core_pipeline/src/fxaa/mod.rs index 4b2a7a2ea9401..58ebf04d511e6 100644 --- a/crates/bevy_core_pipeline/src/fxaa/mod.rs +++ b/crates/bevy_core_pipeline/src/fxaa/mod.rs @@ -2,7 +2,7 @@ use crate::{core_2d, core_3d, fullscreen_vertex_shader::fullscreen_shader_vertex use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_derive::Deref; -use bevy_ecs::{prelude::*, query::QueryItem}; +use bevy_ecs::prelude::*; use bevy_reflect::TypeUuid; use bevy_render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, @@ -40,7 +40,8 @@ impl Sensitivity { } } -#[derive(Component, Clone)] +#[derive(Component, Clone, ExtractComponent)] +#[extract_component_filter(With)] pub struct Fxaa { /// Enable render passes for FXAA. pub enabled: bool, @@ -67,16 +68,6 @@ impl Default for Fxaa { } } -impl ExtractComponent for Fxaa { - type Query = &'static Self; - type Filter = With; - type Out = Self; - - fn extract_component(item: QueryItem) -> Option { - Some(item.clone()) - } -} - const FXAA_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4182761465141723543); diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index f7233fd575102..9839e07baf5be 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -2,7 +2,6 @@ use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state; use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_ecs::query::QueryItem; use bevy_reflect::{Reflect, TypeUuid}; use bevy_render::camera::Camera; use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin}; @@ -145,7 +144,8 @@ pub fn queue_view_tonemapping_pipelines( } } -#[derive(Component, Clone, Reflect, Default)] +#[derive(Component, Clone, Reflect, Default, ExtractComponent)] +#[extract_component_filter(With)] #[reflect(Component)] pub enum Tonemapping { #[default] @@ -160,13 +160,3 @@ impl Tonemapping { matches!(self, Tonemapping::Enabled { .. }) } } - -impl ExtractComponent for Tonemapping { - type Query = &'static Self; - type Filter = With; - type Out = Self; - - fn extract_component(item: QueryItem) -> Option { - Some(item.clone()) - } -} diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index a680a079058ad..471f3b94f8516 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -6,7 +6,7 @@ use bevy_core_pipeline::core_3d::Opaque3d; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::{Reflect, TypeUuid}; -use bevy_render::Extract; +use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy_render::{ extract_resource::{ExtractResource, ExtractResourcePlugin}, mesh::{Mesh, MeshVertexBufferLayout}, @@ -39,27 +39,21 @@ impl Plugin for WireframePlugin { app.register_type::() .register_type::() .init_resource::() - .add_plugin(ExtractResourcePlugin::::default()); + .add_plugin(ExtractResourcePlugin::::default()) + .add_plugin(ExtractComponentPlugin::::default()); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_command::() .init_resource::() .init_resource::>() - .add_system_to_stage(RenderStage::Extract, extract_wireframes) .add_system_to_stage(RenderStage::Queue, queue_wireframes); } } } -fn extract_wireframes(mut commands: Commands, query: Extract>>) { - for entity in &query { - commands.get_or_spawn(entity).insert(Wireframe); - } -} - /// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled -#[derive(Component, Debug, Clone, Default, Reflect)] +#[derive(Component, Debug, Clone, Default, ExtractComponent, Reflect)] #[reflect(Component, Default)] pub struct Wireframe; diff --git a/crates/bevy_render/macros/src/extract_component.rs b/crates/bevy_render/macros/src/extract_component.rs new file mode 100644 index 0000000000000..8e13b08b4df84 --- /dev/null +++ b/crates/bevy_render/macros/src/extract_component.rs @@ -0,0 +1,48 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, parse_quote, DeriveInput, Path}; + +pub fn derive_extract_component(input: TokenStream) -> TokenStream { + let mut ast = parse_macro_input!(input as DeriveInput); + let bevy_render_path: Path = crate::bevy_render_path(); + let bevy_ecs_path: Path = bevy_macro_utils::BevyManifest::default() + .maybe_get_path("bevy_ecs") + .expect("bevy_ecs should be found in manifest"); + + ast.generics + .make_where_clause() + .predicates + .push(parse_quote! { Self: Clone }); + + let struct_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl(); + + let filter = if let Some(attr) = ast + .attrs + .iter() + .find(|a| a.path.is_ident("extract_component_filter")) + { + let filter = attr.parse_args::().unwrap(); + + quote! { + #filter + } + } else { + quote! { + () + } + }; + + TokenStream::from(quote! { + impl #impl_generics #bevy_render_path::extract_component::ExtractComponent for #struct_name #type_generics #where_clause { + type Query = &'static Self; + + type Filter = #filter; + type Out = Self; + + fn extract_component(item: #bevy_ecs_path::query::QueryItem<'_, Self::Query>) -> Option { + Some(item.clone()) + } + } + }) +} diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index e8da33ad3c48b..4a06e0e380b3f 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -1,4 +1,5 @@ mod as_bind_group; +mod extract_component; mod extract_resource; use bevy_macro_utils::BevyManifest; @@ -17,6 +18,11 @@ pub fn derive_extract_resource(input: TokenStream) -> TokenStream { extract_resource::derive_extract_resource(input) } +#[proc_macro_derive(ExtractComponent, attributes(extract_component_filter))] +pub fn derive_extract_component(input: TokenStream) -> TokenStream { + extract_component::derive_extract_component(input) +} + #[proc_macro_derive( AsBindGroup, attributes(uniform, texture, sampler, bind_group_data, storage) diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 7cae7d8065ed5..f29905c1a7bc9 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -14,6 +14,8 @@ use bevy_ecs::{ }; use std::{marker::PhantomData, ops::Deref}; +pub use bevy_render_macros::ExtractComponent; + /// Stores the index of a uniform inside of [`ComponentUniforms`]. #[derive(Component)] pub struct DynamicUniformIndex { diff --git a/crates/bevy_ui/src/camera_config.rs b/crates/bevy_ui/src/camera_config.rs index e653e15b97dbe..097437ac73d36 100644 --- a/crates/bevy_ui/src/camera_config.rs +++ b/crates/bevy_ui/src/camera_config.rs @@ -2,7 +2,6 @@ use bevy_ecs::component::Component; use bevy_ecs::prelude::With; -use bevy_ecs::query::QueryItem; use bevy_render::camera::Camera; use bevy_render::extract_component::ExtractComponent; @@ -11,7 +10,8 @@ use bevy_render::extract_component::ExtractComponent; /// When a [`Camera`] doesn't have the [`UiCameraConfig`] component, /// it will display the UI by default. /// -#[derive(Component, Clone)] +#[derive(Component, Clone, ExtractComponent)] +#[extract_component_filter(With)] pub struct UiCameraConfig { /// Whether to output UI to this camera view. /// @@ -25,13 +25,3 @@ impl Default for UiCameraConfig { Self { show_ui: true } } } - -impl ExtractComponent for UiCameraConfig { - type Query = &'static Self; - type Filter = With; - type Out = Self; - - fn extract_component(item: QueryItem<'_, Self::Query>) -> Option { - Some(item.clone()) - } -} From 6a0aec7ff82136a8b99359e9ad395cc47ba0043c Mon Sep 17 00:00:00 2001 From: Torstein Grindvik Date: Sat, 28 Jan 2023 19:02:28 +0100 Subject: [PATCH 2/3] Error handling, docs Signed-off-by: Torstein Grindvik --- .../macros/src/extract_component.rs | 5 +++- crates/bevy_render/macros/src/lib.rs | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/macros/src/extract_component.rs b/crates/bevy_render/macros/src/extract_component.rs index 8e13b08b4df84..3def17a7b8a51 100644 --- a/crates/bevy_render/macros/src/extract_component.rs +++ b/crates/bevy_render/macros/src/extract_component.rs @@ -22,7 +22,10 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream { .iter() .find(|a| a.path.is_ident("extract_component_filter")) { - let filter = attr.parse_args::().unwrap(); + let filter = match attr.parse_args::() { + Ok(filter) => filter, + Err(e) => return e.to_compile_error().into(), + }; quote! { #filter diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index 4a06e0e380b3f..7655caf9e642d 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -18,6 +18,32 @@ pub fn derive_extract_resource(input: TokenStream) -> TokenStream { extract_resource::derive_extract_resource(input) } +/// Implements `ExtractComponent` trait for a component. +/// The component must implement [`Clone`]. +/// The component will be extracted into the render world via cloning. +/// Note that this only enables extraction of the component, it does not execute the extraction. +/// See `ExtractComponentPlugin` to actually perform the extraction. +/// +/// If you only want to extract a component conditionally, you may use the `extract_component_filter` attribute. +/// +/// # Example +/// +/// ```rust +/// use bevy_ecs::component::Component; +/// use bevy_render_macros::ExtractComponent; +/// +/// #[derive(Component, Clone, ExtractComponent)] +/// #[extract_component_filter(With)] +/// pub struct Foo { +/// pub should_foo: bool, +/// } +/// +/// // Without a filter (unconditional). +/// #[derive(Component, Clone, ExtractComponent)] +/// pub struct Bar { +/// pub should_bar: bool, +/// } +/// ``` #[proc_macro_derive(ExtractComponent, attributes(extract_component_filter))] pub fn derive_extract_component(input: TokenStream) -> TokenStream { extract_component::derive_extract_component(input) From 55283ed8f12d744e49bf5623f6b3dc0ac1815080 Mon Sep 17 00:00:00 2001 From: Torstein Grindvik Date: Sat, 28 Jan 2023 19:30:37 +0100 Subject: [PATCH 3/3] Add no_compile to docs, cannot access those crates from this downstream crate (I think) Signed-off-by: Torstein Grindvik --- crates/bevy_render/macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index 7655caf9e642d..89eec6b220c9a 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -28,7 +28,7 @@ pub fn derive_extract_resource(input: TokenStream) -> TokenStream { /// /// # Example /// -/// ```rust +/// ```no_compile /// use bevy_ecs::component::Component; /// use bevy_render_macros::ExtractComponent; ///