Blacksite/crates/game_hot/src/world/lighting.rs
Rbanh f29712d158
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Initial project import
2026-06-05 21:44:45 -04:00

117 lines
3.7 KiB
Rust

//! Outdoor lighting: a single directional sun with cascaded shadow maps.
use bevy::light::CascadeShadowConfig;
use bevy::prelude::*;
use settings::ProjectSettings;
use shared::{
cascade_config_from_rendering, inspector_component_active, AuthoringLightKind, InspectorOrder,
LevelObject, LightDesc, ProjectSun, COMPONENT_LIGHT_DESC,
};
/// Spawns the directional "sun" from project rendering settings.
#[unsafe(no_mangle)]
pub fn spawn_sun(
mut commands: Commands,
settings: Res<ProjectSettings>,
existing: Query<(), With<DirectionalLight>>,
scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
) {
if !existing.is_empty() {
return;
}
let rendering = &settings.rendering;
let cascades = cascade_config_from_rendering(rendering);
commands.spawn((
Name::new("Sun"),
ProjectSun,
DirectionalLight {
illuminance: rendering.sun_illuminance,
shadows_enabled: !has_scene_sun_override(&scene_suns),
..default()
},
Visibility::default(),
Transform::from_xyz(0.0, 0.0, 0.0).looking_to(Vec3::new(-0.35, -0.85, -0.4), Vec3::Y),
cascades,
));
}
#[unsafe(no_mangle)]
pub fn sync_project_sun_visibility(
scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With<ProjectSun>>,
) {
let scene_override = has_scene_sun_override(&scene_suns);
for (mut sun, mut visibility) in &mut project_suns {
sun.shadows_enabled = !scene_override;
*visibility = if scene_override {
Visibility::Hidden
} else {
Visibility::Visible
};
}
}
fn has_scene_sun_override(
scene_suns: &Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
) -> bool {
scene_suns.iter().any(|(light, order)| {
inspector_component_active(order, COMPONENT_LIGHT_DESC)
&& matches!(light.kind, AuthoringLightKind::Directional)
})
}
/// Keeps the project sun's illuminance in sync with [`ProjectSettings`] when settings change.
#[unsafe(no_mangle)]
pub fn sync_project_sun_illuminance(
settings: Res<ProjectSettings>,
mut project_suns: Query<&mut DirectionalLight, With<ProjectSun>>,
) {
let illuminance = settings.rendering.sun_illuminance;
for mut sun in &mut project_suns {
sun.illuminance = illuminance;
}
}
/// Keeps scene directional (non-[`ProjectSun`]) cascade configs aligned with project shadow settings.
#[unsafe(no_mangle)]
pub fn sync_scene_directional_shadow_cascades(
settings: Res<ProjectSettings>,
mut scene_lights: Query<
&mut CascadeShadowConfig,
(
With<LevelObject>,
With<DirectionalLight>,
Without<ProjectSun>,
),
>,
) {
if !settings.is_changed() {
return;
}
let cascades = cascade_config_from_rendering(&settings.rendering);
for mut config in &mut scene_lights {
*config = cascades.clone();
}
}
#[unsafe(no_mangle)]
pub fn sync_project_sun_from_settings(
settings: Res<ProjectSettings>,
scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With<ProjectSun>>,
) {
let scene_override = has_scene_sun_override(&scene_suns);
let illuminance = settings.rendering.sun_illuminance;
for (mut sun, mut visibility) in &mut project_suns {
sun.illuminance = illuminance;
sun.shadows_enabled = !scene_override;
*visibility = if scene_override {
Visibility::Hidden
} else {
Visibility::Visible
};
}
}