feat(client): add a stackable stats overlay toggle
This commit is contained in:
parent
17e7b465ce
commit
d445a29e5e
|
|
@ -6,6 +6,7 @@
|
|||
//!
|
||||
//! - **F1 + V**: filled terrain with vertex points overlaid, showing where the mesher placed geometry without losing the surface.
|
||||
//! - **F1 + B**: filled terrain with the triangle edges overlaid, showing the size and shape of the emitted quads.
|
||||
//! - **F1 + I**: the debug statistics panel.
|
||||
//!
|
||||
//! Holding a [`SOLO_MODIFIER`] (either Shift) as well drops the filled pass, leaving the debug geometry alone against the clear colour: **F1 + Shift + V** for points only, **F1 + Shift + B** for wireframe only.
|
||||
//!
|
||||
|
|
@ -20,6 +21,13 @@ const DEBUG_MODIFIER: KeyCode = KeyCode::F1;
|
|||
/// The keys that, held alongside [`DEBUG_MODIFIER`], select the solo form of a debug view. Both shifts are accepted so the chord is reachable with either hand.
|
||||
const SOLO_MODIFIER: [KeyCode; 2] = [KeyCode::ShiftLeft, KeyCode::ShiftRight];
|
||||
|
||||
const VERTEX_POINTS_OVERLAY_KEY: KeyCode = KeyCode::KeyV;
|
||||
|
||||
const WIREFRAME_OVERLAY_KEY: KeyCode = KeyCode::KeyB;
|
||||
|
||||
/// The key that, held alongside [`DEBUG_MODIFIER`], toggles the statistics panel.
|
||||
const STATS_KEY: KeyCode = KeyCode::KeyI;
|
||||
|
||||
/// A debug operation requested by the input layer, applied by the caller.
|
||||
///
|
||||
/// The layer deliberately returns an intent rather than acting directly, so it owns no renderer or window handles and stays a pure function of key events.
|
||||
|
|
@ -27,6 +35,8 @@ const SOLO_MODIFIER: [KeyCode; 2] = [KeyCode::ShiftLeft, KeyCode::ShiftRight];
|
|||
pub(crate) enum DebugAction {
|
||||
/// Applies the given rasterisation mode to the renderer.
|
||||
SetRenderMode(RenderMode),
|
||||
/// Enables or disables emission of the statistics panel.
|
||||
SetStatsOverlay(bool),
|
||||
}
|
||||
|
||||
/// Owns debug-only input state and translates key events into [`DebugAction`]s.
|
||||
|
|
@ -38,6 +48,8 @@ pub(crate) struct DebugControls {
|
|||
solo_held: bool,
|
||||
/// The rasterisation mode most recently requested, used to make each chord a toggle back to [`RenderMode::Filled`].
|
||||
render_mode: RenderMode,
|
||||
/// Whether the statistics panel is being emitted.
|
||||
stats_enabled: bool,
|
||||
}
|
||||
|
||||
impl DebugControls {
|
||||
|
|
@ -60,6 +72,12 @@ impl DebugControls {
|
|||
return None;
|
||||
}
|
||||
|
||||
// The statistics chord is resolved before the raster table so the two axes never contend for a key. The solo modifier selects between overlaid and standalone geometry and has no meaning for a panel that draws none, so it is ignored here.
|
||||
if code == STATS_KEY {
|
||||
self.stats_enabled = !self.stats_enabled;
|
||||
return Some(DebugAction::SetStatsOverlay(self.stats_enabled));
|
||||
}
|
||||
|
||||
let requested = render_mode_for_key(code, self.solo_held)?;
|
||||
|
||||
// Re-pressing the chord for the active mode returns to the normal path, so a single chord both enables and disables its mode.
|
||||
|
|
@ -78,10 +96,10 @@ impl DebugControls {
|
|||
/// This is the single table a new rasterisation debug mode is added to: one key, one overlaid form, one solo form.
|
||||
const fn render_mode_for_key(code: KeyCode, solo: bool) -> Option<RenderMode> {
|
||||
match (code, solo) {
|
||||
(KeyCode::KeyV, false) => Some(RenderMode::FilledPoints),
|
||||
(KeyCode::KeyV, true) => Some(RenderMode::Points),
|
||||
(KeyCode::KeyB, false) => Some(RenderMode::FilledWireframe),
|
||||
(KeyCode::KeyB, true) => Some(RenderMode::Wireframe),
|
||||
(VERTEX_POINTS_OVERLAY_KEY, false) => Some(RenderMode::FilledPoints),
|
||||
(VERTEX_POINTS_OVERLAY_KEY, true) => Some(RenderMode::Points),
|
||||
(WIREFRAME_OVERLAY_KEY, false) => Some(RenderMode::FilledWireframe),
|
||||
(WIREFRAME_OVERLAY_KEY, true) => Some(RenderMode::Wireframe),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ struct App {
|
|||
last_center: Option<shared::world::ChunkPos>,
|
||||
/// Streams chunk meshes in and out around the camera. `None` until the renderer is initialised on resume.
|
||||
chunks: Option<chunks::ChunkManager>,
|
||||
/// Whether the debug statistics panel is being emitted. Collection is unconditional; only emission is gated on this.
|
||||
stats_overlay: bool,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
|
|
@ -92,6 +94,7 @@ impl Default for App {
|
|||
connected: false,
|
||||
last_center: None,
|
||||
chunks: None,
|
||||
stats_overlay: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +111,10 @@ impl App {
|
|||
info!(?mode, "render mode toggled");
|
||||
}
|
||||
}
|
||||
debug::DebugAction::SetStatsOverlay(enabled) => {
|
||||
self.stats_overlay = enabled;
|
||||
info!(enabled, "statistics overlay toggled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,3 +141,62 @@ fn solo_modifier_alone_produces_no_action() {
|
|||
assert_eq!(controls.handle_key(KeyCode::ShiftLeft, true), None);
|
||||
assert_eq!(tap(&mut controls, KeyCode::KeyV), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_stats_chord_toggles_the_overlay_on_and_off() {
|
||||
let mut controls = DebugControls::default();
|
||||
controls.handle_key(DEBUG_MODIFIER, true);
|
||||
|
||||
assert_eq!(
|
||||
tap(&mut controls, STATS_KEY),
|
||||
Some(DebugAction::SetStatsOverlay(true))
|
||||
);
|
||||
assert_eq!(
|
||||
tap(&mut controls, STATS_KEY),
|
||||
Some(DebugAction::SetStatsOverlay(false))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_stats_chord_leaves_the_render_mode_untouched() {
|
||||
let mut controls = DebugControls::default();
|
||||
controls.handle_key(DEBUG_MODIFIER, true);
|
||||
tap(&mut controls, KeyCode::KeyV);
|
||||
|
||||
tap(&mut controls, STATS_KEY);
|
||||
|
||||
// The raster axis must survive a toggle on the statistics axis; a single-enum design would have reset it.
|
||||
assert_eq!(controls.render_mode, RenderMode::FilledPoints);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_raster_chord_leaves_the_stats_overlay_untouched() {
|
||||
let mut controls = DebugControls::default();
|
||||
controls.handle_key(DEBUG_MODIFIER, true);
|
||||
tap(&mut controls, STATS_KEY);
|
||||
|
||||
assert_eq!(
|
||||
tap(&mut controls, KeyCode::KeyB),
|
||||
Some(DebugAction::SetRenderMode(RenderMode::FilledWireframe))
|
||||
);
|
||||
assert!(controls.stats_enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_solo_modifier_does_not_change_the_stats_chord() {
|
||||
let mut controls = DebugControls::default();
|
||||
controls.handle_key(DEBUG_MODIFIER, true);
|
||||
controls.handle_key(KeyCode::ShiftLeft, true);
|
||||
|
||||
assert_eq!(
|
||||
tap(&mut controls, STATS_KEY),
|
||||
Some(DebugAction::SetStatsOverlay(true))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_stats_chord_requires_the_debug_modifier() {
|
||||
let mut controls = DebugControls::default();
|
||||
assert_eq!(tap(&mut controls, STATS_KEY), None);
|
||||
assert!(!controls.stats_enabled);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue