use bevy::prelude::*;
use crate::hillshade_material::HillshadeMaterial;
use crate::plugin::MapStateResource;
use crate::systems::frame_change_detection::{frame_unchanged, FrameChangeDetection};
use crate::tile_fog_material::TileFogMaterial;
#[derive(Resource, Default)]
pub struct FogDirtyState {
last_eye_pos: [i32; 3],
last_fog_params: [i32; 4],
last_fog_color: [i32; 4],
last_hillshade_highlight: [i32; 4],
last_hillshade_shadow: [i32; 4],
last_hillshade_accent: [i32; 4],
last_hillshade_light: [i32; 4],
last_tile_material_count: usize,
last_hillshade_material_count: usize,
}
impl FogDirtyState {
fn quantise_vec4(v: Vec4) -> [i32; 4] {
[
(v.x * 1000.0) as i32,
(v.y * 1000.0) as i32,
(v.z * 1000.0) as i32,
(v.w * 1000.0) as i32,
]
}
fn quantise_vec3(x: f32, y: f32, z: f32) -> [i32; 3] {
[
(x * 1000.0) as i32,
(y * 1000.0) as i32,
(z * 1000.0) as i32,
]
}
}
pub(crate) fn sync_horizon_fade(
state: Res<MapStateResource>,
mut materials: ResMut<Assets<TileFogMaterial>>,
mut hillshade_materials: ResMut<Assets<HillshadeMaterial>>,
mut dirty: ResMut<FogDirtyState>,
detection: Res<FrameChangeDetection>,
) {
let tile_count = materials.len();
let hillshade_count = hillshade_materials.len();
if frame_unchanged(&detection, &state.0)
&& tile_count == dirty.last_tile_material_count
&& hillshade_count == dirty.last_hillshade_material_count
{
return;
}
let cam = state.0.camera();
let fog = state.0.computed_fog();
let hillshade = state.0.hillshade().unwrap_or_default();
let eye = cam.eye_offset();
let eye_pos = Vec4::new(eye.x as f32, eye.y as f32, eye.z as f32, 0.0);
let fog_params = Vec4::new(fog.fog_start, fog.fog_end, fog.fog_density, 0.0);
let fog_color = Vec4::new(
fog.fog_color[0],
fog.fog_color[1],
fog.fog_color[2],
fog.fog_color[3],
);
let hs_highlight = Vec4::from_array(hillshade.highlight_color);
let hs_shadow = Vec4::from_array(hillshade.shadow_color);
let hs_accent = Vec4::from_array(hillshade.accent_color);
let hs_light = Vec4::new(
hillshade.illumination_direction,
hillshade.illumination_altitude,
hillshade.exaggeration,
hillshade.opacity,
);
let q_eye = FogDirtyState::quantise_vec3(eye.x as f32, eye.y as f32, eye.z as f32);
let q_fog = FogDirtyState::quantise_vec4(fog_params);
let q_color = FogDirtyState::quantise_vec4(fog_color);
let q_highlight = FogDirtyState::quantise_vec4(hs_highlight);
let q_shadow = FogDirtyState::quantise_vec4(hs_shadow);
let q_accent = FogDirtyState::quantise_vec4(hs_accent);
let q_light = FogDirtyState::quantise_vec4(hs_light);
let params_changed = q_eye != dirty.last_eye_pos
|| q_fog != dirty.last_fog_params
|| q_color != dirty.last_fog_color
|| q_highlight != dirty.last_hillshade_highlight
|| q_shadow != dirty.last_hillshade_shadow
|| q_accent != dirty.last_hillshade_accent
|| q_light != dirty.last_hillshade_light;
let tile_materials_added = tile_count != dirty.last_tile_material_count;
let hillshade_materials_added = hillshade_count != dirty.last_hillshade_material_count;
if !params_changed && !tile_materials_added && !hillshade_materials_added {
return;
}
if params_changed || tile_materials_added {
for (_id, mat) in materials.iter_mut() {
mat.fog.eye_pos = eye_pos;
mat.fog.fog_params = fog_params;
mat.fog.fog_color = fog_color;
mat.fog.hillshade_highlight = hs_highlight;
mat.fog.hillshade_shadow = hs_shadow;
mat.fog.hillshade_accent = hs_accent;
mat.fog.hillshade_light = hs_light;
}
}
if params_changed || hillshade_materials_added {
for (_id, mat) in hillshade_materials.iter_mut() {
mat.fog.eye_pos = eye_pos;
mat.fog.fog_params = fog_params;
mat.fog.fog_color = fog_color;
mat.fog.hillshade_highlight = hs_highlight;
mat.fog.hillshade_shadow = hs_shadow;
mat.fog.hillshade_accent = hs_accent;
mat.fog.hillshade_light = hs_light;
}
}
dirty.last_eye_pos = q_eye;
dirty.last_fog_params = q_fog;
dirty.last_fog_color = q_color;
dirty.last_hillshade_highlight = q_highlight;
dirty.last_hillshade_shadow = q_shadow;
dirty.last_hillshade_accent = q_accent;
dirty.last_hillshade_light = q_light;
dirty.last_tile_material_count = tile_count;
dirty.last_hillshade_material_count = hillshade_count;
}