Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/extract_instances.rs
6595 views
1
//! Convenience logic for turning components from the main world into extracted
2
//! instances in the render world.
3
//!
4
//! This is essentially the same as the `extract_component` module, but
5
//! higher-performance because it avoids the ECS overhead.
6
7
use core::marker::PhantomData;
8
9
use bevy_app::{App, Plugin};
10
use bevy_camera::visibility::ViewVisibility;
11
use bevy_derive::{Deref, DerefMut};
12
use bevy_ecs::{
13
prelude::Entity,
14
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
15
resource::Resource,
16
system::{Query, ResMut},
17
};
18
19
use crate::sync_world::MainEntityHashMap;
20
use crate::{Extract, ExtractSchedule, RenderApp};
21
22
/// Describes how to extract data needed for rendering from a component or
23
/// components.
24
///
25
/// Before rendering, any applicable components will be transferred from the
26
/// main world to the render world in the [`ExtractSchedule`] step.
27
///
28
/// This is essentially the same as
29
/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but
30
/// higher-performance because it avoids the ECS overhead.
31
pub trait ExtractInstance: Send + Sync + Sized + 'static {
32
/// ECS [`ReadOnlyQueryData`] to fetch the components to extract.
33
type QueryData: ReadOnlyQueryData;
34
/// Filters the entities with additional constraints.
35
type QueryFilter: QueryFilter;
36
37
/// Defines how the component is transferred into the "render world".
38
fn extract(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self>;
39
}
40
41
/// This plugin extracts one or more components into the "render world" as
42
/// extracted instances.
43
///
44
/// Therefore it sets up the [`ExtractSchedule`] step for the specified
45
/// [`ExtractedInstances`].
46
#[derive(Default)]
47
pub struct ExtractInstancesPlugin<EI>
48
where
49
EI: ExtractInstance,
50
{
51
only_extract_visible: bool,
52
marker: PhantomData<fn() -> EI>,
53
}
54
55
/// Stores all extract instances of a type in the render world.
56
#[derive(Resource, Deref, DerefMut)]
57
pub struct ExtractedInstances<EI>(MainEntityHashMap<EI>)
58
where
59
EI: ExtractInstance;
60
61
impl<EI> Default for ExtractedInstances<EI>
62
where
63
EI: ExtractInstance,
64
{
65
fn default() -> Self {
66
Self(Default::default())
67
}
68
}
69
70
impl<EI> ExtractInstancesPlugin<EI>
71
where
72
EI: ExtractInstance,
73
{
74
/// Creates a new [`ExtractInstancesPlugin`] that unconditionally extracts to
75
/// the render world, whether the entity is visible or not.
76
pub fn new() -> Self {
77
Self {
78
only_extract_visible: false,
79
marker: PhantomData,
80
}
81
}
82
83
/// Creates a new [`ExtractInstancesPlugin`] that extracts to the render world
84
/// if and only if the entity it's attached to is visible.
85
pub fn extract_visible() -> Self {
86
Self {
87
only_extract_visible: true,
88
marker: PhantomData,
89
}
90
}
91
}
92
93
impl<EI> Plugin for ExtractInstancesPlugin<EI>
94
where
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
109
fn 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
123
fn 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
}
138
139