eulumdat_bevy/viewer/
plugin.rs1use super::camera::CameraPlugin;
10use super::controls::{
11 calculate_all_luminaire_transforms, sync_viewer_to_lights, viewer_controls_system,
12};
13use super::scenes::ScenePlugin;
14use super::wasm_sync::{load_default_ldt, LdtTimestamp, ViewerSettingsTimestamp};
15use super::ViewerSettings;
16use crate::eulumdat_impl::EulumdatLightBundle;
17use crate::photometric::PhotometricPlugin;
18use bevy::prelude::*;
19use eulumdat::Eulumdat;
20
21pub struct EulumdatViewerPlugin {
44 pub initial_ldt: Option<Eulumdat>,
46 pub enable_keyboard_controls: bool,
48 pub enable_local_storage_sync: bool,
51}
52
53impl Default for EulumdatViewerPlugin {
54 fn default() -> Self {
55 Self {
56 initial_ldt: None,
57 enable_keyboard_controls: true,
58 enable_local_storage_sync: cfg!(feature = "wasm-sync"),
59 }
60 }
61}
62
63impl EulumdatViewerPlugin {
64 pub fn new() -> Self {
66 Self::default()
67 }
68
69 pub fn with_ldt(ldt: Eulumdat) -> Self {
71 Self {
72 initial_ldt: Some(ldt),
73 enable_keyboard_controls: true,
74 enable_local_storage_sync: cfg!(feature = "wasm-sync"),
75 }
76 }
77}
78
79impl Plugin for EulumdatViewerPlugin {
80 fn build(&self, app: &mut App) {
81 app.add_plugins(PhotometricPlugin::<Eulumdat>::new());
83
84 app.add_plugins((CameraPlugin, ScenePlugin));
86
87 let settings = ViewerSettings {
89 ldt_data: self.initial_ldt.clone(),
90 ..default()
91 };
92 app.insert_resource(settings);
93 app.insert_resource(LdtTimestamp::default());
94 app.insert_resource(ViewerSettingsTimestamp::default());
95
96 app.add_systems(Startup, setup_viewer_light);
98
99 if self.enable_keyboard_controls {
101 app.add_systems(Update, viewer_controls_system);
102 }
103
104 #[cfg(feature = "wasm-sync")]
108 if self.enable_local_storage_sync {
109 app.add_systems(
110 Update,
111 (
112 super::wasm_sync::poll_ldt_changes,
113 super::wasm_sync::poll_viewer_settings_changes,
114 sync_ldt_to_light,
115 ApplyDeferred,
116 sync_viewer_to_lights,
117 )
118 .chain(),
119 );
120 }
121
122 #[cfg(not(feature = "wasm-sync"))]
124 app.add_systems(Update, sync_viewer_to_lights);
125
126 #[cfg(all(feature = "egui-ui", not(target_arch = "wasm32")))]
128 {
129 app.add_plugins(super::egui_panel::EguiSettingsPlugin);
130 }
131 }
132}
133
134fn setup_viewer_light(mut commands: Commands, settings: Res<ViewerSettings>) {
136 let ldt = settings.ldt_data.clone().or_else(load_default_ldt);
138
139 if let Some(ldt_data) = ldt {
140 let transforms = calculate_all_luminaire_transforms(&settings, &ldt_data);
142
143 for transform in transforms {
144 commands.spawn(
145 EulumdatLightBundle::new(ldt_data.clone())
146 .with_transform(
147 Transform::from_translation(transform.position)
148 .with_rotation(transform.rotation),
149 )
150 .with_solid(settings.show_photometric_solid)
151 .with_model(settings.show_luminaire)
152 .with_shadows(settings.show_shadows),
153 );
154 }
155 }
156}
157
158#[cfg(feature = "wasm-sync")]
161fn sync_ldt_to_light(
162 mut commands: Commands,
163 settings: Res<ViewerSettings>,
164 lights: Query<Entity, With<crate::photometric::PhotometricLight<Eulumdat>>>,
165) {
166 if !settings.is_changed() {
167 return;
168 }
169
170 if let Some(ref new_ldt) = settings.ldt_data {
171 for entity in lights.iter() {
173 commands.entity(entity).despawn();
174 }
175
176 let transforms = calculate_all_luminaire_transforms(&settings, new_ldt);
178
179 #[cfg(target_arch = "wasm32")]
180 web_sys::console::log_1(&format!("[Bevy] Spawning {} luminaires", transforms.len()).into());
181
182 for transform in transforms {
183 commands.spawn(
184 EulumdatLightBundle::new(new_ldt.clone())
185 .with_transform(
186 Transform::from_translation(transform.position)
187 .with_rotation(transform.rotation),
188 )
189 .with_solid(settings.show_photometric_solid)
190 .with_model(settings.show_luminaire)
191 .with_shadows(settings.show_shadows),
192 );
193 }
194 }
195}