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