diff --git a/CHANGELOG.md b/CHANGELOG.md index 140aa4f..e486e8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## Version 0.9 +- update to bevy 0.14 + ## Version 0.8 - update to bevy 0.13 diff --git a/Cargo.toml b/Cargo.toml index 8752c13..77057ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.8.1" +version = "0.9.0" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/jakobhellermann/bevy_editor_pls" @@ -11,14 +11,15 @@ description = "In-App editor tools for bevy apps" readme = "README.md" [workspace.dependencies] -bevy_editor_pls = { version = "0.8.0", path = "crates/bevy_editor_pls" } -bevy_editor_pls_core = { version = "0.8.0", path = "crates/bevy_editor_pls_core" } -bevy_editor_pls_default_windows = { version = "0.8.0", path = "crates/bevy_editor_pls_default_windows" } +bevy_editor_pls = { version = "0.9.0", path = "crates/bevy_editor_pls" } +bevy_editor_pls_core = { version = "0.9.0", path = "crates/bevy_editor_pls_core" } +bevy_editor_pls_default_windows = { version = "0.9.0", path = "crates/bevy_editor_pls_default_windows" } -bevy-inspector-egui = "0.23.0" -egui = "0.26" -egui_dock = "0.11" -egui-gizmo = "0.16" +bevy-inspector-egui = "0.25.0" +egui = "0.28" +egui_dock = "0.13" +# used to be egui-gizmo 0.16 +transform-gizmo-bevy = "0.3" [profile.dev.package."*"] opt-level = 2 diff --git a/README.md b/README.md index a06f385..5a11922 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ fn set_cam3d_controls( | bevy | bevy\_editor\_pls | | ---- | ----------------- | +| 0.14 | 0.9 | | 0.13 | 0.8 | | 0.12 | 0.7 | | 0.12 | 0.6 | diff --git a/crates/bevy_editor_pls/Cargo.toml b/crates/bevy_editor_pls/Cargo.toml index 3655b2e..fafb5d7 100644 --- a/crates/bevy_editor_pls/Cargo.toml +++ b/crates/bevy_editor_pls/Cargo.toml @@ -22,13 +22,13 @@ default = ["default_windows"] [dependencies] bevy_editor_pls_core.workspace = true bevy_editor_pls_default_windows = { workspace = true, optional = true } -bevy = { version = "0.13", default-features = false, features = ["x11"] } +bevy = { version = "0.14", default-features = false, features = ["x11"] } egui.workspace = true -egui-gizmo.workspace = true +transform-gizmo-bevy.workspace = true # bevy_framepace = { version = "0.12", default-features = false } [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = [ +bevy = { version = "0.14", default-features = false, features = [ "bevy_winit", "bevy_core_pipeline", "x11", diff --git a/crates/bevy_editor_pls/examples/2d_3d_mixed.rs b/crates/bevy_editor_pls/examples/2d_3d_mixed.rs index da57d80..603aa31 100644 --- a/crates/bevy_editor_pls/examples/2d_3d_mixed.rs +++ b/crates/bevy_editor_pls/examples/2d_3d_mixed.rs @@ -9,10 +9,13 @@ fn main() { } fn setup_2d(mut commands: Commands) { - commands.spawn(Camera2dBundle::default()); + commands.spawn(Camera2dBundle { + camera: Camera { order: 1, ..Default::default() }, + ..Default::default() + }); commands.spawn(SpriteBundle { sprite: Sprite { - color: Color::rgb(0.25, 0.25, 0.75), + color: Color::srgb(0.25, 0.25, 0.75), custom_size: Some(Vec2::new(50.0, 50.0)), ..Default::default() }, @@ -26,13 +29,13 @@ fn setup_3d( mut materials: ResMut>, ) { commands.spawn(PbrBundle { - mesh: meshes.add(Plane3d::new(Vec3::Y).mesh().size(0.5, 0.5)), - material: materials.add(Color::rgb(0.3, 0.5, 0.3)), + mesh: meshes.add(Plane3d::new(Vec3::Y, Vec2::new(0.25, 0.25)).mesh()), + material: materials.add(Color::srgb(0.3, 0.5, 0.3)), ..Default::default() }); commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(Cuboid::from_size(Vec3::ONE))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6)), + material: materials.add(Color::srgb(0.8, 0.7, 0.6)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..Default::default() }); diff --git a/crates/bevy_editor_pls/examples/basic.rs b/crates/bevy_editor_pls/examples/basic.rs index 31d161d..708e4d0 100644 --- a/crates/bevy_editor_pls/examples/basic.rs +++ b/crates/bevy_editor_pls/examples/basic.rs @@ -36,15 +36,15 @@ fn setup( ) { // plane commands.spawn(PbrBundle { - // mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0))), - mesh: meshes.add(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0)), - material: materials.add(Color::rgb(0.3, 0.5, 0.3)), + // mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y, Vec2::new(2.5, 2.5)).mesh())), + mesh: meshes.add(Plane3d::new(Vec3::Y, Vec2::new(2.5, 2.5)).mesh()), + material: materials.add(Color::srgb(0.3, 0.5, 0.3)), ..Default::default() }); // cube commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(Cuboid::from_size(Vec3::ONE))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6)), + material: materials.add(Color::srgb(0.8, 0.7, 0.6)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..Default::default() }); diff --git a/crates/bevy_editor_pls/examples/breakout.rs b/crates/bevy_editor_pls/examples/breakout.rs index 7ee53d7..bf30d19 100644 --- a/crates/bevy_editor_pls/examples/breakout.rs +++ b/crates/bevy_editor_pls/examples/breakout.rs @@ -39,13 +39,13 @@ const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0; const SCOREBOARD_FONT_SIZE: f32 = 40.0; const SCOREBOARD_TEXT_PADDING: Val = Val::Px(5.0); -const BACKGROUND_COLOR: Color = Color::rgb(0.9, 0.9, 0.9); -const PADDLE_COLOR: Color = Color::rgb(0.3, 0.3, 0.7); -const BALL_COLOR: Color = Color::rgb(1.0, 0.5, 0.5); -const BRICK_COLOR: Color = Color::rgb(0.5, 0.5, 1.0); -const WALL_COLOR: Color = Color::rgb(0.8, 0.8, 0.8); -const TEXT_COLOR: Color = Color::rgb(0.5, 0.5, 1.0); -const SCORE_COLOR: Color = Color::rgb(1.0, 0.5, 0.5); +const BACKGROUND_COLOR: Color = Color::srgb(0.9, 0.9, 0.9); +const PADDLE_COLOR: Color = Color::srgb(0.3, 0.3, 0.7); +const BALL_COLOR: Color = Color::srgb(1.0, 0.5, 0.5); +const BRICK_COLOR: Color = Color::srgb(0.5, 0.5, 1.0); +const WALL_COLOR: Color = Color::srgb(0.8, 0.8, 0.8); +const TEXT_COLOR: Color = Color::srgb(0.5, 0.5, 1.0); +const SCORE_COLOR: Color = Color::srgb(1.0, 0.5, 0.5); fn main() { App::new() @@ -63,7 +63,7 @@ fn main() { // `chain`ing systems together runs them in order .chain(), ) - .add_systems(Update, (update_scoreboard, bevy::window::close_on_esc)) + .add_systems(Update, (update_scoreboard, close_on_esc)) .run(); } @@ -417,3 +417,19 @@ fn collide_with_side(ball: BoundingCircle, wall: Aabb2d) -> Option { Some(side) } + +fn close_on_esc( + mut commands: Commands, + focused_windows: Query<(Entity, &Window)>, + input: Res>, +) { + for (window, focus) in focused_windows.iter() { + if !focus.focused { + continue; + } + + if input.just_pressed(KeyCode::Escape) { + commands.entity(window).despawn(); + } + } +} diff --git a/crates/bevy_editor_pls/examples/controls.rs b/crates/bevy_editor_pls/examples/controls.rs index 6f04f34..f037496 100644 --- a/crates/bevy_editor_pls/examples/controls.rs +++ b/crates/bevy_editor_pls/examples/controls.rs @@ -43,14 +43,14 @@ fn setup( ) { // plane commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0))), - material: materials.add(Color::rgb(0.3, 0.5, 0.3)), + mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y, Vec2::new(2.5, 2.5)).mesh())), + material: materials.add(Color::srgb(0.3, 0.5, 0.3)), ..Default::default() }); // cube commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(Cuboid::from_size(Vec3::ONE))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6)), + material: materials.add(Color::srgb(0.8, 0.7, 0.6)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..Default::default() }); diff --git a/crates/bevy_editor_pls/examples/separate_window.rs b/crates/bevy_editor_pls/examples/separate_window.rs index 42bd726..54e5be2 100644 --- a/crates/bevy_editor_pls/examples/separate_window.rs +++ b/crates/bevy_editor_pls/examples/separate_window.rs @@ -18,14 +18,14 @@ fn setup( ) { // plane commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0))), - material: materials.add(Color::rgb(0.3, 0.5, 0.3)), + mesh: meshes.add(Mesh::from(Plane3d::new(Vec3::Y, Vec2::new(2.5, 2.5)).mesh())), + material: materials.add(Color::srgb(0.3, 0.5, 0.3)), ..Default::default() }); // cube commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(Cuboid::from_size(Vec3::ONE))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6)), + material: materials.add(Color::srgb(0.8, 0.7, 0.6)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..Default::default() }); diff --git a/crates/bevy_editor_pls/examples/ui.rs b/crates/bevy_editor_pls/examples/ui.rs index 70e9aa0..2b55009 100644 --- a/crates/bevy_editor_pls/examples/ui.rs +++ b/crates/bevy_editor_pls/examples/ui.rs @@ -43,7 +43,7 @@ fn setup(mut commands: Commands, asset_server: Res) { border: UiRect::all(Val::Px(2.0)), ..default() }, - background_color: Color::rgb(0.65, 0.65, 0.65).into(), + background_color: Color::srgb(0.65, 0.65, 0.65).into(), ..default() }) .with_children(|parent| { @@ -55,7 +55,7 @@ fn setup(mut commands: Commands, asset_server: Res) { height: Val::Percent(100.0), ..default() }, - background_color: Color::rgb(0.15, 0.15, 0.15).into(), + background_color: Color::srgb(0.15, 0.15, 0.15).into(), ..default() }) .with_children(|parent| { @@ -86,7 +86,7 @@ fn setup(mut commands: Commands, asset_server: Res) { height: Val::Percent(100.0), ..default() }, - background_color: Color::rgb(0.15, 0.15, 0.15).into(), + background_color: Color::srgb(0.15, 0.15, 0.15).into(), ..default() }) .with_children(|parent| { @@ -122,7 +122,7 @@ fn setup(mut commands: Commands, asset_server: Res) { overflow: Overflow::clip(), ..default() }, - background_color: Color::rgb(0.10, 0.10, 0.10).into(), + background_color: Color::srgb(0.10, 0.10, 0.10).into(), ..default() }) .with_children(|parent| { @@ -178,7 +178,7 @@ fn setup(mut commands: Commands, asset_server: Res) { border: UiRect::all(Val::Px(20.0)), ..default() }, - background_color: Color::rgb(0.4, 0.4, 1.0).into(), + background_color: Color::srgb(0.4, 0.4, 1.0).into(), ..default() }) .with_children(|parent| { @@ -188,7 +188,7 @@ fn setup(mut commands: Commands, asset_server: Res) { height: Val::Percent(100.0), ..default() }, - background_color: Color::rgb(0.8, 0.8, 1.0).into(), + background_color: Color::srgb(0.8, 0.8, 1.0).into(), ..default() }); }); @@ -213,7 +213,7 @@ fn setup(mut commands: Commands, asset_server: Res) { height: Val::Px(100.0), ..default() }, - background_color: Color::rgb(1.0, 0.0, 0.0).into(), + background_color: Color::srgb(1.0, 0.0, 0.0).into(), ..default() }) .with_children(|parent| { @@ -226,7 +226,7 @@ fn setup(mut commands: Commands, asset_server: Res) { bottom: Val::Px(20.0), ..default() }, - background_color: Color::rgb(1.0, 0.3, 0.3).into(), + background_color: Color::srgb(1.0, 0.3, 0.3).into(), ..default() }); parent.spawn(NodeBundle { @@ -238,7 +238,7 @@ fn setup(mut commands: Commands, asset_server: Res) { bottom: Val::Px(40.0), ..default() }, - background_color: Color::rgb(1.0, 0.5, 0.5).into(), + background_color: Color::srgb(1.0, 0.5, 0.5).into(), ..default() }); parent.spawn(NodeBundle { @@ -250,7 +250,7 @@ fn setup(mut commands: Commands, asset_server: Res) { bottom: Val::Px(60.0), ..default() }, - background_color: Color::rgb(1.0, 0.7, 0.7).into(), + background_color: Color::srgb(1.0, 0.7, 0.7).into(), ..default() }); // alpha test @@ -263,7 +263,7 @@ fn setup(mut commands: Commands, asset_server: Res) { bottom: Val::Px(80.0), ..default() }, - background_color: Color::rgba(1.0, 0.9, 0.9, 0.4).into(), + background_color: Color::srgba(1.0, 0.9, 0.9, 0.4).into(), ..default() }); }); diff --git a/crates/bevy_editor_pls/src/controls.rs b/crates/bevy_editor_pls/src/controls.rs index 78e0f74..d3b0f73 100644 --- a/crates/bevy_editor_pls/src/controls.rs +++ b/crates/bevy_editor_pls/src/controls.rs @@ -136,6 +136,8 @@ pub enum Action { PauseUnpauseTime, FocusSelected, + // maybe investigate [GizmoOptions].hotkeys + // https://docs.rs/transform-gizmo-bevy/latest/transform_gizmo_bevy/struct.GizmoHotkeys.html #[cfg(feature = "default_windows")] SetGizmoModeTranslate, #[cfg(feature = "default_windows")] @@ -240,7 +242,7 @@ pub fn editor_controls_system( editor .window_state_mut::() .unwrap() - .gizmo_mode = egui_gizmo::GizmoMode::Translate; + .gizmo_modes = transform_gizmo_bevy::GizmoMode::all_translate(); } if controls.just_pressed( Action::SetGizmoModeRotate, @@ -251,7 +253,7 @@ pub fn editor_controls_system( editor .window_state_mut::() .unwrap() - .gizmo_mode = egui_gizmo::GizmoMode::Rotate; + .gizmo_modes = transform_gizmo_bevy::GizmoMode::all_rotate(); } if controls.just_pressed( Action::SetGizmoModeScale, @@ -262,7 +264,7 @@ pub fn editor_controls_system( editor .window_state_mut::() .unwrap() - .gizmo_mode = egui_gizmo::GizmoMode::Scale; + .gizmo_modes = transform_gizmo_bevy::GizmoMode::all_scale(); } } } @@ -395,7 +397,7 @@ impl EditorWindow for ControlsWindow { ui.label(egui::RichText::new(action.to_string()).strong()); let bindings = controls.get(action); for binding in bindings { - ui.add(egui::Label::new(format!("{}", binding)).wrap(false)); + ui.add(egui::Label::new(format!("{}", binding)).extend()); } } } diff --git a/crates/bevy_editor_pls/src/lib.rs b/crates/bevy_editor_pls/src/lib.rs index f479693..aeaddb9 100644 --- a/crates/bevy_editor_pls/src/lib.rs +++ b/crates/bevy_editor_pls/src/lib.rs @@ -85,7 +85,7 @@ impl Plugin for EditorPlugin { if window.title == "Bevy App" { window.title = "bevy_editor_pls".into(); } - let entity = app.world.spawn(window); + let entity = app.world_mut().spawn(window); WindowRef::Entity(entity.id()) } EditorWindowPlacement::Window(entity) => WindowRef::Entity(entity), @@ -128,10 +128,15 @@ impl Plugin for EditorPlugin { app.add_plugins(bevy::pbr::wireframe::WireframePlugin); + // required for the GizmoWindow + if !app.is_plugin_added::() { + app.add_plugins(transform_gizmo_bevy::TransformGizmoPlugin); + } + app.insert_resource(controls::EditorControls::default_bindings()) .add_systems(Update, controls::editor_controls_system); - let mut internal_state = app.world.resource_mut::(); + let mut internal_state = app.world_mut().resource_mut::(); let [game, _inspector] = internal_state.split_right::(egui_dock::NodeIndex::root(), 0.75); diff --git a/crates/bevy_editor_pls_core/Cargo.toml b/crates/bevy_editor_pls_core/Cargo.toml index a39a774..550e53e 100644 --- a/crates/bevy_editor_pls_core/Cargo.toml +++ b/crates/bevy_editor_pls_core/Cargo.toml @@ -8,7 +8,7 @@ description.workspace = true readme.workspace = true [dependencies] -bevy = { version = "0.13", default-features = false } +bevy = { version = "0.14", default-features = false } bevy-inspector-egui.workspace = true indexmap = "2" egui_dock.workspace = true diff --git a/crates/bevy_editor_pls_core/src/editor.rs b/crates/bevy_editor_pls_core/src/editor.rs index 0f6dd7c..2f995b4 100644 --- a/crates/bevy_editor_pls_core/src/editor.rs +++ b/crates/bevy_editor_pls_core/src/editor.rs @@ -457,7 +457,8 @@ impl Editor { } window.show(ctx, |ui| { self.editor_window_inner(world, internal_state, floating_window.window, ui); - ui.allocate_space(ui.available_size() - (5.0, 5.0).into()); + let desired_size = (ui.available_size() - (5.0, 5.0).into()).max((0.0, 0.0).into()); + ui.allocate_space(desired_size); }); if !open { diff --git a/crates/bevy_editor_pls_core/src/editor_window.rs b/crates/bevy_editor_pls_core/src/editor_window.rs index 89dde47..aac990e 100644 --- a/crates/bevy_editor_pls_core/src/editor_window.rs +++ b/crates/bevy_editor_pls_core/src/editor_window.rs @@ -13,6 +13,7 @@ pub trait EditorWindow: 'static { const DEFAULT_SIZE: (f32, f32) = (0.0, 0.0); fn ui(world: &mut World, cx: EditorWindowContext, ui: &mut egui::Ui); + /// Ui shown in the `Open Window` menu item. By default opens the window as a floating window. fn menu_ui(world: &mut World, mut cx: EditorWindowContext, ui: &mut egui::Ui) { let _ = world; diff --git a/crates/bevy_editor_pls_core/src/lib.rs b/crates/bevy_editor_pls_core/src/lib.rs index 4b91e5a..755026c 100644 --- a/crates/bevy_editor_pls_core/src/lib.rs +++ b/crates/bevy_editor_pls_core/src/lib.rs @@ -39,7 +39,7 @@ impl Plugin for WindowSetupPlugin { impl AddEditorWindow for App { fn add_editor_window(&mut self) -> &mut Self { - let mut editor = self.world.get_resource_mut::().expect("Editor resource missing. Make sure to add the `EditorPlugin` before calling `app.add_editor_window`."); + let mut editor = self.world_mut().get_resource_mut::().expect("Editor resource missing. Make sure to add the `EditorPlugin` before calling `app.add_editor_window`."); editor.add_window::(); self.add_plugins(WindowSetupPlugin::(PhantomData)); @@ -69,9 +69,9 @@ impl Plugin for EditorPlugin { let (window_entity, always_active) = match self.window { WindowRef::Primary => { let entity = app - .world + .world_mut() .query_filtered::>() - .single(&app.world); + .single(&app.world()); (entity, false) } WindowRef::Entity(entity) => (entity, true), diff --git a/crates/bevy_editor_pls_default_windows/Cargo.toml b/crates/bevy_editor_pls_default_windows/Cargo.toml index 203cb72..eafc0b8 100644 --- a/crates/bevy_editor_pls_default_windows/Cargo.toml +++ b/crates/bevy_editor_pls_default_windows/Cargo.toml @@ -11,7 +11,7 @@ readme.workspace = true highlight_changes = ["bevy-inspector-egui/highlight_changes"] [dependencies] -bevy = { version = "0.13", default-features = false, features = [ +bevy = { version = "0.14", default-features = false, features = [ "bevy_scene", "bevy_text", "bevy_ui", @@ -29,6 +29,6 @@ bevy-inspector-egui.workspace = true # ] } indexmap = "2" pretty-type-name = "1.0" -bevy_mod_debugdump = "0.10" +bevy_mod_debugdump = "0.11" opener = "0.6.0" -egui-gizmo.workspace = true +transform-gizmo-bevy.workspace = true diff --git a/crates/bevy_editor_pls_default_windows/src/cameras/mod.rs b/crates/bevy_editor_pls_default_windows/src/cameras/mod.rs index 56894ec..42601d5 100644 --- a/crates/bevy_editor_pls_default_windows/src/cameras/mod.rs +++ b/crates/bevy_editor_pls_default_windows/src/cameras/mod.rs @@ -13,13 +13,14 @@ use bevy_editor_pls_core::{ Editor, EditorEvent, }; use bevy_inspector_egui::egui; +use transform_gizmo_bevy::GizmoCamera; // use bevy_mod_picking::prelude::PickRaycastSource; use crate::hierarchy::{HideInEditor, HierarchyWindow}; use self::camera_3d_panorbit::PanOrbitCamera; -pub const EDITOR_RENDER_LAYER: u8 = 19; +pub const EDITOR_RENDER_LAYER: usize = 19; // Present on all editor cameras #[derive(Component)] @@ -232,7 +233,8 @@ fn spawn_editor_cameras(mut commands: Commands, editor: Res) { HideInEditor, Name::new("Editor Camera 3D Free"), NotInScene, - render_layers, + GizmoCamera, + render_layers.clone(), )); commands.spawn(( @@ -254,7 +256,8 @@ fn spawn_editor_cameras(mut commands: Commands, editor: Res) { HideInEditor, Name::new("Editor Camera 3D Pan/Orbit"), NotInScene, - render_layers, + GizmoCamera, + render_layers.clone(), )); commands.spawn(( @@ -275,6 +278,7 @@ fn spawn_editor_cameras(mut commands: Commands, editor: Res) { HideInEditor, Name::new("Editor Camera 2D Pan/Zoom"), NotInScene, + GizmoCamera, render_layers, )); } @@ -600,7 +604,7 @@ fn set_main_pass_viewport( } }); - cameras.iter_mut().for_each(|mut cam| { - cam.viewport = viewport.clone(); - }); + cameras + .iter_mut() + .for_each(|mut cam| cam.viewport.clone_from(&viewport)); } diff --git a/crates/bevy_editor_pls_default_windows/src/debug_settings/debugdump.rs b/crates/bevy_editor_pls_default_windows/src/debug_settings/debugdump.rs index 509999d..05b31bc 100644 --- a/crates/bevy_editor_pls_default_windows/src/debug_settings/debugdump.rs +++ b/crates/bevy_editor_pls_default_windows/src/debug_settings/debugdump.rs @@ -19,12 +19,12 @@ pub struct DotGraphs { pub fn setup(app: &mut App) { let render_app = match app.get_sub_app(RenderApp) { - Ok(render_app) => render_app, - Err(_label) => { + Some(render_app) => render_app, + None => { return; } }; - let render_graph = render_app.world.get_resource::().unwrap(); + let render_graph = render_app.world().get_resource::().unwrap(); let schedule_settings = schedule_graph::settings::Settings { include_system: Some(Box::new(|system| { @@ -35,18 +35,18 @@ pub fn setup(app: &mut App) { let rendergraph_settings = render_graph::settings::Settings::default(); let update_schedule = app.get_schedule(Update).map(|schedule| { - schedule_graph::schedule_graph_dot(schedule, &app.world, &schedule_settings) + schedule_graph::schedule_graph_dot(schedule, &app.world(), &schedule_settings) }); let fixed_update_schedule = app.get_schedule(FixedUpdate).map(|schedule| { - schedule_graph::schedule_graph_dot(schedule, &app.world, &schedule_settings) + schedule_graph::schedule_graph_dot(schedule, &app.world(), &schedule_settings) }); let render_main_schedule = render_app.get_schedule(Render).map(|schedule| { - schedule_graph::schedule_graph_dot(schedule, &app.world, &schedule_settings) + schedule_graph::schedule_graph_dot(schedule, &app.world(), &schedule_settings) }); let render_extract_schedule = render_app.get_schedule(ExtractSchedule).map(|schedule| { - schedule_graph::schedule_graph_dot(schedule, &app.world, &schedule_settings) + schedule_graph::schedule_graph_dot(schedule, &app.world(), &schedule_settings) }); let render_graph = render_graph::render_graph_dot(render_graph, &rendergraph_settings); diff --git a/crates/bevy_editor_pls_default_windows/src/debug_settings/mod.rs b/crates/bevy_editor_pls_default_windows/src/debug_settings/mod.rs index c2702d1..da01e19 100644 --- a/crates/bevy_editor_pls_default_windows/src/debug_settings/mod.rs +++ b/crates/bevy_editor_pls_default_windows/src/debug_settings/mod.rs @@ -118,7 +118,7 @@ fn debug_ui_options( if ui .add( egui::DragValue::new(&mut speed) - .clamp_range(0..=20) + .range(0..=20) .speed(0.1), ) .changed() @@ -141,8 +141,7 @@ fn debug_ui_options( } else { ui.label("Wireframes (enable POLYGON_MODE_LINE feature)"); } - ui.scope(|ui| { - ui.set_enabled(wireframe_enabled); + ui.add_enabled_ui(wireframe_enabled, |ui| { if ui_for_value(&mut state.wireframes, ui, type_registry) { world .get_resource_or_insert_with(WireframeConfig::default) @@ -156,8 +155,7 @@ fn debug_ui_options( } ui.label("Highlight selected entity"); - ui.scope(|ui| { - ui.set_enabled(wireframe_enabled); + ui.add_enabled_ui(wireframe_enabled, |ui| { ui.checkbox(&mut state.highlight_selected, ""); }); ui.end_row(); diff --git a/crates/bevy_editor_pls_default_windows/src/gizmos.rs b/crates/bevy_editor_pls_default_windows/src/gizmos.rs index 1f5482f..46dfa02 100644 --- a/crates/bevy_editor_pls_default_windows/src/gizmos.rs +++ b/crates/bevy_editor_pls_default_windows/src/gizmos.rs @@ -1,28 +1,31 @@ use bevy::{ - ecs::query::QueryFilter, + ecs::{query::QueryFilter, system::RunSystemOnce}, prelude::*, - render::{camera::CameraProjection, view::RenderLayers}, + render::view::RenderLayers, }; use bevy_editor_pls_core::editor_window::{EditorWindow, EditorWindowContext}; -use bevy_inspector_egui::{bevy_inspector::hierarchy::SelectedEntities, egui}; -use egui_gizmo::GizmoMode; +use bevy_inspector_egui::egui; +use transform_gizmo_bevy::GizmoTarget; +use transform_gizmo_bevy::{EnumSet, GizmoMode}; use crate::{ - cameras::{ActiveEditorCamera, CameraWindow, EditorCamera, EDITOR_RENDER_LAYER}, + cameras::{EditorCamera, EDITOR_RENDER_LAYER}, hierarchy::HierarchyWindow, }; pub struct GizmoState { + /// If [false], doesn't show any gizmos pub camera_gizmo_active: bool, - pub gizmo_mode: GizmoMode, + /// Synced with the [transform_gizmo_bevy::GizmoOptions] resource + pub gizmo_modes: EnumSet, } impl Default for GizmoState { fn default() -> Self { Self { camera_gizmo_active: true, - gizmo_mode: GizmoMode::Translate, + gizmo_modes: GizmoMode::all_translate(), } } } @@ -36,41 +39,104 @@ impl EditorWindow for GizmoWindow { fn ui(_world: &mut World, _cx: EditorWindowContext, ui: &mut egui::Ui) { ui.label("Gizmos can currently not be configured"); + // could definitely change some settings here in the future } - fn viewport_toolbar_ui(world: &mut World, cx: EditorWindowContext, ui: &mut egui::Ui) { + /// Called every frame (hopefully), could this invariant (namely being called every frame) be documented, + /// ideally in the [EditorWindow] trait? + fn viewport_toolbar_ui(world: &mut World, cx: EditorWindowContext, _ui: &mut egui::Ui) { let gizmo_state = cx.state::().unwrap(); + // syncs the [GizmoOptions] resource with the current state of the gizmo window + let mut gizmo_options = world.resource_mut::(); + gizmo_options.gizmo_modes = gizmo_state.gizmo_modes; + if gizmo_state.camera_gizmo_active { - if let (Some(hierarchy_state), Some(_camera_state)) = - (cx.state::(), cx.state::()) - { - draw_gizmo(ui, world, &hierarchy_state.selected, gizmo_state.gizmo_mode); + /// Before [hydrate_gizmos] and [deconstruct_gizmos] are run, this system resets the state of all entities that have a [EntityShouldShowGizmo] component. + /// Then, according to selection logic some entities are marked as focussed, and [hydrate_gizmos] and [deconstruct_gizmos] is run to sync the gizmo state with the selection state. + fn reset_gizmos_selected_state( + mut commands: Commands, + entities: Query>, + ) { + for entity in entities.iter() { + commands.entity(entity).remove::(); + } + } + + /// Takes all entities marked with [EntityShouldShowGizmo] and adds the [GizmoTarget] component to them. + fn hydrate_gizmos( + mut commands: Commands, + entities: Query, Without)>, + ) { + for entity in entities.iter() { + if let Some(mut entity) = commands.get_entity(entity) { + trace!( + "Hydrating a gizmo on entity {:?} because it is selected", + entity.id() + ); + // implicitly assumes it is the only gizmo target in the world, + // otherwise setting [GizmoTarget].is_focussed may be necessary + entity.insert(GizmoTarget::default()); + } + } + } + + /// Takes all entities that should have their [GizmoTarget] removed because they are no longer selected. + fn deconstruct_gizmos( + mut commands: Commands, + entities: Query, Without)>, + ) { + for entity in entities.iter() { + if let Some(mut entity) = commands.get_entity(entity) { + entity.remove::(); + debug!( + "Removing GizmoTarget from entity {:?} because it has lost focus", + entity.id() + ); + } + } + } + + if let Some(hierarchy_state) = cx.state::() { + // here should assign the `EntityShouldShowGizmo` component, which is later synced + // with the actual gizmo ui system + + world.run_system_once(reset_gizmos_selected_state); + + let selected_entities = hierarchy_state.selected.iter(); + for entity in selected_entities { + if let Some(mut entity) = world.get_entity_mut(entity) { + entity.insert(EntityShouldShowGizmo); + } + } + + world.run_system_once(hydrate_gizmos); + world.run_system_once(deconstruct_gizmos); } } } fn app_setup(app: &mut App) { - let mut materials = app.world.resource_mut::>(); + let mut materials = app.world_mut().resource_mut::>(); let material_light = materials.add(StandardMaterial { - base_color: Color::rgba_u8(222, 208, 103, 255), + base_color: Color::srgba_u8(222, 208, 103, 255), unlit: true, fog_enabled: false, alpha_mode: AlphaMode::Add, ..default() }); let material_camera = materials.add(StandardMaterial { - base_color: Color::rgb(1.0, 1.0, 1.0), + base_color: Color::srgb(1.0, 1.0, 1.0), unlit: true, fog_enabled: false, alpha_mode: AlphaMode::Multiply, ..default() }); - let mut meshes = app.world.resource_mut::>(); + let mut meshes = app.world_mut().resource_mut::>(); let sphere = meshes.add(Sphere { radius: 0.3 }); - app.world.insert_resource(GizmoMarkerConfig { + app.world_mut().insert_resource(GizmoMarkerConfig { point_light_mesh: sphere.clone(), point_light_material: material_light.clone(), directional_light_mesh: sphere.clone(), @@ -93,9 +159,15 @@ struct GizmoMarkerConfig { camera_material: Handle, } +/// can somebody document what this does? is it a duplicate of [EntityShouldShowGizmo]? #[derive(Component)] struct HasGizmoMarker; +/// When on an entity, this entity should be controllable using some sort of user gizmo. +/// Currently uses [transform_gizmo_bevy], and puts the [GizmoTarget] on the entity. +#[derive(Component)] +struct EntityShouldShowGizmo; + type GizmoMarkerQuery<'w, 's, T, F = ()> = Query<'w, 's, Entity, (With, Without, F)>; @@ -119,7 +191,7 @@ fn add_gizmo_markers( .entity(entity) .insert(HasGizmoMarker) .with_children(|commands| { - commands.spawn((f(), render_layers, Name::new(name))); + commands.spawn((f(), render_layers.clone(), Name::new(name))); }); } } @@ -159,62 +231,9 @@ fn add_gizmo_markers( material: gizmo_marker_meshes.camera_material.clone_weak(), ..default() }, - render_layers, + render_layers.clone(), Name::new("Camera Gizmo"), )); }); } } - -fn draw_gizmo( - ui: &mut egui::Ui, - world: &mut World, - selected_entities: &SelectedEntities, - gizmo_mode: GizmoMode, -) { - let Ok((cam_transform, projection)) = world - .query_filtered::<(&GlobalTransform, &Projection), With>() - .get_single(world) - else { - return; - }; - let view_matrix = Mat4::from(cam_transform.affine().inverse()); - let projection_matrix = projection.get_projection_matrix(); - - if selected_entities.len() != 1 { - return; - } - - for selected in selected_entities.iter() { - let Some(global_transform) = world.get::(selected) else { - continue; - }; - let model_matrix = global_transform.compute_matrix(); - - let Some(result) = egui_gizmo::Gizmo::new(selected) - .model_matrix(model_matrix.into()) - .view_matrix(view_matrix.into()) - .projection_matrix(projection_matrix.into()) - .orientation(egui_gizmo::GizmoOrientation::Local) - .mode(gizmo_mode) - .interact(ui) - else { - continue; - }; - - let global_affine = global_transform.affine(); - - let mut transform = world.get_mut::(selected).unwrap(); - - let parent_affine = global_affine * transform.compute_affine().inverse(); - let inverse_parent_transform = GlobalTransform::from(parent_affine.inverse()); - - let global_transform = Transform { - translation: result.translation.into(), - rotation: result.rotation.into(), - scale: result.scale.into(), - }; - - *transform = (inverse_parent_transform * global_transform).into(); - } -} diff --git a/crates/bevy_editor_pls_default_windows/src/hierarchy/mod.rs b/crates/bevy_editor_pls_default_windows/src/hierarchy/mod.rs index 1c5a9eb..0a5c441 100644 --- a/crates/bevy_editor_pls_default_windows/src/hierarchy/mod.rs +++ b/crates/bevy_editor_pls_default_windows/src/hierarchy/mod.rs @@ -41,23 +41,21 @@ impl EditorWindow for HierarchyWindow { } }; - ScrollArea::vertical() - .auto_shrink([false, false]) - .show(ui, |ui| { - let type_registry = world.resource::().clone(); - let type_registry = type_registry.read(); - let new_selected = Hierarchy { - world, - state: hierarchy_state, - type_registry: &type_registry, - add_state: add_state.as_deref(), - } - .show(ui); + ScrollArea::vertical().show(ui, |ui| { + let type_registry = world.resource::().clone(); + let type_registry = type_registry.read(); + let new_selected = Hierarchy { + world, + state: hierarchy_state, + type_registry: &type_registry, + add_state: add_state.as_deref(), + } + .show(ui); - if new_selected { - inspector_state.selected = InspectorSelection::Entities; - } - }); + if new_selected { + inspector_state.selected = InspectorSelection::Entities; + } + }); } fn app_setup(app: &mut bevy::prelude::App) { diff --git a/crates/bevy_editor_pls_default_windows/src/renderer.rs b/crates/bevy_editor_pls_default_windows/src/renderer.rs index cb3fb6f..e8d29dd 100644 --- a/crates/bevy_editor_pls_default_windows/src/renderer.rs +++ b/crates/bevy_editor_pls_default_windows/src/renderer.rs @@ -17,44 +17,42 @@ impl EditorWindow for RendererWindow { let type_registry = world.resource::().clone(); let type_registry = type_registry.read(); - egui::ScrollArea::vertical() - .auto_shrink([false, false]) - .show(ui, |ui| { - let render_device = world.get_resource::().unwrap(); - - let limits = render_device.limits(); - let features = render_device.features(); - - ui.heading("Settings"); - egui::Grid::new("directional_light_shadow_map").show(ui, |ui| { - let mut directional_light_shadow_map = world - .get_resource_mut::() - .unwrap(); - ui.label("Directional light shadow map size"); - let mut size = directional_light_shadow_map.size; - - let mut context = Context::default(); - let mut env = InspectorUi::new_no_short_circuit(&type_registry, &mut context); - if env.ui_for_reflect_with_options( - &mut size, - ui, - egui::Id::NULL, - &NumberOptions::at_least(1).with_speed(4.0), - ) { - directional_light_shadow_map.size = size; - } - ui.end_row(); - }); - - ui.collapsing("Limits", |ui| { - ui.label(RichText::new(format!("{:#?}", limits)).monospace()); - }); - ui.collapsing("Features", |ui| { - let features = format!("{:#?}", features); - for feature in features.split(" | ") { - ui.label(RichText::new(format!("- {}", feature)).monospace()); - } - }); + egui::ScrollArea::vertical().show(ui, |ui| { + let render_device = world.get_resource::().unwrap(); + + let limits = render_device.limits(); + let features = render_device.features(); + + ui.heading("Settings"); + egui::Grid::new("directional_light_shadow_map").show(ui, |ui| { + let mut directional_light_shadow_map = world + .get_resource_mut::() + .unwrap(); + ui.label("Directional light shadow map size"); + let mut size = directional_light_shadow_map.size; + + let mut context = Context::default(); + let mut env = InspectorUi::new_no_short_circuit(&type_registry, &mut context); + if env.ui_for_reflect_with_options( + &mut size, + ui, + egui::Id::NULL, + &NumberOptions::at_least(1).with_speed(4.0), + ) { + directional_light_shadow_map.size = size; + } + ui.end_row(); }); + + ui.collapsing("Limits", |ui| { + ui.label(RichText::new(format!("{:#?}", limits)).monospace()); + }); + ui.collapsing("Features", |ui| { + let features = format!("{:#?}", features); + for feature in features.split(" | ") { + ui.label(RichText::new(format!("- {}", feature)).monospace()); + } + }); + }); } } diff --git a/crates/bevy_editor_pls_default_windows/src/scenes.rs b/crates/bevy_editor_pls_default_windows/src/scenes.rs index bba31ea..faabbda 100644 --- a/crates/bevy_editor_pls_default_windows/src/scenes.rs +++ b/crates/bevy_editor_pls_default_windows/src/scenes.rs @@ -64,12 +64,13 @@ fn save_world( name: &str, entities: std::collections::HashSet, ) -> Result<(), Box> { - let type_registry = world.get_resource::().unwrap(); + let type_registry_arc = world.get_resource::().unwrap(); + let type_registry = type_registry_arc.read(); let mut scene_builder = DynamicSceneBuilder::from_world(world); scene_builder = scene_builder.extract_entities(entities.into_iter()); let scene = scene_builder.build(); - let ron = scene.serialize_ron(type_registry)?; + let ron = scene.serialize(&type_registry)?; std::fs::write(name, ron)?; Ok(()) }