rustial-renderer-bevy 0.0.1

Bevy Engine renderer for the rustial 2.5D map engine
//! Synchronise engine lighting configuration to Bevy light entities.
//!
//! Reads [`MapState::computed_lighting()`] each frame and ensures the
//! ECS contains matching [`DirectionalLight3d`] and [`AmbientLight`]
//! components.  This drives Bevy's built-in PBR shading for lit
//! materials (e.g. fill-extrusion `StandardMaterial` with `unlit: false`).

use bevy::light::GlobalAmbientLight;
use bevy::prelude::*;

use crate::MapStateResource;

/// Marker component for the engine-owned directional light entity.
#[derive(Component)]
pub struct RustialDirectionalLight;

/// Synchronise engine lighting to Bevy light entities.
///
/// On first run, spawns a [`DirectionalLight3d`] entity.  Every frame,
/// updates the light's direction, colour, and intensity from the
/// engine's [`ComputedLighting`](rustial_engine::ComputedLighting).
pub fn sync_lights(
    mut commands: Commands,
    map: Res<MapStateResource>,
    mut ambient: ResMut<GlobalAmbientLight>,
    mut q_light: Query<
        (Entity, &mut DirectionalLight, &mut Transform),
        With<RustialDirectionalLight>,
    >,
) {
    let lighting = map.0.computed_lighting();

    // Ambient light: update Bevy's global ambient resource.
    ambient.color = Color::linear_rgb(
        lighting.ambient_color[0],
        lighting.ambient_color[1],
        lighting.ambient_color[2],
    );
    ambient.brightness = 80.0; // intensity already baked into colour channels

    let dir = lighting.directional_dir;
    let color = Color::linear_rgb(
        lighting.directional_color[0],
        lighting.directional_color[1],
        lighting.directional_color[2],
    );

    // Bevy's DirectionalLight shines along -Z of its transform.
    // We need a rotation that points -Z toward the light's incoming
    // direction (i.e. the negation of the "toward light" vector).
    let incoming = Vec3::new(-dir[0], -dir[1], -dir[2]);
    let rotation = if incoming.length_squared() > 1e-6 {
        Transform::default().looking_to(incoming, Vec3::Z).rotation
    } else {
        Quat::IDENTITY
    };

    let shadows_on = lighting.shadows_enabled;

    if let Ok((_entity, mut dl, mut transform)) = q_light.single_mut() {
        // Update existing light.
        dl.color = color;
        dl.illuminance = if lighting.lighting_enabled > 0.5 {
            10_000.0
        } else {
            0.0
        };
        dl.shadows_enabled = shadows_on;
        transform.rotation = rotation;
    } else {
        // Spawn new directional light.
        commands.spawn((
            DirectionalLight {
                color,
                illuminance: if lighting.lighting_enabled > 0.5 {
                    10_000.0
                } else {
                    0.0
                },
                shadows_enabled: shadows_on,
                ..Default::default()
            },
            Transform::from_rotation(rotation),
            RustialDirectionalLight,
        ));
    }
}