use crate::{ render_resource::DynamicUniformVec, renderer::{RenderDevice, RenderQueue}, RenderApp, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_asset::{Asset, Handle}; use bevy_ecs::{ component::Component, prelude::*, query::{FilterFetch, QueryItem, ReadOnlyFetch, WorldQuery}, system::{ lifetimeless::{Read, SCommands, SQuery}, RunSystem, SystemParamItem, }, }; use crevice::std140::AsStd140; use std::{marker::PhantomData, ops::Deref}; pub struct DynamicUniformIndex { index: u32, marker: PhantomData, } impl DynamicUniformIndex { #[inline] pub fn index(&self) -> u32 { self.index } } pub trait ExtractComponent: Component { type Query: WorldQuery; type Filter: WorldQuery; fn extract_component(item: QueryItem) -> Self; } /// Extracts assets into gpu-usable data pub struct UniformComponentPlugin(PhantomData C>); impl Default for UniformComponentPlugin { fn default() -> Self { Self(PhantomData) } } impl Plugin for UniformComponentPlugin { fn build(&self, app: &mut App) { app.sub_app(RenderApp) .insert_resource(ComponentUniforms::::default()) .add_system_to_stage( RenderStage::Prepare, prepare_uniform_components::.system(), ); } } pub struct ComponentUniforms { uniforms: DynamicUniformVec, } impl Deref for ComponentUniforms { type Target = DynamicUniformVec; #[inline] fn deref(&self) -> &Self::Target { &self.uniforms } } impl ComponentUniforms { #[inline] pub fn uniforms(&self) -> &DynamicUniformVec { &self.uniforms } } impl Default for ComponentUniforms { fn default() -> Self { Self { uniforms: Default::default(), } } } fn prepare_uniform_components( mut commands: Commands, render_device: Res, render_queue: Res, mut component_uniforms: ResMut>, components: Query<(Entity, &C)>, ) where C: AsStd140 + Clone, { let len = components.iter().len(); component_uniforms .uniforms .reserve_and_clear(len, &render_device); for (entity, component) in components.iter() { commands .get_or_spawn(entity) .insert(DynamicUniformIndex:: { index: component_uniforms.uniforms.push(component.clone()), marker: PhantomData, }); } component_uniforms.uniforms.write_buffer(&render_queue); } pub struct ExtractComponentPlugin(PhantomData (C, F)>); impl Default for ExtractComponentPlugin { fn default() -> Self { Self(PhantomData) } } impl Plugin for ExtractComponentPlugin where ::Fetch: ReadOnlyFetch, ::Fetch: FilterFetch, { fn build(&self, app: &mut App) { let system = ExtractComponentSystem::::system(&mut app.world); let render_app = app.sub_app(RenderApp); render_app.add_system_to_stage(RenderStage::Extract, system); } } impl ExtractComponent for Handle { type Query = Read>; type Filter = (); #[inline] fn extract_component(handle: QueryItem) -> Self { handle.clone_weak() } } pub struct ExtractComponentSystem(PhantomData); impl RunSystem for ExtractComponentSystem where ::Fetch: FilterFetch, ::Fetch: ReadOnlyFetch, { type Param = ( SCommands, Local<'static, usize>, SQuery<(Entity, C::Query), C::Filter>, ); fn run((mut commands, mut previous_len, query): SystemParamItem) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in query.iter() { values.push((entity, (C::extract_component(query_item),))); } *previous_len = values.len(); commands.insert_or_spawn_batch(values); } }