From 4fb38490ffd59913658aecb9be50b4521ee4426a Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 26 Jan 2025 21:06:50 +0300 Subject: [PATCH 1/6] Refactor selection system with observer pattern and simplify picking logic --- crates/editor_ui/src/lib.rs | 13 +--- crates/editor_ui/src/selection.rs | 114 +++++++----------------------- 2 files changed, 28 insertions(+), 99 deletions(-) diff --git a/crates/editor_ui/src/lib.rs b/crates/editor_ui/src/lib.rs index 36973055..996c02be 100644 --- a/crates/editor_ui/src/lib.rs +++ b/crates/editor_ui/src/lib.rs @@ -63,17 +63,6 @@ pub mod icons; use bevy_debug_grid::{Grid, GridAxis, SubGrid, TrackedGrid}; -/* -use bevy_picking::{ - backends::raycast::RaycastPickable, - events::{Down, Pointer}, - picking_core::Pickable, - pointer::PointerButton, - prelude::*, - PickableBundle, -}; -*/ - use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use camera_view::CameraViewTabPlugin; use space_editor_core::prelude::*; @@ -200,7 +189,7 @@ impl PluginGroup for EditorPluginGroup { .add(DefaultInspectorConfigPlugin); res = EditorUiPlugin::default().add_plugins_to_group(res); res.add(PanOrbitCameraPlugin) - //.add(selection::EditorPickingPlugin) + .add(selection::plugin) .add(bevy_debug_grid::DebugGridPlugin::without_floor_grid()) .add( WorldInspectorPlugin::default() diff --git a/crates/editor_ui/src/selection.rs b/crates/editor_ui/src/selection.rs index cb9fb603..c8f87b77 100644 --- a/crates/editor_ui/src/selection.rs +++ b/crates/editor_ui/src/selection.rs @@ -1,123 +1,63 @@ use crate::*; use bevy::prelude::*; -/* -pub struct EditorPickingPlugin; -impl Plugin for EditorPickingPlugin { - #[cfg(not(tarpaulin_include))] - fn build(&self, app: &mut App) { - app.add_plugins(MeshPickingPlugin); - if let Some(mut raycast_backend) = - app.world_mut() - .get_resource_mut::() - { - raycast_backend.require_markers = true; - } +#[cfg(not(tarpaulin_include))] +pub fn plugin(app: &mut App) { + app.add_plugins(MeshPickingPlugin); - app.add_systems( - PostUpdate, - (auto_add_picking, select_listener.after(UiSystemSet)) - .run_if(in_state(EditorState::Editor)), - ); - app.add_systems(PostUpdate, auto_add_picking_dummy); - } -} + app.add_systems( + Update, + delete_selected + ); -pub fn auto_add_picking( - mut commands: Commands, - query: Query, Without)>, -) { - for e in query.iter() { - commands.entity(e).insert(( - PickableBundle::default(), - On::>::send_event::(), - RayCastPickable, - )); - } + app.add_observer(select_listener); + app.add_observer(reemit_pointer_click); } -//Auto add picking for each child to propagate picking event up to prefab entity -pub fn auto_add_picking_dummy( +fn reemit_pointer_click( + mut trigger: Trigger>, mut commands: Commands, - query: Query<(Entity, &Handle), AutoAddQueryFilter>, - meshs: Res>, ) { - for (e, mesh) in query.iter() { - //Only meshed entity need to be pickable - if let Some(mesh) = meshs.get(mesh) { - if mesh.primitive_topology() == PrimitiveTopology::TriangleList { - commands - .entity(e) - .insert((PickableBundle::default(), RaycastPickable)); - } - } - } + commands.trigger_targets(SelectEvent, trigger.entity()); } pub fn select_listener( + mut trigger: Trigger, mut commands: Commands, query: Query>, // may need to be optimized a bit so that there is less overlap prefabs: Query>, parents: Query<&Parent>, - mut events: EventReader, pan_orbit_state: ResMut, keyboard: Res>, ) { + if !pan_orbit_state.0 { - events.clear(); + trigger.propagate(false); return; } - let mut stack = events.read().cloned().collect::>(); + info!("Select Event: {:?}", trigger.entity()); - while let Some(event) = stack.pop() { - info!("Select Event: {:?}", event.e); - - if let Ok(entity) = prefabs.get(event.e) { - match event.event.button { - PointerButton::Primary => { - commands.entity(entity).insert(Selected); - if !keyboard.pressed(KeyCode::ShiftLeft) { - for e in query.iter() { - commands.entity(e).remove::(); - } - } - } - PointerButton::Secondary => { /*Show context menu?*/ } - PointerButton::Middle => {} + if let Ok(entity) = prefabs.get(trigger.entity()) { + commands.entity(entity).insert(Selected); + if !keyboard.pressed(KeyCode::ShiftLeft) { + for e in query.iter() { + commands.entity(e).remove::(); } - } else if let Ok(parent) = parents.get(event.e) { - stack.push(SelectEvent { - e: parent.get(), - event: event.event.clone(), - }); - } - } -} - - - -impl From>> for SelectEvent { - fn from(value: ListenerInput>) -> Self { - Self { - e: value.target(), - event: value, } + } else if let Ok(parent) = parents.get(trigger.entity()) { + // Just stupid propagation (Need to make it with Event trait) + commands.trigger_targets(SelectEvent, parent.get()); } } - /// This event used for selecting entities -#[derive(Event, Clone, EntityEvent)] -pub struct SelectEvent { - #[target] - e: Entity, - event: ListenerInput>, -} +#[derive(Event, Clone)] +pub struct SelectEvent; pub fn delete_selected( mut commands: Commands, @@ -135,4 +75,4 @@ pub fn delete_selected( } } } -*/ + From 227c10f3ec6f9427bad04b4e836dc78089ee630a Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 26 Jan 2025 21:27:58 +0300 Subject: [PATCH 2/6] Selection works. Deselection is not working --- crates/editor_ui/src/selection.rs | 42 +++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/crates/editor_ui/src/selection.rs b/crates/editor_ui/src/selection.rs index c8f87b77..c599f5ea 100644 --- a/crates/editor_ui/src/selection.rs +++ b/crates/editor_ui/src/selection.rs @@ -1,5 +1,5 @@ use crate::*; -use bevy::prelude::*; +use bevy::{color::palettes::tailwind::{PINK_100, RED_500}, picking::pointer::PointerInteraction, prelude::*}; @@ -7,20 +7,52 @@ use bevy::prelude::*; pub fn plugin(app: &mut App) { app.add_plugins(MeshPickingPlugin); + + app.add_systems( + Update, + (delete_selected, reemit_pointer_click) + ); + app.add_systems( Update, - delete_selected + draw_mesh_intersections.run_if(in_state(EditorState::Editor)) ); app.add_observer(select_listener); - app.add_observer(reemit_pointer_click); + + app.insert_resource(MeshPickingSettings { + require_markers: false, + ray_cast_visibility: RayCastVisibility::Any + }); } +/// From bevy examples +/// A system that draws hit indicators for every pointer. +fn draw_mesh_intersections(pointers: Query<&PointerInteraction>, mut gizmos: Gizmos) { + for (point, normal) in pointers + .iter() + .filter_map(|interaction| interaction.get_nearest_hit()) + .filter_map(|(_entity, hit)| hit.position.zip(hit.normal)) + { + gizmos.sphere(point, 0.05, RED_500); + gizmos.arrow(point, point + normal.normalize() * 0.5, PINK_100); + } +} + +/// Reemits the pointer click event to the entity that is being clicked on +/// Its not a good solution, but it works for now fn reemit_pointer_click( - mut trigger: Trigger>, + pointers: Query<&PointerInteraction>, mut commands: Commands, + q_meshes: Query>, ) { - commands.trigger_targets(SelectEvent, trigger.entity()); + for pointer in pointers.iter() { + if let Some((e, _)) = pointer.get_nearest_hit() { + if q_meshes.contains(*e) { + commands.trigger_targets(SelectEvent, *e); + } + } + } } pub fn select_listener( From 485b488c46acefe12bc7cfdaa232ec83a7e9bc02 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 26 Jan 2025 21:39:48 +0300 Subject: [PATCH 3/6] Update selection.rs --- crates/editor_ui/src/selection.rs | 43 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/crates/editor_ui/src/selection.rs b/crates/editor_ui/src/selection.rs index c599f5ea..c88540f3 100644 --- a/crates/editor_ui/src/selection.rs +++ b/crates/editor_ui/src/selection.rs @@ -10,7 +10,7 @@ pub fn plugin(app: &mut App) { app.add_systems( Update, - (delete_selected, reemit_pointer_click) + (delete_selected, reemit_pointer_click, auto_add_markers) ); app.add_systems( @@ -18,14 +18,51 @@ pub fn plugin(app: &mut App) { draw_mesh_intersections.run_if(in_state(EditorState::Editor)) ); + app.add_event::(); + app.add_observer(select_listener); + app.add_observer(recursive_add_markers); app.insert_resource(MeshPickingSettings { - require_markers: false, - ray_cast_visibility: RayCastVisibility::Any + require_markers: true, + ray_cast_visibility: RayCastVisibility::VisibleInView }); } +fn auto_add_markers( + mut commands: Commands, + q_prefabs: Query, Without)>, + q_cameras: Query, Without)>, +) { + for entity in q_prefabs.iter() { + commands.trigger_targets(AddMarkersEvent, entity); + } + + for entity in q_cameras.iter() { + commands.entity(entity).insert(RayCastPickable); + } +} + +#[derive(Event, Clone)] +struct AddMarkersEvent; + +fn recursive_add_markers( + trigger: Trigger, + q_children: Query<&Children>, + q_meshes: Query>, + mut commands: Commands, +) { + if q_meshes.contains(trigger.entity()) { + commands.entity(trigger.entity()).insert(RayCastPickable); + } + + if let Ok(children) = q_children.get(trigger.entity()) { + for child in children.iter() { + commands.trigger_targets(AddMarkersEvent, *child); + } + } +} + /// From bevy examples /// A system that draws hit indicators for every pointer. fn draw_mesh_intersections(pointers: Query<&PointerInteraction>, mut gizmos: Gizmos) { From c250d4027eb9781e35f5a0146c602380f7f2302f Mon Sep 17 00:00:00 2001 From: MiniMinerX Date: Mon, 27 Jan 2025 22:48:25 -0800 Subject: [PATCH 4/6] fixed reflect issues As a temporary fix I had turned off component reflection but I found one line to fix it. However I did change the show_component function to use PartialReflect so yall may want it different. --- crates/editor_ui/src/inspector/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/editor_ui/src/inspector/mod.rs b/crates/editor_ui/src/inspector/mod.rs index 12dee652..6907604c 100644 --- a/crates/editor_ui/src/inspector/mod.rs +++ b/crates/editor_ui/src/inspector/mod.rs @@ -211,7 +211,8 @@ impl EditorTab for InspectorTab { { let (ptr, mut set_changed) = mut_untyped_split(data); - let value = unsafe { reflect_from_ptr.from_ptr_mut()(ptr) }; + let value_reflect = unsafe { reflect_from_ptr.from_ptr_mut()(ptr) }; + let value = value_reflect.as_partial_reflect_mut(); if is_editor_component { if !editor_registry_resource @@ -380,7 +381,7 @@ impl InspectorTab { e: bevy::ecs::world::unsafe_world_cell::UnsafeEntityCell<'_>, name: &String, env: &mut InspectorUi<'_, '_>, - value: &mut dyn Reflect, + value: &mut dyn PartialReflect, set_changed: &mut impl FnMut(), ) { ui.push_id(format!("{:?}-{}", &e.id(), &name), |ui| { @@ -389,10 +390,10 @@ impl InspectorTab { .default_open(*self.open_components.get(name).unwrap_or(&default)) .show(ui, |ui| { ui.push_id(format!("content-{:?}-{}", &e.id(), &name), |ui| { - //if env.ui_for_reflect_with_options(value, ui, ui.id(), &()) { - // (set_changed)(); - //} - ui.label("show component function error"); + if env.ui_for_reflect_with_options(value, ui, ui.id(), &()) { + (set_changed)(); + } + //ui.label("show component function error"); }); }); if header.header_response.clicked() { From 367ca131a8f535c3c10e60a778ccc140b3d04a6e Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 9 Feb 2025 09:15:03 +0300 Subject: [PATCH 5/6] fix multiple selections --- Cargo.lock | 32 ++- Cargo.toml | 4 +- crates/editor_core/Cargo.toml | 2 +- crates/editor_core/src/selected.rs | 12 +- crates/editor_ui/Cargo.toml | 2 +- crates/editor_ui/src/game_view.rs | 2 +- crates/editor_ui/src/selection.rs | 10 +- crates/editor_ui/src/tools/gizmo.rs | 304 +--------------------------- 8 files changed, 51 insertions(+), 317 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fe9f233..eac84e00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5030,7 +5030,7 @@ dependencies = [ "space_prefab", "space_shared", "space_undo", - "transform-gizmo-egui", + "transform-gizmo-bevy", "workspace-hakari", ] @@ -5465,8 +5465,8 @@ dependencies = [ [[package]] name = "transform-gizmo" -version = "0.4.0" -source = "git+https://github.com/MiniMinerX/transform-gizmo.git#dc2727027145a671ea727cb47aeac7f7b01ec71e" +version = "0.5.1" +source = "git+https://github.com/UnderbudgetGames/transform-gizmo.git#41a0ee91067fb7a10bc7a08ad17742e0ec12463f" dependencies = [ "ahash", "ecolor", @@ -5479,12 +5479,30 @@ dependencies = [ ] [[package]] -name = "transform-gizmo-egui" -version = "0.4.0" -source = "git+https://github.com/MiniMinerX/transform-gizmo.git#dc2727027145a671ea727cb47aeac7f7b01ec71e" +name = "transform-gizmo-bevy" +version = "0.5.1" +source = "git+https://github.com/UnderbudgetGames/transform-gizmo.git#41a0ee91067fb7a10bc7a08ad17742e0ec12463f" dependencies = [ - "egui", + "bevy_app", + "bevy_asset", + "bevy_core", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_picking", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bytemuck", "transform-gizmo", + "uuid", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4c58c6cf..c0caff18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,8 +69,7 @@ convert_case = "0.7.1" egui_dock = "0.15.0" egui_extras = { version = "0.30.0", features = ["all_loaders"] } egui_file = { rev = "bcacedf", git = "https://github.com/Barugon/egui_file.git"} -transform-gizmo-egui = {git = "https://github.com/MiniMinerX/transform-gizmo.git"} -transform-gizmo-bevy = { git = "https://github.com/MiniMinerX/transform-gizmo.git"} +transform-gizmo-bevy = { git = "https://github.com/UnderbudgetGames/transform-gizmo.git"} egui-toast = "0.16.0" image = {version = "0.25.5", feature = ["png"] } pretty-type-name = "1" @@ -78,6 +77,7 @@ rand = "*" ron = "0.8" serde = "1" + # Community Modules game_app = { version = "0.1.0", path = "game" } diff --git a/crates/editor_core/Cargo.toml b/crates/editor_core/Cargo.toml index 5b4b5c74..c4f6bd11 100644 --- a/crates/editor_core/Cargo.toml +++ b/crates/editor_core/Cargo.toml @@ -26,7 +26,7 @@ bevy_mod_outline = {git = "https://github.com/komadori/bevy_mod_outline.git", op workspace-hakari = { version = "0.1", path = "../../workspace-hakari" } [features] -default = ["persistence_editor", "bevy_mod_outline"] +default = ["persistence_editor"] persistence_editor = [] bevy_mod_outline = ["dep:bevy_mod_outline"] diff --git a/crates/editor_core/src/selected.rs b/crates/editor_core/src/selected.rs index 16b839b3..43344b88 100644 --- a/crates/editor_core/src/selected.rs +++ b/crates/editor_core/src/selected.rs @@ -112,8 +112,8 @@ mod tests { }); app.update(); - let mut query = app.world.query_filtered::>(); - assert_eq!(0, query.iter(&app.world).count()); + let mut query = app.world_mut().query_filtered::>(); + assert_eq!(0, query.iter(&app.world_mut()).count()); } #[test] @@ -127,8 +127,8 @@ mod tests { }); app.update(); - let mut query = app.world.query_filtered::>(); - assert_eq!(0, query.iter(&app.world).count()); + let mut query = app.world_mut().query_filtered::>(); + assert_eq!(0, query.iter(&app.world_mut()).count()); } #[test] @@ -143,8 +143,8 @@ mod tests { app.update(); let mut query = app - .world + .world_mut() .query_filtered::, With)>(); - assert_eq!(2, query.iter(&app.world).count()); + assert_eq!(2, query.iter(&app.world_mut()).count()); } } diff --git a/crates/editor_ui/Cargo.toml b/crates/editor_ui/Cargo.toml index 6fbaf32c..71b2c808 100644 --- a/crates/editor_ui/Cargo.toml +++ b/crates/editor_ui/Cargo.toml @@ -26,7 +26,7 @@ space_editor_tabs.workspace = true serde.workspace = true pretty-type-name.workspace = true bevy_egui.workspace = true -transform-gizmo-egui.workspace = true +transform-gizmo-bevy.workspace = true egui_dock.workspace = true bevy_debug_grid.workspace = true bevy-inspector-egui.workspace = true diff --git a/crates/editor_ui/src/game_view.rs b/crates/editor_ui/src/game_view.rs index b3e97974..7e1fc48e 100644 --- a/crates/editor_ui/src/game_view.rs +++ b/crates/editor_ui/src/game_view.rs @@ -5,9 +5,9 @@ use bevy_egui::{ EguiContextSettings, }; use space_undo::UndoRedo; -use transform_gizmo_egui::GizmoMode; use space_shared::*; +use transform_gizmo_bevy::GizmoMode; use crate::editor_tab_name::EditorTabName; diff --git a/crates/editor_ui/src/selection.rs b/crates/editor_ui/src/selection.rs index c88540f3..b065b911 100644 --- a/crates/editor_ui/src/selection.rs +++ b/crates/editor_ui/src/selection.rs @@ -79,17 +79,25 @@ fn draw_mesh_intersections(pointers: Query<&PointerInteraction>, mut gizmos: Giz /// Reemits the pointer click event to the entity that is being clicked on /// Its not a good solution, but it works for now fn reemit_pointer_click( + mut is_pressed: Local, pointers: Query<&PointerInteraction>, mut commands: Commands, q_meshes: Query>, + ) { for pointer in pointers.iter() { if let Some((e, _)) = pointer.get_nearest_hit() { if q_meshes.contains(*e) { + if *is_pressed { + return; + } commands.trigger_targets(SelectEvent, *e); + *is_pressed = true; + return; } } } + *is_pressed = false; } pub fn select_listener( @@ -102,9 +110,9 @@ pub fn select_listener( pan_orbit_state: ResMut, keyboard: Res>, ) { + trigger.propagate(false); if !pan_orbit_state.0 { - trigger.propagate(false); return; } diff --git a/crates/editor_ui/src/tools/gizmo.rs b/crates/editor_ui/src/tools/gizmo.rs index c4739759..a69a0cb1 100644 --- a/crates/editor_ui/src/tools/gizmo.rs +++ b/crates/editor_ui/src/tools/gizmo.rs @@ -2,7 +2,7 @@ use bevy::{prelude::*, render::camera::CameraProjection}; use bevy_egui::egui::{self, Key}; use space_editor_core::prelude::*; use space_shared::*; -use transform_gizmo_egui::{EnumSet, Gizmo, GizmoExt, GizmoMode}; +use transform_gizmo_bevy::{EnumSet, Gizmo, GizmoMode}; use crate::EditorGizmo; use crate::{colors::*, sizing::Sizing}; @@ -88,53 +88,15 @@ const MODE_TO_KEY: [(EnumSet, GizmoHotkey); 3] = [ (GizmoMode::all_scale(), GizmoHotkey::Scale), ]; -fn bevy_to_gizmo_transform(transform: &Transform) -> transform_gizmo_egui::math::Transform { - transform_gizmo_egui::math::Transform { - scale: transform_gizmo_egui::mint::Vector3::::from_slice( - &transform.scale.as_dvec3().to_array(), - ), - rotation: transform_gizmo_egui::mint::Quaternion:: { - v: transform_gizmo_egui::mint::Vector3:: { - x: transform.rotation.x as f64, - y: transform.rotation.y as f64, - z: transform.rotation.z as f64, - }, - s: transform.rotation.w as f64, - }, - translation: transform_gizmo_egui::mint::Vector3::::from_slice( - &transform.translation.as_dvec3().to_array(), - ), - } -} - -fn gizmo_to_bevy_transform(transform: &transform_gizmo_egui::math::Transform) -> Transform { - Transform { - scale: Vec3::new( - transform.scale.x as f32, - transform.scale.y as f32, - transform.scale.z as f32, - ), - translation: Vec3::new( - transform.translation.x as f32, - transform.translation.y as f32, - transform.translation.z as f32, - ), - rotation: Quat::from_xyzw( - transform.rotation.v.x as f32, - transform.rotation.v.y as f32, - transform.rotation.v.z as f32, - transform.rotation.s as f32, - ), - ..Default::default() - } -} - impl EditorTool for GizmoTool { fn name(&self) -> &str { "Gizmo" } fn ui(&mut self, ui: &mut egui::Ui, commands: &mut Commands, world: &mut World) { + + return; + let sizing = world.resource::(); ui.spacing(); @@ -167,6 +129,7 @@ impl EditorTool for GizmoTool { let mut del = false; let mut clone_pressed = false; let mut multiple_pressed = false; + let mut disable_pan_orbit = false; for (mode, key) in MODE_TO_KEY { if input.just_pressed(key) { @@ -199,262 +162,7 @@ impl EditorTool for GizmoTool { return; } - let (cam_transform, cam_proj) = { - let mut cam_query = - world.query_filtered::<(&GlobalTransform, &Projection), With>(); - let Ok((ref_tr, ref_cam)) = cam_query.get_single(world) else { - return; - }; - (*ref_tr, ref_cam.clone()) - }; - - let selected = world - .query_filtered::>() - .iter(world) - .collect::>(); - let mut disable_pan_orbit = false; - - let cell = world.as_unsafe_world_cell(); - - let view_matrix = Mat4::from(cam_transform.affine().inverse()); - if multiple_pressed { - let mut mean_transform = Transform::IDENTITY; - for e in &selected { - let Some(ecell) = cell.get_entity(*e) else { - continue; - }; - let Some(global_transform) = (unsafe { ecell.get::() }) else { - continue; - }; - let tr = global_transform.compute_transform(); - mean_transform.translation += tr.translation; - mean_transform.scale += tr.scale; - } - mean_transform.translation /= selected.len() as f32; - mean_transform.scale /= selected.len() as f32; - - let mut global_mean = GlobalTransform::from(mean_transform); - - unsafe { - cell.world_mut().insert_resource(MultipleCenter { - center: Some(global_mean.translation()), - }); - } - - let mut loc_transform = vec![]; - for e in &selected { - let Some(ecell) = cell.get_entity(*e) else { - continue; - }; - let Some(global_transform) = (unsafe { ecell.get::() }) else { - continue; - }; - loc_transform.push(global_transform.reparented_to(&global_mean)); - } - - let mut gizmo_interacted = false; - - let proj_mat = cam_proj.get_clip_from_view(); - let proj_mat = transform_gizmo_egui::math::DMat4 { - x_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.x_axis.as_dvec4().to_array(), - ), - y_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.y_axis.as_dvec4().to_array(), - ), - z_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.z_axis.as_dvec4().to_array(), - ), - w_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.w_axis.as_dvec4().to_array(), - ), - }; - - let view_matrix = transform_gizmo_egui::math::DMat4 { - x_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.x_axis.as_dvec4().to_array(), - ), - y_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.y_axis.as_dvec4().to_array(), - ), - z_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.z_axis.as_dvec4().to_array(), - ), - w_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.w_axis.as_dvec4().to_array(), - ), - }; - - let gizmo_config = transform_gizmo_egui::GizmoConfig { - projection_matrix: proj_mat.into(), - view_matrix: view_matrix.into(), - modes: self.gizmo_mode.into(), - viewport: ui.clip_rect(), - ..Default::default() - }; - - self.gizmo.update_config(gizmo_config); - - info!("{:?}", &mean_transform); - - if let Some((_, transforms)) = self - .gizmo - .interact(ui, &[bevy_to_gizmo_transform(&mean_transform)]) - { - gizmo_interacted = true; - mean_transform = gizmo_to_bevy_transform(&transforms[0]); - disable_pan_orbit = true; - } - - global_mean = GlobalTransform::from(mean_transform); - - if gizmo_interacted && clone_pressed { - if self.is_move_cloned_entities { - } else { - for e in selected.iter() { - unsafe { cell.world_mut().send_event(CloneEvent { id: *e }) }; - } - self.is_move_cloned_entities = true; - return; - } - } - - if gizmo_interacted { - for (idx, e) in selected.iter().enumerate() { - let Some(ecell) = cell.get_entity(*e) else { - continue; - }; - let Some(mut transform) = (unsafe { ecell.get_mut::() }) else { - continue; - }; - - let new_global = global_mean.mul_transform(loc_transform[idx]); - - if let Some(parent) = unsafe { ecell.get::() } { - if let Some(parent) = cell.get_entity(parent.get()) { - if let Some(parent_global) = unsafe { parent.get::() } - { - *transform = new_global.reparented_to(parent_global); - } - } - } else { - *transform = new_global.compute_transform(); - } - } - } - } else { - unsafe { - cell.world_mut() - .insert_resource(MultipleCenter { center: None }); - } - - for e in &selected { - let Some(ecell) = cell.get_entity(*e) else { - continue; - }; - let Some(mut transform) = (unsafe { ecell.get_mut::() }) else { - continue; - }; - - let proj_mat = cam_proj.get_clip_from_view(); - let proj_mat = transform_gizmo_egui::math::DMat4 { - x_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.x_axis.as_dvec4().to_array(), - ), - y_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.y_axis.as_dvec4().to_array(), - ), - z_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.z_axis.as_dvec4().to_array(), - ), - w_axis: transform_gizmo_egui::math::DVec4::from_array( - proj_mat.w_axis.as_dvec4().to_array(), - ), - }; - - let view_matrix = transform_gizmo_egui::math::DMat4 { - x_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.x_axis.as_dvec4().to_array(), - ), - y_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.y_axis.as_dvec4().to_array(), - ), - z_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.z_axis.as_dvec4().to_array(), - ), - w_axis: transform_gizmo_egui::math::DVec4::from_array( - view_matrix.w_axis.as_dvec4().to_array(), - ), - }; - - let gizmo_config = transform_gizmo_egui::GizmoConfig { - projection_matrix: proj_mat.into(), - view_matrix: view_matrix.into(), - modes: self.gizmo_mode.into(), - viewport: ui.clip_rect(), - ..Default::default() - }; - - if let Some(parent) = unsafe { ecell.get::() } { - if let Some(parent) = cell.get_entity(parent.get()) { - if let Some(parent_global) = unsafe { parent.get::() } { - if let Some(global) = unsafe { ecell.get::() } { - self.gizmo.update_config(gizmo_config); - - if let Some((_, transforms)) = self.gizmo.interact( - ui, - &[bevy_to_gizmo_transform(&global.compute_transform())], - ) { - disable_pan_orbit = true; - let new_transform = gizmo_to_bevy_transform(&transforms[0]); - - if clone_pressed { - if self.is_move_cloned_entities { - let new_transform = - GlobalTransform::from(new_transform); - *transform = new_transform.reparented_to(parent_global); - transform.set_changed(); - disable_pan_orbit = true; - } else { - unsafe { - cell.world_mut().send_event(CloneEvent { id: *e }) - }; - self.is_move_cloned_entities = true; - } - } else { - let new_transform = GlobalTransform::from(new_transform); - *transform = new_transform.reparented_to(parent_global); - transform.set_changed(); - } - } - continue; - } - } - } - } - - self.gizmo.update_config(gizmo_config); - if let Some((_, transforms)) = self - .gizmo - .interact(ui, &[bevy_to_gizmo_transform(&transform)]) - { - if clone_pressed { - if self.is_move_cloned_entities { - *transform = gizmo_to_bevy_transform(&transforms[0]); - transform.set_changed(); - } else { - unsafe { cell.world_mut().send_event(CloneEvent { id: *e }) }; - self.is_move_cloned_entities = true; - } - } else { - *transform = gizmo_to_bevy_transform(&transforms[0]); - transform.set_changed(); - } - disable_pan_orbit = true; - } - } - } if ui.ctx().wants_pointer_input() { disable_pan_orbit = true; @@ -462,7 +170,7 @@ impl EditorTool for GizmoTool { if disable_pan_orbit { unsafe { - cell.get_resource_mut::() + world.get_resource_mut::() .unwrap() .0 = false }; From 0f739f54de7998f9de3e05cce65ce7a3a358d6c9 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 9 Feb 2025 09:39:55 +0300 Subject: [PATCH 6/6] Tried PR for transform-gizmo-bevy Not working --- crates/editor_ui/src/tools/gizmo.rs | 52 +++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/crates/editor_ui/src/tools/gizmo.rs b/crates/editor_ui/src/tools/gizmo.rs index a69a0cb1..7a8eebf0 100644 --- a/crates/editor_ui/src/tools/gizmo.rs +++ b/crates/editor_ui/src/tools/gizmo.rs @@ -2,7 +2,7 @@ use bevy::{prelude::*, render::camera::CameraProjection}; use bevy_egui::egui::{self, Key}; use space_editor_core::prelude::*; use space_shared::*; -use transform_gizmo_bevy::{EnumSet, Gizmo, GizmoMode}; +use transform_gizmo_bevy::{EnumSet, Gizmo, GizmoMode, GizmoTarget}; use crate::EditorGizmo; use crate::{colors::*, sizing::Sizing}; @@ -18,7 +18,10 @@ pub struct GizmoToolPlugin; impl Plugin for GizmoToolPlugin { #[cfg(not(tarpaulin_include))] fn build(&self, app: &mut App) { + use transform_gizmo_bevy::GizmoOptions; + app.editor_tool(GizmoTool::default()); + app.add_plugins(transform_gizmo_bevy::TransformGizmoPlugin); if let Some(mut game_view_tab) = app.world_mut().get_resource_mut::() { game_view_tab.active_tool = Some(0); @@ -33,9 +36,27 @@ impl Plugin for GizmoToolPlugin { app.editor_hotkey(GizmoHotkey::Clone, vec![KeyCode::AltLeft]); app.add_systems(Update, draw_lines_system.in_set(EditorSet::Editor)); + + app.add_systems(Update, toggle_picking_enabled.in_set(EditorSet::Editor)); + app.insert_resource(GizmoOptions { + hotkeys: Some(transform_gizmo_bevy::GizmoHotkeys::default()), + ..Default::default() + }); } } +fn toggle_picking_enabled( + gizmo_targets: Query<&GizmoTarget>, + mut picking_settings: ResMut, +) { + // Picking is disabled when any of the gizmos is focused or active. + + picking_settings.is_enabled = gizmo_targets + .iter() + .all(|target| !target.is_focused() && !target.is_active()); +} + + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] pub enum GizmoHotkey { Translate, @@ -95,8 +116,6 @@ impl EditorTool for GizmoTool { fn ui(&mut self, ui: &mut egui::Ui, commands: &mut Commands, world: &mut World) { - return; - let sizing = world.resource::(); ui.spacing(); @@ -163,6 +182,33 @@ impl EditorTool for GizmoTool { } + let selected; + { + let mut q_selected = world.query_filtered::>(); + selected = q_selected.iter(&world).collect::>(); + } + + let has_gizmo_targets; + { + let mut q_gizmo_targets = world.query_filtered::>(); + has_gizmo_targets = q_gizmo_targets.iter(&world).collect::>(); + } + + // Add gizmo targets to the selected without gizmo targets + for s in selected.iter() { + if !has_gizmo_targets.contains(s) { + info!("Adding gizmo target to {:?}", s); + commands.entity(*s).insert(GizmoTarget::default()); + } + } + // Remove gizmo targets from the gizmo which are not selected + for s in has_gizmo_targets.iter() { + if !selected.contains(s) { + info!("Removing gizmo target from {:?}", s); + commands.entity(*s).remove::(); + } + } + if ui.ctx().wants_pointer_input() { disable_pan_orbit = true;