#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
use super::SceneType;
use super::ViewerSettings;
use bevy::prelude::*;
use eulumdat::Eulumdat;
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
const LDT_STORAGE_KEY: &str = "eulumdat_current_ldt";
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
const LDT_TIMESTAMP_KEY: &str = "eulumdat_ldt_timestamp";
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
const VIEWER_SETTINGS_KEY: &str = "eulumdat_viewer_settings";
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
const VIEWER_SETTINGS_TIMESTAMP_KEY: &str = "eulumdat_viewer_settings_timestamp";
#[derive(Resource, Default)]
pub struct LdtTimestamp(pub String);
#[derive(Resource, Default)]
pub struct ViewerSettingsTimestamp(pub String);
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
pub fn load_from_local_storage() -> Option<Eulumdat> {
let window = web_sys::window()?;
let storage = window.local_storage().ok()??;
let ldt_string = storage.get_item(LDT_STORAGE_KEY).ok()??;
web_sys::console::log_1(
&format!(
"[Bevy] Loading LDT from localStorage, {} bytes",
ldt_string.len()
)
.into(),
);
match Eulumdat::parse(&ldt_string) {
Ok(ldt) => {
web_sys::console::log_1(
&format!(
"[Bevy] Parsed LDT: {} lumens, {} cd/klm max",
ldt.total_luminous_flux(),
ldt.max_intensity()
)
.into(),
);
Some(ldt)
}
Err(e) => {
web_sys::console::error_1(&format!("[Bevy] Failed to parse LDT: {:?}", e).into());
None
}
}
}
#[cfg(not(all(target_arch = "wasm32", feature = "wasm-sync")))]
pub fn load_from_local_storage() -> Option<Eulumdat> {
None
}
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
pub fn get_ldt_timestamp() -> Option<String> {
let window = web_sys::window()?;
let storage = window.local_storage().ok()??;
storage.get_item(LDT_TIMESTAMP_KEY).ok()?
}
#[cfg(not(all(target_arch = "wasm32", feature = "wasm-sync")))]
pub fn get_ldt_timestamp() -> Option<String> {
None
}
pub fn load_default_ldt() -> Option<Eulumdat> {
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
{
load_from_local_storage()
}
#[cfg(all(target_arch = "wasm32", not(feature = "wasm-sync")))]
{
None
}
#[cfg(not(target_arch = "wasm32"))]
{
let sample_paths = [
"crates/eulumdat-wasm/templates/road_luminaire.ldt",
"../eulumdat-wasm/templates/road_luminaire.ldt",
"crates/eulumdat-wasm/templates/fluorescent_luminaire.ldt",
"../eulumdat-wasm/templates/fluorescent_luminaire.ldt",
"templates/road_luminaire.ldt",
"sample.ldt",
];
for path in sample_paths {
if let Ok(ldt) = Eulumdat::from_file(path) {
return Some(ldt);
}
}
None
}
}
#[cfg(feature = "wasm-sync")]
#[allow(unused_mut, unused_variables)]
pub fn poll_ldt_changes(
mut settings: ResMut<ViewerSettings>,
mut last_timestamp: ResMut<LdtTimestamp>,
) {
#[cfg(target_arch = "wasm32")]
{
if let Some(new_timestamp) = get_ldt_timestamp() {
if new_timestamp != last_timestamp.0 {
web_sys::console::log_1(
&format!(
"[Bevy] LDT timestamp changed: {} -> {}",
last_timestamp.0, new_timestamp
)
.into(),
);
if let Some(ldt) = load_from_local_storage() {
web_sys::console::log_1(
&format!("[Bevy] Updating ViewerSettings with new LDT").into(),
);
settings.ldt_data = Some(ldt);
last_timestamp.0 = new_timestamp;
}
}
}
}
}
#[cfg(not(feature = "wasm-sync"))]
#[allow(unused_mut, unused_variables, dead_code)]
pub fn poll_ldt_changes(
mut settings: ResMut<ViewerSettings>,
mut last_timestamp: ResMut<LdtTimestamp>,
) {
}
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
pub fn get_viewer_settings_timestamp() -> Option<String> {
let window = web_sys::window()?;
let storage = window.local_storage().ok()??;
storage.get_item(VIEWER_SETTINGS_TIMESTAMP_KEY).ok()?
}
#[cfg(not(all(target_arch = "wasm32", feature = "wasm-sync")))]
pub fn get_viewer_settings_timestamp() -> Option<String> {
None
}
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
pub fn load_viewer_settings_from_local_storage(current: &ViewerSettings) -> Option<ViewerSettings> {
let window = web_sys::window()?;
let storage = window.local_storage().ok()??;
let json_string = storage.get_item(VIEWER_SETTINGS_KEY).ok()??;
parse_viewer_settings_json(&json_string, current)
}
#[cfg(not(all(target_arch = "wasm32", feature = "wasm-sync")))]
pub fn load_viewer_settings_from_local_storage(
_current: &ViewerSettings,
) -> Option<ViewerSettings> {
None
}
#[cfg(all(target_arch = "wasm32", feature = "wasm-sync"))]
fn parse_viewer_settings_json(json: &str, current: &ViewerSettings) -> Option<ViewerSettings> {
let get_f32 = |key: &str| -> Option<f32> {
let pattern = format!("\"{}\":", key);
let start = json.find(&pattern)? + pattern.len();
let rest = &json[start..];
let end = rest.find([',', '}'])?;
rest[..end].trim().parse().ok()
};
let get_bool = |key: &str| -> Option<bool> {
let pattern = format!("\"{}\":", key);
let start = json.find(&pattern)? + pattern.len();
let rest = &json[start..];
let end = rest.find([',', '}'])?;
let value = rest[..end].trim();
Some(value == "true")
};
let get_u8 = |key: &str| -> Option<u8> {
let pattern = format!("\"{}\":", key);
let start = json.find(&pattern)? + pattern.len();
let rest = &json[start..];
let end = rest.find([',', '}'])?;
rest[..end].trim().parse().ok()
};
let scene_type = match get_u8("scene_type")? {
0 => SceneType::Room,
1 => SceneType::Road,
2 => SceneType::Parking,
3 => SceneType::Outdoor,
_ => SceneType::Room,
};
Some(ViewerSettings {
scene_type,
room_width: get_f32("room_width").unwrap_or(current.room_width),
room_length: get_f32("room_length").unwrap_or(current.room_length),
room_height: get_f32("room_height").unwrap_or(current.room_height),
mounting_height: get_f32("mounting_height").unwrap_or(current.mounting_height),
pendulum_length: get_f32("pendulum_length").unwrap_or(current.pendulum_length),
light_intensity: get_f32("light_intensity").unwrap_or(current.light_intensity),
show_luminaire: get_bool("show_luminaire").unwrap_or(current.show_luminaire),
show_photometric_solid: get_bool("show_photometric_solid")
.unwrap_or(current.show_photometric_solid),
show_shadows: get_bool("show_shadows").unwrap_or(current.show_shadows),
ldt_data: current.ldt_data.clone(),
luminaire_tilt: get_f32("luminaire_tilt").unwrap_or(current.luminaire_tilt),
lane_width: get_f32("lane_width").unwrap_or(current.lane_width),
num_lanes: get_u8("num_lanes").unwrap_or(current.num_lanes as u8) as u32,
sidewalk_width: get_f32("sidewalk_width").unwrap_or(current.sidewalk_width),
pole_spacing: get_f32("pole_spacing").unwrap_or(current.pole_spacing),
})
}
#[cfg(feature = "wasm-sync")]
#[allow(unused_mut, unused_variables)]
pub fn poll_viewer_settings_changes(
mut settings: ResMut<ViewerSettings>,
mut last_timestamp: ResMut<ViewerSettingsTimestamp>,
) {
#[cfg(target_arch = "wasm32")]
{
if let Some(new_timestamp) = get_viewer_settings_timestamp() {
if new_timestamp != last_timestamp.0 {
if let Some(new_settings) = load_viewer_settings_from_local_storage(&settings) {
*settings = new_settings;
last_timestamp.0 = new_timestamp;
}
}
}
}
}
#[cfg(not(feature = "wasm-sync"))]
#[allow(unused_mut, unused_variables, dead_code)]
pub fn poll_viewer_settings_changes(
mut settings: ResMut<ViewerSettings>,
mut last_timestamp: ResMut<ViewerSettingsTimestamp>,
) {
}