diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index de01341..139c7d6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,7 +11,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.72.0 + toolchain: 1.83.0 - name: install dependencies run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev diff --git a/Cargo.toml b/Cargo.toml index d437a05..1cea600 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ bevy_window = { version = "0.15", default-features = false } bevy_transform = { version = "0.15", default-features = false } bevy_derive = { version = "0.15", default-features = false } bevy_image = { version = "0.15", default-features = false } +bevy_picking = {version = "0.15", default-features = false} [profile.release] opt-level = "s" diff --git a/crates/transform-gizmo-bevy/Cargo.toml b/crates/transform-gizmo-bevy/Cargo.toml index d9e1321..7509144 100644 --- a/crates/transform-gizmo-bevy/Cargo.toml +++ b/crates/transform-gizmo-bevy/Cargo.toml @@ -27,6 +27,7 @@ bevy_core.workspace = true bevy_core_pipeline.workspace = true bevy_reflect.workspace = true bevy_math.workspace = true +bevy_picking.workspace = true bevy_render.workspace = true bevy_input.workspace = true bevy_asset.workspace = true diff --git a/crates/transform-gizmo-bevy/src/render.rs b/crates/transform-gizmo-bevy/src/render.rs index 04702b9..4a922e3 100644 --- a/crates/transform-gizmo-bevy/src/render.rs +++ b/crates/transform-gizmo-bevy/src/render.rs @@ -192,6 +192,10 @@ impl RenderCommand

