From edbc1fa30fa0f923fdc3e444d03c9ff3c88d5ece Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Thu, 2 Nov 2023 15:25:14 -0400 Subject: [PATCH] Debug toggling (#9) #8 introduced some additional debug information to the view, which was already rendering some information and visualizations which were not necessary relevant to the end-user experience. This PR adds an input action (bound to Ctrl + `) to toggle the display of those visualizations, and disables them by default. --- studio-frontend/src/app/help.element.ts | 121 ++++++++++++------------ studio-frontend/src/app/util.ts | 5 + studio/src/debug.rs | 83 ++++++++++++++++ studio/src/input.rs | 12 +++ studio/src/interaction.rs | 2 + studio/src/lib.rs | 45 +-------- studio/src/ui/fps.rs | 54 +++++++---- 7 files changed, 203 insertions(+), 119 deletions(-) create mode 100644 studio-frontend/src/app/util.ts create mode 100644 studio/src/debug.rs diff --git a/studio-frontend/src/app/help.element.ts b/studio-frontend/src/app/help.element.ts index d7c207b..4cbef5c 100644 --- a/studio-frontend/src/app/help.element.ts +++ b/studio-frontend/src/app/help.element.ts @@ -1,7 +1,8 @@ -import { LitElement, html, unsafeCSS } from "lit"; +import { LitElement, html, unsafeCSS, nothing, HTMLTemplateResult } from "lit"; import { customElement } from "lit/decorators.js"; import styles from "./help.element.scss?inline"; +import { isDevEnvironment } from "./util"; @customElement("sts-help") export class HelpElement extends LitElement { @@ -9,68 +10,62 @@ export class HelpElement extends LitElement { protected override render = () => html` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ${section("Navigation", [ + { name: "Pan View", controls: "MMB" }, + { name: "Orbit around point", controls: "Alt + LMB" }, + { name: "Zoom", controls: ["Alt + RMB", "Mouse Wheel"]}, + { name: "Free fly", controls: "W, A, S, D, E, Q" }, + { name: "Free look", controls: ["RMB", "Shift"] }, + ])} + ${section("Interaction", [ + { name: "Select", controls: "LMB" }, + { name: "Clear selection", controls: "Esc" }, + { name: "Focus selection", controls: "F" }, + ])} + ${isDevEnvironment() + ? section("Developer", [ + { name: "Toggle debug info", controls: html`Ctrl + `` } + ]) + : nothing}
- Navigation -
ActionControlsAlternate
Pan viewMMB
Orbit around pointAlt + LMB
ZoomAlt + RMBMouse Wheel
Free flyW, A, S, D, E, Q
Free lookRMBShift
- Interaction -
ActionControlsAlternate
SelectLMB
Clear SelectionEsc
Focus SelectionF
`; } + +interface Action { + name: string | HTMLTemplateResult; + controls: + | string + | HTMLTemplateResult + | [ + string | HTMLTemplateResult, + string | HTMLTemplateResult + ]; +} + +function section(title: string, actions: Action[]): HTMLTemplateResult { + return html` + + + ${title} + + + Action + Controls + Alternate + + + + ${actions.map(({ name, controls }) => html` + + ${name} + ${Array.isArray(controls) ? html` + ${controls[0]} + ${controls[1]} + ` : html` + ${controls} + `} + + `)} + + ` +} diff --git a/studio-frontend/src/app/util.ts b/studio-frontend/src/app/util.ts new file mode 100644 index 0000000..302c206 --- /dev/null +++ b/studio-frontend/src/app/util.ts @@ -0,0 +1,5 @@ +export function isDevEnvironment(): boolean { + return window.location.hostname === "localhost" + || window.location.hostname === "127.0.0.1" + || window.location.hostname.includes("deploy-preview"); +} diff --git a/studio/src/debug.rs b/studio/src/debug.rs new file mode 100644 index 0000000..567e201 --- /dev/null +++ b/studio/src/debug.rs @@ -0,0 +1,83 @@ +use bevy::{prelude::*, window::PrimaryWindow}; +use bevy_inspector_egui::quick::WorldInspectorPlugin; +use bevy_mod_picking::debug::DebugPickingMode; + +use crate::{ + camera_controller::{CameraController, CameraMotionSystem}, + input::{Action, InputAction, Lifecycle}, +}; + +#[derive(Resource, Deref, DerefMut)] +pub struct DebugMode(bool); + +pub struct DebugPlugin; +impl Plugin for DebugPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(DebugMode(false)) + .add_plugins(WorldInspectorPlugin::new().run_if(is_debug_mode)) + .insert_resource(State::new(DebugPickingMode::Disabled)) + .insert_resource(GizmoConfig { + enabled: true, + depth_bias: -0.1, + line_perspective: false, + line_width: 2., + ..default() + }) + .add_systems( + Update, + ( + toggle_debug_mode, + update_debug_picking_mode.run_if(resource_changed::()), + update_gizmo_line_thickness, + draw_world_axes + .after(CameraMotionSystem) + .run_if(is_debug_mode), + ), + ); + } +} + +fn toggle_debug_mode(mut input: EventReader, mut r_debug: ResMut) { + if input + .iter() + .any(|action| matches!(action, InputAction(Lifecycle::Stop, Action::ToggleDebug))) + { + **r_debug = !**r_debug; + } +} + +fn update_debug_picking_mode( + r_debug: Res, + mut s_debug_picking: ResMut>, +) { + s_debug_picking.set(match **r_debug { + true => DebugPickingMode::Normal, + false => DebugPickingMode::Disabled, + }); +} + +pub fn is_debug_mode(r_debug: Res) -> bool { + **r_debug +} + +fn update_gizmo_line_thickness( + mut config: ResMut, + q_window: Query<&Window, (Changed, With)>, +) { + if let Ok(scale_factor) = q_window.get_single().map(|win| win.scale_factor() as f32) { + config.line_width = 2. * scale_factor; + } +} + +fn draw_world_axes(mut gizmos: Gizmos, q: Query<&CameraController>) { + let &CameraController { focus, radius, .. } = q.single(); + + let mut draw_axis = |direction: Vec3, color: Color| { + let end = focus + direction * radius / 15.; + gizmos.line(focus, end, color); + }; + + draw_axis(Vec3::X, Color::RED); + draw_axis(Vec3::Y, Color::GREEN); + draw_axis(Vec3::Z, Color::BLUE); +} diff --git a/studio/src/input.rs b/studio/src/input.rs index bd404af..00f31b8 100644 --- a/studio/src/input.rs +++ b/studio/src/input.rs @@ -15,6 +15,7 @@ impl Plugin for StudioInputPlugin { PreUpdate, ( translate_selection_events, + translate_debug_toggle, translate_dcc_camera_events, translate_fps_camera_events, ) @@ -38,6 +39,7 @@ pub enum Lifecycle { pub enum Action { Camera(CameraMotion), Selection(Selection), + ToggleDebug, } #[derive(Clone, Copy)] @@ -83,6 +85,16 @@ fn translate_selection_events(keyboard: Res>, mut input: EventWri } } +fn translate_debug_toggle(keyboard: Res>, mut input: EventWriter) { + if keyboard.pressed(KeyCode::ControlLeft) || keyboard.pressed(KeyCode::ControlRight) { + if keyboard.just_pressed(KeyCode::Grave) { + input.send(InputAction(Lifecycle::Start, Action::ToggleDebug)); + } else if keyboard.just_released(KeyCode::Grave) { + input.send(InputAction(Lifecycle::Stop, Action::ToggleDebug)); + } + } +} + fn translate_dcc_camera_events( mouse_motion: EventReader, mouse_buttons: Res>, diff --git a/studio/src/interaction.rs b/studio/src/interaction.rs index 73ad115..1b08a45 100644 --- a/studio/src/interaction.rs +++ b/studio/src/interaction.rs @@ -6,6 +6,7 @@ use bevy_mod_picking::{prelude::Pointer, selection::Select}; use crate::{ camera_controller::CameraMotionSystem, + debug, input::{self, Action, InputAction, Lifecycle}, }; @@ -29,6 +30,7 @@ impl Plugin for InteractionPlugin { draw_selection_outline.run_if(resource_changed_or_removed::()), draw_selection_axes .run_if(resource_exists::()) + .run_if(debug::is_debug_mode) .after(CameraMotionSystem), ), ); diff --git a/studio/src/lib.rs b/studio/src/lib.rs index 9d8f3cd..24d92b9 100644 --- a/studio/src/lib.rs +++ b/studio/src/lib.rs @@ -1,9 +1,9 @@ #![allow(clippy::type_complexity, clippy::too_many_arguments)] -use bevy::{prelude::*, window::PrimaryWindow}; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +use bevy::prelude::*; use bevy_mod_picking::DefaultPickingPlugins; -use camera_controller::{CameraController, CameraControllerPlugin, CameraMotionSystem}; +use camera_controller::CameraControllerPlugin; +use debug::DebugPlugin; use input::StudioInputPlugin; use interaction::InteractionPlugin; use math::InterpolationPlugin; @@ -14,6 +14,7 @@ use viewport::ViewportSize; use wasm_bindgen::prelude::*; mod camera_controller; +mod debug; mod input; mod interaction; mod math; @@ -42,7 +43,7 @@ pub fn init(viewport_size: ViewportSize) { ..default() }), DefaultPickingPlugins, - WorldInspectorPlugin::new(), + DebugPlugin, InteractionPlugin, StudioInputPlugin, InterpolationPlugin, @@ -51,41 +52,5 @@ pub fn init(viewport_size: ViewportSize) { SkyboxPlugin, UiLayerPlugin, )) - .insert_resource(GizmoConfig { - enabled: true, - depth_bias: -0.1, - line_perspective: false, - line_width: 2., - ..default() - }) - .add_systems( - Update, - ( - update_gizmo_line_thickness, - draw_world_axes.after(CameraMotionSystem), - ), - ) .run(); } - -fn update_gizmo_line_thickness( - mut config: ResMut, - q_window: Query<&Window, (Changed, With)>, -) { - if let Ok(scale_factor) = q_window.get_single().map(|win| win.scale_factor() as f32) { - config.line_width = 2. * scale_factor; - } -} - -fn draw_world_axes(mut gizmos: Gizmos, q: Query<&CameraController>) { - let &CameraController { focus, radius, .. } = q.single(); - - let mut draw_axis = |direction: Vec3, color: Color| { - let end = focus + direction * radius / 15.; - gizmos.line(focus, end, color); - }; - - draw_axis(Vec3::X, Color::RED); - draw_axis(Vec3::Y, Color::GREEN); - draw_axis(Vec3::Z, Color::BLUE); -} diff --git a/studio/src/ui/fps.rs b/studio/src/ui/fps.rs index 101566d..4c6799d 100644 --- a/studio/src/ui/fps.rs +++ b/studio/src/ui/fps.rs @@ -3,13 +3,19 @@ use bevy::{ prelude::*, }; +use crate::debug::DebugMode; + pub(super) struct FpsCounterPlugin; impl Plugin for FpsCounterPlugin { fn build(&self, app: &mut App) { app.add_plugins(FrameTimeDiagnosticsPlugin) .add_systems(Startup, layout) - .add_systems(Update, update); + .add_systems(Update, update) + .add_systems( + Update, + update_visibility.run_if(resource_exists_and_changed::()), + ); } } @@ -17,24 +23,28 @@ impl Plugin for FpsCounterPlugin { struct FramerateCounter; fn layout(mut cmd: Commands) { + let mut text_bundle = TextBundle::from_section( + "0 fps", + TextStyle { + color: Color::GREEN, + font_size: 14., + ..default() + }, + ) + .with_text_alignment(TextAlignment::Right) + .with_style(Style { + position_type: PositionType::Absolute, + right: Val::Px(16.), + bottom: Val::Px(16.), + ..default() + }); + + text_bundle.visibility = Visibility::Hidden; + cmd.spawn(( FramerateCounter, Name::new("Framerate Counter"), - TextBundle::from_section( - "0 fps", - TextStyle { - color: Color::GREEN, - font_size: 14., - ..default() - }, - ) - .with_text_alignment(TextAlignment::Right) - .with_style(Style { - position_type: PositionType::Absolute, - right: Val::Px(16.), - bottom: Val::Px(16.), - ..default() - }), + text_bundle, )); } @@ -53,3 +63,15 @@ fn update( counter.single_mut().sections[0].value = format!("{fps:.2} fps"); } } + +fn update_visibility( + r_debug: Res, + mut q_visibility: Query<&mut Visibility, With>, +) { + for mut visibility in q_visibility.iter_mut() { + *visibility = match **r_debug { + true => Visibility::Inherited, + false => Visibility::Hidden, + } + } +}