Create mjpDecoder, mj_parse, and mju_decodeResource

- plugin system similar to mjpResourceProvider, but instead of loading a resource it converts an existing mjResource into an mjSpec.
  - The returned spec is then composed into the referencing spec.
  - This enables different file types to generate arbitrary specs, and allows us to separate format parsing from compilation code.

Follow up CLs will move some of the logic in src/engine for PNG, USD, KTX, OBJ loading into decoders.

The mj_parse function MjSpec from a given file, it's a more generic version of mj_parseXML.

In it's implementation, mj_parse as opposed to mj_parseXML will look for any registered decoder and
not assume we are striclty dealing with MJCF.

PiperOrigin-RevId: 826149497
Change-Id: I0ece26904280cb94bd5ded6dd5a565c539d60254
This commit is contained in:
Sam Haves
2025-10-30 12:53:40 -07:00
committed by Copybara-Service
parent f2badc05ac
commit 57f7145806
16 changed files with 2063 additions and 1555 deletions
+20
View File
@@ -17,6 +17,7 @@
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjvisualize.h>
@@ -64,6 +65,25 @@ struct mjpResourceProvider {
};
typedef struct mjpResourceProvider mjpResourceProvider;
//---------------------------------- Decoder -------------------------------------------------------
// function pointer types
// return an mjSpec representing the decoded resource.
typedef mjSpec* (*mjfDecode)(const mjResource* resource);
// return true if the given resource can be decoded.
typedef int (*mjfCanDecode)(const mjResource* resource);
// the struct defining the decoder plugin's interface
struct mjpDecoder {
const char* content_type;
const char* extension;
// user-facing functions
mjfCanDecode can_decode; // quickly check if this decoder can handle the resource
mjfDecode decode; // main decoding function
// the caller takes ownership of the spec returned by decode and is responsible
// for cleaning it up
};
typedef struct mjpDecoder mjpDecoder;
//---------------------------------- Plugins -------------------------------------------------------
+16
View File
@@ -123,6 +123,11 @@ MJAPI mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, i
// Nullable: vfs, error
MJAPI mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);
// Parse spec from a file.
// Nullable: vfs, error
MJAPI mjSpec* mj_parse(const char* filename, const char* content_type,
const mjVFS* vfs, char* error, int error_sz);
// Compile spec to model.
// Nullable: vfs
MJAPI mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);
@@ -1449,6 +1454,17 @@ MJAPI const mjpResourceProvider* mjp_getResourceProvider(const char* resource_na
// If invalid slot number, return NULL.
MJAPI const mjpResourceProvider* mjp_getResourceProviderAtSlot(int slot);
// Globally register a decoder. This function is thread-safe.
// If an identical mjpDecoder is already registered, this function does nothing.
// If a non-identical mjpDecoder with the same name is already registered, an mju_error is raised.
MJAPI void mjp_registerDecoder(const mjpDecoder* decoder);
// Set default resource decoder definition.
MJAPI void mjp_defaultDecoder(mjpDecoder* decoder);
// Return the resource provider with the prefix that matches against the resource name.
// If no match, return NULL.
MJAPI const mjpDecoder* mjp_findDecoder(const mjResource* resource, const char* content_type);
//---------------------------------- Threads -------------------------------------------------------