use std::time::Duration;
use std::cell::RefCell;
use std::rc::Rc;
use mujoco_rs::viewer::MjViewer;
use mujoco_rs::prelude::*;
const EXAMPLE_MODEL: &str = "
<mujoco>
<worldbody>
<light ambient=\"0.2 0.2 0.2\" pos=\".2 .2 .2\"/>
<body name=\"ball\" pos=\"0 0 0.5\">
<geom name=\"green_sphere\" size=\".1\" rgba=\"0 1 0 1\"/>
<joint type=\"free\"/>
</body>
<geom name=\"floor\" type=\"plane\" size=\"10 10 1\" euler=\"5 0 0\"/>
</worldbody>
</mujoco>
";
struct CustomSimulation {
data: MjData<Rc<MjModel>>,
viewer: MjViewer
}
struct CallbackStorage {
window_open: bool
}
impl CustomSimulation {
fn new(model_xml_string: &str) -> Self {
let model = Rc::new(MjModel::from_xml_string(model_xml_string).expect("could not load the model"));
let data = MjData::new(model.clone());
let mut viewer = MjViewer::launch_passive(model.clone(), 100)
.expect("could not launch the viewer");
let storage = Rc::new(RefCell::new(CallbackStorage { window_open: false }));
viewer.add_ui_callback({
let storage = storage.clone();
move |ctx, _| { use mujoco_rs::viewer::egui;
let mut storage_borrow = storage.borrow_mut();
if ctx.input(|reader| reader.key_pressed(egui::Key::V)) {
storage_borrow.window_open = !storage_borrow.window_open;
}
ctx.input(|reader| {
for event in reader.events.iter() {
match event {
egui::Event::Key { key, pressed: true, ..} => {
println!("A new key has been pressed: {}", key.name());
}
_ => {}
}
}
});
egui::SidePanel::right("custom_panel")
.show(ctx, |ui| {
ui.heading("Custom Panel");
ui.separator();
ui.label("This is a custom side panel");
ui.label("Added via add_ui_callback!");
if ui.button("Example Button").clicked() {
storage_borrow.window_open = !storage_borrow.window_open;
}
});
egui::Window::new("Simulation Info")
.open(&mut storage_borrow.window_open)
.show(ctx, |ui| {
ui.heading("Simulation Information");
ui.separator();
ui.label("This is a custom information window.");
ui.label("You can add any egui widgets here!");
});
}
});
viewer.add_ui_callback({
let storage = storage.clone();
move |ctx, _| {
use mujoco_rs::viewer::egui;
let storage_borrow = storage.borrow();
egui::TopBottomPanel::top("custom_top_panel")
.show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label("Custom Top Bar");
ui.separator();
ui.label("MuJoCo Rust Viewer with Custom Widgets");
});
ui.label(format!("Is window opened: {}", storage_borrow.window_open));
});
}
});
Self { data, viewer }
}
fn viewer_running(&self) -> bool {
self.viewer.running()
}
fn step(&mut self) {
self.data.step();
self.viewer.sync_data(&mut self.data);
self.viewer.render().unwrap();
}
}
fn main() {
let mut simulation = CustomSimulation::new(EXAMPLE_MODEL);
while simulation.viewer_running() {
simulation.step();
std::thread::sleep(Duration::from_millis(2));
}
}