use bevy::{ ecs::system::{ lifetimeless::{Read, SQuery, SRes}, SystemParamItem, }, prelude::*, render::{ extract_component::{ComponentUniforms, DynamicUniformIndex}, render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry, ShaderType}, renderer::RenderDevice, Extract, }, }; use crate::{pipeline::OutlinePipeline, Outline}; #[derive(Clone, Component, ShaderType)] pub struct OutlineVertexUniform { pub width: f32, } #[derive(Clone, Component, ShaderType)] pub struct OutlineFragmentUniform { pub colour: Vec4, } pub struct OutlineBindGroup { pub bind_group: BindGroup, } pub fn extract_outline_uniforms(mut commands: Commands, query: Extract>) { for (entity, outline) in query.iter() { if !outline.visible || outline.colour.a() == 0.0 { continue; } commands .get_or_spawn(entity) .insert(OutlineVertexUniform { width: outline.width, }) .insert(OutlineFragmentUniform { colour: outline.colour.as_linear_rgba_f32().into(), }); } } pub fn queue_outline_bind_group( mut commands: Commands, render_device: Res, outline_pipeline: Res, vertex: Res>, fragment: Res>, ) { if let (Some(vertex_binding), Some(fragment_binding)) = (vertex.binding(), fragment.binding()) { let bind_group = render_device.create_bind_group(&BindGroupDescriptor { entries: &[ BindGroupEntry { binding: 0, resource: vertex_binding.clone(), }, BindGroupEntry { binding: 1, resource: fragment_binding.clone(), }, ], label: Some("outline_bind_group"), layout: &outline_pipeline.outline_bind_group_layout, }); commands.insert_resource(OutlineBindGroup { bind_group }); } } pub struct SetOutlineBindGroup(); impl EntityRenderCommand for SetOutlineBindGroup { type Param = ( SRes, SQuery<( Read>, Read>, )>, ); fn render<'w>( _view: Entity, item: Entity, (bind_group, query): SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { let (vertex, fragment) = query.get(item).unwrap(); pass.set_bind_group( I, &bind_group.into_inner().bind_group, &[vertex.index(), fragment.index()], ); RenderCommandResult::Success } }