aboutsummaryrefslogtreecommitdiff
path: root/src_testbed/ui.rs
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2021-05-18 10:52:06 +0200
committerGitHub <noreply@github.com>2021-05-18 10:52:06 +0200
commit3bac79ecacdeaa18de19127b7a6c82cbfab29d14 (patch)
tree0d227def6b11bbfe8e14cd021f01ac54f6500f52 /src_testbed/ui.rs
parent355f7a3a3934043a330763ca985264cdb1375405 (diff)
parent47139323e01f978a94ed7aa2c33bbf63b00f4c30 (diff)
downloadrapier-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.rs719
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,
+ )
}