wde_renderer/sync/
extract_component_plugin.rs1use std::marker::PhantomData;
2
3use bevy::{
4 ecs::{
5 bundle::NoBundleEffect,
6 query::{QueryFilter, ReadOnlyQueryData},
7 },
8 prelude::*,
9};
10
11use crate::{
12 core::{Extract, ExtractWorld, RenderApp},
13 sync::{RenderEntity, SyncComponent, SyncComponentPlugin},
14};
15
16pub use bevy::ecs::query::QueryItem;
17
18pub trait ExtractComponent<F = ()>: SyncComponent<F> {
25 type QueryData: ReadOnlyQueryData;
27 type QueryFilter: QueryFilter;
29 type Out: Bundle<Effect: NoBundleEffect>;
31
32 fn extract_component(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out>;
35}
36
37pub struct ExtractComponentPlugin<C, F = ()>(PhantomData<fn() -> (C, F)>);
43impl<C, F> Default for ExtractComponentPlugin<C, F> {
44 fn default() -> Self {
45 Self(PhantomData)
46 }
47}
48impl<C: ExtractComponent<F>, F: 'static + Send + Sync> Plugin for ExtractComponentPlugin<C, F> {
49 fn build(&self, app: &mut App) {
50 app.add_plugins(SyncComponentPlugin::<C, F>::default());
51 app.get_sub_app_mut(RenderApp)
52 .unwrap()
53 .add_systems(Extract, extract_components::<C, F>);
54 }
55}
56
57#[allow(clippy::type_complexity)]
59fn extract_components<C: ExtractComponent<F>, F>(
60 mut commands: Commands,
61 mut previous_len: Local<usize>,
62 query: ExtractWorld<Query<(RenderEntity, C::QueryData), C::QueryFilter>>,
63) {
64 let mut values = Vec::with_capacity(*previous_len);
65 for (entity, query_item) in &query {
66 if let Some(component) = C::extract_component(query_item) {
67 values.push((entity, component));
68 } else {
69 commands.entity(entity).remove::<C::Target>();
70 }
71 }
72 *previous_len = values.len();
73 commands.try_insert_batch(values);
74}