Path: blob/main/crates/bevy_render/src/extract_instances.rs
6595 views
//! Convenience logic for turning components from the main world into extracted1//! instances in the render world.2//!3//! This is essentially the same as the `extract_component` module, but4//! higher-performance because it avoids the ECS overhead.56use core::marker::PhantomData;78use bevy_app::{App, Plugin};9use bevy_camera::visibility::ViewVisibility;10use bevy_derive::{Deref, DerefMut};11use bevy_ecs::{12prelude::Entity,13query::{QueryFilter, QueryItem, ReadOnlyQueryData},14resource::Resource,15system::{Query, ResMut},16};1718use crate::sync_world::MainEntityHashMap;19use crate::{Extract, ExtractSchedule, RenderApp};2021/// Describes how to extract data needed for rendering from a component or22/// components.23///24/// Before rendering, any applicable components will be transferred from the25/// main world to the render world in the [`ExtractSchedule`] step.26///27/// This is essentially the same as28/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but29/// higher-performance because it avoids the ECS overhead.30pub trait ExtractInstance: Send + Sync + Sized + 'static {31/// ECS [`ReadOnlyQueryData`] to fetch the components to extract.32type QueryData: ReadOnlyQueryData;33/// Filters the entities with additional constraints.34type QueryFilter: QueryFilter;3536/// Defines how the component is transferred into the "render world".37fn extract(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self>;38}3940/// This plugin extracts one or more components into the "render world" as41/// extracted instances.42///43/// Therefore it sets up the [`ExtractSchedule`] step for the specified44/// [`ExtractedInstances`].45#[derive(Default)]46pub struct ExtractInstancesPlugin<EI>47where48EI: ExtractInstance,49{50only_extract_visible: bool,51marker: PhantomData<fn() -> EI>,52}5354/// Stores all extract instances of a type in the render world.55#[derive(Resource, Deref, DerefMut)]56pub struct ExtractedInstances<EI>(MainEntityHashMap<EI>)57where58EI: ExtractInstance;5960impl<EI> Default for ExtractedInstances<EI>61where62EI: ExtractInstance,63{64fn default() -> Self {65Self(Default::default())66}67}6869impl<EI> ExtractInstancesPlugin<EI>70where71EI: ExtractInstance,72{73/// Creates a new [`ExtractInstancesPlugin`] that unconditionally extracts to74/// the render world, whether the entity is visible or not.75pub fn new() -> Self {76Self {77only_extract_visible: false,78marker: PhantomData,79}80}8182/// Creates a new [`ExtractInstancesPlugin`] that extracts to the render world83/// if and only if the entity it's attached to is visible.84pub fn extract_visible() -> Self {85Self {86only_extract_visible: true,87marker: PhantomData,88}89}90}9192impl<EI> Plugin for ExtractInstancesPlugin<EI>93where94EI: ExtractInstance,95{96fn build(&self, app: &mut App) {97if let Some(render_app) = app.get_sub_app_mut(RenderApp) {98render_app.init_resource::<ExtractedInstances<EI>>();99if self.only_extract_visible {100render_app.add_systems(ExtractSchedule, extract_visible::<EI>);101} else {102render_app.add_systems(ExtractSchedule, extract_all::<EI>);103}104}105}106}107108fn extract_all<EI>(109mut extracted_instances: ResMut<ExtractedInstances<EI>>,110query: Extract<Query<(Entity, EI::QueryData), EI::QueryFilter>>,111) where112EI: ExtractInstance,113{114extracted_instances.clear();115for (entity, other) in &query {116if let Some(extract_instance) = EI::extract(other) {117extracted_instances.insert(entity.into(), extract_instance);118}119}120}121122fn extract_visible<EI>(123mut extracted_instances: ResMut<ExtractedInstances<EI>>,124query: Extract<Query<(Entity, &ViewVisibility, EI::QueryData), EI::QueryFilter>>,125) where126EI: ExtractInstance,127{128extracted_instances.clear();129for (entity, view_visibility, other) in &query {130if view_visibility.get()131&& let Some(extract_instance) = EI::extract(other)132{133extracted_instances.insert(entity.into(), extract_instance);134}135}136}137138139