Add mjz support to studio.
PiperOrigin-RevId: 861627355 Change-Id: Iafd291965ca78d03fdc1efe0e40dabcd4f2dacc4
This commit is contained in:
committed by
Copybara-Service
parent
32a4412e2b
commit
fe16255602
@@ -41,6 +41,7 @@
|
|||||||
#include "experimental/platform/renderer.h"
|
#include "experimental/platform/renderer.h"
|
||||||
#include "experimental/platform/step_control.h"
|
#include "experimental/platform/step_control.h"
|
||||||
#include "experimental/platform/window.h"
|
#include "experimental/platform/window.h"
|
||||||
|
#include "user/user_resource.h"
|
||||||
|
|
||||||
namespace mujoco::studio {
|
namespace mujoco::studio {
|
||||||
|
|
||||||
@@ -202,6 +203,22 @@ void App::LoadModelFromFile(const std::string& filepath) {
|
|||||||
mj_deleteVFS(&vfs);
|
mj_deleteVFS(&vfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BufferProvider : public mjpResourceProvider {
|
||||||
|
BufferProvider(std::span<const std::byte> buffer) : buffer(buffer) {
|
||||||
|
mjp_defaultResourceProvider(this);
|
||||||
|
open = [](mjResource* resource) {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
read = [](mjResource* resource, const void** buffer) {
|
||||||
|
BufferProvider* self = (BufferProvider*)resource->provider;
|
||||||
|
*buffer = self->buffer.data();
|
||||||
|
return static_cast<int>(self->buffer.size());
|
||||||
|
};
|
||||||
|
close = [](mjResource* resource) {};
|
||||||
|
}
|
||||||
|
std::span<const std::byte> buffer;
|
||||||
|
};
|
||||||
|
|
||||||
void App::LoadModelFromBuffer(std::span<const std::byte> buffer,
|
void App::LoadModelFromBuffer(std::span<const std::byte> buffer,
|
||||||
std::string_view content_type,
|
std::string_view content_type,
|
||||||
std::string_view filename) {
|
std::string_view filename) {
|
||||||
@@ -217,6 +234,14 @@ void App::LoadModelFromBuffer(std::span<const std::byte> buffer,
|
|||||||
spec = mj_parseXMLString(ptr, nullptr, err, sizeof(err));
|
spec = mj_parseXMLString(ptr, nullptr, err, sizeof(err));
|
||||||
} else if (content_type == "application/mjb") {
|
} else if (content_type == "application/mjb") {
|
||||||
model = mj_loadModelBuffer(buffer.data(), buffer.size());
|
model = mj_loadModelBuffer(buffer.data(), buffer.size());
|
||||||
|
} else if (content_type == "application/zip") {
|
||||||
|
BufferProvider provider(buffer);
|
||||||
|
mjResource resource;
|
||||||
|
memset(&resource, 0, sizeof(mjResource));
|
||||||
|
resource.vfs = &vfs;
|
||||||
|
resource.provider = &provider;
|
||||||
|
resource.name = (char*)filename.data();
|
||||||
|
spec = mju_decodeResource(&resource, content_type.data(), &vfs);
|
||||||
} else {
|
} else {
|
||||||
SetLoadError(
|
SetLoadError(
|
||||||
"Unknown content type; expected text/xml or application/mjb");
|
"Unknown content type; expected text/xml or application/mjb");
|
||||||
|
|||||||
@@ -45,11 +45,13 @@ class App {
|
|||||||
void InitEmptyModel();
|
void InitEmptyModel();
|
||||||
|
|
||||||
// Loads an mjModel from the given file. This extension should be one of:
|
// Loads an mjModel from the given file. This extension should be one of:
|
||||||
// .xml or .mjb.
|
// .xml, .mjb, or .mjz.
|
||||||
void LoadModelFromFile(const std::string& filepath);
|
void LoadModelFromFile(const std::string& filepath);
|
||||||
|
|
||||||
// Loads an mjModel from the given memory buffer. The content_type should be
|
// Loads an mjModel from the given memory buffer. The content_type should be
|
||||||
// one of: "text/xml" or "application/mjb".
|
// one of: "text/xml", "application/mjb", or "application/mjz". For zip files,
|
||||||
|
// a name is required in order to uniquely identify the model within the
|
||||||
|
// archive.
|
||||||
void LoadModelFromBuffer(std::span<const std::byte> buffer,
|
void LoadModelFromBuffer(std::span<const std::byte> buffer,
|
||||||
std::string_view content_type,
|
std::string_view content_type,
|
||||||
std::string_view name);
|
std::string_view name);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<body style="margin: 0; overflow: hidden">
|
<body style="margin: 0; overflow: hidden">
|
||||||
<div style="position: absolute; top: 3px; right: 3px; z-index: 1;">
|
<div style="position: absolute; top: 3px; right: 3px; z-index: 1;">
|
||||||
<button id="uploadButton">Upload Model</button>
|
<button id="uploadButton">Upload Model</button>
|
||||||
<input type="file" id="fileInput" accept=".xml,.mjb" style="display: none;">
|
<input type="file" id="fileInput" accept=".xml,.mjb,.mjz,.zip" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
<canvas
|
<canvas
|
||||||
class="emscripten"
|
class="emscripten"
|
||||||
|
|||||||
@@ -104,6 +104,10 @@ void LoadFile(const std::string& filename, const std::string& data) {
|
|||||||
std::string content_type;
|
std::string content_type;
|
||||||
if (filename.ends_with(".mjb")) {
|
if (filename.ends_with(".mjb")) {
|
||||||
content_type = "application/mjb";
|
content_type = "application/mjb";
|
||||||
|
} else if (filename.ends_with(".mjz")) {
|
||||||
|
content_type = "application/zip";
|
||||||
|
} else if (filename.ends_with(".zip")) {
|
||||||
|
content_type = "application/zip";
|
||||||
} else if (filename.ends_with(".xml")) {
|
} else if (filename.ends_with(".xml")) {
|
||||||
content_type = "text/xml";
|
content_type = "text/xml";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user