Replace Kiss3d by Bevy for the testbed renderer.
This commit is contained in:
@@ -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(feature = "dim3")]
|
||||
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
|
||||
}
|
||||
|
||||
#[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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ui.separator();
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
ui.separator();
|
||||
|
||||
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;
|
||||
}
|
||||
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,
|
||||
))
|
||||
});
|
||||
});
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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,
|
||||
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."),
|
||||
);
|
||||
#[cfg(feature = "parallel")]
|
||||
{
|
||||
ui.add(
|
||||
Slider::new(&mut harness.state.num_threads, 1..num_cpus::get_physical())
|
||||
.text("num. threads"),
|
||||
);
|
||||
}
|
||||
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 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 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 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,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user