bevy_entitiles 0.3.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
use bevy::{
    ecs::{
        component::Component,
        entity::Entity,
        system::{ParallelCommands, Res, Resource},
    },
    prelude::{Query, ResMut},
};

use crate::{math::CameraAabb2d, tilemap::map::TilemapAabbs};

use super::{
    chunk::RenderChunkStorage,
    extract::{ExtractedTilemap, ExtractedView},
};

#[derive(Component)]
pub struct InvisibleTilemap;

#[derive(Resource)]
pub struct FrustumCulling(pub bool);

impl Default for FrustumCulling {
    fn default() -> Self {
        Self(true)
    }
}

pub fn cull_tilemaps(
    commands: ParallelCommands,
    tilemaps: Query<(Entity, &TilemapAabbs)>,
    cameras: Query<&CameraAabb2d>,
    culling: Res<FrustumCulling>,
) {
    if !culling.0 {
        return;
    }

    cameras.par_iter().for_each(|camera| {
        tilemaps.par_iter().for_each(|(entity, aabbs)| {
            commands.command_scope(|mut c| {
                if !aabbs.world_aabb.is_intersected(camera.0) {
                    c.entity(entity).insert(InvisibleTilemap);
                } else {
                    c.entity(entity).remove::<InvisibleTilemap>();
                }
            });
        });
    });
}

pub fn cull_chunks(
    tilemaps: Query<&ExtractedTilemap>,
    mut render_chunk_storage: ResMut<RenderChunkStorage>,
    cameras: Query<&ExtractedView>,
    culling: Res<FrustumCulling>,
) {
    if !culling.0 {
        return;
    }

    cameras.for_each(|cam_aabb| {
        tilemaps.for_each(|tilemap| {
            let Some(chunks) = render_chunk_storage.get_chunks_mut(tilemap.id) else {
                return;
            };

            chunks.values_mut().for_each(|c| {
                if c.aabb.is_intersected(cam_aabb.0) {
                    c.visible = true;
                } else {
                    c.visible = false;
                }
            });
        });
    });
}