Add a ModelPlugin that can be used to load and update models.

PiperOrigin-RevId: 861077626
Change-Id: I3ef4989cfbfff3632c5915c00ebda1e7a48716e8
This commit is contained in:
Haroon Qureshi
2026-01-26 01:23:51 -08:00
committed by Copybara-Service
parent e933081ff1
commit bdb553ff8a
4 changed files with 131 additions and 26 deletions
+37
View File
@@ -36,10 +36,26 @@ void ForEachGuiPlugin(const std::function<void(GuiPlugin*)>& fn) {
}
}
void RegisterModelPlugin(const ModelPlugin* plugin) {
if (plugin->name == nullptr || plugin->name[0] == '\0') {
mju_error("Plugin name must not be empty or null.");
}
GlobalTable<ModelPlugin>::GetSingleton().AppendIfUnique(*plugin);
}
void ForEachModelPlugin(const std::function<void(ModelPlugin*)>& fn) {
auto& table = GlobalTable<ModelPlugin>::GetSingleton();
for (int i = 0; i < table.count(); ++i) {
const ModelPlugin* plugin = table.GetAtSlot(i);
fn(const_cast<ModelPlugin*>(plugin));
}
}
} // namespace mujoco::platform
using mujoco::GlobalTable;
using GuiPlugin = mujoco::platform::GuiPlugin;
using ModelPlugin = mujoco::platform::ModelPlugin;
template <>
const char* GlobalTable<GuiPlugin>::HumanReadableTypeName() {
@@ -61,3 +77,24 @@ bool GlobalTable<GuiPlugin>::CopyObject(GuiPlugin& dst, const GuiPlugin& src, Er
dst = src;
return true;
}
template <>
const char* GlobalTable<ModelPlugin>::HumanReadableTypeName() {
return "model plugin";
}
template <>
std::string_view GlobalTable<ModelPlugin>::ObjectKey(const ModelPlugin& plugin) {
return std::string_view(plugin.name);
}
template <>
bool GlobalTable<ModelPlugin>::ObjectEqual(const ModelPlugin& p1, const ModelPlugin& p2) {
return CaseInsensitiveEqual(p1.name, p2.name);
}
template <>
bool GlobalTable<ModelPlugin>::CopyObject(ModelPlugin& dst, const ModelPlugin& src, ErrorMessage& err) {
dst = src;
return true;
}
+36
View File
@@ -16,6 +16,7 @@
#define MUJOCO_SRC_EXPERIMENTAL_PLATFORM_PLUGIN_H_
#include <functional>
#include <mujoco/mujoco.h>
namespace mujoco::platform {
@@ -46,6 +47,34 @@ struct GuiPlugin final {
void* data = nullptr;
};
struct ModelPlugin final {
using GetModelToLoadFn = const char* (*)(ModelPlugin * self, int* size,
char* content_type,
int content_type_size,
char* model_name,
int model_name_size);
using PostModelLoadedFn = void (*)(ModelPlugin* self, const char* model_path);
using DoUpdateFn = bool (*)(ModelPlugin* self, mjModel* model, mjData* data);
// The name of the plugin; must be unique.
const char* name = "";
// Callback for when the plugin wants to load a new model. This function will
// return a buffer containing the model data as well as the content type of
// the buffer. Returns nullptr if no model needs to be loaded.s
GetModelToLoadFn get_model_to_load = nullptr;
// Callback when a new model is loaded.
PostModelLoadedFn post_model_loaded = nullptr;
// Callback when the physics simulation is updated. Returns true if the
// simulation should be stepped.
DoUpdateFn do_update = nullptr;
// Optional data pointer.
void* data = nullptr;
};
// Registers a plugin with a global registry. The plugin must have a
// case-insensitive unique name.
void RegisterGuiPlugin(const GuiPlugin* plugin);
@@ -53,6 +82,13 @@ void RegisterGuiPlugin(const GuiPlugin* plugin);
// Executes the given function for each registered plugin.
void ForEachGuiPlugin(const std::function<void(GuiPlugin*)>& fn);
// Registers a plugin with a global registry. The plugin must have a
// case-insensitive unique name.
void RegisterModelPlugin(const ModelPlugin* plugin);
// Executes the given function for each registered plugin.
void ForEachModelPlugin(const std::function<void(ModelPlugin*)>& fn);
} // namespace mujoco::platform
#endif // MUJOCO_SRC_EXPERIMENTAL_PLATFORM_PLUGIN_H_