bevy_render/
extract_component.rs1use crate::{
2 sync_component::{SyncComponent, SyncComponentPlugin},
3 sync_world::RenderEntity,
4 Extract, ExtractSchedule, RenderApp,
5};
6use bevy_app::{App, Plugin};
7use bevy_camera::visibility::ViewVisibility;
8use bevy_ecs::{
9 bundle::NoBundleEffect,
10 prelude::*,
11 query::{QueryFilter, QueryItem, ReadOnlyQueryData},
12};
13use core::marker::PhantomData;
14
15pub use crate::uniform::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin};
16
17pub use bevy_render_macros::ExtractComponent;
18
19pub trait ExtractComponent<F = ()>: SyncComponent<F> {
31 type QueryData: ReadOnlyQueryData;
33 type QueryFilter: QueryFilter;
35 type Out: Bundle<Effect: NoBundleEffect>;
40 fn extract_component(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out>;
48}
49
50pub struct ExtractComponentPlugin<C, F = ()> {
61 only_extract_visible: bool,
62 marker: PhantomData<fn() -> (C, F)>,
63}
64
65impl<C, F> Default for ExtractComponentPlugin<C, F> {
66 fn default() -> Self {
67 Self {
68 only_extract_visible: false,
69 marker: PhantomData,
70 }
71 }
72}
73
74impl<C, F> ExtractComponentPlugin<C, F> {
75 pub fn extract_visible() -> Self {
76 Self {
77 only_extract_visible: true,
78 marker: PhantomData,
79 }
80 }
81}
82
83impl<C: ExtractComponent<F>, F: 'static + Send + Sync> Plugin for ExtractComponentPlugin<C, F> {
84 fn build(&self, app: &mut App) {
85 app.add_plugins(SyncComponentPlugin::<C, F>::default());
86
87 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
88 if self.only_extract_visible {
89 render_app.add_systems(ExtractSchedule, extract_visible_components::<C, F>);
90 } else {
91 render_app.add_systems(ExtractSchedule, extract_components::<C, F>);
92 }
93 }
94 }
95}
96
97fn extract_components<C: ExtractComponent<F>, F>(
99 mut commands: Commands,
100 mut previous_len: Local<usize>,
101 query: Extract<Query<(RenderEntity, C::QueryData), C::QueryFilter>>,
102) {
103 let mut values = Vec::with_capacity(*previous_len);
104 for (entity, query_item) in &query {
105 if let Some(component) = C::extract_component(query_item) {
106 values.push((entity, component));
107 } else {
108 commands.entity(entity).remove::<C::Target>();
109 }
110 }
111 *previous_len = values.len();
112 commands.try_insert_batch(values);
113}
114
115fn extract_visible_components<C: ExtractComponent<F>, F>(
117 mut commands: Commands,
118 mut previous_len: Local<usize>,
119 query: Extract<Query<(RenderEntity, &ViewVisibility, C::QueryData), C::QueryFilter>>,
120) {
121 let mut values = Vec::with_capacity(*previous_len);
122 for (entity, view_visibility, query_item) in &query {
123 if view_visibility.get() {
124 if let Some(component) = C::extract_component(query_item) {
125 values.push((entity, component));
126 } else {
127 commands.entity(entity).remove::<C::Target>();
128 }
129 }
130 }
131 *previous_len = values.len();
132 commands.try_insert_batch(values);
133}