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