diff options
| author | Sébastien Crozet <developer@crozet.re> | 2021-05-18 10:52:06 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-18 10:52:06 +0200 |
| commit | 3bac79ecacdeaa18de19127b7a6c82cbfab29d14 (patch) | |
| tree | 0d227def6b11bbfe8e14cd021f01ac54f6500f52 /src_testbed/ui.rs | |
| parent | 355f7a3a3934043a330763ca985264cdb1375405 (diff) | |
| parent | 47139323e01f978a94ed7aa2c33bbf63b00f4c30 (diff) | |
| download | rapier-3bac79ecacdeaa18de19127b7a6c82cbfab29d14.tar.gz rapier-3bac79ecacdeaa18de19127b7a6c82cbfab29d14.tar.bz2 rapier-3bac79ecacdeaa18de19127b7a6c82cbfab29d14.zip | |
Merge pull request #189 from dimforge/bevy_renderer
Testbed: replace Kiss3d by Bevy
Diffstat (limited to 'src_testbed/ui.rs')
| -rw-r--r-- | src_testbed/ui.rs | 719 |
1 files changed, 214 insertions, 505 deletions
diff --git a/src_testbed/ui.rs b/src_testbed/ui.rs index 43cdf17..4a21072 100644 --- a/src_testbed/ui.rs +++ b/src_testbed/ui.rs @@ -1,225 +1,65 @@ -use kiss3d::conrod::{self, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget}; -use kiss3d::window::Window; -use rapier::dynamics::IntegrationParameters; +use rapier::counters::Counters; -use crate::harness::RunState; +use crate::harness::Harness; use crate::testbed::{RunMode, TestbedActionFlags, TestbedState, TestbedStateFlags}; -const SIDEBAR_W: f64 = 200.0; -const ELEMENT_W: f64 = SIDEBAR_W - 20.0; -const ELEMENT_H: f64 = 20.0; -const VSPACE: f64 = 4.0; -const TITLE_VSPACE: f64 = 4.0; -const LEFT_MARGIN: f64 = 10.0; -const ALPHA: f32 = 0.9; +use crate::PhysicsState; +use bevy_egui::egui::Slider; +use bevy_egui::{egui, EguiContext}; -widget_ids! { - pub struct ConrodIds { - canvas, - title_backends_list, - title_demos_list, - title_slider_vel_iter, - title_slider_pos_iter, - title_slider_num_threads, - title_slider_ccd_substeps, - title_slider_min_island_size, - title_warmstart_coeff, - title_frequency, - backends_list, - demos_list, - button_pause, - button_single_step, - button_restart, - button_quit, - button_prev_example, - button_next_example, - button_take_snapshot, - button_restore_snapshot, - slider_vel_iter, - slider_pos_iter, - slider_num_threads, - slider_ccd_substeps, - slider_min_island_size, - slider_warmstart_coeff, - slider_frequency, - toggle_sleep, - toggle_warm_starting, - toggle_sub_stepping, - toggle_shapes, - toggle_joints, - toggle_aabbs, - toggle_contact_points, - toggle_contact_normals, - toggle_center_of_masses, - toggle_statistics, - toggle_profile, - toggle_debug, - toggle_wireframe, - separator0, - separator1, - separator2, - } -} - -pub struct TestbedUi { - ids: ConrodIds, -} - -impl TestbedUi { - pub fn new(window: &mut Window) -> Self { - use conrod::position::{Align, Direction, Padding, Position, Relative}; - - let mut ui = window.conrod_ui_mut(); - ui.theme = conrod::Theme { - name: "Testbed theme".to_string(), - padding: Padding::none(), - x_position: Position::Relative(Relative::Align(Align::Start), None), - y_position: Position::Relative(Relative::Direction(Direction::Backwards, 20.0), None), - background_color: conrod::color::DARK_CHARCOAL.alpha(ALPHA), - shape_color: conrod::color::LIGHT_CHARCOAL.alpha(ALPHA), - border_color: conrod::color::BLACK.alpha(ALPHA), - border_width: 0.0, - label_color: conrod::color::WHITE.alpha(ALPHA), - font_id: None, - font_size_large: 15, - font_size_medium: 11, - font_size_small: 8, - widget_styling: conrod::theme::StyleMap::default(), - mouse_drag_threshold: 0.0, - double_click_threshold: std::time::Duration::from_millis(500), - }; - - Self { - ids: ConrodIds::new(ui.widget_id_generator()), - } - } - - pub fn update( - &mut self, - window: &mut Window, - integration_parameters: &mut IntegrationParameters, - state: &mut TestbedState, - _run_state: &mut RunState, - ) { - let ui_root = window.conrod_ui().window; - let mut ui = window.conrod_ui_mut().set_widgets(); - conrod::widget::Canvas::new() - // .title_bar("Demos") - // .title_bar_color(conrod::color::Color::Rgba(1.0, 0.0, 0.0, 1.0)) - // .pad(100.0) - // .pad_left(MARGIN) - // .pad_right(MARGIN) - .scroll_kids_vertically() - .mid_right_with_margin(10.0) - .w(SIDEBAR_W) - .padded_h_of(ui_root, 10.0) - .set(self.ids.canvas, &mut ui); - - // NOTE: If examples_names is empty, we can't change the backend because - // we have no way to properly restart the simulation. +pub fn update_ui(ui_context: &EguiContext, state: &mut TestbedState, harness: &mut Harness) { + egui::Window::new("Parameters").show(ui_context.ctx(), |ui| { if state.backend_names.len() > 1 && !state.example_names.is_empty() { - /* - * Backend drop-down. - */ - conrod::widget::Text::new("Select backend:") - .top_left_with_margins_on(self.ids.canvas, VSPACE, LEFT_MARGIN) - .set(self.ids.title_backends_list, &mut ui); - - for selected in conrod::widget::DropDownList::new( - &state.backend_names, - Some(state.selected_backend), - ) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_backends_list, TITLE_VSPACE) - .left_justify_label() - .w_h(ELEMENT_W, ELEMENT_H) - .color(conrod::color::LIGHT_CHARCOAL) // No alpha. - .set(self.ids.backends_list, &mut ui) - { - if selected != state.selected_backend { - #[cfg(all(feature = "dim3", feature = "other-backends"))] - fn is_physx(id: usize) -> bool { - id == crate::testbed::PHYSX_BACKEND_PATCH_FRICTION - || id == crate::testbed::PHYSX_BACKEND_TWO_FRICTION_DIR + #[cfg(all(feature = "dim3", feature = "other-backends"))] + let prev_selected_backend = state.selected_backend; + let mut changed = false; + egui::ComboBox::from_label("backend") + .width(150.0) + .selected_text(state.backend_names[state.selected_backend]) + .show_ui(ui, |ui| { + for (id, name) in state.backend_names.iter().enumerate() { + changed = ui + .selectable_value(&mut state.selected_backend, id, *name) + .changed() + || changed; } + }); - #[cfg(all(feature = "dim3", feature = "other-backends"))] - if (is_physx(state.selected_backend) && !is_physx(selected)) - || (!is_physx(state.selected_backend) && is_physx(selected)) - { - // PhysX defaults (4 position iterations, 1 velocity) are the - // opposite of rapier's (4 velocity iterations, 1 position). - std::mem::swap( - &mut integration_parameters.max_position_iterations, - &mut integration_parameters.max_velocity_iterations, - ); - } + if changed { + state + .action_flags + .set(TestbedActionFlags::BACKEND_CHANGED, true); - state.selected_backend = selected; - state - .action_flags - .set(TestbedActionFlags::BACKEND_CHANGED, true) + #[cfg(all(feature = "dim3", feature = "other-backends"))] + fn is_physx(id: usize) -> bool { + id == crate::testbed::PHYSX_BACKEND_PATCH_FRICTION + || id == crate::testbed::PHYSX_BACKEND_TWO_FRICTION_DIR } - } - - separator( - self.ids.canvas, - self.ids.backends_list, - self.ids.separator0, - &mut ui, - ); - } else { - conrod::widget::Text::new("") - .top_left_with_margins_on(self.ids.canvas, 0.0, LEFT_MARGIN) - .set(self.ids.separator0, &mut ui); - } - - let display_ticks = state.example_names.len() > 1; - let _select_example_title = if display_ticks { - "Select example:" - } else { - "Current example:" - }; - let tick_width = if display_ticks { 20.0 } else { 0.0 }; - - /* - * Examples drop-down. - */ - conrod::widget::Text::new("Select example:") - .down_from(self.ids.separator0, VSPACE) - // .top_left_with_margins_on(self.ids.canvas, VSPACE, LEFT_MARGIN) - // .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.title_demos_list, &mut ui); - for selected in - conrod::widget::DropDownList::new(&state.example_names, Some(state.selected_example)) - // .mid_top_with_margin_on(self.ids.canvas, 20.0) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_demos_list, TITLE_VSPACE) - // .right_from(self.ids.button_prev_example, 0.0) - .left_justify_label() - .w_h(ELEMENT_W - tick_width, ELEMENT_H) - .color(conrod::color::LIGHT_CHARCOAL) // No alpha. - .set(self.ids.demos_list, &mut ui) - { - if selected != state.selected_example { - state.selected_example = selected; - state - .action_flags - .set(TestbedActionFlags::EXAMPLE_CHANGED, true) + #[cfg(all(feature = "dim3", feature = "other-backends"))] + if (is_physx(state.selected_backend) && !is_physx(prev_selected_backend)) + || (!is_physx(state.selected_backend) && is_physx(prev_selected_backend)) + { + // PhysX defaults (4 position iterations, 1 velocity) are the + // opposite of rapier's (4 velocity iterations, 1 position). + std::mem::swap( + &mut harness + .physics + .integration_parameters + .max_position_iterations, + &mut harness + .physics + .integration_parameters + .max_velocity_iterations, + ); + } } + + ui.separator(); } - if display_ticks { - for _click in conrod::widget::Button::new() - .label("<") - .align_middle_x_of(self.ids.canvas) - .left_from(self.ids.demos_list, 0.0) - .w_h(10.0, ELEMENT_H) - .enabled(state.selected_example > 0) - .color(conrod::color::LIGHT_CHARCOAL) // No alpha. - .set(self.ids.button_prev_example, &mut ui) - { + ui.horizontal(|ui| { + if ui.button("<").clicked() { if state.selected_example > 0 { state.selected_example -= 1; state @@ -228,15 +68,7 @@ impl TestbedUi { } } - for _click in conrod::widget::Button::new() - .label(">") - .align_middle_x_of(self.ids.canvas) - .right_from(self.ids.demos_list, 0.0) - .w_h(10.0, ELEMENT_H) - .enabled(state.selected_example + 1 < state.example_names.len()) - .color(conrod::color::LIGHT_CHARCOAL) // No alpha. - .set(self.ids.button_next_example, &mut ui) - { + if ui.button(">").clicked() { if state.selected_example + 1 < state.example_names.len() { state.selected_example += 1; state @@ -244,199 +76,94 @@ impl TestbedUi { .set(TestbedActionFlags::EXAMPLE_CHANGED, true) } } - } - separator( - self.ids.canvas, - self.ids.demos_list, - self.ids.separator1, - &mut ui, + let mut changed = false; + egui::ComboBox::from_label("example") + .width(150.0) + .selected_text(state.example_names[state.selected_example]) + .show_ui(ui, |ui| { + for (id, name) in state.example_names.iter().enumerate() { + changed = ui + .selectable_value(&mut state.selected_example, id, *name) + .changed() + || changed; + } + }); + if changed { + state + .action_flags + .set(TestbedActionFlags::EXAMPLE_CHANGED, true); + } + }); + + ui.separator(); + + ui.collapsing("Profile infos", |ui| { + ui.horizontal_wrapped(|ui| { + ui.label(profiling_string(&harness.physics.pipeline.counters)) + }); + }); + ui.collapsing("Serialization infos", |ui| { + ui.horizontal_wrapped(|ui| { + ui.label(serialization_string( + harness.state.timestep_id, + &harness.physics, + )) + }); + }); + + let integration_parameters = &mut harness.physics.integration_parameters; + ui.add( + Slider::new(&mut integration_parameters.max_velocity_iterations, 0..=200) + .text("vels. iters."), + ); + ui.add( + Slider::new(&mut integration_parameters.max_position_iterations, 0..=200) + .text("pos. iters."), ); - - let curr_vel_iters = integration_parameters.max_velocity_iterations; - let curr_pos_iters = integration_parameters.max_position_iterations; - #[cfg(feature = "parallel")] - let curr_num_threads = _run_state.num_threads; - let curr_max_ccd_substeps = integration_parameters.max_ccd_substeps; - let curr_min_island_size = integration_parameters.min_island_size; - let curr_warmstart_coeff = integration_parameters.warmstart_coeff; - let curr_frequency = integration_parameters.inv_dt().round() as usize; - - conrod::widget::Text::new("Vel. Iters.:") - .down_from(self.ids.separator1, VSPACE) - .set(self.ids.title_slider_vel_iter, &mut ui); - - for val in conrod::widget::Slider::new(curr_vel_iters as f32, 0.0, 200.0) - .label(&curr_vel_iters.to_string()) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_slider_vel_iter, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_vel_iter, &mut ui) - { - integration_parameters.max_velocity_iterations = val as usize; - } - - conrod::widget::Text::new("Pos. Iters.:") - .down_from(self.ids.slider_vel_iter, VSPACE) - .set(self.ids.title_slider_pos_iter, &mut ui); - - for val in conrod::widget::Slider::new(curr_pos_iters as f32, 0.0, 200.0) - .label(&curr_pos_iters.to_string()) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_slider_pos_iter, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_pos_iter, &mut ui) - { - integration_parameters.max_position_iterations = val as usize; - } - #[cfg(feature = "parallel")] { - conrod::widget::Text::new("Num. Threads.:") - .down_from(self.ids.slider_pos_iter, VSPACE) - .set(self.ids.title_slider_num_threads, &mut ui); - - for val in conrod::widget::Slider::new( - curr_num_threads as f32, - 1.0, - num_cpus::get_physical() as f32, - ) - .label(&curr_num_threads.to_string()) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_slider_num_threads, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_num_threads, &mut ui) - { - if _run_state.num_threads != val as usize { - _run_state.num_threads = val as usize; - _run_state.thread_pool = rapier::rayon::ThreadPoolBuilder::new() - .num_threads(_run_state.num_threads) - .build() - .unwrap(); - } - } - } - - conrod::widget::Text::new("CCD substeps:") - .down_from( - if cfg!(feature = "parallel") { - self.ids.slider_num_threads - } else { - self.ids.slider_pos_iter - }, - VSPACE, - ) - .set(self.ids.title_slider_ccd_substeps, &mut ui); - - for val in conrod::widget::Slider::new(curr_max_ccd_substeps as f32, 0.0, 10.0) - .label(&curr_max_ccd_substeps.to_string()) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_slider_ccd_substeps, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_ccd_substeps, &mut ui) - { - integration_parameters.max_ccd_substeps = val as usize; - } - - conrod::widget::Text::new("Min island size:") - .down_from(self.ids.slider_ccd_substeps, VSPACE) - .set(self.ids.title_slider_min_island_size, &mut ui); - - for val in conrod::widget::Slider::new(curr_min_island_size as f32, 1.0, 10000.0) - .label(&curr_min_island_size.to_string()) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_slider_min_island_size, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_min_island_size, &mut ui) - { - integration_parameters.min_island_size = val as usize; - } - - conrod::widget::Text::new("Warm-start coeff.:") - .down_from(self.ids.slider_min_island_size, VSPACE) - .set(self.ids.title_warmstart_coeff, &mut ui); - - for val in conrod::widget::Slider::new(curr_warmstart_coeff as f32, 0.0, 1.0) - .label(&format!("{:.2}", curr_warmstart_coeff)) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_warmstart_coeff, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_warmstart_coeff, &mut ui) - { - integration_parameters.warmstart_coeff = val; - } - - conrod::widget::Text::new("Frequency:") - .down_from(self.ids.slider_warmstart_coeff, VSPACE) - .set(self.ids.title_frequency, &mut ui); - - for val in conrod::widget::Slider::new(curr_frequency as f32, 0.0, 240.0) - .label(&format!("{:.2}Hz", curr_frequency)) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.title_frequency, TITLE_VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.slider_frequency, &mut ui) - { - integration_parameters.set_inv_dt(val.round()); + ui.add( + Slider::new(&mut harness.state.num_threads, 1..=num_cpus::get_physical()) + .text("num. threads"), + ); } - - let toggle_list = [ - ("Sleep", self.ids.toggle_sleep, TestbedStateFlags::SLEEP), - // ("Warm Starting", self.ids.toggle_warm_starting, TestbedStateFlags::WARM_STARTING), - ( - "Sub-Stepping", - self.ids.toggle_sub_stepping, - TestbedStateFlags::SUB_STEPPING, - ), - ("", self.ids.separator2, TestbedStateFlags::NONE), - // ("Shapes", self.ids.toggle_shapes, TestbedStateFlags::SHAPES), - // ("Joints", self.ids.toggle_joints, TestbedStateFlags::JOINTS), - ("AABBs", self.ids.toggle_aabbs, TestbedStateFlags::AABBS), - ( - "Contacts", - self.ids.toggle_contact_points, - TestbedStateFlags::CONTACT_POINTS, - ), - // ("ContactManifold Normals", self.ids.toggle_contact_normals, TestbedStateFlags::CONTACT_NORMALS), - ( - "Wireframe", - self.ids.toggle_wireframe, - TestbedStateFlags::WIREFRAME, - ), - // ("Center of Masses", self.ids.toggle_center_of_masses, TestbedStateFlags::CENTER_OF_MASSES), - // ("Statistics", self.ids.toggle_statistics, TestbedStateFlags::STATISTICS), - ( - "Profile", - self.ids.toggle_profile, - TestbedStateFlags::PROFILE, - ), - ( - "Debug infos", - self.ids.toggle_debug, - TestbedStateFlags::DEBUG, - ), - ]; - - toggles( - &toggle_list, - self.ids.canvas, - self.ids.slider_frequency, - &mut ui, - &mut state.flags, + ui.add( + Slider::new(&mut integration_parameters.max_ccd_substeps, 0..=10).text("CCD substeps"), ); + ui.add( + Slider::new(&mut integration_parameters.min_island_size, 1..=10_000) + .text("min island size"), + ); + ui.add( + Slider::new(&mut integration_parameters.warmstart_coeff, 0.0..=1.0) + .text("warmstart coeff"), + ); + let mut frequency = integration_parameters.inv_dt().round() as u32; + ui.add(Slider::new(&mut frequency, 0..=240).text("frequency (Hz)")); + integration_parameters.set_inv_dt(frequency as f32); + + let mut sleep = state.flags.contains(TestbedStateFlags::SLEEP); + // let mut contact_points = state.flags.contains(TestbedStateFlags::CONTACT_POINTS); + // let mut wireframe = state.flags.contains(TestbedStateFlags::WIREFRAME); + ui.checkbox(&mut sleep, "sleep enabled"); + // ui.checkbox(&mut contact_points, "draw contacts"); + // ui.checkbox(&mut wireframe, "draw wireframes"); + + state.flags.set(TestbedStateFlags::SLEEP, sleep); + // state + // .flags + // .set(TestbedStateFlags::CONTACT_POINTS, contact_points); + // state.flags.set(TestbedStateFlags::WIREFRAME, wireframe); + ui.separator(); let label = if state.running == RunMode::Stop { "Start (T)" } else { "Pause (T)" }; - for _press in conrod::widget::Button::new() - .label(label) - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.toggle_debug, VSPACE) - .w_h(ELEMENT_W, ELEMENT_H) - .set(self.ids.button_pause, &mut ui) - { + + if ui.button(label).clicked() { if state.running == RunMode::Stop { state.running = RunMode::Running } else { @@ -444,127 +171,109 @@ impl TestbedUi { } } - for _press in conrod::widget::Button::new() - .label("Single Step (S)") - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.button_pause, VSPACE) - .set(self.ids.button_single_step, &mut ui) - { - state.running = RunMode::Step + if ui.button("Single Step (S)").clicked() { + state.running = RunMode::Step; } - for _press in conrod::widget::Button::new() - .label("Take snapshot") - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.button_single_step, VSPACE) - .set(self.ids.button_take_snapshot, &mut ui) - { + if ui.button("Take snapshot").clicked() { state .action_flags .set(TestbedActionFlags::TAKE_SNAPSHOT, true); } - for _press in conrod::widget::Button::new() - .label("Restore snapshot") - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.button_take_snapshot, VSPACE) - .set(self.ids.button_restore_snapshot, &mut ui) - { + if ui.button("Restore snapshot").clicked() { state .action_flags .set(TestbedActionFlags::RESTORE_SNAPSHOT, true); } - let before_quit_button_id = if !state.example_names.is_empty() { - for _press in conrod::widget::Button::new() - .label("Restart (R)") - .align_middle_x_of(self.ids.canvas) - .down_from(self.ids.button_restore_snapshot, VSPACE) - .set(self.ids.button_restart, &mut ui) - { - state.action_flags.set(TestbedActionFlags::RESTART, true); - } - - self.ids.button_restart - } else { - self.ids.button_restore_snapshot - }; - - #[cfg(not(target_arch = "wasm32"))] - for _press in conrod::widget::Button::new() - .label("Quit (Esc)") - .align_middle_x_of(self.ids.canvas) - .down_from(before_quit_button_id, VSPACE) - .set(self.ids.button_quit, &mut ui) - { - state.running = RunMode::Quit + if ui.button("Restart (R)").clicked() { + state.action_flags.set(TestbedActionFlags::RESTART, true); } - } + }); } -fn toggles( - toggles: &[(&str, conrod::widget::Id, TestbedStateFlags)], - canvas: conrod::widget::Id, - prev: conrod::widget::Id, - ui: &mut conrod::UiCell, - flags: &mut TestbedStateFlags, -) { - toggle( - toggles[0].0, - toggles[0].2, - canvas, - prev, - toggles[0].1, - ui, - flags, - ); - - for win in toggles.windows(2) { - toggle(win[1].0, win[1].2, canvas, win[0].1, win[1].1, ui, flags) - } -} - -fn toggle( - title: &str, - flag: TestbedStateFlags, - canvas: conrod::widget::Id, - prev: conrod::widget::Id, - curr: conrod::widget::Id, - ui: &mut conrod::UiCell, - flags: &mut TestbedStateFlags, -) { - if title == "" { - // This is a separator. - separator(canvas, prev, curr, ui) - } else { - for _pressed in conrod::widget::Toggle::new(flags.contains(flag)) - .mid_left_with_margin_on(canvas, LEFT_MARGIN) - .down_from(prev, VSPACE) - .w_h(20.0 /*ELEMENT_W*/, ELEMENT_H) - .label(title) - .label_color(kiss3d::conrod::color::WHITE) - .label_x(conrod::position::Relative::Direction( - conrod::position::Direction::Forwards, - 5.0, - )) - .border(2.0) - // .border_color(kiss3d::conrod::color::WHITE) - .set(curr, ui) - { - flags.toggle(flag) - } - } +fn profiling_string(counters: &Counters) -> String { + format!( + r#"Total: {:.2}ms +Collision detection: {:.2}ms +|_ Broad-phase: {:.2}ms + Narrow-phase: {:.2}ms +Island computation: {:.2}ms +Solver: {:.2}ms +|_ Velocity assembly: {:.2}ms + Velocity resolution: {:.2}ms + Velocity integration: {:.2}ms + Position assembly: {:.2}ms + Position resolution: {:.2}ms +CCD: {:.2}ms +|_ # of substeps: {} + TOI computation: {:.2}ms + Broad-phase: {:.2}ms + Narrow-phase: {:.2}ms + Solver: {:.2}ms"#, + counters.step_time(), + counters.collision_detection_time(), + counters.broad_phase_time(), + counters.narrow_phase_time(), + counters.island_construction_time(), + counters.solver_time(), + counters.solver.velocity_assembly_time.time(), + counters.velocity_resolution_time(), + counters.solver.velocity_update_time.time(), + counters.solver.position_assembly_time.time(), + counters.position_resolution_time(), + counters.ccd_time(), + counters.ccd.num_substeps, + counters.ccd.toi_computation_time.time(), + counters.ccd.broad_phase_time.time(), + counters.ccd.narrow_phase_time.time(), + counters.ccd.solver_time.time(), + ) } -fn separator( - canvas: conrod::widget::Id, - prev: conrod::widget::Id, - curr: conrod::widget::Id, - ui: &mut conrod::UiCell, -) { - conrod::widget::Line::centred([-ELEMENT_W / 2.0, 0.0], [ELEMENT_W / 2.0, 0.0]) - .align_middle_x_of(canvas) - .down_from(prev, VSPACE) - .w(ELEMENT_W) - .set(curr, ui); +fn serialization_string(timestep_id: usize, physics: &PhysicsState) -> String { + let t = instant::now(); + // let t = instant::now(); + let bf = bincode::serialize(&physics.broad_phase).unwrap(); + // println!("bf: {}", instant::now() - t); + // let t = instant::now(); + let nf = bincode::serialize(&physics.narrow_phase).unwrap(); + // println!("nf: {}", instant::now() - t); + // let t = instant::now(); + let bs = bincode::serialize(&physics.bodies).unwrap(); + // println!("bs: {}", instant::now() - t); + // let t = instant::now(); + let cs = bincode::serialize(&physics.colliders).unwrap(); + // println!("cs: {}", instant::now() - t); + // let t = instant::now(); + let js = bincode::serialize(&physics.joints).unwrap(); + // println!("js: {}", instant::now() - t); + let serialization_time = instant::now() - t; + let hash_bf = md5::compute(&bf); + let hash_nf = md5::compute(&nf); + let hash_bodies = md5::compute(&bs); + let hash_colliders = md5::compute(&cs); + let hash_joints = md5::compute(&js); + format!( + r#"Serialization time: {:.2}ms +Hashes at frame: {} +|_ Broad phase [{:.1}KB]: {} +|_ Narrow phase [{:.1}KB]: {} +|_ Bodies [{:.1}KB]: {} +|_ Colliders [{:.1}KB]: {} +|_ Joints [{:.1}KB]: {}"#, + serialization_time, + timestep_id, + bf.len() as f32 / 1000.0, + format!("{:?}", hash_bf).split_at(10).0, + nf.len() as f32 / 1000.0, + format!("{:?}", hash_nf).split_at(10).0, + bs.len() as f32 / 1000.0, + format!("{:?}", hash_bodies).split_at(10).0, + cs.len() as f32 / 1000.0, + format!("{:?}", hash_colliders).split_at(10).0, + js.len() as f32 / 1000.0, + format!("{:?}", hash_joints).split_at(10).0, + ) } |
