bevy_light_2d 0.9.0

General purpose 2d lighting for the Bevy game engine.
Documentation
use bevy::core_pipeline::FullscreenShader;
use bevy::image::BevyDefault;
use bevy::prelude::*;
use bevy::render::render_resource::binding_types::{sampler, texture_2d};
use bevy::render::render_resource::{
    BindGroupLayoutDescriptor, BindGroupLayoutEntries, ColorTargetState, ColorWrites,
    FragmentState, MultisampleState, PrimitiveState, RenderPipelineDescriptor, Sampler,
    SamplerBindingType, SamplerDescriptor, ShaderStages, SpecializedRenderPipeline, TextureFormat,
    TextureSampleType,
};
use bevy::render::renderer::RenderDevice;
use bevy::render::view::ViewTarget;

use super::{LIGHTING_SHADER, LightingPipelineKey};

const LIGHTING_PIPELINE: &str = "lighting_pipeline";
const LIGHTING_BIND_GROUP_LAYOUT: &str = "lighting_bind_group_layout";

#[derive(Resource)]
pub struct LightingPipeline {
    pub layout_descriptor: BindGroupLayoutDescriptor,
    pub sampler: Sampler,
    pub fullscreen_shader: FullscreenShader,
}

impl FromWorld for LightingPipeline {
    fn from_world(world: &mut World) -> Self {
        let render_device = world.resource::<RenderDevice>();

        let layout_descriptor = BindGroupLayoutDescriptor::new(
            LIGHTING_BIND_GROUP_LAYOUT,
            &BindGroupLayoutEntries::sequential(
                ShaderStages::FRAGMENT,
                (
                    texture_2d(TextureSampleType::Float { filterable: true }),
                    texture_2d(TextureSampleType::Float { filterable: true }),
                    sampler(SamplerBindingType::Filtering),
                ),
            ),
        );

        let sampler = render_device.create_sampler(&SamplerDescriptor::default());

        let fullscreen_shader = world.resource::<FullscreenShader>().clone();
        Self {
            layout_descriptor,
            sampler,
            fullscreen_shader,
        }
    }
}

impl SpecializedRenderPipeline for LightingPipeline {
    type Key = LightingPipelineKey;

    fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
        RenderPipelineDescriptor {
            label: Some(LIGHTING_PIPELINE.into()),
            layout: vec![self.layout_descriptor.clone()],
            vertex: self.fullscreen_shader.to_vertex_state(),
            fragment: Some(FragmentState {
                shader: LIGHTING_SHADER,
                shader_defs: vec![],
                entry_point: Some("fragment".into()),
                targets: vec![Some(ColorTargetState {
                    format: if key.hdr {
                        ViewTarget::TEXTURE_FORMAT_HDR
                    } else {
                        TextureFormat::bevy_default()
                    },
                    blend: None,
                    write_mask: ColorWrites::ALL,
                })],
            }),
            primitive: PrimitiveState::default(),
            depth_stencil: None,
            multisample: MultisampleState::default(),
            push_constant_ranges: vec![],
            zero_initialize_workgroup_memory: false,
        }
    }
}