From 5b759d0cb64c961ecebcfe7ba4fd58093ad405e1 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 11 Jul 2024 15:22:16 -0700 Subject: [PATCH] Move the debug hud into blade-helpers --- Cargo.toml | 3 +- blade-helpers/Cargo.toml | 1 + blade-helpers/src/hud.rs | 105 ++++++++++++++++++++++++++++++ blade-helpers/src/lib.rs | 2 + blade-render/src/render/mod.rs | 13 ++-- examples/move/main.rs | 23 +++++++ examples/scene/main.rs | 115 +++------------------------------ src/lib.rs | 46 +++++++++---- 8 files changed, 181 insertions(+), 127 deletions(-) create mode 100644 blade-helpers/src/hud.rs diff --git a/Cargo.toml b/Cargo.toml index ddbc7f8a..6ab8955f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ readme = "docs/README.md" blade-asset = { version = "0.2", path = "blade-asset" } blade-egui = { version = "0.3", path = "blade-egui" } blade-graphics = { version = "0.4", path = "blade-graphics" } +blade-helpers = { version = "0.1", path = "blade-helpers" } blade-util = { version = "0.1", path = "blade-util" } base64 = { workspace = true } choir = { workspace = true } @@ -62,14 +63,12 @@ profiling = { workspace = true } rapier3d = { version = "0.19", features = ["debug-render"] } serde = { version = "1", features = ["serde_derive"] } slab = "0.4" -strum = { workspace = true } winit = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] blade-render = { version = "0.3", path = "blade-render" } [dev-dependencies] -blade-helpers = { version = "0.1", path = "blade-helpers" } blade-macros = { version = "0.2", path = "blade-macros" } bytemuck = { workspace = true } choir = { workspace = true } diff --git a/blade-helpers/Cargo.toml b/blade-helpers/Cargo.toml index 462e4560..7a91909a 100644 --- a/blade-helpers/Cargo.toml +++ b/blade-helpers/Cargo.toml @@ -17,6 +17,7 @@ blade-render = { version = "0.3", path = "../blade-render" } egui = { workspace = true } glam = { workspace = true } mint = { workspace = true } +strum = { workspace = true } winit = { workspace = true } [package.metadata.cargo_check_external_types] diff --git a/blade-helpers/src/hud.rs b/blade-helpers/src/hud.rs new file mode 100644 index 00000000..4d3d7a5d --- /dev/null +++ b/blade-helpers/src/hud.rs @@ -0,0 +1,105 @@ +pub fn populate_debug_hud(debug: &mut blade_render::DebugConfig, ui: &mut egui::Ui) { + use strum::IntoEnumIterator as _; + + egui::ComboBox::from_label("View mode") + .selected_text(format!("{:?}", debug.view_mode)) + .show_ui(ui, |ui| { + for value in blade_render::DebugMode::iter() { + ui.selectable_value(&mut debug.view_mode, value, format!("{value:?}")); + } + }); + + ui.label("Draw debug:"); + for (name, bit) in blade_render::DebugDrawFlags::all().iter_names() { + let mut enabled = debug.draw_flags.contains(bit); + ui.checkbox(&mut enabled, name); + debug.draw_flags.set(bit, enabled); + } + ui.label("Ignore textures:"); + for (name, bit) in blade_render::DebugTextureFlags::all().iter_names() { + let mut enabled = debug.texture_flags.contains(bit); + ui.checkbox(&mut enabled, name); + debug.texture_flags.set(bit, enabled); + } +} + +pub fn populate_debug_selection( + mouse_pos: &mut Option<[i32; 2]>, + selection: &blade_render::SelectionInfo, + asset_hub: &blade_render::AssetHub, + ui: &mut egui::Ui, +) { + let screen_pos = match *mouse_pos { + Some(pos) => pos, + None => return, + }; + + let style = ui.style(); + egui::Frame::group(style).show(ui, |ui| { + ui.horizontal(|ui| { + ui.label("Pixel:"); + ui.colored_label( + egui::Color32::WHITE, + format!("{}x{}", screen_pos[0], screen_pos[1]), + ); + if ui.button("Unselect").clicked() { + *mouse_pos = None; + } + }); + ui.horizontal(|ui| { + let sd = &selection.std_deviation; + ui.label("Std Deviation:"); + ui.colored_label( + egui::Color32::WHITE, + format!("{:.2} {:.2} {:.2}", sd.x, sd.y, sd.z), + ); + }); + ui.horizontal(|ui| { + ui.label("Samples:"); + let power = selection + .std_deviation_history + .next_power_of_two() + .trailing_zeros(); + ui.colored_label(egui::Color32::WHITE, format!("2^{}", power)); + }); + ui.horizontal(|ui| { + ui.label("Depth:"); + ui.colored_label(egui::Color32::WHITE, format!("{:.2}", selection.depth)); + }); + ui.horizontal(|ui| { + let tc = &selection.tex_coords; + ui.label("Texture coords:"); + ui.colored_label(egui::Color32::WHITE, format!("{:.2} {:.2}", tc.x, tc.y)); + }); + ui.horizontal(|ui| { + let wp = &selection.position; + ui.label("World pos:"); + ui.colored_label( + egui::Color32::WHITE, + format!("{:.2} {:.2} {:.2}", wp.x, wp.y, wp.z), + ); + }); + ui.horizontal(|ui| { + ui.label("Base color:"); + if let Some(handle) = selection.base_color_texture { + let name = asset_hub + .textures + .get_main_source_path(handle) + .map(|path| path.display().to_string()) + .unwrap_or_default(); + ui.colored_label(egui::Color32::WHITE, name); + } + }); + ui.horizontal(|ui| { + ui.label("Normal:"); + if let Some(handle) = selection.normal_texture { + let name = asset_hub + .textures + .get_main_source_path(handle) + .map(|path| path.display().to_string()) + .unwrap_or_default(); + ui.colored_label(egui::Color32::WHITE, name); + } + }); + }); +} diff --git a/blade-helpers/src/lib.rs b/blade-helpers/src/lib.rs index 1db6ac4c..201d95a6 100644 --- a/blade-helpers/src/lib.rs +++ b/blade-helpers/src/lib.rs @@ -1,6 +1,8 @@ #![cfg(not(any(gles, target_arch = "wasm32")))] mod camera; +mod hud; pub use blade_render::Camera; pub use camera::ControlledCamera; +pub use hud::{populate_debug_hud, populate_debug_selection}; diff --git a/blade-render/src/render/mod.rs b/blade-render/src/render/mod.rs index c6cf07c2..982bc168 100644 --- a/blade-render/src/render/mod.rs +++ b/blade-render/src/render/mod.rs @@ -1064,12 +1064,13 @@ impl Renderer { self.debug.reset_lines(&mut transfer); } let total_reservoirs = self.surface_size.width as u64 * self.surface_size.height as u64; - let prev_reservoir_buf = self.targets.reservoir_buf[self.frame_index % 2]; - transfer.fill_buffer( - prev_reservoir_buf.into(), - total_reservoirs * self.reservoir_size as u64, - 0, - ); + for reservoir_buf in self.targets.reservoir_buf.iter() { + transfer.fill_buffer( + reservoir_buf.at(0), + total_reservoirs * self.reservoir_size as u64, + 0, + ); + } } self.frame_index += 1; diff --git a/examples/move/main.rs b/examples/move/main.rs index 42de64b3..f3b32dcd 100644 --- a/examples/move/main.rs +++ b/examples/move/main.rs @@ -16,6 +16,8 @@ struct Game { object_handle: blade::ObjectHandle, angle: f32, last_event: time::Instant, + last_mouse_pos: [i32; 2], + is_point_selected: bool, } #[derive(Debug)] @@ -100,6 +102,8 @@ impl Game { object_handle, angle: 0.0, last_event: time::Instant::now(), + last_mouse_pos: [0; 2], + is_point_selected: false, } } @@ -168,6 +172,19 @@ impl Game { }, ); } + winit::event::WindowEvent::MouseInput { + state, + button: winit::event::MouseButton::Right, + .. + } => { + self.is_point_selected = match state { + winit::event::ElementState::Pressed => true, + winit::event::ElementState::Released => false, + }; + } + winit::event::WindowEvent::CursorMoved { position, .. } => { + self.last_mouse_pos = [position.x as i32, position.y as i32]; + } _ => {} } @@ -191,6 +208,12 @@ impl Game { fn on_draw(&mut self) -> time::Duration { self.update_time(); + self.engine.debug_mouse_pos(if self.is_point_selected { + Some(self.last_mouse_pos) + } else { + None + }); + let raw_input = self.egui_state.take_egui_input(&self.window); let egui_context = self.egui_state.egui_ctx().clone(); let egui_output = egui_context.run(raw_input, |egui_ctx| { diff --git a/examples/scene/main.rs b/examples/scene/main.rs index afd11def..55d3b97f 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -2,7 +2,7 @@ #![cfg(not(target_arch = "wasm32"))] use blade_graphics as gpu; -use blade_helpers::ControlledCamera; +use blade_helpers::{populate_debug_hud, populate_debug_selection, ControlledCamera}; use std::{ collections::VecDeque, fmt, fs, @@ -577,112 +577,13 @@ impl Example { egui::CollapsingHeader::new("Debug") .default_open(true) .show(ui, |ui| { - // debug mode - egui::ComboBox::from_label("View mode") - .selected_text(format!("{:?}", self.debug.view_mode)) - .show_ui(ui, |ui| { - for value in blade_render::DebugMode::iter() { - ui.selectable_value( - &mut self.debug.view_mode, - value, - format!("{value:?}"), - ); - } - }); - // debug flags - ui.label("Draw debug:"); - for (name, bit) in blade_render::DebugDrawFlags::all().iter_names() { - let mut enabled = self.debug.draw_flags.contains(bit); - ui.checkbox(&mut enabled, name); - self.debug.draw_flags.set(bit, enabled); - } - ui.label("Ignore textures:"); - for (name, bit) in blade_render::DebugTextureFlags::all().iter_names() { - let mut enabled = self.debug.texture_flags.contains(bit); - ui.checkbox(&mut enabled, name); - self.debug.texture_flags.set(bit, enabled); - } - - // selection info - if let Some(screen_pos) = self.debug.mouse_pos { - let style = ui.style(); - egui::Frame::group(style).show(ui, |ui| { - ui.horizontal(|ui| { - ui.label("Pixel:"); - ui.colored_label( - egui::Color32::WHITE, - format!("{}x{}", screen_pos[0], screen_pos[1]), - ); - if ui.button("Unselect").clicked() { - self.debug.mouse_pos = None; - } - }); - ui.horizontal(|ui| { - let sd = &selection.std_deviation; - ui.label("Std Deviation:"); - ui.colored_label( - egui::Color32::WHITE, - format!("{:.2} {:.2} {:.2}", sd.x, sd.y, sd.z), - ); - }); - ui.horizontal(|ui| { - ui.label("Samples:"); - let power = selection - .std_deviation_history - .next_power_of_two() - .trailing_zeros(); - ui.colored_label(egui::Color32::WHITE, format!("2^{}", power)); - self.need_accumulation_reset |= ui.button("Reset").clicked(); - }); - ui.horizontal(|ui| { - ui.label("Depth:"); - ui.colored_label( - egui::Color32::WHITE, - format!("{:.2}", selection.depth), - ); - }); - ui.horizontal(|ui| { - let tc = &selection.tex_coords; - ui.label("Texture coords:"); - ui.colored_label( - egui::Color32::WHITE, - format!("{:.2} {:.2}", tc.x, tc.y), - ); - }); - ui.horizontal(|ui| { - let wp = &selection.position; - ui.label("World pos:"); - ui.colored_label( - egui::Color32::WHITE, - format!("{:.2} {:.2} {:.2}", wp.x, wp.y, wp.z), - ); - }); - ui.horizontal(|ui| { - ui.label("Base color:"); - if let Some(handle) = selection.base_color_texture { - let name = self - .asset_hub - .textures - .get_main_source_path(handle) - .map(|path| path.display().to_string()) - .unwrap_or_default(); - ui.colored_label(egui::Color32::WHITE, name); - } - }); - ui.horizontal(|ui| { - ui.label("Normal:"); - if let Some(handle) = selection.normal_texture { - let name = self - .asset_hub - .textures - .get_main_source_path(handle) - .map(|path| path.display().to_string()) - .unwrap_or_default(); - ui.colored_label(egui::Color32::WHITE, name); - } - }); - }); - } + populate_debug_hud(&mut self.debug, ui); + populate_debug_selection( + &mut self.debug.mouse_pos, + &selection, + &self.asset_hub, + ui, + ); // blits ui.label("Debug blit:"); diff --git a/src/lib.rs b/src/lib.rs index a0f4c4a7..a012dc9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -711,25 +711,28 @@ impl Engine { #[profiling::function] pub fn populate_hud(&mut self, ui: &mut egui::Ui) { - use strum::IntoEnumIterator as _; + let mut selection = blade_render::SelectionInfo::default(); + if self.debug.mouse_pos.is_some() { + selection = self.renderer.read_debug_selection_info(); + self.selected_object_handle = self.find_object(selection.custom_index); + } + ui.checkbox(&mut self.track_hot_reloads, "Hot reloading"); + egui::CollapsingHeader::new("Rendering") .default_open(true) .show(ui, |ui| { self.need_accumulation_reset |= ui.button("Reset Accumulation").clicked(); ui.checkbox(&mut self.denoiser_enabled, "Enable Denoiser"); - egui::ComboBox::from_label("Debug mode") - .selected_text(format!("{:?}", self.debug.view_mode)) - .show_ui(ui, |ui| { - for value in blade_render::DebugMode::iter() { - ui.selectable_value( - &mut self.debug.view_mode, - value, - format!("{value:?}"), - ); - } - }); + blade_helpers::populate_debug_hud(&mut self.debug, ui); + blade_helpers::populate_debug_selection( + &mut self.debug.mouse_pos, + &selection, + &self.asset_hub, + ui, + ); }); + egui::CollapsingHeader::new("Visualize") .default_open(false) .show(ui, |ui| { @@ -744,6 +747,7 @@ impl Engine { self.physics.debug_pipeline.mode.set(flag, enabled); } }); + egui::CollapsingHeader::new("Objects") .default_open(true) .show(ui, |ui| { @@ -849,6 +853,20 @@ impl Engine { size.width as f32 / size.height.max(1) as f32 } + fn find_object(&self, geometry_index: u32) -> Option { + let mut index = geometry_index as usize; + for (obj_handle, object) in self.objects.iter() { + for visual in object.visuals.iter() { + let model = &self.asset_hub.models[visual.model]; + match index.checked_sub(model.geometries.len()) { + Some(i) => index = i, + None => return Some(ObjectHandle(obj_handle)), + } + } + } + None + } + pub fn add_object( &mut self, config: &config::Object, @@ -1143,4 +1161,8 @@ impl Engine { pub fn set_average_luminosity(&mut self, avg_lum: f32) { self.post_proc_config.average_luminocity = avg_lum; } + + pub fn debug_mouse_pos(&mut self, mouse_pos: Option<[i32; 2]>) { + self.debug.mouse_pos = mouse_pos; + } }