diff --git a/src/experimental/platform/ux/plugin.h b/src/experimental/platform/ux/plugin.h index 482a666e..79a9bf72 100644 --- a/src/experimental/platform/ux/plugin.h +++ b/src/experimental/platform/ux/plugin.h @@ -62,6 +62,10 @@ struct ModelPlugin final { int model_name_size); using PostModelLoadedFn = void (*)(ModelPlugin* self, const char* model_path); using DoUpdateFn = bool (*)(ModelPlugin* self, mjModel* model, mjData* data); + using PreStepFn = void (*)(ModelPlugin* self, const mjModel* model, + mjData* data); + using PostStepFn = void (*)(ModelPlugin* self, const mjModel* model, + mjData* data); // The name of the plugin; must be unique. const char* name = ""; @@ -79,6 +83,14 @@ struct ModelPlugin final { // simulation should be stepped. DoUpdateFn do_update = nullptr; + // Callback immediately before mj_step is called on the model. This may be + // called multiple times per update/frame. + PreStepFn pre_step = nullptr; + + // Callback immediately after mj_step is called on the model. This may be + // called multiple times per update/frame. + PostStepFn post_step = nullptr; + // Optional data pointer. void* data = nullptr; }; diff --git a/src/experimental/studio/app.cc b/src/experimental/studio/app.cc index ef2ddfde..7b5855e6 100644 --- a/src/experimental/studio/app.cc +++ b/src/experimental/studio/app.cc @@ -97,6 +97,11 @@ App::App(Config config) mjv_defaultOption(&vis_options_); profiler_.Clear(); + + step_control_.SetPreStepCallback( + [this](const mjModel* m, mjData* d) { PreStep(m, d); }); + step_control_.SetPostStepCallback( + [this](const mjModel* m, mjData* d) { PostStep(m, d); }); } void App::SwitchGraphicsMode(int width, int height, @@ -329,6 +334,22 @@ void App::UpdatePhysics() { } } +void App::PreStep(const mjModel* m, mjData* d) { + platform::ForEachPlugin([&](auto* plugin) { + if (plugin->pre_step) { + plugin->pre_step(plugin, m, d); + } + }); +} + +void App::PostStep(const mjModel* m, mjData* d) { + platform::ForEachPlugin([&](auto* plugin) { + if (plugin->post_step) { + plugin->post_step(plugin, m, d); + } + }); +} + void App::LoadHistory(int offset) { std::span state = sim_history_.SetIndex(offset); if (!state.empty()) { diff --git a/src/experimental/studio/app.h b/src/experimental/studio/app.h index 6676c0d6..d70fb739 100644 --- a/src/experimental/studio/app.h +++ b/src/experimental/studio/app.h @@ -198,6 +198,8 @@ class App { void ResetPhysics(); void UpdatePhysics(); + void PreStep(const mjModel* m, mjData* d); + void PostStep(const mjModel* m, mjData* d); void LoadSettings(); void SaveSettings();