feat: full egui control panel + pointer routing

This commit is contained in:
xfy 2026-07-13 09:57:54 +08:00
parent 90e8c9b3a4
commit 7e0ac65d55
3 changed files with 56 additions and 7 deletions

View File

@ -24,6 +24,10 @@ impl Default for OrbitCamera {
} }
} }
/// Set by the UI system each frame; the orbit controller ignores input when true.
#[derive(Resource, Default)]
pub struct WantsPointer(pub bool);
impl OrbitCamera { impl OrbitCamera {
/// Compute the camera eye position and an orthonormal basis (forward/right/up) /// Compute the camera eye position and an orthonormal basis (forward/right/up)
/// in Bevy's right-handed Y-up coordinate system. The black hole sits at origin. /// in Bevy's right-handed Y-up coordinate system. The black hole sits at origin.
@ -50,11 +54,18 @@ impl OrbitCamera {
} }
pub fn orbit_controller( pub fn orbit_controller(
wants: Res<WantsPointer>,
mut camera: ResMut<OrbitCamera>, mut camera: ResMut<OrbitCamera>,
mouse: Res<ButtonInput<MouseButton>>, mouse: Res<ButtonInput<MouseButton>>,
mut motion: MessageReader<MouseMotion>, mut motion: MessageReader<MouseMotion>,
mut wheel: MessageReader<MouseWheel>, mut wheel: MessageReader<MouseWheel>,
) { ) {
if wants.0 {
// egui is using the pointer: drain events so they don't pile up, and ignore.
motion.clear();
wheel.clear();
return;
}
if mouse.pressed(MouseButton::Left) { if mouse.pressed(MouseButton::Left) {
for ev in motion.read() { for ev in motion.read() {
camera.yaw -= ev.delta.x * 0.005; camera.yaw -= ev.delta.x * 0.005;

View File

@ -8,6 +8,7 @@ pub struct BlackHolePlugin;
impl Plugin for BlackHolePlugin { impl Plugin for BlackHolePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<crate::camera::OrbitCamera>() app.init_resource::<crate::camera::OrbitCamera>()
.init_resource::<crate::camera::WantsPointer>()
.init_resource::<crate::params::BlackHoleParams>() .init_resource::<crate::params::BlackHoleParams>()
.add_plugins(Material2dPlugin::<BlackHoleMaterial>::default()) .add_plugins(Material2dPlugin::<BlackHoleMaterial>::default())
.add_plugins(bevy_egui::EguiPlugin::default()) .add_plugins(bevy_egui::EguiPlugin::default())

View File

@ -4,14 +4,51 @@ use bevy_egui::egui;
pub fn ui_system( pub fn ui_system(
mut contexts: bevy_egui::EguiContexts, mut contexts: bevy_egui::EguiContexts,
mut params: ResMut<crate::params::BlackHoleParams>, mut params: ResMut<crate::params::BlackHoleParams>,
mut camera: ResMut<crate::camera::OrbitCamera>,
mut wants: ResMut<crate::camera::WantsPointer>,
) { ) {
if let Ok(ctx) = contexts.ctx_mut() { if let Ok(ctx) = contexts.ctx_mut() {
egui::Window::new("Controls").show(ctx, |ui| { egui::Window::new("Controls")
ui.add( .collapsible(true)
egui::Slider::new(&mut params.disk_brightness, 0.0..=3.0) .default_pos([16.0, 16.0])
.text("Disk brightness"), .show(ctx, |ui| {
); egui::CollapsingHeader::new("Camera")
ui.add(egui::Slider::new(&mut params.steps, 50..=600).text("Steps")); .default_open(true)
.show(ui, |ui| {
ui.add(egui::Slider::new(&mut camera.distance, 3.0..=200.0).text("Distance"));
ui.add(egui::Slider::new(&mut camera.yaw, -3.14..=3.14).text("Yaw"));
ui.add(egui::Slider::new(&mut camera.pitch, 0.05..=3.09).text("Pitch"));
ui.add(egui::Slider::new(&mut camera.fov, 0.3..=2.0).text("FOV"));
}); });
egui::CollapsingHeader::new("Accretion Disk")
.default_open(true)
.show(ui, |ui| {
ui.add(egui::Slider::new(&mut params.disk_inner, 1.5..=6.0).text("Inner radius"));
ui.add(egui::Slider::new(&mut params.disk_outer, 6.0..=40.0).text("Outer radius"));
ui.add(egui::Slider::new(&mut params.disk_tilt, 0.0..=3.14).text("Tilt"));
ui.add(egui::Slider::new(&mut params.disk_brightness, 0.0..=3.0).text("Brightness"));
ui.add(egui::Slider::new(&mut params.disk_rotation_speed, 0.0..=3.0).text("Rotation speed"));
});
egui::CollapsingHeader::new("Doppler").show(ui, |ui| {
ui.checkbox(&mut params.doppler_enabled, "Enabled");
ui.add_enabled(params.doppler_enabled, egui::Slider::new(&mut params.doppler_strength, 0.0..=3.0).text("Strength"));
});
egui::CollapsingHeader::new("Renderer").show(ui, |ui| {
ui.add(egui::Slider::new(&mut params.steps, 50..=600).text("Steps"));
ui.add(egui::Slider::new(&mut params.render_scale, 0.5..=1.0).text("Render scale"));
});
egui::CollapsingHeader::new("Background").show(ui, |ui| {
ui.add(egui::Slider::new(&mut params.star_intensity, 0.0..=3.0).text("Star intensity"));
ui.add(egui::Slider::new(&mut params.skybox_intensity, 0.0..=3.0).text("Skybox intensity"));
});
egui::CollapsingHeader::new("Grid").show(ui, |ui| {
ui.checkbox(&mut params.grid_enabled, "Enabled");
ui.add_enabled(params.grid_enabled, egui::Slider::new(&mut params.grid_density, 0.1..=4.0).text("Density"));
});
});
// egui captures pointer when the cursor is over a window or being interacted with.
wants.0 = ctx.egui_wants_pointer_input();
} else {
wants.0 = false;
} }
} }