bevy_render/
extract_instances.rs1use core::marker::PhantomData;
8
9use bevy_app::{App, Plugin};
10use bevy_derive::{Deref, DerefMut};
11use bevy_ecs::{
12 prelude::Entity,
13 query::{QueryFilter, QueryItem, ReadOnlyQueryData},
14 resource::Resource,
15 system::{Query, ResMut},
16};
17
18use crate::sync_world::MainEntityHashMap;
19use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
20
21pub trait ExtractInstance: Send + Sync + Sized + 'static {
31 type QueryData: ReadOnlyQueryData;
33 type QueryFilter: QueryFilter;
35
36 fn extract(item: QueryItem<'_, Self::QueryData>) -> Option<Self>;
38}
39
40#[derive(Default)]
46pub struct ExtractInstancesPlugin<EI>
47where
48 EI: ExtractInstance,
49{
50 only_extract_visible: bool,
51 marker: PhantomData<fn() -> EI>,
52}
53
54#[derive(Resource, Deref, DerefMut)]
56pub struct ExtractedInstances<EI>(MainEntityHashMap<EI>)
57where
58 EI: ExtractInstance;
59
60impl<EI> Default for ExtractedInstances<EI>
61where
62 EI: ExtractInstance,
63{
64 fn default() -> Self {
65 Self(Default::default())
66 }
67}
68
69impl<EI> ExtractInstancesPlugin<EI>
70where
71 EI: ExtractInstance,
72{
73 pub fn new() -> Self {
76 Self {
77 only_extract_visible: false,
78 marker: PhantomData,
79 }
80 }
81
82 pub fn extract_visible() -> Self {
85 Self {
86 only_extract_visible: true,
87 marker: PhantomData,
88 }
89 }
90}
91
92impl<EI> Plugin for ExtractInstancesPlugin<EI>
93where
94 EI: ExtractInstance,
95{
96 fn build(&self, app: &mut App) {
97 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
98 render_app.init_resource::<ExtractedInstances<EI>>();
99 if self.only_extract_visible {
100 render_app.add_systems(ExtractSchedule, extract_visible::<EI>);
101 } else {
102 render_app.add_systems(ExtractSchedule, extract_all::<EI>);
103 }
104 }
105 }
106}
107
108fn extract_all<EI>(
109 mut extracted_instances: ResMut<ExtractedInstances<EI>>,
110 query: Extract<Query<(Entity, EI::QueryData), EI::QueryFilter>>,
111) where
112 EI: ExtractInstance,
113{
114 extracted_instances.clear();
115 for (entity, other) in &query {
116 if let Some(extract_instance) = EI::extract(other) {
117 extracted_instances.insert(entity.into(), extract_instance);
118 }
119 }
120}
121
122fn extract_visible<EI>(
123 mut extracted_instances: ResMut<ExtractedInstances<EI>>,
124 query: Extract<Query<(Entity, &ViewVisibility, EI::QueryData), EI::QueryFilter>>,
125) where
126 EI: ExtractInstance,
127{
128 extracted_instances.clear();
129 for (entity, view_visibility, other) in &query {
130 if view_visibility.get() {
131 if let Some(extract_instance) = EI::extract(other) {
132 extracted_instances.insert(entity.into(), extract_instance);
133 }
134 }
135 }
136}