bevy_entitiles 0.11.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
Documentation
use std::marker::PhantomData;

use bevy::{
    app::{App, Plugin},
    asset::{Asset, AssetApp, AssetId},
    color::LinearRgba,
    core_pipeline::core_2d::Transparent2d,
    ecs::{schedule::IntoSystemConfigs, system::SystemParamItem},
    prelude::{Deref, DerefMut},
    reflect::TypePath,
    render::{
        extract_instances::ExtractInstancesPlugin,
        render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin},
        render_phase::AddRenderCommand,
        render_resource::{
            AsBindGroup, RenderPipelineDescriptor, ShaderRef, ShaderType,
            SpecializedRenderPipelines,
        },
        Render, RenderApp, RenderSet,
    },
};

use crate::render::{
    binding::{self, TilemapBindGroups},
    chunk::{self},
    draw::{DrawTilemapNonTextured, DrawTilemapTextured},
    pipeline::EntiTilesPipeline,
    prepare, queue,
};

#[derive(Default)]
pub struct EntiTilesMaterialPlugin<M: TilemapMaterial>(PhantomData<M>);

impl<M: TilemapMaterial> Plugin for EntiTilesMaterialPlugin<M> {
    fn build(&self, app: &mut App) {
        app.add_plugins((
            ExtractInstancesPlugin::<AssetId<M>>::new(),
            RenderAssetPlugin::<ExtractedTilemapMaterialWrapper<M>>::default(),
        ))
        .init_asset::<M>();

        let render_app = app.sub_app_mut(RenderApp);

        render_app
            .add_systems(
                Render,
                (
                    prepare::prepare_tiles::<M>,
                    prepare::prepare_unloaded_chunks::<M>,
                    prepare::prepare_despawned_tilemaps::<M>,
                    prepare::prepare_despawned_tiles::<M>,
                    chunk::prepare_chunks::<M>,
                )
                    .in_set(RenderSet::PrepareResources),
            )
            .add_systems(
                Render,
                (
                    binding::bind_tilemap_buffers::<M>,
                    binding::bind_materials::<M>,
                    binding::bind_textures::<M>,
                )
                    .in_set(RenderSet::PrepareBindGroups),
            )
            .add_systems(
                Render,
                prepare::sort_chunks::<M>.in_set(RenderSet::PrepareResources),
            )
            .add_systems(Render, queue::queue_tilemaps::<M>.in_set(RenderSet::Queue))
            .init_resource::<TilemapBindGroups<M>>()
            .add_render_command::<Transparent2d, DrawTilemapTextured<M>>()
            .add_render_command::<Transparent2d, DrawTilemapNonTextured<M>>();
    }

    fn finish(&self, app: &mut bevy::prelude::App) {
        let render_app = app.sub_app_mut(RenderApp);

        render_app
            .init_resource::<EntiTilesPipeline<M>>()
            .init_resource::<SpecializedRenderPipelines<EntiTilesPipeline<M>>>();
    }
}

pub trait TilemapMaterial: Default + Asset + AsBindGroup + TypePath + Clone {
    fn vertex_shader() -> ShaderRef {
        super::TILEMAP_SHADER.into()
    }

    fn fragment_shader() -> ShaderRef {
        super::TILEMAP_SHADER.into()
    }

    #[allow(unused_variables)]
    fn specialize(descriptor: &mut RenderPipelineDescriptor) {}
}

#[derive(Deref, DerefMut)]
pub struct ExtractedTilemapMaterialWrapper<M: TilemapMaterial>(M);

impl<M> RenderAsset for ExtractedTilemapMaterialWrapper<M>
where
    M: TilemapMaterial,
{
    type SourceAsset = M;

    type Param = ();

    #[inline]
    fn prepare_asset(
        source_asset: Self::SourceAsset,
        _param: &mut SystemParamItem<Self::Param>,
    ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
        Ok(ExtractedTilemapMaterialWrapper(source_asset))
    }
}

#[derive(ShaderType)]
pub struct StandardTilemapUniform {
    pub tint: LinearRgba,
}

impl From<&StandardTilemapMaterial> for StandardTilemapUniform {
    fn from(value: &StandardTilemapMaterial) -> Self {
        Self { tint: value.tint }
    }
}

#[derive(Default, Asset, AsBindGroup, TypePath, Clone)]
#[cfg_attr(feature = "serializing", derive(serde::Serialize, serde::Deserialize))]
#[uniform(0, StandardTilemapUniform)]
pub struct StandardTilemapMaterial {
    pub tint: LinearRgba,
}

impl TilemapMaterial for StandardTilemapMaterial {
    fn vertex_shader() -> ShaderRef {
        super::TILEMAP_SHADER.into()
    }

    fn fragment_shader() -> ShaderRef {
        super::TILEMAP_SHADER.into()
    }
}