use std::marker::PhantomData; use bevy_app::{App, Plugin}; #[cfg(debug_assertions)] use bevy_ecs::system::Local; use bevy_ecs::system::{Commands, Res, ResMut, Resource}; pub use bevy_render_macros::ExtractResource; use crate::{Extract, 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(PhantomData); impl Default for ExtractResourcePlugin { fn default() -> Self { Self(PhantomData) } } impl Plugin for ExtractResourcePlugin { 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::); } } } /// This system extracts the resource of the corresponding [`Resource`] type pub fn extract_resource( mut commands: Commands, main_resource: Extract>, target_resource: Option>, #[cfg(debug_assertions)] mut has_warned_on_remove: Local, ) { if let Some(mut target_resource) = target_resource { if main_resource.is_changed() { *target_resource = R::extract_resource(&*main_resource); } } else { #[cfg(debug_assertions)] if !main_resource.is_added() && !*has_warned_on_remove { *has_warned_on_remove = true; bevy_log::warn!( "Removing resource {} from render world not expected, adding using `Commands`. This may decrease performance", std::any::type_name::() ); } commands.insert_resource(R::extract_resource(&*main_resource)); } }