use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ComputedVisibility, Extract, RenderApp, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_asset::{Asset, Handle}; use bevy_ecs::{ component::Component, prelude::*, query::{QueryItem, ReadOnlyWorldQuery, WorldQuery}, system::lifetimeless::Read, }; use std::{marker::PhantomData, ops::Deref}; /// Stores the index of a uniform inside of [`ComponentUniforms`]. #[derive(Component)] pub struct DynamicUniformIndex { index: u32, marker: PhantomData, } impl DynamicUniformIndex { #[inline] pub fn index(&self) -> u32 { self.index } } /// Describes how a component gets extracted for rendering. /// /// Therefore the component is transferred from the "app world" into the "render world" /// in the [`RenderStage::Extract`](crate::RenderStage::Extract) step. pub trait ExtractComponent: Component { /// ECS [`WorldQuery`] to fetch the components to extract. type Query: WorldQuery + ReadOnlyWorldQuery; /// Filters the entities with additional constraints. type Filter: WorldQuery + ReadOnlyWorldQuery; /// Defines how the component is transferred into the "render world". fn extract_component(item: QueryItem) -> Self; } /// This plugin prepares the components of the corresponding type for the GPU /// by transforming them into uniforms. /// /// They can then be accessed from the [`ComponentUniforms`] resource. /// For referencing the newly created uniforms a [`DynamicUniformIndex`] is inserted /// for every processed entity. /// /// Therefore it sets up the [`RenderStage::Prepare`](crate::RenderStage::Prepare) step /// for the specified [`ExtractComponent`]. pub struct UniformComponentPlugin(PhantomData C>); impl Default for UniformComponentPlugin { fn default() -> Self { Self(PhantomData) } } impl Plugin for UniformComponentPlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .insert_resource(ComponentUniforms::::default()) .add_system_to_stage(RenderStage::Prepare, prepare_uniform_components::); } } } /// Stores all uniforms of the component type. pub struct ComponentUniforms { uniforms: DynamicUniformBuffer, } impl Deref for ComponentUniforms { type Target = DynamicUniformBuffer; #[inline] fn deref(&self) -> &Self::Target { &self.uniforms } } impl ComponentUniforms { #[inline] pub fn uniforms(&self) -> &DynamicUniformBuffer { &self.uniforms } } impl Default for ComponentUniforms { fn default() -> Self { Self { uniforms: Default::default(), } } } /// This system prepares all components of the corresponding component type. /// They are transformed into uniforms and stored in the [`ComponentUniforms`] resource. fn prepare_uniform_components( mut commands: Commands, render_device: Res, render_queue: Res, mut component_uniforms: ResMut>, components: Query<(Entity, &C)>, ) where C: ShaderType + WriteInto + Clone, { component_uniforms.uniforms.clear(); let entities = components .iter() .map(|(entity, component)| { ( entity, (DynamicUniformIndex:: { index: component_uniforms.uniforms.push(component.clone()), marker: PhantomData, },), ) }) .collect::>(); commands.insert_or_spawn_batch(entities); component_uniforms .uniforms .write_buffer(&render_device, &render_queue); } /// This plugin extracts the components into the "render world". /// /// Therefore it sets up the [`RenderStage::Extract`](crate::RenderStage::Extract) step /// for the specified [`ExtractComponent`]. pub struct ExtractComponentPlugin { only_extract_visible: bool, marker: PhantomData (C, F)>, } impl Default for ExtractComponentPlugin { fn default() -> Self { Self { only_extract_visible: false, marker: PhantomData, } } } impl ExtractComponentPlugin { pub fn extract_visible() -> Self { Self { only_extract_visible: true, marker: PhantomData, } } } impl Plugin for ExtractComponentPlugin { fn build(&self, app: &mut App) { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { if self.only_extract_visible { render_app .add_system_to_stage(RenderStage::Extract, extract_visible_components::); } else { render_app.add_system_to_stage(RenderStage::Extract, extract_components::); } } } } impl ExtractComponent for Handle { type Query = Read>; type Filter = (); #[inline] fn extract_component(handle: QueryItem) -> Self { handle.clone_weak() } } /// This system extracts all components of the corresponding [`ExtractComponent`] type. fn extract_components( mut commands: Commands, mut previous_len: Local, mut query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in query.iter_mut() { values.push((entity, (C::extract_component(query_item),))); } *previous_len = values.len(); commands.insert_or_spawn_batch(values); } /// This system extracts all visible components of the corresponding [`ExtractComponent`] type. fn extract_visible_components( mut commands: Commands, mut previous_len: Local, mut query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, computed_visibility, query_item) in query.iter_mut() { if computed_visibility.is_visible { values.push((entity, (C::extract_component(query_item),))); } } *previous_len = values.len(); commands.insert_or_spawn_batch(values); }