nightshade 0.57.0

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::world::World;

pub fn update_instanced_mesh_caches_system(world: &mut World) {
    let _span = tracing::info_span!("instanced_meshes").entered();

    let mut transform_dirty = std::mem::take(
        &mut world
            .res_mut::<crate::ecs::world::scratch::Scratch>()
            .transform_dirty,
    );
    let mut local_matrices_dirty = std::mem::take(
        &mut world
            .res_mut::<crate::ecs::world::scratch::Scratch>()
            .local_matrices_dirty,
    );
    let mut seen = std::mem::take(
        &mut world
            .res_mut::<crate::ecs::world::scratch::Scratch>()
            .instanced_seen,
    );
    transform_dirty.clear();
    local_matrices_dirty.clear();
    seen.clear();
    let mut needs_compute_dispatch = false;

    let mut matrix_entries = world
        .res_mut::<crate::ecs::mesh::components::InstancedMeshMatrices>()
        .take_entries();

    world
        .query::<(
            &mut crate::ecs::mesh::components::InstancedMesh,
            Option<&crate::ecs::transform::components::GlobalTransform>,
        )>()
        .for_each(|entity, (instanced_mesh, global_transform)| {
            let parent_transform = global_transform
                .map(|global| global.0)
                .unwrap_or_else(nalgebra_glm::Mat4::identity);
            let was_dirty = instanced_mesh.dirty;
            let had_gpu_dirty = instanced_mesh.local_matrices_gpu_dirty();
            let parent_only_changed = matrix_entries.entry(entity).or_default().update(
                &instanced_mesh.instances,
                instanced_mesh.dirty,
                &parent_transform,
            );
            instanced_mesh.dirty = false;
            let custom_data_dirty = !instanced_mesh.take_dirty_custom_data_indices().is_empty();
            seen.insert(entity);
            if was_dirty || custom_data_dirty {
                transform_dirty.push(entity);
            }
            if had_gpu_dirty {
                local_matrices_dirty.push(entity);
                instanced_mesh.clear_local_matrices_gpu_dirty();
            }
            if parent_only_changed {
                needs_compute_dispatch = true;
            }
        });

    matrix_entries.retain(|entity, _| seen.contains(entity));
    world
        .res_mut::<crate::ecs::mesh::components::InstancedMeshMatrices>()
        .restore_entries(matrix_entries);

    for entity in transform_dirty.drain(..) {
        world
            .res_mut::<crate::render::mesh_state::MeshRenderState>()
            .mark_transform_dirty(entity);
    }
    for entity in local_matrices_dirty.drain(..) {
        world
            .res_mut::<crate::render::mesh_state::MeshRenderState>()
            .mark_instanced_local_matrices_dirty(entity);
    }
    if needs_compute_dispatch {
        world
            .res_mut::<crate::render::mesh_state::MeshRenderState>()
            .mark_instanced_compute_dispatch_needed();
    }

    world
        .res_mut::<crate::ecs::world::scratch::Scratch>()
        .transform_dirty = transform_dirty;
    world
        .res_mut::<crate::ecs::world::scratch::Scratch>()
        .local_matrices_dirty = local_matrices_dirty;
    world
        .res_mut::<crate::ecs::world::scratch::Scratch>()
        .instanced_seen = seen;
}