ExtractResourcePlugin (#3745)
# Objective - Add an `ExtractResourcePlugin` for convenience and consistency ## Solution - Add an `ExtractResourcePlugin` similar to `ExtractComponentPlugin` but for ECS `Resource`s. The system that is executed simply clones the main world resource into a render world resource, if and only if the main world resource was either added or changed since the last execution of the system. - Add an `ExtractResource` trait with a `fn extract_resource(res: &Self) -> Self` function. This is used by the `ExtractResourcePlugin` to extract the resource - Add a derive macro for `ExtractResource` on a `Resource` with the `Clone` trait, that simply returns `res.clone()` - Use `ExtractResourcePlugin` wherever both possible and appropriate
This commit is contained in:
parent
ba53a44956
commit
a0a3d8798b
@ -24,6 +24,7 @@ use bevy_ecs::prelude::*;
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{ActiveCamera, Camera2d, Camera3d, ExtractedCamera, RenderTarget},
|
camera::{ActiveCamera, Camera2d, Camera3d, ExtractedCamera, RenderTarget},
|
||||||
color::Color,
|
color::Color,
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
||||||
render_phase::{
|
render_phase::{
|
||||||
batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem,
|
batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem,
|
||||||
@ -33,7 +34,7 @@ use bevy_render::{
|
|||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureCache,
|
texture::TextureCache,
|
||||||
view::{ExtractedView, Msaa, ViewDepthTexture},
|
view::{ExtractedView, Msaa, ViewDepthTexture},
|
||||||
RenderApp, RenderStage, RenderWorld,
|
RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ use bevy_utils::FloatOrd;
|
|||||||
///
|
///
|
||||||
/// This color appears as the "background" color for simple apps, when
|
/// This color appears as the "background" color for simple apps, when
|
||||||
/// there are portions of the screen with nothing rendered.
|
/// there are portions of the screen with nothing rendered.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, ExtractResource)]
|
||||||
pub struct ClearColor(pub Color);
|
pub struct ClearColor(pub Color);
|
||||||
|
|
||||||
impl Default for ClearColor {
|
impl Default for ClearColor {
|
||||||
@ -50,7 +51,7 @@ impl Default for ClearColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default, ExtractResource)]
|
||||||
pub struct RenderTargetClearColors {
|
pub struct RenderTargetClearColors {
|
||||||
colors: HashMap<RenderTarget, Color>,
|
colors: HashMap<RenderTarget, Color>,
|
||||||
}
|
}
|
||||||
@ -113,7 +114,9 @@ pub enum CorePipelineRenderSystems {
|
|||||||
impl Plugin for CorePipelinePlugin {
|
impl Plugin for CorePipelinePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<ClearColor>()
|
app.init_resource::<ClearColor>()
|
||||||
.init_resource::<RenderTargetClearColors>();
|
.init_resource::<RenderTargetClearColors>()
|
||||||
|
.add_plugin(ExtractResourcePlugin::<ClearColor>::default())
|
||||||
|
.add_plugin(ExtractResourcePlugin::<RenderTargetClearColors>::default());
|
||||||
|
|
||||||
let render_app = match app.get_sub_app_mut(RenderApp) {
|
let render_app = match app.get_sub_app_mut(RenderApp) {
|
||||||
Ok(render_app) => render_app,
|
Ok(render_app) => render_app,
|
||||||
@ -125,7 +128,6 @@ impl Plugin for CorePipelinePlugin {
|
|||||||
.init_resource::<DrawFunctions<Opaque3d>>()
|
.init_resource::<DrawFunctions<Opaque3d>>()
|
||||||
.init_resource::<DrawFunctions<AlphaMask3d>>()
|
.init_resource::<DrawFunctions<AlphaMask3d>>()
|
||||||
.init_resource::<DrawFunctions<Transparent3d>>()
|
.init_resource::<DrawFunctions<Transparent3d>>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_clear_color)
|
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases)
|
.add_system_to_stage(RenderStage::Extract, extract_core_pipeline_camera_phases)
|
||||||
.add_system_to_stage(RenderStage::Prepare, prepare_core_views_system)
|
.add_system_to_stage(RenderStage::Prepare, prepare_core_views_system)
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
@ -347,24 +349,6 @@ impl CachedRenderPipelinePhaseItem for Transparent3d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_clear_color(
|
|
||||||
clear_color: Res<ClearColor>,
|
|
||||||
clear_colors: Res<RenderTargetClearColors>,
|
|
||||||
mut render_world: ResMut<RenderWorld>,
|
|
||||||
) {
|
|
||||||
// If the clear color has changed
|
|
||||||
if clear_color.is_changed() {
|
|
||||||
// Update the clear color resource in the render world
|
|
||||||
render_world.insert_resource(clear_color.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the clear color has changed
|
|
||||||
if clear_colors.is_changed() {
|
|
||||||
// Update the clear color resource in the render world
|
|
||||||
render_world.insert_resource(clear_colors.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_core_pipeline_camera_phases(
|
pub fn extract_core_pipeline_camera_phases(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
active_2d: Res<ActiveCamera<Camera2d>>,
|
active_2d: Res<ActiveCamera<Camera2d>>,
|
||||||
|
|||||||
@ -39,6 +39,7 @@ use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
|
|||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_resource::ExtractResourcePlugin,
|
||||||
prelude::Color,
|
prelude::Color,
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions},
|
render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions},
|
||||||
@ -76,6 +77,7 @@ impl Plugin for PbrPlugin {
|
|||||||
.init_resource::<GlobalVisiblePointLights>()
|
.init_resource::<GlobalVisiblePointLights>()
|
||||||
.init_resource::<DirectionalLightShadowMap>()
|
.init_resource::<DirectionalLightShadowMap>()
|
||||||
.init_resource::<PointLightShadowMap>()
|
.init_resource::<PointLightShadowMap>()
|
||||||
|
.add_plugin(ExtractResourcePlugin::<AmbientLight>::default())
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
CoreStage::PostUpdate,
|
CoreStage::PostUpdate,
|
||||||
// NOTE: Clusters need to have been added before update_clusters is run so
|
// NOTE: Clusters need to have been added before update_clusters is run so
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use bevy_reflect::prelude::*;
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, CameraProjection, OrthographicProjection},
|
camera::{Camera, CameraProjection, OrthographicProjection},
|
||||||
color::Color,
|
color::Color,
|
||||||
|
extract_resource::ExtractResource,
|
||||||
prelude::Image,
|
prelude::Image,
|
||||||
primitives::{Aabb, CubemapFrusta, Frustum, Plane, Sphere},
|
primitives::{Aabb, CubemapFrusta, Frustum, Plane, Sphere},
|
||||||
render_resource::BufferBindingType,
|
render_resource::BufferBindingType,
|
||||||
@ -170,7 +171,7 @@ impl Default for DirectionalLightShadowMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An ambient light, which lights the entire scene equally.
|
/// An ambient light, which lights the entire scene equally.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, ExtractResource)]
|
||||||
pub struct AmbientLight {
|
pub struct AmbientLight {
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
/// A direct scale factor multiplied with `color` before being passed to the shader.
|
/// A direct scale factor multiplied with `color` before being passed to the shader.
|
||||||
|
|||||||
@ -15,9 +15,9 @@ use bevy_ecs::{
|
|||||||
world::FromWorld,
|
world::FromWorld,
|
||||||
};
|
};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_component::ExtractComponentPlugin,
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayout},
|
||||||
render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets},
|
render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets},
|
||||||
render_component::ExtractComponentPlugin,
|
|
||||||
render_phase::{
|
render_phase::{
|
||||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||||
SetItemPipeline, TrackedRenderPass,
|
SetItemPipeline, TrackedRenderPass,
|
||||||
|
|||||||
@ -45,11 +45,6 @@ pub enum RenderLightSystems {
|
|||||||
QueueShadows,
|
QueueShadows,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtractedAmbientLight {
|
|
||||||
color: Color,
|
|
||||||
brightness: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct ExtractedPointLight {
|
pub struct ExtractedPointLight {
|
||||||
color: Color,
|
color: Color,
|
||||||
@ -63,8 +58,6 @@ pub struct ExtractedPointLight {
|
|||||||
shadow_normal_bias: f32,
|
shadow_normal_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ExtractedPointLightShadowMap = PointLightShadowMap;
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct ExtractedDirectionalLight {
|
pub struct ExtractedDirectionalLight {
|
||||||
color: Color,
|
color: Color,
|
||||||
@ -76,8 +69,6 @@ pub struct ExtractedDirectionalLight {
|
|||||||
shadow_normal_bias: f32,
|
shadow_normal_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ExtractedDirectionalLightShadowMap = DirectionalLightShadowMap;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, ShaderType, Default, Debug)]
|
#[derive(Copy, Clone, ShaderType, Default, Debug)]
|
||||||
pub struct GpuPointLight {
|
pub struct GpuPointLight {
|
||||||
// The lower-right 2x2 values of the projection matrix 22 23 32 33
|
// The lower-right 2x2 values of the projection matrix 22 23 32 33
|
||||||
@ -408,7 +399,6 @@ pub fn extract_clusters(mut commands: Commands, views: Query<(Entity, &Clusters)
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn extract_lights(
|
pub fn extract_lights(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
ambient_light: Res<AmbientLight>,
|
|
||||||
point_light_shadow_map: Res<PointLightShadowMap>,
|
point_light_shadow_map: Res<PointLightShadowMap>,
|
||||||
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
||||||
global_point_lights: Res<GlobalVisiblePointLights>,
|
global_point_lights: Res<GlobalVisiblePointLights>,
|
||||||
@ -422,14 +412,14 @@ pub fn extract_lights(
|
|||||||
)>,
|
)>,
|
||||||
mut previous_point_lights_len: Local<usize>,
|
mut previous_point_lights_len: Local<usize>,
|
||||||
) {
|
) {
|
||||||
commands.insert_resource(ExtractedAmbientLight {
|
// NOTE: These shadow map resources are extracted here as they are used here too so this avoids
|
||||||
color: ambient_light.color,
|
// races between scheduling of ExtractResourceSystems and this system.
|
||||||
brightness: ambient_light.brightness,
|
if point_light_shadow_map.is_changed() {
|
||||||
});
|
commands.insert_resource(point_light_shadow_map.clone());
|
||||||
commands.insert_resource::<ExtractedPointLightShadowMap>(point_light_shadow_map.clone());
|
}
|
||||||
commands.insert_resource::<ExtractedDirectionalLightShadowMap>(
|
if directional_light_shadow_map.is_changed() {
|
||||||
directional_light_shadow_map.clone(),
|
commands.insert_resource(directional_light_shadow_map.clone());
|
||||||
);
|
}
|
||||||
// This is the point light shadow map texel size for one face of the cube as a distance of 1.0
|
// This is the point light shadow map texel size for one face of the cube as a distance of 1.0
|
||||||
// world unit from the light.
|
// world unit from the light.
|
||||||
// point_light_texel_size = 2.0 * 1.0 * tan(PI / 4.0) / cube face width in texels
|
// point_light_texel_size = 2.0 * 1.0 * tan(PI / 4.0) / cube face width in texels
|
||||||
@ -665,9 +655,9 @@ pub fn prepare_lights(
|
|||||||
(Entity, &ExtractedView, &ExtractedClusterConfig),
|
(Entity, &ExtractedView, &ExtractedClusterConfig),
|
||||||
With<RenderPhase<Transparent3d>>,
|
With<RenderPhase<Transparent3d>>,
|
||||||
>,
|
>,
|
||||||
ambient_light: Res<ExtractedAmbientLight>,
|
ambient_light: Res<AmbientLight>,
|
||||||
point_light_shadow_map: Res<ExtractedPointLightShadowMap>,
|
point_light_shadow_map: Res<PointLightShadowMap>,
|
||||||
directional_light_shadow_map: Res<ExtractedDirectionalLightShadowMap>,
|
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
||||||
point_lights: Query<(Entity, &ExtractedPointLight)>,
|
point_lights: Query<(Entity, &ExtractedPointLight)>,
|
||||||
directional_lights: Query<(Entity, &ExtractedDirectionalLight)>,
|
directional_lights: Query<(Entity, &ExtractedDirectionalLight)>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -12,12 +12,12 @@ use bevy_ecs::{
|
|||||||
use bevy_math::{Mat4, Vec2};
|
use bevy_math::{Mat4, Vec2};
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
|
||||||
mesh::{
|
mesh::{
|
||||||
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
|
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
|
||||||
GpuBufferInfo, Mesh, MeshVertexBufferLayout,
|
GpuBufferInfo, Mesh, MeshVertexBufferLayout,
|
||||||
},
|
},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
|
|
||||||
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use bevy_ecs::{prelude::*, reflect::ReflectComponent};
|
|||||||
use bevy_reflect::std_traits::ReflectDefault;
|
use bevy_reflect::std_traits::ReflectDefault;
|
||||||
use bevy_reflect::{Reflect, TypeUuid};
|
use bevy_reflect::{Reflect, TypeUuid};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayout},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
||||||
@ -34,7 +35,8 @@ impl Plugin for WireframePlugin {
|
|||||||
Shader::from_wgsl
|
Shader::from_wgsl
|
||||||
);
|
);
|
||||||
|
|
||||||
app.init_resource::<WireframeConfig>();
|
app.init_resource::<WireframeConfig>()
|
||||||
|
.add_plugin(ExtractResourcePlugin::<WireframeConfig>::default());
|
||||||
|
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
@ -42,18 +44,11 @@ impl Plugin for WireframePlugin {
|
|||||||
.init_resource::<WireframePipeline>()
|
.init_resource::<WireframePipeline>()
|
||||||
.init_resource::<SpecializedMeshPipelines<WireframePipeline>>()
|
.init_resource::<SpecializedMeshPipelines<WireframePipeline>>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_wireframes)
|
.add_system_to_stage(RenderStage::Extract, extract_wireframes)
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_wireframe_config)
|
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_wireframes);
|
.add_system_to_stage(RenderStage::Queue, queue_wireframes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_wireframe_config(mut commands: Commands, wireframe_config: Res<WireframeConfig>) {
|
|
||||||
if wireframe_config.is_added() || wireframe_config.is_changed() {
|
|
||||||
commands.insert_resource(wireframe_config.into_inner().clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wireframe>>) {
|
fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wireframe>>) {
|
||||||
for entity in query.iter() {
|
for entity in query.iter() {
|
||||||
commands.get_or_spawn(entity).insert(Wireframe);
|
commands.get_or_spawn(entity).insert(Wireframe);
|
||||||
@ -65,7 +60,7 @@ fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wirefram
|
|||||||
#[reflect(Component, Default)]
|
#[reflect(Component, Default)]
|
||||||
pub struct Wireframe;
|
pub struct Wireframe;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default, ExtractResource)]
|
||||||
pub struct WireframeConfig {
|
pub struct WireframeConfig {
|
||||||
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
|
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
|
||||||
pub global: bool,
|
pub global: bool,
|
||||||
|
|||||||
@ -36,6 +36,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" }
|
|||||||
bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.8.0-dev" }
|
bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.8.0-dev" }
|
||||||
bevy_math = { path = "../bevy_math", version = "0.8.0-dev" }
|
bevy_math = { path = "../bevy_math", version = "0.8.0-dev" }
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
|
||||||
|
bevy_render_macros = { path = "macros", version = "0.8.0-dev" }
|
||||||
bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" }
|
bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" }
|
||||||
bevy_window = { path = "../bevy_window", version = "0.8.0-dev" }
|
bevy_window = { path = "../bevy_window", version = "0.8.0-dev" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }
|
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }
|
||||||
|
|||||||
19
crates/bevy_render/macros/Cargo.toml
Normal file
19
crates/bevy_render/macros/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "bevy_render_macros"
|
||||||
|
version = "0.8.0-dev"
|
||||||
|
edition = "2021"
|
||||||
|
description = "Derive implementations for bevy_render"
|
||||||
|
homepage = "https://bevyengine.org"
|
||||||
|
repository = "https://github.com/bevyengine/bevy"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
keywords = ["bevy"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" }
|
||||||
|
|
||||||
|
syn = "1.0"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
26
crates/bevy_render/macros/src/extract_resource.rs
Normal file
26
crates/bevy_render/macros/src/extract_resource.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, parse_quote, DeriveInput, Path};
|
||||||
|
|
||||||
|
pub fn derive_extract_resource(input: TokenStream) -> TokenStream {
|
||||||
|
let mut ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
let bevy_render_path: Path = crate::bevy_render_path();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
impl #impl_generics #bevy_render_path::extract_resource::ExtractResource for #struct_name #type_generics #where_clause {
|
||||||
|
type Source = Self;
|
||||||
|
|
||||||
|
fn extract_resource(source: &Self::Source) -> Self {
|
||||||
|
source.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
16
crates/bevy_render/macros/src/lib.rs
Normal file
16
crates/bevy_render/macros/src/lib.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
mod extract_resource;
|
||||||
|
|
||||||
|
use bevy_macro_utils::BevyManifest;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
pub(crate) fn bevy_render_path() -> syn::Path {
|
||||||
|
BevyManifest::default()
|
||||||
|
.maybe_get_path("bevy_render")
|
||||||
|
// NOTE: If the derivation is within bevy_render, then we need to return 'crate'
|
||||||
|
.unwrap_or_else(|| BevyManifest::parse_str("crate"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ExtractResource)]
|
||||||
|
pub fn derive_extract_resource(input: TokenStream) -> TokenStream {
|
||||||
|
extract_resource::derive_extract_resource(input)
|
||||||
|
}
|
||||||
46
crates/bevy_render/src/extract_resource.rs
Normal file
46
crates/bevy_render/src/extract_resource.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use bevy_app::{App, Plugin};
|
||||||
|
use bevy_ecs::system::{Commands, Res, Resource};
|
||||||
|
pub use bevy_render_macros::ExtractResource;
|
||||||
|
|
||||||
|
use crate::{RenderApp, RenderStage};
|
||||||
|
|
||||||
|
/// Describes how a resource gets extracted for rendering.
|
||||||
|
///
|
||||||
|
/// Therefore the resource is transferred from the "main world" into the "render world"
|
||||||
|
/// in the [`RenderStage::Extract`](crate::RenderStage::Extract) step.
|
||||||
|
pub trait ExtractResource: Resource {
|
||||||
|
type Source: Resource;
|
||||||
|
|
||||||
|
/// Defines how the resource is transferred into the "render world".
|
||||||
|
fn extract_resource(source: &Self::Source) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This plugin extracts the resources into the "render world".
|
||||||
|
///
|
||||||
|
/// Therefore it sets up the [`RenderStage::Extract`](crate::RenderStage::Extract) step
|
||||||
|
/// for the specified [`Resource`].
|
||||||
|
pub struct ExtractResourcePlugin<R: ExtractResource>(PhantomData<R>);
|
||||||
|
|
||||||
|
impl<R: ExtractResource> Default for ExtractResourcePlugin<R> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: ExtractResource> Plugin for ExtractResourcePlugin<R> {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
|
render_app.add_system_to_stage(RenderStage::Extract, extract_resource::<R>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This system extracts the resource of the corresponding [`Resource`] type
|
||||||
|
/// by cloning it.
|
||||||
|
pub fn extract_resource<R: ExtractResource>(mut commands: Commands, resource: Res<R::Source>) {
|
||||||
|
if resource.is_changed() {
|
||||||
|
commands.insert_resource(R::extract_resource(resource.into_inner()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,10 +2,11 @@ extern crate core;
|
|||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
pub mod extract_component;
|
||||||
|
pub mod extract_resource;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod render_asset;
|
pub mod render_asset;
|
||||||
pub mod render_component;
|
|
||||||
pub mod render_graph;
|
pub mod render_graph;
|
||||||
pub mod render_phase;
|
pub mod render_phase;
|
||||||
pub mod render_resource;
|
pub mod render_resource;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub use window::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
prelude::Image,
|
prelude::Image,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
|
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
|
||||||
@ -27,12 +28,14 @@ pub struct ViewPlugin;
|
|||||||
|
|
||||||
impl Plugin for ViewPlugin {
|
impl Plugin for ViewPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<Msaa>().add_plugin(VisibilityPlugin);
|
app.init_resource::<Msaa>()
|
||||||
|
// NOTE: windows.is_changed() handles cases where a window was resized
|
||||||
|
.add_plugin(ExtractResourcePlugin::<Msaa>::default())
|
||||||
|
.add_plugin(VisibilityPlugin);
|
||||||
|
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ViewUniforms>()
|
.init_resource::<ViewUniforms>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_msaa)
|
|
||||||
.add_system_to_stage(RenderStage::Prepare, prepare_view_uniforms)
|
.add_system_to_stage(RenderStage::Prepare, prepare_view_uniforms)
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
RenderStage::Prepare,
|
RenderStage::Prepare,
|
||||||
@ -42,7 +45,7 @@ impl Plugin for ViewPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, ExtractResource)]
|
||||||
/// Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing).
|
/// Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing).
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -70,11 +73,6 @@ impl Default for Msaa {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_msaa(mut commands: Commands, msaa: Res<Msaa>) {
|
|
||||||
// NOTE: windows.is_changed() handles cases where a window was resized
|
|
||||||
commands.insert_resource(msaa.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct ExtractedView {
|
pub struct ExtractedView {
|
||||||
pub projection: Mat4,
|
pub projection: Mat4,
|
||||||
|
|||||||
@ -12,9 +12,9 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_log::error;
|
use bevy_log::error;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_component::ExtractComponentPlugin,
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayout},
|
||||||
render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets},
|
render_asset::{RenderAsset, RenderAssetPlugin, RenderAssets},
|
||||||
render_component::ExtractComponentPlugin,
|
|
||||||
render_phase::{
|
render_phase::{
|
||||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||||
SetItemPipeline, TrackedRenderPass,
|
SetItemPipeline, TrackedRenderPass,
|
||||||
|
|||||||
@ -7,9 +7,9 @@ use bevy_ecs::{
|
|||||||
use bevy_math::{Mat4, Vec2};
|
use bevy_math::{Mat4, Vec2};
|
||||||
use bevy_reflect::{Reflect, TypeUuid};
|
use bevy_reflect::{Reflect, TypeUuid};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
|
||||||
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
|
|
||||||
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use bevy::{
|
|||||||
core_pipeline::node::MAIN_PASS_DEPENDENCIES,
|
core_pipeline::node::MAIN_PASS_DEPENDENCIES,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_graph::{self, RenderGraph},
|
render_graph::{self, RenderGraph},
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
@ -66,10 +67,12 @@ pub struct GameOfLifeComputePlugin;
|
|||||||
|
|
||||||
impl Plugin for GameOfLifeComputePlugin {
|
impl Plugin for GameOfLifeComputePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
// Extract the game of life image resource from the main world into the render world
|
||||||
|
// for operation on by the compute shader and display on the sprite.
|
||||||
|
app.add_plugin(ExtractResourcePlugin::<GameOfLifeImage>::default());
|
||||||
let render_app = app.sub_app_mut(RenderApp);
|
let render_app = app.sub_app_mut(RenderApp);
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<GameOfLifePipeline>()
|
.init_resource::<GameOfLifePipeline>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_game_of_life_image)
|
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_bind_group);
|
.add_system_to_stage(RenderStage::Queue, queue_bind_group);
|
||||||
|
|
||||||
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
|
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
|
||||||
@ -80,15 +83,11 @@ impl Plugin for GameOfLifeComputePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref)]
|
#[derive(Clone, Deref, ExtractResource)]
|
||||||
struct GameOfLifeImage(Handle<Image>);
|
struct GameOfLifeImage(Handle<Image>);
|
||||||
|
|
||||||
struct GameOfLifeImageBindGroup(BindGroup);
|
struct GameOfLifeImageBindGroup(BindGroup);
|
||||||
|
|
||||||
fn extract_game_of_life_image(mut commands: Commands, image: Res<GameOfLifeImage>) {
|
|
||||||
commands.insert_resource(GameOfLifeImage(image.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn queue_bind_group(
|
fn queue_bind_group(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
pipeline: Res<GameOfLifePipeline>,
|
pipeline: Res<GameOfLifePipeline>,
|
||||||
|
|||||||
@ -8,9 +8,9 @@ use bevy::{
|
|||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
mesh::MeshVertexBufferLayout,
|
mesh::MeshVertexBufferLayout,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_component::{ExtractComponent, ExtractComponentPlugin},
|
|
||||||
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
PipelineCache, RenderPipelineDescriptor, SpecializedMeshPipeline,
|
PipelineCache, RenderPipelineDescriptor, SpecializedMeshPipeline,
|
||||||
|
|||||||
@ -7,9 +7,9 @@ use bevy::{
|
|||||||
pbr::{MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup},
|
pbr::{MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
mesh::{GpuBufferInfo, MeshVertexBufferLayout},
|
mesh::{GpuBufferInfo, MeshVertexBufferLayout},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_component::{ExtractComponent, ExtractComponentPlugin},
|
|
||||||
render_phase::{
|
render_phase::{
|
||||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||||
SetItemPipeline, TrackedRenderPass,
|
SetItemPipeline, TrackedRenderPass,
|
||||||
|
|||||||
@ -22,6 +22,7 @@ crates=(
|
|||||||
bevy_transform
|
bevy_transform
|
||||||
bevy_window
|
bevy_window
|
||||||
bevy_encase_derive
|
bevy_encase_derive
|
||||||
|
bevy_render/macros
|
||||||
bevy_render
|
bevy_render
|
||||||
bevy_core_pipeline
|
bevy_core_pipeline
|
||||||
bevy_input
|
bevy_input
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user