for DrawTransformGizmo { return RenderCommandResult::Failure("No GizmoDrawDataHandle inner found"); }; + if gizmo.index_buffer.size() == 0 { + return RenderCommandResult::Failure("gizmo.index_buffer is empty"); + } + pass.set_index_buffer(gizmo.index_buffer.slice(..), 0, IndexFormat::Uint32); pass.set_vertex_buffer(0, gizmo.position_buffer.slice(..)); pass.set_vertex_buffer(1, gizmo.color_buffer.slice(..)); diff --git a/crates/transform-gizmo/src/config.rs b/crates/transform-gizmo/src/config.rs index 16f1578..6f6072b 100644 --- a/crates/transform-gizmo/src/config.rs +++ b/crates/transform-gizmo/src/config.rs @@ -459,7 +459,7 @@ impl Default for GizmoVisuals { z_color: Color32::from_rgb(0, 125, 255), s_color: Color32::from_rgb(255, 255, 255), inactive_alpha: 0.7, - highlight_alpha: 1.0, + highlight_alpha: 0.1, highlight_color: None, stroke_width: 4.0, gizmo_size: 75.0, diff --git a/crates/transform-gizmo/src/gizmo.rs b/crates/transform-gizmo/src/gizmo.rs index c15b578..5f5c4b2 100644 --- a/crates/transform-gizmo/src/gizmo.rs +++ b/crates/transform-gizmo/src/gizmo.rs @@ -325,6 +325,7 @@ impl Gizmo { } /// Picks the subgizmo that is closest to the given world space ray. + #[allow(clippy::manual_inspect)] fn pick_subgizmo(&mut self, ray: Ray) -> Option<&mut SubGizmo> { // If mode is overridden, assume we only have that mode, and choose it. if self.config.mode_override.is_some() { diff --git a/examples/bevy/Cargo.toml b/examples/bevy/Cargo.toml index 66a3537..b8aaf13 100644 --- a/examples/bevy/Cargo.toml +++ b/examples/bevy/Cargo.toml @@ -13,12 +13,12 @@ publish = false transform-gizmo-bevy.workspace = true bevy.workspace = true -bevy_infinite_grid = { git = "https://github.com/tychedelia/bevy_infinite_grid.git", rev = "4044e3219868d82a7db4326a48af58f829c109aa" } -bevy_mod_picking = "0.20.0" -bevy_mod_outline = { git = "https://github.com/komadori/bevy_mod_outline.git", rev = "d24b2eaec26b02f91ef99ebf0d86b982ea05a0ed" } +bevy_infinite_grid = "0.14" +# When bevy_mod_outline is updated to 0.10. Replace this with that. This rev is to use update with jump_flood unwrap panic fix. +bevy_mod_outline = { git = "https://github.com/komadori/bevy_mod_outline.git", rev = "3bd8357c656f6100c3fe13a2d6bab50f6de72a6f" } [dependencies.bevy_egui] -version = "0.29" +version = "0.31" features = ["open_url", "default_fonts", "render"] default-features = false diff --git a/examples/bevy/src/gui.rs b/examples/bevy/src/gui.rs index 54dc21f..76bb3d2 100644 --- a/examples/bevy/src/gui.rs +++ b/examples/bevy/src/gui.rs @@ -152,7 +152,7 @@ fn draw_options(ui: &mut egui::Ui, gizmo_options: &mut GizmoOptions) { .num_columns(2) .show(ui, |ui| { ui.label("Orientation"); - egui::ComboBox::from_id_source("orientation_cb") + egui::ComboBox::from_id_salt("orientation_cb") .selected_text(format!("{:?}", gizmo_options.gizmo_orientation)) .show_ui(ui, |ui| { for orientation in [GizmoOrientation::Global, GizmoOrientation::Local] { @@ -166,7 +166,7 @@ fn draw_options(ui: &mut egui::Ui, gizmo_options: &mut GizmoOptions) { ui.end_row(); ui.label("Pivot point"); - egui::ComboBox::from_id_source("pivot_cb") + egui::ComboBox::from_id_salt("pivot_cb") .selected_text(format!("{:?}", gizmo_options.pivot_point)) .show_ui(ui, |ui| { for pivot_point in [ diff --git a/examples/bevy/src/main.rs b/examples/bevy/src/main.rs index 2a26d7a..e34c7f8 100644 --- a/examples/bevy/src/main.rs +++ b/examples/bevy/src/main.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use camera::PanOrbitCameraPlugin; use gui::GuiPlugin; -use picking::PickingPlugin; +use picking::GizmoPickingPlugin; use scene::ScenePlugin; use transform_gizmo_bevy::GizmoHotkeys; @@ -27,7 +27,7 @@ fn main() { .add_plugins(PanOrbitCameraPlugin) .add_plugins(ScenePlugin) .add_plugins(TransformGizmoPlugin) - .add_plugins(PickingPlugin) + .add_plugins(GizmoPickingPlugin) .insert_resource(GizmoOptions { hotkeys: Some(GizmoHotkeys::default()), ..default() diff --git a/examples/bevy/src/picking.rs b/examples/bevy/src/picking.rs index 4d8f285..6d602a9 100644 --- a/examples/bevy/src/picking.rs +++ b/examples/bevy/src/picking.rs @@ -1,29 +1,31 @@ -use bevy::prelude::*; -use bevy_mod_outline::*; -use bevy_mod_picking::{ - picking_core::PickingPluginsSettings, prelude::*, selection::SelectionPluginSettings, +use bevy::{ + picking::pointer::{PointerInteraction, PointerPress}, + prelude::*, }; +use bevy_mod_outline::*; use transform_gizmo_bevy::GizmoTarget; +#[derive(Component, Clone, Copy)] +pub struct PickSelection { + pub is_selected: bool, +} + /// Integrates picking with gizmo and highlighting. -pub struct PickingPlugin; +pub struct GizmoPickingPlugin; -impl Plugin for PickingPlugin { +impl Plugin for GizmoPickingPlugin { fn build(&self, app: &mut bevy::prelude::App) { - app.add_plugins(DefaultPickingPlugins.build()) - .add_plugins(OutlinePlugin) - .insert_resource(SelectionPluginSettings { - click_nothing_deselect_all: false, - ..default() - }) + app.add_plugins(OutlinePlugin) + .add_plugins(MeshPickingPlugin) .add_systems(PreUpdate, toggle_picking_enabled) - .add_systems(Update, update_picking); + .add_systems(Update, update_picking) + .add_systems(Update, manage_selection); } } fn toggle_picking_enabled( gizmo_targets: Query<&GizmoTarget>, - mut picking_settings: ResMut, + mut picking_settings: ResMut, ) { // Picking is disabled when any of the gizmos is focused or active. @@ -32,17 +34,18 @@ fn toggle_picking_enabled( .all(|target| !target.is_focused() && !target.is_active()); } -fn update_picking( +pub fn update_picking( + mut targets: Query< + ( + Entity, + &PickSelection, + &mut OutlineVolume, + Option<&GizmoTarget>, + ), + Changed, + >, mut commands: Commands, - mut targets: Query<( - Entity, - &PickSelection, - &mut OutlineVolume, - Option<&GizmoTarget>, - )>, ) { - // Continuously update entities based on their picking state - for (entity, pick_interaction, mut outline, gizmo_target) in &mut targets { let mut entity_cmd = commands.entity(entity); @@ -59,3 +62,45 @@ fn update_picking( } } } + +pub fn manage_selection( + pointers: Query<&PointerInteraction, Changed>, + mouse: Res>, + keys: Res>, + mut pick_selection: Query<&mut PickSelection>, +) { + // don't continue if the pointer was just pressed. + if !mouse.just_released(MouseButton::Left) { + return; + }; + let pointer = match pointers.get_single() { + Ok(pointer) => pointer, + Err(err) => match err { + bevy::ecs::query::QuerySingleError::NoEntities(_) => { + // warn!(err); + return; + } + bevy::ecs::query::QuerySingleError::MultipleEntities(_) => { + warn!("demo only works with one pointer. delete extra pointer sources!"); + return; + } + }, + }; + if let Some((e, _)) = pointer.first() { + let Ok(root) = pick_selection.get(*e).map(|n| n.is_selected) else { + return; + }; + + if !keys.pressed(KeyCode::ShiftLeft) { + for mut pick in &mut pick_selection { + pick.is_selected = false; + } + } + + let Ok(mut pick) = pick_selection.get_mut(*e) else { + return; + }; + pick.is_selected = root; + pick.is_selected ^= true; + } +} diff --git a/examples/bevy/src/scene.rs b/examples/bevy/src/scene.rs index 54ec037..deb0c58 100644 --- a/examples/bevy/src/scene.rs +++ b/examples/bevy/src/scene.rs @@ -1,11 +1,11 @@ use bevy::color::palettes::css::{BLUE, LIME, RED}; use bevy::prelude::*; use bevy_mod_outline::*; -use bevy_mod_picking::prelude::*; use transform_gizmo_bevy::GizmoCamera; use crate::camera::PanOrbitCamera; +use crate::picking::PickSelection; pub struct ScenePlugin; @@ -27,10 +27,8 @@ fn setup_scene( radius: camera_transform.translation.length(), ..Default::default() }, - Camera3dBundle { - transform: camera_transform.looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }, + Camera3d::default(), + camera_transform.looking_at(Vec3::ZERO, Vec3::Y), GizmoCamera, )); @@ -41,39 +39,27 @@ fn setup_scene( let colors: [Color; 3] = [RED.into(), LIME.into(), BLUE.into()]; for i in 0..cube_count { - commands - .spawn(( - PbrBundle { - mesh: cube_mesh.clone(), - material: materials.add(colors[i as usize % colors.len()]), - transform: Transform::from_xyz( - -(cube_count / 2) as f32 * 1.5 + (i as f32 * 1.5), - 0.0, - 0.0, - ), - ..default() - }, - PickableBundle { - selection: PickSelection { is_selected: true }, - ..default() - }, - )) - .insert(OutlineBundle { - outline: OutlineVolume { - visible: false, - colour: Color::WHITE, - width: 2.0, - }, - ..default() - }); + commands.spawn(( + Mesh3d(cube_mesh.clone()), + MeshMaterial3d(materials.add(colors[i as usize % colors.len()])), + Transform::from_xyz(-(cube_count / 2) as f32 * 1.5 + (i as f32 * 1.5), 0.0, 0.0), + // Pick, + OutlineVolume { + visible: false, + colour: Color::WHITE, + width: 2.0, + }, + PickSelection { is_selected: true }, + OutlineStencil::default(), + OutlineMode::default(), + ComputedOutline::default(), + )); } - - commands.spawn(PointLightBundle { - point_light: PointLight { + commands.spawn(( + PointLight { shadows_enabled: true, ..default() }, - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }); + Transform::from_xyz(4.0, 8.0, 4.0), + )); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8a909eb..0af9708 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.82.0" +channel = "1.83.0" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"]