16 |
17 | ## The Power of MuJoCo in your Browser.
18 |
19 | Load and Run MuJoCo 2.3.1 Models using JavaScript and WebAssembly.
20 |
21 | This repo is a fork of @stillonearth 's starter repository, adding tons of functionality and a comprehensive example scene.
22 |
23 | ### [See the Live Demo Here](https://zalo.github.io/mujoco_wasm/)
24 |
25 | ### [See a more Advanced Example Here](https://kzakka.com/robopianist/)
26 |
27 | ## Building
28 |
29 | **1. Install emscripten**
30 |
31 | **2. Autogenerate the bindings by running src/parse_mjxmacro.py**
32 |
33 | **3. Build the mujoco_wasm Binary**
34 |
35 | On Linux, use:
36 | ```bash
37 | mkdir build
38 | cd build
39 | emcmake cmake ..
40 | make
41 | ```
42 |
43 | On Windows, run `build_windows.bat`.
44 |
45 | An older version of Emscripten (<3.1.56) may be necessary.
46 |
47 | *4. (Optional) Update MuJoCo libs*
48 |
49 | Build MuJoCo libs with wasm target and place to lib. Currently v2.3.1 included.
50 |
51 | ## JavaScript API
52 |
53 | ```javascript
54 | import load_mujoco from "./mujoco_wasm.js";
55 |
56 | // Load the MuJoCo Module
57 | const mujoco = await load_mujoco();
58 |
59 | // Set up Emscripten's Virtual File System
60 | mujoco.FS.mkdir('/working');
61 | mujoco.FS.mount(mujoco.MEMFS, { root: '.' }, '/working');
62 | mujoco.FS.writeFile("/working/humanoid.xml", await (await fetch("./examples/scenes/humanoid.xml")).text());
63 |
64 | // Load in the state from XML
65 | let model = new mujoco.Model("/working/humanoid.xml");
66 | let state = new mujoco.State(model);
67 | let simulation = new mujoco.Simulation(model, state);
68 | ```
69 |
70 | Typescript definitions are available.
71 |
72 | ## Work In Progress Disclaimer
73 |
74 | So far, most mjModel and mjData state variables and functions (that do not require custom structs) are exposed.
75 |
76 | At some point, I'd like to de-opinionate the binding and make it match the original MuJoCo API better.
77 |
--------------------------------------------------------------------------------
/build_windows.bat:
--------------------------------------------------------------------------------
1 | rem This script requires that the Emscripten SDK has been set up in the directory above this one.
2 | rem Follow the instructions here: https://emscripten.org/docs/getting_started/downloads.html
3 |
4 | call python src/parse_mjxmacro.py
5 | rmdir /s /q build
6 | call ../emsdk/emsdk activate latest
7 | mkdir build
8 | cd build
9 | call emcmake cmake ..
10 | call emmake make
11 | cd ../dist
12 | pause
--------------------------------------------------------------------------------
/dist/mujoco_wasm.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/dist/mujoco_wasm.wasm
--------------------------------------------------------------------------------
/examples/MuJoCoBanner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/examples/MuJoCoBanner.png
--------------------------------------------------------------------------------
/examples/MuJoCoWasmLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/examples/MuJoCoWasmLogo.png
--------------------------------------------------------------------------------
/examples/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/examples/favicon.png
--------------------------------------------------------------------------------
/examples/main.js:
--------------------------------------------------------------------------------
1 |
2 | import * as THREE from 'three';
3 | import { GUI } from '../node_modules/three/examples/jsm/libs/lil-gui.module.min.js';
4 | import { OrbitControls } from '../node_modules/three/examples/jsm/controls/OrbitControls.js';
5 | import { DragStateManager } from './utils/DragStateManager.js';
6 | import { setupGUI, downloadExampleScenesFolder, loadSceneFromURL, getPosition, getQuaternion, toMujocoPos, standardNormal } from './mujocoUtils.js';
7 | import load_mujoco from '../dist/mujoco_wasm.js';
8 |
9 | // Load the MuJoCo Module
10 | const mujoco = await load_mujoco();
11 |
12 | // Set up Emscripten's Virtual File System
13 | var initialScene = "humanoid.xml";
14 | mujoco.FS.mkdir('/working');
15 | mujoco.FS.mount(mujoco.MEMFS, { root: '.' }, '/working');
16 | mujoco.FS.writeFile("/working/" + initialScene, await(await fetch("./examples/scenes/" + initialScene)).text());
17 |
18 | export class MuJoCoDemo {
19 | constructor() {
20 | this.mujoco = mujoco;
21 |
22 | // Load in the state from XML
23 | this.model = new mujoco.Model("/working/" + initialScene);
24 | this.state = new mujoco.State(this.model);
25 | this.simulation = new mujoco.Simulation(this.model, this.state);
26 |
27 | // Define Random State Variables
28 | this.params = { scene: initialScene, paused: false, help: false, ctrlnoiserate: 0.0, ctrlnoisestd: 0.0, keyframeNumber: 0 };
29 | this.mujoco_time = 0.0;
30 | this.bodies = {}, this.lights = {};
31 | this.tmpVec = new THREE.Vector3();
32 | this.tmpQuat = new THREE.Quaternion();
33 | this.updateGUICallbacks = [];
34 |
35 | this.container = document.createElement( 'div' );
36 | document.body.appendChild( this.container );
37 |
38 | this.scene = new THREE.Scene();
39 | this.scene.name = 'scene';
40 |
41 | this.camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.001, 100 );
42 | this.camera.name = 'PerspectiveCamera';
43 | this.camera.position.set(2.0, 1.7, 1.7);
44 | this.scene.add(this.camera);
45 |
46 | this.scene.background = new THREE.Color(0.15, 0.25, 0.35);
47 | this.scene.fog = new THREE.Fog(this.scene.background, 15, 25.5 );
48 |
49 | this.ambientLight = new THREE.AmbientLight( 0xffffff, 0.1 );
50 | this.ambientLight.name = 'AmbientLight';
51 | this.scene.add( this.ambientLight );
52 |
53 | this.renderer = new THREE.WebGLRenderer( { antialias: true } );
54 | this.renderer.setPixelRatio( window.devicePixelRatio );
55 | this.renderer.setSize( window.innerWidth, window.innerHeight );
56 | this.renderer.shadowMap.enabled = true;
57 | this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
58 | this.renderer.setAnimationLoop( this.render.bind(this) );
59 |
60 | this.container.appendChild( this.renderer.domElement );
61 |
62 | this.controls = new OrbitControls(this.camera, this.renderer.domElement);
63 | this.controls.target.set(0, 0.7, 0);
64 | this.controls.panSpeed = 2;
65 | this.controls.zoomSpeed = 1;
66 | this.controls.enableDamping = true;
67 | this.controls.dampingFactor = 0.10;
68 | this.controls.screenSpacePanning = true;
69 | this.controls.update();
70 |
71 | window.addEventListener('resize', this.onWindowResize.bind(this));
72 |
73 | // Initialize the Drag State Manager.
74 | this.dragStateManager = new DragStateManager(this.scene, this.renderer, this.camera, this.container.parentElement, this.controls);
75 | }
76 |
77 | async init() {
78 | // Download the the examples to MuJoCo's virtual file system
79 | await downloadExampleScenesFolder(mujoco);
80 |
81 | // Initialize the three.js Scene using the .xml Model in initialScene
82 | [this.model, this.state, this.simulation, this.bodies, this.lights] =
83 | await loadSceneFromURL(mujoco, initialScene, this);
84 |
85 | this.gui = new GUI();
86 | setupGUI(this);
87 | }
88 |
89 | onWindowResize() {
90 | this.camera.aspect = window.innerWidth / window.innerHeight;
91 | this.camera.updateProjectionMatrix();
92 | this.renderer.setSize( window.innerWidth, window.innerHeight );
93 | }
94 |
95 | render(timeMS) {
96 | this.controls.update();
97 |
98 | if (!this.params["paused"]) {
99 | let timestep = this.model.getOptions().timestep;
100 | if (timeMS - this.mujoco_time > 35.0) { this.mujoco_time = timeMS; }
101 | while (this.mujoco_time < timeMS) {
102 |
103 | // Jitter the control state with gaussian random noise
104 | if (this.params["ctrlnoisestd"] > 0.0) {
105 | let rate = Math.exp(-timestep / Math.max(1e-10, this.params["ctrlnoiserate"]));
106 | let scale = this.params["ctrlnoisestd"] * Math.sqrt(1 - rate * rate);
107 | let currentCtrl = this.simulation.ctrl;
108 | for (let i = 0; i < currentCtrl.length; i++) {
109 | currentCtrl[i] = rate * currentCtrl[i] + scale * standardNormal();
110 | this.params["Actuator " + i] = currentCtrl[i];
111 | }
112 | }
113 |
114 | // Clear old perturbations, apply new ones.
115 | for (let i = 0; i < this.simulation.qfrc_applied.length; i++) { this.simulation.qfrc_applied[i] = 0.0; }
116 | let dragged = this.dragStateManager.physicsObject;
117 | if (dragged && dragged.bodyID) {
118 | for (let b = 0; b < this.model.nbody; b++) {
119 | if (this.bodies[b]) {
120 | getPosition (this.simulation.xpos , b, this.bodies[b].position);
121 | getQuaternion(this.simulation.xquat, b, this.bodies[b].quaternion);
122 | this.bodies[b].updateWorldMatrix();
123 | }
124 | }
125 | let bodyID = dragged.bodyID;
126 | this.dragStateManager.update(); // Update the world-space force origin
127 | let force = toMujocoPos(this.dragStateManager.currentWorld.clone().sub(this.dragStateManager.worldHit).multiplyScalar(this.model.body_mass[bodyID] * 250));
128 | let point = toMujocoPos(this.dragStateManager.worldHit.clone());
129 | this.simulation.applyForce(force.x, force.y, force.z, 0, 0, 0, point.x, point.y, point.z, bodyID);
130 |
131 | // TODO: Apply pose perturbations (mocap bodies only).
132 | }
133 |
134 | this.simulation.step();
135 |
136 | this.mujoco_time += timestep * 1000.0;
137 | }
138 |
139 | } else if (this.params["paused"]) {
140 | this.dragStateManager.update(); // Update the world-space force origin
141 | let dragged = this.dragStateManager.physicsObject;
142 | if (dragged && dragged.bodyID) {
143 | let b = dragged.bodyID;
144 | getPosition (this.simulation.xpos , b, this.tmpVec , false); // Get raw coordinate from MuJoCo
145 | getQuaternion(this.simulation.xquat, b, this.tmpQuat, false); // Get raw coordinate from MuJoCo
146 |
147 | let offset = toMujocoPos(this.dragStateManager.currentWorld.clone()
148 | .sub(this.dragStateManager.worldHit).multiplyScalar(0.3));
149 | if (this.model.body_mocapid[b] >= 0) {
150 | // Set the root body's mocap position...
151 | console.log("Trying to move mocap body", b);
152 | let addr = this.model.body_mocapid[b] * 3;
153 | let pos = this.simulation.mocap_pos;
154 | pos[addr+0] += offset.x;
155 | pos[addr+1] += offset.y;
156 | pos[addr+2] += offset.z;
157 | } else {
158 | // Set the root body's position directly...
159 | let root = this.model.body_rootid[b];
160 | let addr = this.model.jnt_qposadr[this.model.body_jntadr[root]];
161 | let pos = this.simulation.qpos;
162 | pos[addr+0] += offset.x;
163 | pos[addr+1] += offset.y;
164 | pos[addr+2] += offset.z;
165 |
166 | //// Save the original root body position
167 | //let x = pos[addr + 0], y = pos[addr + 1], z = pos[addr + 2];
168 | //let xq = pos[addr + 3], yq = pos[addr + 4], zq = pos[addr + 5], wq = pos[addr + 6];
169 |
170 | //// Clear old perturbations, apply new ones.
171 | //for (let i = 0; i < this.simulation.qfrc_applied().length; i++) { this.simulation.qfrc_applied()[i] = 0.0; }
172 | //for (let bi = 0; bi < this.model.nbody(); bi++) {
173 | // if (this.bodies[b]) {
174 | // getPosition (this.simulation.xpos (), bi, this.bodies[bi].position);
175 | // getQuaternion(this.simulation.xquat(), bi, this.bodies[bi].quaternion);
176 | // this.bodies[bi].updateWorldMatrix();
177 | // }
178 | //}
179 | ////dragStateManager.update(); // Update the world-space force origin
180 | //let force = toMujocoPos(this.dragStateManager.currentWorld.clone()
181 | // .sub(this.dragStateManager.worldHit).multiplyScalar(this.model.body_mass()[b] * 0.01));
182 | //let point = toMujocoPos(this.dragStateManager.worldHit.clone());
183 | //// This force is dumped into xrfc_applied
184 | //this.simulation.applyForce(force.x, force.y, force.z, 0, 0, 0, point.x, point.y, point.z, b);
185 | //this.simulation.integratePos(this.simulation.qpos(), this.simulation.qfrc_applied(), 1);
186 |
187 | //// Add extra drag to the root body
188 | //pos[addr + 0] = x + (pos[addr + 0] - x ) * 0.1;
189 | //pos[addr + 1] = y + (pos[addr + 1] - y ) * 0.1;
190 | //pos[addr + 2] = z + (pos[addr + 2] - z ) * 0.1;
191 | //pos[addr + 3] = xq + (pos[addr + 3] - xq) * 0.1;
192 | //pos[addr + 4] = yq + (pos[addr + 4] - yq) * 0.1;
193 | //pos[addr + 5] = zq + (pos[addr + 5] - zq) * 0.1;
194 | //pos[addr + 6] = wq + (pos[addr + 6] - wq) * 0.1;
195 |
196 |
197 | }
198 | }
199 |
200 | this.simulation.forward();
201 | }
202 |
203 | // Update body transforms.
204 | for (let b = 0; b < this.model.nbody; b++) {
205 | if (this.bodies[b]) {
206 | getPosition (this.simulation.xpos , b, this.bodies[b].position);
207 | getQuaternion(this.simulation.xquat, b, this.bodies[b].quaternion);
208 | this.bodies[b].updateWorldMatrix();
209 | }
210 | }
211 |
212 | // Update light transforms.
213 | for (let l = 0; l < this.model.nlight; l++) {
214 | if (this.lights[l]) {
215 | getPosition(this.simulation.light_xpos, l, this.lights[l].position);
216 | getPosition(this.simulation.light_xdir, l, this.tmpVec);
217 | this.lights[l].lookAt(this.tmpVec.add(this.lights[l].position));
218 | }
219 | }
220 |
221 | // Update tendon transforms.
222 | let numWraps = 0;
223 | if (this.mujocoRoot && this.mujocoRoot.cylinders) {
224 | let mat = new THREE.Matrix4();
225 | for (let t = 0; t < this.model.ntendon; t++) {
226 | let startW = this.simulation.ten_wrapadr[t];
227 | let r = this.model.tendon_width[t];
228 | for (let w = startW; w < startW + this.simulation.ten_wrapnum[t] -1 ; w++) {
229 | let tendonStart = getPosition(this.simulation.wrap_xpos, w , new THREE.Vector3());
230 | let tendonEnd = getPosition(this.simulation.wrap_xpos, w + 1, new THREE.Vector3());
231 | let tendonAvg = new THREE.Vector3().addVectors(tendonStart, tendonEnd).multiplyScalar(0.5);
232 |
233 | let validStart = tendonStart.length() > 0.01;
234 | let validEnd = tendonEnd .length() > 0.01;
235 |
236 | if (validStart) { this.mujocoRoot.spheres.setMatrixAt(numWraps , mat.compose(tendonStart, new THREE.Quaternion(), new THREE.Vector3(r, r, r))); }
237 | if (validEnd ) { this.mujocoRoot.spheres.setMatrixAt(numWraps + 1, mat.compose(tendonEnd , new THREE.Quaternion(), new THREE.Vector3(r, r, r))); }
238 | if (validStart && validEnd) {
239 | mat.compose(tendonAvg, new THREE.Quaternion().setFromUnitVectors(
240 | new THREE.Vector3(0, 1, 0), tendonEnd.clone().sub(tendonStart).normalize()),
241 | new THREE.Vector3(r, tendonStart.distanceTo(tendonEnd), r));
242 | this.mujocoRoot.cylinders.setMatrixAt(numWraps, mat);
243 | numWraps++;
244 | }
245 | }
246 | }
247 | this.mujocoRoot.cylinders.count = numWraps;
248 | this.mujocoRoot.spheres .count = numWraps > 0 ? numWraps + 1: 0;
249 | this.mujocoRoot.cylinders.instanceMatrix.needsUpdate = true;
250 | this.mujocoRoot.spheres .instanceMatrix.needsUpdate = true;
251 | }
252 |
253 | // Render!
254 | this.renderer.render( this.scene, this.camera );
255 | }
256 | }
257 |
258 | let demo = new MuJoCoDemo();
259 | await demo.init();
260 |
--------------------------------------------------------------------------------
/examples/scenes/adhesion.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/examples/scenes/agility_cassie/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022 Agility Robotics
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to
5 | deal in the Software without restriction, including without limitation the
6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 | sell copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 | IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/scenes/agility_cassie/README.md:
--------------------------------------------------------------------------------
1 | # Agility Cassie Description (MJCF)
2 |
3 | ## Overview
4 |
5 | This package contains a simplified robot description (MJCF) of the Cassie
6 | bipedal robot. The original MJCF and assets were provided directly by
7 | [Agility Robotics](http://www.agilityrobotics.com/) under an
8 | [MIT License](LICENSE).
9 |
10 |
11 |
12 |
13 |
14 | ## Modifications made to the original model
15 |
16 | 1. Replaced single quotes with double quotes.
17 | 2. Made collision geoms visible, put them in hidden group 3.
18 | 3. Removed `nuser_actuator` and `nuser_sensor` (automatically inferred since
19 | MuJoCo 2.1.2).
20 | 4. Changed solver from PGS to Newton.
21 | 5. Removed `` clause.
22 | 6. Removed attribute specs which are already default.
23 | 7. Improved collision geometry.
24 | 8. Added `scene.xml` which includes the robot, with a textured groundplane, skybox, and haze.
25 |
26 | ## License
27 |
28 | This model is released under an [MIT License](LICENSE).
29 |
--------------------------------------------------------------------------------
/examples/scenes/agility_cassie/assets/cassie-texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/examples/scenes/agility_cassie/assets/cassie-texture.png
--------------------------------------------------------------------------------
/examples/scenes/agility_cassie/scene.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/examples/scenes/arm26.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/examples/scenes/balloons.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/examples/scenes/flag.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/scenes/generate_index.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | import json
3 |
4 | _HERE = Path(__file__).parent
5 |
6 | _ALLOWED_EXTENSIONS = [".xml", ".png", ".stl", ".obj"]
7 |
8 | if __name__ == "__main__":
9 | files_to_download = []
10 | for path in _HERE.rglob("*"):
11 | if path.is_file() and path.suffix in _ALLOWED_EXTENSIONS:
12 | files_to_download.append(str(path.relative_to(_HERE)))
13 | files_to_download.sort()
14 | with open("index.json", mode="w") as f:
15 | json.dump(files_to_download, f, indent=2)
16 |
--------------------------------------------------------------------------------
/examples/scenes/hammock.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/examples/scenes/humanoid.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
236 |
242 |
248 |
249 |
250 |
--------------------------------------------------------------------------------
/examples/scenes/humanoid_body.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/examples/scenes/index.json:
--------------------------------------------------------------------------------
1 | [
2 | "22_humanoids.xml",
3 | "adhesion.xml",
4 | "agility_cassie/assets/achilles-rod.obj",
5 | "agility_cassie/assets/cassie-texture.png",
6 | "agility_cassie/assets/foot-crank.obj",
7 | "agility_cassie/assets/foot.obj",
8 | "agility_cassie/assets/heel-spring.obj",
9 | "agility_cassie/assets/hip-pitch.obj",
10 | "agility_cassie/assets/hip-roll.obj",
11 | "agility_cassie/assets/hip-yaw.obj",
12 | "agility_cassie/assets/knee-spring.obj",
13 | "agility_cassie/assets/knee.obj",
14 | "agility_cassie/assets/pelvis.obj",
15 | "agility_cassie/assets/plantar-rod.obj",
16 | "agility_cassie/assets/shin.obj",
17 | "agility_cassie/assets/tarsus.obj",
18 | "agility_cassie/cassie.xml",
19 | "agility_cassie/scene.xml",
20 | "arm26.xml",
21 | "balloons.xml",
22 | "flag.xml",
23 | "hammock.xml",
24 | "humanoid.xml",
25 | "humanoid_body.xml",
26 | "mug.obj",
27 | "mug.png",
28 | "mug.xml",
29 | "scene.xml",
30 | "shadow_hand/assets/f_distal_pst.obj",
31 | "shadow_hand/assets/f_knuckle.obj",
32 | "shadow_hand/assets/f_middle.obj",
33 | "shadow_hand/assets/f_proximal.obj",
34 | "shadow_hand/assets/forearm_0.obj",
35 | "shadow_hand/assets/forearm_1.obj",
36 | "shadow_hand/assets/forearm_collision.obj",
37 | "shadow_hand/assets/lf_metacarpal.obj",
38 | "shadow_hand/assets/mounting_plate.obj",
39 | "shadow_hand/assets/palm.obj",
40 | "shadow_hand/assets/th_distal_pst.obj",
41 | "shadow_hand/assets/th_middle.obj",
42 | "shadow_hand/assets/th_proximal.obj",
43 | "shadow_hand/assets/wrist.obj",
44 | "shadow_hand/left_hand.xml",
45 | "shadow_hand/right_hand.xml",
46 | "shadow_hand/scene_left.xml",
47 | "shadow_hand/scene_right.xml",
48 | "simple.xml",
49 | "slider_crank.xml"
50 | ]
--------------------------------------------------------------------------------
/examples/scenes/model_with_tendon.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/examples/scenes/mug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/examples/scenes/mug.png
--------------------------------------------------------------------------------
/examples/scenes/mug.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/examples/scenes/shadow_hand/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2022 Shadow Robot Company Ltd
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/examples/scenes/shadow_hand/README.md:
--------------------------------------------------------------------------------
1 | # Shadow Hand E3M5 Description (MJCF)
2 |
3 | ## Overview
4 |
5 | This package contains assets of the "E3M5" version of the Shadow Hand robot,
6 | including both right-handed and left-handed versions.
7 | The original URDF and assets were provided directly by
8 | [Shadow Robot Company](https://www.shadowrobot.com/) under the
9 | [Apache 2.0 License](LICENSE).
10 |
11 |
12 |
13 |
14 |
15 | ## URDF → MJCF derivation steps
16 |
17 | 1. Converted the DAE [mesh
18 | files](https://github.com/shadow-robot/sr_common/tree/noetic-devel/sr_description/meshes/)
19 | to OBJ format using [Blender](https://www.blender.org/).
20 | 2. Processed `.obj` files with [`obj2mjcf`](https://github.com/kevinzakka/obj2mjcf).
21 | 3. Added `` to the
22 | [URDF](https://github.com/shadow-robot/sr_common/blob/noetic-devel/sr_description/hand/xacro/forearm/forearm_e.urdf.xacro)'s
23 | `` clause in order to preserve visual geometries.
24 | 4. Loaded the URDF into MuJoCo and saved a corresponding MJCF.
25 | 5. Removed `_E3M5` suffix from mesh names.
26 | 6. Added forearm body and its corresponding inertial specs.
27 | 7. Removed 2 artifact boxes left from the URDF conversion.
28 | 8. Manually edited the MJCF to extract common properties into the `` section.
29 | 9. Added `` clauses to prevent collisions between the forearm and the
30 | wrist and thumb bodies.
31 | 10. Added position-controlled actuators.
32 | 11. Added `impratio=10` for better noslip.
33 | 12. Hardened the contacts on the hand geoms.
34 | 13. Added `scene_left.xml` and `scene_right.xml` which include the robot, with
35 | an object, textured groundplane, skybox, and haze.
36 |
37 | ## License
38 |
39 | These models are released under an [Apache-2.0 License](LICENSE).
40 |
--------------------------------------------------------------------------------
/examples/scenes/shadow_hand/scene_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/examples/scenes/shadow_hand/scene_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/examples/scenes/simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/scenes/slider_crank.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/utils/Debug.js:
--------------------------------------------------------------------------------
1 | /** This class provides Debug Utilities. */
2 | class Debug {
3 |
4 | /** Reroute Console Errors to the Main Screen (for mobile) */
5 | constructor() {
6 | // Intercept Main Window Errors as well
7 | window.realConsoleError = console.error;
8 | window.addEventListener('error', (event) => {
9 | let path = event.filename.split("/");
10 | this.display((path[path.length - 1] + ":" + event.lineno + " - " + event.message));
11 | });
12 | console.error = this.fakeError.bind(this);
13 |
14 | // Record whether we're on Safari or Mobile (unused so far)
15 | this.safari = /(Safari)/g.test( navigator.userAgent ) && ! /(Chrome)/g.test( navigator.userAgent );
16 | this.mobile = /(Android|iPad|iPhone|iPod|Oculus)/g.test(navigator.userAgent) || this.safari;
17 | }
18 |
19 | // Log Errors as
s over the main viewport
20 | fakeError(...args) {
21 | if (args.length > 0 && args[0]) { this.display(JSON.stringify(args[0])); }
22 | window.realConsoleError.apply(console, arguments);
23 | }
24 |
25 | display(text) {
26 | //if (this.mobile) {
27 | let errorNode = window.document.getElementById("error");
28 | errorNode.innerHTML += "\n\n"+text.fontcolor("red");
29 | //window.document.getElementById("info").appendChild(errorNode);
30 | //}
31 | }
32 |
33 | }
34 |
35 | export { Debug };
36 | let debug = new Debug();
--------------------------------------------------------------------------------
/examples/utils/DragStateManager.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 | import { Vector3 } from 'three';
3 |
4 | export class DragStateManager {
5 | constructor(scene, renderer, camera, container, controls) {
6 | this.scene = scene;
7 | this.renderer = renderer;
8 | this.camera = camera;
9 | this.mousePos = new THREE.Vector2();
10 | this.raycaster = new THREE.Raycaster();
11 | //this.raycaster.layers.set(1);
12 | // this.raycaster.params.Mesh.threshold = 3;
13 | this.raycaster.params.Line.threshold = 0.1;
14 | this.grabDistance = 0.0;
15 | this.active = false;
16 | this.physicsObject = null;
17 | this.controls = controls;
18 |
19 | this.arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 0), 15, 0x666666);
20 | this.arrow.setLength(15, 3, 1);
21 | this.scene.add(this.arrow);
22 | //this.residuals.push(arrow);
23 | this.arrow.line.material.transparent = true;
24 | this.arrow.cone.material.transparent = true;
25 | this.arrow.line.material.opacity = 0.5;
26 | this.arrow.cone.material.opacity = 0.5;
27 | this.arrow.visible = false;
28 |
29 | this.previouslySelected = null;
30 | this.higlightColor = 0xff0000; // 0x777777
31 |
32 | this.localHit = new Vector3();
33 | this.worldHit = new Vector3();
34 | this.currentWorld = new Vector3();
35 |
36 | container.addEventListener( 'pointerdown', this.onPointer.bind(this), true );
37 | document.addEventListener( 'pointermove', this.onPointer.bind(this), true );
38 | document.addEventListener( 'pointerup' , this.onPointer.bind(this), true );
39 | document.addEventListener( 'pointerout' , this.onPointer.bind(this), true );
40 | container.addEventListener( 'dblclick', this.onPointer.bind(this), false );
41 | }
42 | updateRaycaster(x, y) {
43 | var rect = this.renderer.domElement.getBoundingClientRect();
44 | this.mousePos.x = ((x - rect.left) / rect.width) * 2 - 1;
45 | this.mousePos.y = -((y - rect.top) / rect.height) * 2 + 1;
46 | this.raycaster.setFromCamera(this.mousePos, this.camera);
47 | }
48 | start(x, y) {
49 | this.physicsObject = null;
50 | this.updateRaycaster(x, y);
51 | let intersects = this.raycaster.intersectObjects(this.scene.children);
52 | for (let i = 0; i < intersects.length; i++) {
53 | let obj = intersects[i].object;
54 | if (obj.bodyID && obj.bodyID > 0) {
55 | this.physicsObject = obj;
56 | this.grabDistance = intersects[0].distance;
57 | let hit = this.raycaster.ray.origin.clone();
58 | hit.addScaledVector(this.raycaster.ray.direction, this.grabDistance);
59 | this.arrow.position.copy(hit);
60 | //this.physicsObject.startGrab(hit);
61 | this.active = true;
62 | this.controls.enabled = false;
63 | this.localHit = obj.worldToLocal(hit.clone());
64 | this.worldHit.copy(hit);
65 | this.currentWorld.copy(hit);
66 | this.arrow.visible = true;
67 | break;
68 | }
69 | }
70 | }
71 | move(x, y) {
72 | if (this.active) {
73 | this.updateRaycaster(x, y);
74 | let hit = this.raycaster.ray.origin.clone();
75 | hit.addScaledVector(this.raycaster.ray.direction, this.grabDistance);
76 | this.currentWorld.copy(hit);
77 |
78 | this.update();
79 |
80 | if (this.physicsObject != null) {
81 | //this.physicsObject.moveGrabbed(hit);
82 | }
83 | }
84 | }
85 | update() {
86 | if (this.worldHit && this.localHit && this.currentWorld && this.arrow && this.physicsObject) {
87 | this.worldHit.copy(this.localHit);
88 | this.physicsObject.localToWorld(this.worldHit);
89 | this.arrow.position.copy(this.worldHit);
90 | this.arrow.setDirection(this.currentWorld.clone().sub(this.worldHit).normalize());
91 | this.arrow.setLength(this.currentWorld.clone().sub(this.worldHit).length());
92 | }
93 | }
94 | end(evt) {
95 | //this.physicsObject.endGrab();
96 | this.physicsObject = null;
97 |
98 | this.active = false;
99 | this.controls.enabled = true;
100 | //this.controls.onPointerUp(evt);
101 | this.arrow.visible = false;
102 | this.mouseDown = false;
103 | }
104 | onPointer(evt) {
105 | if (evt.type == "pointerdown") {
106 | this.start(evt.clientX, evt.clientY);
107 | this.mouseDown = true;
108 | } else if (evt.type == "pointermove" && this.mouseDown) {
109 | if (this.active) { this.move(evt.clientX, evt.clientY); }
110 | } else if (evt.type == "pointerup" /*|| evt.type == "pointerout"*/) {
111 | this.end(evt);
112 | }
113 | if (evt.type == "dblclick") {
114 | this.start(evt.clientX, evt.clientY);
115 | this.doubleClick = true;
116 | if (this.physicsObject) {
117 | if (this.physicsObject == this.previouslySelected) {
118 | this.physicsObject.material.emissive.setHex(0x000000);
119 | this.previouslySelected = null;
120 | } else {
121 | if (this.previouslySelected) {
122 | this.previouslySelected.material.emissive.setHex(0x000000);
123 | }
124 | this.physicsObject.material.emissive.setHex(this.higlightColor);
125 | this.previouslySelected = this.physicsObject;
126 | }
127 | } else {
128 | if (this.previouslySelected) {
129 | this.previouslySelected.material.emissive.setHex(0x000000);
130 | this.previouslySelected = null;
131 | }
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/examples/utils/Reflector.js:
--------------------------------------------------------------------------------
1 | import {
2 | Color,
3 | Matrix4,
4 | Mesh,
5 | PerspectiveCamera,
6 | Plane,
7 | ShaderMaterial,
8 | UniformsUtils,
9 | Vector3,
10 | Vector4,
11 | WebGLRenderTarget,
12 | HalfFloatType,
13 | NoToneMapping,
14 | LinearEncoding,
15 | MeshPhysicalMaterial
16 | } from 'three';
17 |
18 | class Reflector extends Mesh {
19 |
20 | constructor( geometry, options = {} ) {
21 |
22 | super( geometry );
23 |
24 | this.isReflector = true;
25 |
26 | this.type = 'Reflector';
27 | this.camera = new PerspectiveCamera();
28 |
29 | const scope = this;
30 |
31 | const color = ( options.color !== undefined ) ? new Color( options.color ) : new Color( 0x7F7F7F );
32 | const textureWidth = options.textureWidth || 512;
33 | const textureHeight = options.textureHeight || 512;
34 | const clipBias = options.clipBias || 0;
35 | const shader = options.shader || Reflector.ReflectorShader;
36 | const multisample = ( options.multisample !== undefined ) ? options.multisample : 4;
37 | const blendTexture = options.texture || undefined;
38 |
39 | //
40 |
41 | const reflectorPlane = new Plane();
42 | const normal = new Vector3();
43 | const reflectorWorldPosition = new Vector3();
44 | const cameraWorldPosition = new Vector3();
45 | const rotationMatrix = new Matrix4();
46 | const lookAtPosition = new Vector3( 0, 0, - 1 );
47 | const clipPlane = new Vector4();
48 |
49 | const view = new Vector3();
50 | const target = new Vector3();
51 | const q = new Vector4();
52 |
53 | const textureMatrix = new Matrix4();
54 | const virtualCamera = this.camera;
55 |
56 | const renderTarget = new WebGLRenderTarget( textureWidth, textureHeight, { samples: multisample, type: HalfFloatType } );
57 |
58 | this.material = new MeshPhysicalMaterial( { map: blendTexture });
59 | this.material.uniforms = { tDiffuse : { value: renderTarget.texture },
60 | textureMatrix: { value: textureMatrix }};
61 | this.material.onBeforeCompile = ( shader ) => {
62 |
63 | // Vertex Shader: Set Vertex Positions to the Unwrapped UV Positions
64 | let bodyStart = shader.vertexShader.indexOf( 'void main() {' );
65 | shader.vertexShader =
66 | shader.vertexShader.slice(0, bodyStart) +
67 | '\nuniform mat4 textureMatrix;\nvarying vec4 vUv3;\n' +
68 | shader.vertexShader.slice( bodyStart - 1, - 1 ) +
69 | ' vUv3 = textureMatrix * vec4( position, 1.0 ); }';
70 |
71 | // Fragment Shader: Set Pixels to 9-tap box blur the current frame's Shadows
72 | bodyStart = shader.fragmentShader.indexOf( 'void main() {' );
73 | shader.fragmentShader =
74 | //'#define USE_UV\n' +
75 | '\nuniform sampler2D tDiffuse; \n varying vec4 vUv3;\n' +
76 | shader.fragmentShader.slice( 0, bodyStart ) +
77 | shader.fragmentShader.slice( bodyStart - 1, - 1 ) +
78 | ` gl_FragColor = vec4( mix( texture2DProj( tDiffuse, vUv3 ).rgb, gl_FragColor.rgb , 0.5), 1.0 );
79 | }`;
80 |
81 | // Set the LightMap Accumulation Buffer
82 | shader.uniforms.tDiffuse = { value: renderTarget.texture };
83 | shader.uniforms.textureMatrix = { value: textureMatrix };
84 | this.material.uniforms = shader.uniforms;
85 |
86 | // Set the new Shader to this
87 | this.material.userData.shader = shader;
88 | };
89 | this.receiveShadow = true;
90 |
91 |
92 | this.onBeforeRender = function ( renderer, scene, camera ) {
93 |
94 | reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
95 | cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
96 |
97 | rotationMatrix.extractRotation( scope.matrixWorld );
98 |
99 | normal.set( 0, 0, 1 );
100 | normal.applyMatrix4( rotationMatrix );
101 |
102 | view.subVectors( reflectorWorldPosition, cameraWorldPosition );
103 |
104 | // Avoid rendering when reflector is facing away
105 |
106 | if ( view.dot( normal ) > 0 ) return;
107 |
108 | view.reflect( normal ).negate();
109 | view.add( reflectorWorldPosition );
110 |
111 | rotationMatrix.extractRotation( camera.matrixWorld );
112 |
113 | lookAtPosition.set( 0, 0, - 1 );
114 | lookAtPosition.applyMatrix4( rotationMatrix );
115 | lookAtPosition.add( cameraWorldPosition );
116 |
117 | target.subVectors( reflectorWorldPosition, lookAtPosition );
118 | target.reflect( normal ).negate();
119 | target.add( reflectorWorldPosition );
120 |
121 | virtualCamera.position.copy( view );
122 | virtualCamera.up.set( 0, 1, 0 );
123 | virtualCamera.up.applyMatrix4( rotationMatrix );
124 | virtualCamera.up.reflect( normal );
125 | virtualCamera.lookAt( target );
126 |
127 | virtualCamera.far = camera.far; // Used in WebGLBackground
128 |
129 | virtualCamera.updateMatrixWorld();
130 | virtualCamera.projectionMatrix.copy( camera.projectionMatrix );
131 |
132 | // Update the texture matrix
133 | textureMatrix.set(
134 | 0.5, 0.0, 0.0, 0.5,
135 | 0.0, 0.5, 0.0, 0.5,
136 | 0.0, 0.0, 0.5, 0.5,
137 | 0.0, 0.0, 0.0, 1.0
138 | );
139 | textureMatrix.multiply( virtualCamera.projectionMatrix );
140 | textureMatrix.multiply( virtualCamera.matrixWorldInverse );
141 | textureMatrix.multiply( scope.matrixWorld );
142 |
143 | // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
144 | // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
145 | reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition );
146 | reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );
147 |
148 | clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant );
149 |
150 | const projectionMatrix = virtualCamera.projectionMatrix;
151 |
152 | q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
153 | q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
154 | q.z = - 1.0;
155 | q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
156 |
157 | // Calculate the scaled plane vector
158 | clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
159 |
160 | // Replacing the third row of the projection matrix
161 | projectionMatrix.elements[ 2 ] = clipPlane.x;
162 | projectionMatrix.elements[ 6 ] = clipPlane.y;
163 | projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
164 | projectionMatrix.elements[ 14 ] = clipPlane.w;
165 |
166 | // Render
167 | scope.visible = false;
168 |
169 | const currentRenderTarget = renderer.getRenderTarget();
170 |
171 | const currentXrEnabled = renderer.xr.enabled;
172 | const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
173 | const currentOutputEncoding = renderer.outputEncoding;
174 | const currentToneMapping = renderer.toneMapping;
175 |
176 | renderer.xr.enabled = false; // Avoid camera modification
177 | renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
178 | renderer.outputEncoding = LinearEncoding;
179 | renderer.toneMapping = NoToneMapping;
180 |
181 | renderer.setRenderTarget( renderTarget );
182 |
183 | renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897
184 |
185 | if ( renderer.autoClear === false ) renderer.clear();
186 | renderer.render( scene, virtualCamera );
187 |
188 | renderer.xr.enabled = currentXrEnabled;
189 | renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
190 | renderer.outputEncoding = currentOutputEncoding;
191 | renderer.toneMapping = currentToneMapping;
192 |
193 | renderer.setRenderTarget( currentRenderTarget );
194 |
195 | // Restore viewport
196 |
197 | const viewport = camera.viewport;
198 |
199 | if ( viewport !== undefined ) {
200 |
201 | renderer.state.viewport( viewport );
202 |
203 | }
204 |
205 | scope.visible = true;
206 |
207 | };
208 |
209 | this.getRenderTarget = function () {
210 |
211 | return renderTarget;
212 |
213 | };
214 |
215 | this.dispose = function () {
216 |
217 | renderTarget.dispose();
218 | scope.material.dispose();
219 |
220 | };
221 |
222 | }
223 |
224 | }
225 |
226 | export { Reflector };
227 |
--------------------------------------------------------------------------------
/include/mujoco/mjexport.h:
--------------------------------------------------------------------------------
1 | // Copyright 2021 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_MJEXPORT_H_
16 | #define MUJOCO_MJEXPORT_H_
17 |
18 | #if defined _WIN32 || defined __CYGWIN__
19 | #define MUJOCO_HELPER_DLL_IMPORT __declspec(dllimport)
20 | #define MUJOCO_HELPER_DLL_EXPORT __declspec(dllexport)
21 | #define MUJOCO_HELPER_DLL_LOCAL
22 | #else
23 | #if __GNUC__ >= 4
24 | #define MUJOCO_HELPER_DLL_IMPORT __attribute__ ((visibility ("default")))
25 | #define MUJOCO_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
26 | #define MUJOCO_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden")))
27 | #else
28 | #define MUJOCO_HELPER_DLL_IMPORT
29 | #define MUJOCO_HELPER_DLL_EXPORT
30 | #define MUJOCO_HELPER_DLL_LOCAL
31 | #endif
32 | #endif
33 |
34 | #ifdef MJ_STATIC
35 | // static library
36 | #define MJAPI
37 | #define MJLOCAL
38 | #else
39 | #ifdef MUJOCO_DLL_EXPORTS
40 | #define MJAPI MUJOCO_HELPER_DLL_EXPORT
41 | #else
42 | #define MJAPI MUJOCO_HELPER_DLL_IMPORT
43 | #endif
44 | #define MJLOCAL MUJOCO_HELPER_DLL_LOCAL
45 | #endif
46 |
47 | #endif // MUJOCO_MJEXPORT_H_
48 |
--------------------------------------------------------------------------------
/include/mujoco/mjplugin.h:
--------------------------------------------------------------------------------
1 | // Copyright 2022 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_INCLUDE_MJPLUGIN_H_
16 | #define MUJOCO_INCLUDE_MJPLUGIN_H_
17 |
18 | #include
19 | #include
20 | #include
21 |
22 |
23 | typedef enum mjtPluginTypeBit_ {
24 | mjPLUGIN_ACTUATOR = 1<<0,
25 | mjPLUGIN_SENSOR = 1<<1,
26 | mjPLUGIN_PASSIVE = 1<<2,
27 | } mjtPluginTypeBit;
28 |
29 | struct mjpPlugin_ {
30 | const char* name; // globally unique name identifying the plugin
31 |
32 | int nattribute; // number of configuration attributes
33 | const char* const* attributes; // name of configuration attributes
34 |
35 | int type; // bitfield of mjtPluginTypeBits specifying the plugin type
36 | int needstage; // an mjtStage enum value specifying the sensor computation stage
37 |
38 | // number of mjtNums needed to store the state of a plugin instance (required)
39 | int (*nstate)(const mjModel* m, int instance);
40 |
41 | // dimension of the specified sensor's output (required only for sensor plugins)
42 | int (*nsensordata)(const mjModel* m, int instance, int sensor_id);
43 |
44 | // called when a new mjData is being created (required), returns 0 on success or -1 on failure
45 | int (*init)(const mjModel* m, mjData* d, int instance);
46 |
47 | // called when an mjData is being freed (optional)
48 | void (*destroy)(mjData* d, int instance);
49 |
50 | // called when an mjData is being copied (optional)
51 | void (*copy)(mjData* dest, const mjModel* m, const mjData* src, int instance);
52 |
53 | // called when an mjData is being reset (required)
54 | void (*reset)(const mjModel* m, mjData* d, int instance);
55 |
56 | // called when the plugin needs to update its outputs (required)
57 | void (*compute)(const mjModel* m, mjData* d, int instance, int type);
58 |
59 | // called when time integration occurs (optional)
60 | void (*advance)(const mjModel* m, mjData* d, int instance);
61 |
62 | // called by mjv_updateScene (optional)
63 | void (*visualize)(const mjModel*m, mjData* d, mjvScene* scn, int instance);
64 | };
65 | typedef struct mjpPlugin_ mjpPlugin;
66 |
67 | #if defined(__has_attribute)
68 |
69 | #if __has_attribute(constructor)
70 | #define mjPLUGIN_DYNAMIC_LIBRARY_INIT \
71 | __attribute__((constructor)) static void _mjplugin_init(void)
72 | #endif
73 |
74 | #elif defined(_MSC_VER)
75 |
76 | #ifndef mjDLLMAIN
77 | #define mjDLLMAIN DllMain
78 | #endif
79 |
80 | #if !defined(mjEXTERNC)
81 | #if defined(__cplusplus)
82 | #define mjEXTERNC extern "C"
83 | #else
84 | #define mjEXTERNC
85 | #endif // defined(__cplusplus)
86 | #endif // !defined(mjEXTERNC)
87 |
88 | // NOLINTBEGIN(runtime/int)
89 | #define mjPLUGIN_DYNAMIC_LIBRARY_INIT \
90 | static void _mjplugin_dllmain(void); \
91 | mjEXTERNC int __stdcall mjDLLMAIN(void* hinst, unsigned long reason, void* reserved) { \
92 | if (reason == 1) { \
93 | _mjplugin_dllmain(); \
94 | } \
95 | return 1; \
96 | } \
97 | static void _mjplugin_dllmain(void)
98 | // NOLINTEND(runtime/int)
99 |
100 | #endif // defined(_MSC_VER)
101 |
102 | // function pointer type for mj_loadAllPluginLibraries callback
103 | typedef void (*mjfPluginLibraryLoadCallback)(const char* filename, int first, int count);
104 |
105 | #endif // MUJOCO_INCLUDE_MJPLUGIN_H_
106 |
--------------------------------------------------------------------------------
/include/mujoco/mjrender.h:
--------------------------------------------------------------------------------
1 | // Copyright 2021 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_MJRENDER_H_
16 | #define MUJOCO_MJRENDER_H_
17 |
18 | #include
19 |
20 | #if defined(__cplusplus)
21 | extern "C" {
22 | #endif
23 |
24 | #define mjNAUX 10 // number of auxiliary buffers
25 | #define mjMAXTEXTURE 1000 // maximum number of textures
26 |
27 |
28 | //---------------------------------- primitive types (mjt) -----------------------------------------
29 |
30 | typedef enum mjtGridPos_ { // grid position for overlay
31 | mjGRID_TOPLEFT = 0, // top left
32 | mjGRID_TOPRIGHT, // top right
33 | mjGRID_BOTTOMLEFT, // bottom left
34 | mjGRID_BOTTOMRIGHT // bottom right
35 | } mjtGridPos;
36 |
37 |
38 | typedef enum mjtFramebuffer_ { // OpenGL framebuffer option
39 | mjFB_WINDOW = 0, // default/window buffer
40 | mjFB_OFFSCREEN // offscreen buffer
41 | } mjtFramebuffer;
42 |
43 |
44 | typedef enum mjtFontScale_ { // font scale, used at context creation
45 | mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering
46 | mjFONTSCALE_100 = 100, // normal scale, suitable in the absence of DPI scaling
47 | mjFONTSCALE_150 = 150, // 150% scale
48 | mjFONTSCALE_200 = 200, // 200% scale
49 | mjFONTSCALE_250 = 250, // 250% scale
50 | mjFONTSCALE_300 = 300 // 300% scale
51 | } mjtFontScale;
52 |
53 |
54 | typedef enum mjtFont_ { // font type, used at each text operation
55 | mjFONT_NORMAL = 0, // normal font
56 | mjFONT_SHADOW, // normal font with shadow (for higher contrast)
57 | mjFONT_BIG // big font (for user alerts)
58 | } mjtFont;
59 |
60 |
61 | struct mjrRect_ { // OpenGL rectangle
62 | int left; // left (usually 0)
63 | int bottom; // bottom (usually 0)
64 | int width; // width (usually buffer width)
65 | int height; // height (usually buffer height)
66 | };
67 | typedef struct mjrRect_ mjrRect;
68 |
69 |
70 | //---------------------------------- mjrContext ----------------------------------------------------
71 |
72 | struct mjrContext_ { // custom OpenGL context
73 | // parameters copied from mjVisual
74 | float lineWidth; // line width for wireframe rendering
75 | float shadowClip; // clipping radius for directional lights
76 | float shadowScale; // fraction of light cutoff for spot lights
77 | float fogStart; // fog start = stat.extent * vis.map.fogstart
78 | float fogEnd; // fog end = stat.extent * vis.map.fogend
79 | float fogRGBA[4]; // fog rgba
80 | int shadowSize; // size of shadow map texture
81 | int offWidth; // width of offscreen buffer
82 | int offHeight; // height of offscreen buffer
83 | int offSamples; // number of offscreen buffer multisamples
84 |
85 | // parameters specified at creation
86 | int fontScale; // font scale
87 | int auxWidth[mjNAUX]; // auxiliary buffer width
88 | int auxHeight[mjNAUX]; // auxiliary buffer height
89 | int auxSamples[mjNAUX]; // auxiliary buffer multisamples
90 |
91 | // offscreen rendering objects
92 | unsigned int offFBO; // offscreen framebuffer object
93 | unsigned int offFBO_r; // offscreen framebuffer for resolving multisamples
94 | unsigned int offColor; // offscreen color buffer
95 | unsigned int offColor_r; // offscreen color buffer for resolving multisamples
96 | unsigned int offDepthStencil; // offscreen depth and stencil buffer
97 | unsigned int offDepthStencil_r; // offscreen depth and stencil buffer for resolving multisamples
98 |
99 | // shadow rendering objects
100 | unsigned int shadowFBO; // shadow map framebuffer object
101 | unsigned int shadowTex; // shadow map texture
102 |
103 | // auxiliary buffers
104 | unsigned int auxFBO[mjNAUX]; // auxiliary framebuffer object
105 | unsigned int auxFBO_r[mjNAUX]; // auxiliary framebuffer object for resolving
106 | unsigned int auxColor[mjNAUX]; // auxiliary color buffer
107 | unsigned int auxColor_r[mjNAUX];// auxiliary color buffer for resolving
108 |
109 | // texture objects and info
110 | int ntexture; // number of allocated textures
111 | int textureType[100]; // type of texture (mjtTexture) (ntexture)
112 | unsigned int texture[100]; // texture names
113 |
114 | // displaylist starting positions
115 | unsigned int basePlane; // all planes from model
116 | unsigned int baseMesh; // all meshes from model
117 | unsigned int baseHField; // all hfields from model
118 | unsigned int baseBuiltin; // all buildin geoms, with quality from model
119 | unsigned int baseFontNormal; // normal font
120 | unsigned int baseFontShadow; // shadow font
121 | unsigned int baseFontBig; // big font
122 |
123 | // displaylist ranges
124 | int rangePlane; // all planes from model
125 | int rangeMesh; // all meshes from model
126 | int rangeHField; // all hfields from model
127 | int rangeBuiltin; // all builtin geoms, with quality from model
128 | int rangeFont; // all characters in font
129 |
130 | // skin VBOs
131 | int nskin; // number of skins
132 | unsigned int* skinvertVBO; // skin vertex position VBOs (nskin)
133 | unsigned int* skinnormalVBO; // skin vertex normal VBOs (nskin)
134 | unsigned int* skintexcoordVBO; // skin vertex texture coordinate VBOs (nskin)
135 | unsigned int* skinfaceVBO; // skin face index VBOs (nskin)
136 |
137 | // character info
138 | int charWidth[127]; // character widths: normal and shadow
139 | int charWidthBig[127]; // chacarter widths: big
140 | int charHeight; // character heights: normal and shadow
141 | int charHeightBig; // character heights: big
142 |
143 | // capabilities
144 | int glInitialized; // is OpenGL initialized
145 | int windowAvailable; // is default/window framebuffer available
146 | int windowSamples; // number of samples for default/window framebuffer
147 | int windowStereo; // is stereo available for default/window framebuffer
148 | int windowDoublebuffer; // is default/window framebuffer double buffered
149 |
150 | // framebuffer
151 | int currentBuffer; // currently active framebuffer: mjFB_WINDOW or mjFB_OFFSCREEN
152 | };
153 | typedef struct mjrContext_ mjrContext;
154 |
155 | #if defined(__cplusplus)
156 | }
157 | #endif
158 | #endif // MUJOCO_MJRENDER_H_
159 |
--------------------------------------------------------------------------------
/include/mujoco/mjtnum.h:
--------------------------------------------------------------------------------
1 | // Copyright 2021 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_INCLUDE_MJTNUM_H_
16 | #define MUJOCO_INCLUDE_MJTNUM_H_
17 |
18 | //---------------------------------- floating-point definitions ------------------------------------
19 |
20 | // compile-time configuration options
21 | #define mjUSEDOUBLE // single or double precision for mjtNum
22 |
23 |
24 | // floating point data type and minval
25 | #ifdef mjUSEDOUBLE
26 | typedef double mjtNum;
27 | #define mjMINVAL 1E-15 // minimum value in any denominator
28 | #else
29 | typedef float mjtNum;
30 | #define mjMINVAL 1E-15f
31 | #endif
32 |
33 |
34 | #endif // MUJOCO_INCLUDE_MJTNUM_H_
35 |
--------------------------------------------------------------------------------
/include/mujoco/mjui.h:
--------------------------------------------------------------------------------
1 | // Copyright 2021 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_MJUI_H_
16 | #define MUJOCO_MJUI_H_
17 |
18 | #include
19 |
20 | #define mjMAXUISECT 10 // maximum number of sections
21 | #define mjMAXUIITEM 80 // maximum number of items per section
22 | #define mjMAXUITEXT 300 // maximum number of chars in edittext and other
23 | #define mjMAXUINAME 40 // maximum number of chars in name
24 | #define mjMAXUIMULTI 35 // maximum number of radio/select items in group
25 | #define mjMAXUIEDIT 7 // maximum number of elements in edit list
26 | #define mjMAXUIRECT 25 // maximum number of rectangles
27 |
28 | #define mjSEPCLOSED 1000 // closed state of adjustable separator
29 |
30 |
31 | // key codes matching GLFW (user must remap for other frameworks)
32 | #define mjKEY_ESCAPE 256
33 | #define mjKEY_ENTER 257
34 | #define mjKEY_TAB 258
35 | #define mjKEY_BACKSPACE 259
36 | #define mjKEY_INSERT 260
37 | #define mjKEY_DELETE 261
38 | #define mjKEY_RIGHT 262
39 | #define mjKEY_LEFT 263
40 | #define mjKEY_DOWN 264
41 | #define mjKEY_UP 265
42 | #define mjKEY_PAGE_UP 266
43 | #define mjKEY_PAGE_DOWN 267
44 | #define mjKEY_HOME 268
45 | #define mjKEY_END 269
46 | #define mjKEY_F1 290
47 | #define mjKEY_F2 291
48 | #define mjKEY_F3 292
49 | #define mjKEY_F4 293
50 | #define mjKEY_F5 294
51 | #define mjKEY_F6 295
52 | #define mjKEY_F7 296
53 | #define mjKEY_F8 297
54 | #define mjKEY_F9 298
55 | #define mjKEY_F10 299
56 | #define mjKEY_F11 300
57 | #define mjKEY_F12 301
58 |
59 |
60 | //---------------------------------- primitive types (mjt) -----------------------------------------
61 |
62 | typedef enum mjtButton_ { // mouse button
63 | mjBUTTON_NONE = 0, // no button
64 | mjBUTTON_LEFT, // left button
65 | mjBUTTON_RIGHT, // right button
66 | mjBUTTON_MIDDLE // middle button
67 | } mjtButton;
68 |
69 |
70 | typedef enum mjtEvent_ { // mouse and keyboard event type
71 | mjEVENT_NONE = 0, // no event
72 | mjEVENT_MOVE, // mouse move
73 | mjEVENT_PRESS, // mouse button press
74 | mjEVENT_RELEASE, // mouse button release
75 | mjEVENT_SCROLL, // scroll
76 | mjEVENT_KEY, // key press
77 | mjEVENT_RESIZE // resize
78 | } mjtEvent;
79 |
80 |
81 | typedef enum mjtItem_ { // UI item type
82 | mjITEM_END = -2, // end of definition list (not an item)
83 | mjITEM_SECTION = -1, // section (not an item)
84 | mjITEM_SEPARATOR = 0, // separator
85 | mjITEM_STATIC, // static text
86 | mjITEM_BUTTON, // button
87 |
88 | // the rest have data pointer
89 | mjITEM_CHECKINT, // check box, int value
90 | mjITEM_CHECKBYTE, // check box, mjtByte value
91 | mjITEM_RADIO, // radio group
92 | mjITEM_RADIOLINE, // radio group, single line
93 | mjITEM_SELECT, // selection box
94 | mjITEM_SLIDERINT, // slider, int value
95 | mjITEM_SLIDERNUM, // slider, mjtNum value
96 | mjITEM_EDITINT, // editable array, int values
97 | mjITEM_EDITNUM, // editable array, mjtNum values
98 | mjITEM_EDITTXT, // editable text
99 |
100 | mjNITEM // number of item types
101 | } mjtItem;
102 |
103 |
104 | // predicate function: set enable/disable based on item category
105 | typedef int (*mjfItemEnable)(int category, void* data);
106 |
107 |
108 | //---------------------------------- mjuiState -----------------------------------------------------
109 |
110 | struct mjuiState_ { // mouse and keyboard state
111 | // constants set by user
112 | int nrect; // number of rectangles used
113 | mjrRect rect[mjMAXUIRECT]; // rectangles (index 0: entire window)
114 | void* userdata; // pointer to user data (for callbacks)
115 |
116 | // event type
117 | int type; // (type mjtEvent)
118 |
119 | // mouse buttons
120 | int left; // is left button down
121 | int right; // is right button down
122 | int middle; // is middle button down
123 | int doubleclick; // is last press a double click
124 | int button; // which button was pressed (mjtButton)
125 | double buttontime; // time of last button press
126 |
127 | // mouse position
128 | double x; // x position
129 | double y; // y position
130 | double dx; // x displacement
131 | double dy; // y displacement
132 | double sx; // x scroll
133 | double sy; // y scroll
134 |
135 | // keyboard
136 | int control; // is control down
137 | int shift; // is shift down
138 | int alt; // is alt down
139 | int key; // which key was pressed
140 | double keytime; // time of last key press
141 |
142 | // rectangle ownership and dragging
143 | int mouserect; // which rectangle contains mouse
144 | int dragrect; // which rectangle is dragged with mouse
145 | int dragbutton; // which button started drag (mjtButton)
146 | };
147 | typedef struct mjuiState_ mjuiState;
148 |
149 |
150 | //---------------------------------- mjuiThemeSpacing ----------------------------------------------
151 |
152 | struct mjuiThemeSpacing_ { // UI visualization theme spacing
153 | int total; // total width
154 | int scroll; // scrollbar width
155 | int label; // label width
156 | int section; // section gap
157 | int itemside; // item side gap
158 | int itemmid; // item middle gap
159 | int itemver; // item vertical gap
160 | int texthor; // text horizontal gap
161 | int textver; // text vertical gap
162 | int linescroll; // number of pixels to scroll
163 | int samples; // number of multisamples
164 | };
165 | typedef struct mjuiThemeSpacing_ mjuiThemeSpacing;
166 |
167 |
168 | //---------------------------------- mjuiThemeColor ------------------------------------------------
169 |
170 | struct mjuiThemeColor_ { // UI visualization theme color
171 | float master[3]; // master background
172 | float thumb[3]; // scrollbar thumb
173 | float secttitle[3]; // section title
174 | float sectfont[3]; // section font
175 | float sectsymbol[3]; // section symbol
176 | float sectpane[3]; // section pane
177 | float shortcut[3]; // shortcut background
178 | float fontactive[3]; // font active
179 | float fontinactive[3]; // font inactive
180 | float decorinactive[3]; // decor inactive
181 | float decorinactive2[3]; // inactive slider color 2
182 | float button[3]; // button
183 | float check[3]; // check
184 | float radio[3]; // radio
185 | float select[3]; // select
186 | float select2[3]; // select pane
187 | float slider[3]; // slider
188 | float slider2[3]; // slider color 2
189 | float edit[3]; // edit
190 | float edit2[3]; // edit invalid
191 | float cursor[3]; // edit cursor
192 | };
193 | typedef struct mjuiThemeColor_ mjuiThemeColor;
194 |
195 |
196 | //---------------------------------- mjuiItem ------------------------------------------------------
197 |
198 | struct mjuiItemSingle_ { // check and button-related
199 | int modifier; // 0: none, 1: control, 2: shift; 4: alt
200 | int shortcut; // shortcut key; 0: undefined
201 | };
202 |
203 |
204 | struct mjuiItemMulti_ { // static, radio and select-related
205 | int nelem; // number of elements in group
206 | char name[mjMAXUIMULTI][mjMAXUINAME]; // element names
207 | };
208 |
209 |
210 | struct mjuiItemSlider_ { // slider-related
211 | double range[2]; // slider range
212 | double divisions; // number of range divisions
213 | };
214 |
215 |
216 | struct mjuiItemEdit_ { // edit-related
217 | int nelem; // number of elements in list
218 | double range[mjMAXUIEDIT][2]; // element range (min>=max: ignore)
219 | };
220 |
221 |
222 | struct mjuiItem_ { // UI item
223 | // common properties
224 | int type; // type (mjtItem)
225 | char name[mjMAXUINAME]; // name
226 | int state; // 0: disable, 1: enable, 2+: use predicate
227 | void *pdata; // data pointer (type-specific)
228 | int sectionid; // id of section containing item
229 | int itemid; // id of item within section
230 |
231 | // type-specific properties
232 | union {
233 | struct mjuiItemSingle_ single; // check and button
234 | struct mjuiItemMulti_ multi; // static, radio and select
235 | struct mjuiItemSlider_ slider; // slider
236 | struct mjuiItemEdit_ edit; // edit
237 | };
238 |
239 | // internal
240 | mjrRect rect; // rectangle occupied by item
241 | };
242 | typedef struct mjuiItem_ mjuiItem;
243 |
244 |
245 | //---------------------------------- mjuiSection ---------------------------------------------------
246 |
247 | struct mjuiSection_ { // UI section
248 | // properties
249 | char name[mjMAXUINAME]; // name
250 | int state; // 0: closed, 1: open
251 | int modifier; // 0: none, 1: control, 2: shift; 4: alt
252 | int shortcut; // shortcut key; 0: undefined
253 | int nitem; // number of items in use
254 | mjuiItem item[mjMAXUIITEM]; // preallocated array of items
255 |
256 | // internal
257 | mjrRect rtitle; // rectangle occupied by title
258 | mjrRect rcontent; // rectangle occupied by content
259 | };
260 | typedef struct mjuiSection_ mjuiSection;
261 |
262 |
263 | //---------------------------------- mjUI ----------------------------------------------------------
264 |
265 | struct mjUI_ { // entire UI
266 | // constants set by user
267 | mjuiThemeSpacing spacing; // UI theme spacing
268 | mjuiThemeColor color; // UI theme color
269 | mjfItemEnable predicate; // callback to set item state programmatically
270 | void* userdata; // pointer to user data (passed to predicate)
271 | int rectid; // index of this ui rectangle in mjuiState
272 | int auxid; // aux buffer index of this ui
273 | int radiocol; // number of radio columns (0 defaults to 2)
274 |
275 | // UI sizes (framebuffer units)
276 | int width; // width
277 | int height; // current heigth
278 | int maxheight; // height when all sections open
279 | int scroll; // scroll from top of UI
280 |
281 | // mouse focus
282 | int mousesect; // 0: none, -1: scroll, otherwise 1+section
283 | int mouseitem; // item within section
284 | int mousehelp; // help button down: print shortcuts
285 |
286 | // keyboard focus and edit
287 | int editsect; // 0: none, otherwise 1+section
288 | int edititem; // item within section
289 | int editcursor; // cursor position
290 | int editscroll; // horizontal scroll
291 | char edittext[mjMAXUITEXT]; // current text
292 | mjuiItem* editchanged; // pointer to changed edit in last mjui_event
293 |
294 | // sections
295 | int nsect; // number of sections in use
296 | mjuiSection sect[mjMAXUISECT]; // preallocated array of sections
297 | };
298 | typedef struct mjUI_ mjUI;
299 |
300 |
301 | //---------------------------------- mjuiDef -------------------------------------------------------
302 |
303 | struct mjuiDef_ { // table passed to mjui_add()
304 | int type; // type (mjtItem); -1: section
305 | char name[mjMAXUINAME]; // name
306 | int state; // state
307 | void* pdata; // pointer to data
308 | char other[mjMAXUITEXT]; // string with type-specific properties
309 | };
310 | typedef struct mjuiDef_ mjuiDef;
311 |
312 | #endif // MUJOCO_MJUI_H_
313 |
--------------------------------------------------------------------------------
/include/mujoco/mjvisualize.h:
--------------------------------------------------------------------------------
1 | // Copyright 2021 DeepMind Technologies Limited
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef MUJOCO_MJVISUALIZE_H_
16 | #define MUJOCO_MJVISUALIZE_H_
17 |
18 | #include
19 | #include
20 |
21 | #define mjNGROUP 6 // number of geom, site, joint, skin groups with visflags
22 | #define mjMAXLIGHT 100 // maximum number of lights in a scene
23 | #define mjMAXOVERLAY 500 // maximum number of characters in overlay text
24 | #define mjMAXLINE 100 // maximum number of lines per plot
25 | #define mjMAXLINEPNT 1000 // maximum number points per line
26 | #define mjMAXPLANEGRID 200 // maximum number of grid divisions for plane
27 |
28 |
29 | //---------------------------------- primitive types (mjt) -----------------------------------------
30 |
31 | typedef enum mjtCatBit_ { // bitflags for mjvGeom category
32 | mjCAT_STATIC = 1, // model elements in body 0
33 | mjCAT_DYNAMIC = 2, // model elements in all other bodies
34 | mjCAT_DECOR = 4, // decorative geoms
35 | mjCAT_ALL = 7 // select all categories
36 | } mjtCatBit;
37 |
38 |
39 | typedef enum mjtMouse_ { // mouse interaction mode
40 | mjMOUSE_NONE = 0, // no action
41 | mjMOUSE_ROTATE_V, // rotate, vertical plane
42 | mjMOUSE_ROTATE_H, // rotate, horizontal plane
43 | mjMOUSE_MOVE_V, // move, vertical plane
44 | mjMOUSE_MOVE_H, // move, horizontal plane
45 | mjMOUSE_ZOOM, // zoom
46 | mjMOUSE_SELECT // selection
47 | } mjtMouse;
48 |
49 |
50 | typedef enum mjtPertBit_ { // mouse perturbations
51 | mjPERT_TRANSLATE = 1, // translation
52 | mjPERT_ROTATE = 2 // rotation
53 | } mjtPertBit;
54 |
55 |
56 | typedef enum mjtCamera_ { // abstract camera type
57 | mjCAMERA_FREE = 0, // free camera
58 | mjCAMERA_TRACKING, // tracking camera; uses trackbodyid
59 | mjCAMERA_FIXED, // fixed camera; uses fixedcamid
60 | mjCAMERA_USER // user is responsible for setting OpenGL camera
61 | } mjtCamera;
62 |
63 |
64 | typedef enum mjtLabel_ { // object labeling
65 | mjLABEL_NONE = 0, // nothing
66 | mjLABEL_BODY, // body labels
67 | mjLABEL_JOINT, // joint labels
68 | mjLABEL_GEOM, // geom labels
69 | mjLABEL_SITE, // site labels
70 | mjLABEL_CAMERA, // camera labels
71 | mjLABEL_LIGHT, // light labels
72 | mjLABEL_TENDON, // tendon labels
73 | mjLABEL_ACTUATOR, // actuator labels
74 | mjLABEL_CONSTRAINT, // constraint labels
75 | mjLABEL_SKIN, // skin labels
76 | mjLABEL_SELECTION, // selected object
77 | mjLABEL_SELPNT, // coordinates of selection point
78 | mjLABEL_CONTACTFORCE, // magnitude of contact force
79 |
80 | mjNLABEL // number of label types
81 | } mjtLabel;
82 |
83 |
84 | typedef enum mjtFrame_ { // frame visualization
85 | mjFRAME_NONE = 0, // no frames
86 | mjFRAME_BODY, // body frames
87 | mjFRAME_GEOM, // geom frames
88 | mjFRAME_SITE, // site frames
89 | mjFRAME_CAMERA, // camera frames
90 | mjFRAME_LIGHT, // light frames
91 | mjFRAME_CONTACT, // contact frames
92 | mjFRAME_WORLD, // world frame
93 |
94 | mjNFRAME // number of visualization frames
95 | } mjtFrame;
96 |
97 |
98 | typedef enum mjtVisFlag_ { // flags enabling model element visualization
99 | mjVIS_CONVEXHULL = 0, // mesh convex hull
100 | mjVIS_TEXTURE, // textures
101 | mjVIS_JOINT, // joints
102 | mjVIS_CAMERA, // cameras
103 | mjVIS_ACTUATOR, // actuators
104 | mjVIS_ACTIVATION, // activations
105 | mjVIS_LIGHT, // lights
106 | mjVIS_TENDON, // tendons
107 | mjVIS_RANGEFINDER, // rangefinder sensors
108 | mjVIS_CONSTRAINT, // point constraints
109 | mjVIS_INERTIA, // equivalent inertia boxes
110 | mjVIS_SCLINERTIA, // scale equivalent inertia boxes with mass
111 | mjVIS_PERTFORCE, // perturbation force
112 | mjVIS_PERTOBJ, // perturbation object
113 | mjVIS_CONTACTPOINT, // contact points
114 | mjVIS_CONTACTFORCE, // contact force
115 | mjVIS_CONTACTSPLIT, // split contact force into normal and tanget
116 | mjVIS_TRANSPARENT, // make dynamic geoms more transparent
117 | mjVIS_AUTOCONNECT, // auto connect joints and body coms
118 | mjVIS_COM, // center of mass
119 | mjVIS_SELECT, // selection point
120 | mjVIS_STATIC, // static bodies
121 | mjVIS_SKIN, // skin
122 |
123 | mjNVISFLAG // number of visualization flags
124 | } mjtVisFlag;
125 |
126 |
127 | typedef enum mjtRndFlag_ { // flags enabling rendering effects
128 | mjRND_SHADOW = 0, // shadows
129 | mjRND_WIREFRAME, // wireframe
130 | mjRND_REFLECTION, // reflections
131 | mjRND_ADDITIVE, // additive transparency
132 | mjRND_SKYBOX, // skybox
133 | mjRND_FOG, // fog
134 | mjRND_HAZE, // haze
135 | mjRND_SEGMENT, // segmentation with random color
136 | mjRND_IDCOLOR, // segmentation with segid+1 color
137 | mjRND_CULL_FACE, // cull backward faces
138 |
139 | mjNRNDFLAG // number of rendering flags
140 | } mjtRndFlag;
141 |
142 |
143 | typedef enum mjtStereo_ { // type of stereo rendering
144 | mjSTEREO_NONE = 0, // no stereo; use left eye only
145 | mjSTEREO_QUADBUFFERED, // quad buffered; revert to side-by-side if no hardware support
146 | mjSTEREO_SIDEBYSIDE // side-by-side
147 | } mjtStereo;
148 |
149 |
150 | //---------------------------------- mjvPerturb ----------------------------------------------------
151 |
152 | struct mjvPerturb_ { // object selection and perturbation
153 | int select; // selected body id; non-positive: none
154 | int skinselect; // selected skin id; negative: none
155 | int active; // perturbation bitmask (mjtPertBit)
156 | int active2; // secondary perturbation bitmask (mjtPertBit)
157 | mjtNum refpos[3]; // desired position for selected object
158 | mjtNum refquat[4]; // desired orientation for selected object
159 | mjtNum localpos[3]; // selection point in object coordinates
160 | mjtNum scale; // relative mouse motion-to-space scaling (set by initPerturb)
161 | };
162 | typedef struct mjvPerturb_ mjvPerturb;
163 |
164 |
165 | //---------------------------------- mjvCamera -----------------------------------------------------
166 |
167 | struct mjvCamera_ { // abstract camera
168 | // type and ids
169 | int type; // camera type (mjtCamera)
170 | int fixedcamid; // fixed camera id
171 | int trackbodyid; // body id to track
172 |
173 | // abstract camera pose specification
174 | mjtNum lookat[3]; // lookat point
175 | mjtNum distance; // distance to lookat point or tracked body
176 | mjtNum azimuth; // camera azimuth (deg)
177 | mjtNum elevation; // camera elevation (deg)
178 | };
179 | typedef struct mjvCamera_ mjvCamera;
180 |
181 |
182 | //---------------------------------- mjvGLCamera ---------------------------------------------------
183 |
184 | struct mjvGLCamera_ { // OpenGL camera
185 | // camera frame
186 | float pos[3]; // position
187 | float forward[3]; // forward direction
188 | float up[3]; // up direction
189 |
190 | // camera projection
191 | float frustum_center; // hor. center (left,right set to match aspect)
192 | float frustum_bottom; // bottom
193 | float frustum_top; // top
194 | float frustum_near; // near
195 | float frustum_far; // far
196 | };
197 | typedef struct mjvGLCamera_ mjvGLCamera;
198 |
199 |
200 | //---------------------------------- mjvGeom -------------------------------------------------------
201 |
202 | struct mjvGeom_ { // abstract geom
203 | // type info
204 | int type; // geom type (mjtGeom)
205 | int dataid; // mesh, hfield or plane id; -1: none
206 | int objtype; // mujoco object type; mjOBJ_UNKNOWN for decor
207 | int objid; // mujoco object id; -1 for decor
208 | int category; // visual category
209 | int texid; // texture id; -1: no texture
210 | int texuniform; // uniform cube mapping
211 | int texcoord; // mesh geom has texture coordinates
212 | int segid; // segmentation id; -1: not shown
213 |
214 | // OpenGL info
215 | float texrepeat[2]; // texture repetition for 2D mapping
216 | float size[3]; // size parameters
217 | float pos[3]; // Cartesian position
218 | float mat[9]; // Cartesian orientation
219 | float rgba[4]; // color and transparency
220 | float emission; // emission coef
221 | float specular; // specular coef
222 | float shininess; // shininess coef
223 | float reflectance; // reflectance coef
224 | char label[100]; // text label
225 |
226 | // transparency rendering (set internally)
227 | float camdist; // distance to camera (used by sorter)
228 | float modelrbound; // geom rbound from model, 0 if not model geom
229 | mjtByte transparent; // treat geom as transparent
230 | };
231 | typedef struct mjvGeom_ mjvGeom;
232 |
233 |
234 | //---------------------------------- mjvLight ------------------------------------------------------
235 |
236 | struct mjvLight_ { // OpenGL light
237 | float pos[3]; // position rel. to body frame
238 | float dir[3]; // direction rel. to body frame
239 | float attenuation[3]; // OpenGL attenuation (quadratic model)
240 | float cutoff; // OpenGL cutoff
241 | float exponent; // OpenGL exponent
242 | float ambient[3]; // ambient rgb (alpha=1)
243 | float diffuse[3]; // diffuse rgb (alpha=1)
244 | float specular[3]; // specular rgb (alpha=1)
245 | mjtByte headlight; // headlight
246 | mjtByte directional; // directional light
247 | mjtByte castshadow; // does light cast shadows
248 | };
249 | typedef struct mjvLight_ mjvLight;
250 |
251 |
252 | //---------------------------------- mjvOption -----------------------------------------------------
253 |
254 | struct mjvOption_ { // abstract visualization options
255 | int label; // what objects to label (mjtLabel)
256 | int frame; // which frame to show (mjtFrame)
257 | mjtByte geomgroup[mjNGROUP]; // geom visualization by group
258 | mjtByte sitegroup[mjNGROUP]; // site visualization by group
259 | mjtByte jointgroup[mjNGROUP]; // joint visualization by group
260 | mjtByte tendongroup[mjNGROUP]; // tendon visualization by group
261 | mjtByte actuatorgroup[mjNGROUP]; // actuator visualization by group
262 | mjtByte skingroup[mjNGROUP]; // skin visualization by group
263 | mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag)
264 | };
265 | typedef struct mjvOption_ mjvOption;
266 |
267 |
268 | //---------------------------------- mjvScene ------------------------------------------------------
269 |
270 | struct mjvScene_ { // abstract scene passed to OpenGL renderer
271 | // abstract geoms
272 | int maxgeom; // size of allocated geom buffer
273 | int ngeom; // number of geoms currently in buffer
274 | mjvGeom* geoms; // buffer for geoms (ngeom)
275 | int* geomorder; // buffer for ordering geoms by distance to camera (ngeom)
276 |
277 | // skin data
278 | int nskin; // number of skins
279 | int* skinfacenum; // number of faces in skin (nskin)
280 | int* skinvertadr; // address of skin vertices (nskin)
281 | int* skinvertnum; // number of vertices in skin (nskin)
282 | float* skinvert; // skin vertex data (nskin)
283 | float* skinnormal; // skin normal data (nskin)
284 |
285 | // OpenGL lights
286 | int nlight; // number of lights currently in buffer
287 | mjvLight lights[mjMAXLIGHT]; // buffer for lights (nlight)
288 |
289 | // OpenGL cameras
290 | mjvGLCamera camera[2]; // left and right camera
291 |
292 | // OpenGL model transformation
293 | mjtByte enabletransform; // enable model transformation
294 | float translate[3]; // model translation
295 | float rotate[4]; // model quaternion rotation
296 | float scale; // model scaling
297 |
298 | // OpenGL rendering effects
299 | int stereo; // stereoscopic rendering (mjtStereo)
300 | mjtByte flags[mjNRNDFLAG]; // rendering flags (indexed by mjtRndFlag)
301 |
302 | // framing
303 | int framewidth; // frame pixel width; 0: disable framing
304 | float framergb[3]; // frame color
305 | };
306 | typedef struct mjvScene_ mjvScene;
307 |
308 |
309 | //---------------------------------- mjvFigure -----------------------------------------------------
310 |
311 | struct mjvFigure_ { // abstract 2D figure passed to OpenGL renderer
312 | // enable flags
313 | int flg_legend; // show legend
314 | int flg_ticklabel[2]; // show grid tick labels (x,y)
315 | int flg_extend; // automatically extend axis ranges to fit data
316 | int flg_barplot; // isolated line segments (i.e. GL_LINES)
317 | int flg_selection; // vertical selection line
318 | int flg_symmetric; // symmetric y-axis
319 |
320 | // style settings
321 | float linewidth; // line width
322 | float gridwidth; // grid line width
323 | int gridsize[2]; // number of grid points in (x,y)
324 | float gridrgb[3]; // grid line rgb
325 | float figurergba[4]; // figure color and alpha
326 | float panergba[4]; // pane color and alpha
327 | float legendrgba[4]; // legend color and alpha
328 | float textrgb[3]; // text color
329 | float linergb[mjMAXLINE][3]; // line colors
330 | float range[2][2]; // axis ranges; (min>=max) automatic
331 | char xformat[20]; // x-tick label format for sprintf
332 | char yformat[20]; // y-tick label format for sprintf
333 | char minwidth[20]; // string used to determine min y-tick width
334 |
335 | // text labels
336 | char title[1000]; // figure title; subplots separated with 2+ spaces
337 | char xlabel[100]; // x-axis label
338 | char linename[mjMAXLINE][100]; // line names for legend
339 |
340 | // dynamic settings
341 | int legendoffset; // number of lines to offset legend
342 | int subplot; // selected subplot (for title rendering)
343 | int highlight[2]; // if point is in legend rect, highlight line
344 | int highlightid; // if id>=0 and no point, highlight id
345 | float selection; // selection line x-value
346 |
347 | // line data
348 | int linepnt[mjMAXLINE]; // number of points in line; (0) disable
349 | float linedata[mjMAXLINE][2*mjMAXLINEPNT]; // line data (x,y)
350 |
351 | // output from renderer
352 | int xaxispixel[2]; // range of x-axis in pixels
353 | int yaxispixel[2]; // range of y-axis in pixels
354 | float xaxisdata[2]; // range of x-axis in data units
355 | float yaxisdata[2]; // range of y-axis in data units
356 | };
357 | typedef struct mjvFigure_ mjvFigure;
358 |
359 | #endif // MUJOCO_MJVISUALIZE_H_
360 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MuJoCo Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/lib/libccd.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libccd.a
--------------------------------------------------------------------------------
/lib/libelasticity.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libelasticity.a
--------------------------------------------------------------------------------
/lib/liblodepng.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/liblodepng.a
--------------------------------------------------------------------------------
/lib/libmujoco.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libmujoco.a
--------------------------------------------------------------------------------
/lib/libqhullstatic_r.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libqhullstatic_r.a
--------------------------------------------------------------------------------
/lib/libtinyobjloader.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libtinyobjloader.a
--------------------------------------------------------------------------------
/lib/libtinyxml2.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/lib/libtinyxml2.a
--------------------------------------------------------------------------------
/node_modules/three/examples/jsm/controls/DragControls.js:
--------------------------------------------------------------------------------
1 | import {
2 | EventDispatcher,
3 | Matrix4,
4 | Plane,
5 | Raycaster,
6 | Vector2,
7 | Vector3
8 | } from 'three';
9 |
10 | const _plane = new Plane();
11 | const _raycaster = new Raycaster();
12 |
13 | const _pointer = new Vector2();
14 | const _offset = new Vector3();
15 | const _intersection = new Vector3();
16 | const _worldPosition = new Vector3();
17 | const _inverseMatrix = new Matrix4();
18 |
19 | class DragControls extends EventDispatcher {
20 |
21 | constructor( _objects, _camera, _domElement ) {
22 |
23 | super();
24 |
25 | _domElement.style.touchAction = 'none'; // disable touch scroll
26 |
27 | let _selected = null, _hovered = null;
28 |
29 | const _intersections = [];
30 |
31 | //
32 |
33 | const scope = this;
34 |
35 | function activate() {
36 |
37 | _domElement.addEventListener( 'pointermove', onPointerMove );
38 | _domElement.addEventListener( 'pointerdown', onPointerDown );
39 | _domElement.addEventListener( 'pointerup', onPointerCancel );
40 | _domElement.addEventListener( 'pointerleave', onPointerCancel );
41 |
42 | }
43 |
44 | function deactivate() {
45 |
46 | _domElement.removeEventListener( 'pointermove', onPointerMove );
47 | _domElement.removeEventListener( 'pointerdown', onPointerDown );
48 | _domElement.removeEventListener( 'pointerup', onPointerCancel );
49 | _domElement.removeEventListener( 'pointerleave', onPointerCancel );
50 |
51 | _domElement.style.cursor = '';
52 |
53 | }
54 |
55 | function dispose() {
56 |
57 | deactivate();
58 |
59 | }
60 |
61 | function getObjects() {
62 |
63 | return _objects;
64 |
65 | }
66 |
67 | function getRaycaster() {
68 |
69 | return _raycaster;
70 |
71 | }
72 |
73 | function onPointerMove( event ) {
74 |
75 | if ( scope.enabled === false ) return;
76 |
77 | updatePointer( event );
78 |
79 | _raycaster.setFromCamera( _pointer, _camera );
80 |
81 | if ( _selected ) {
82 |
83 | if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
84 |
85 | _selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) );
86 |
87 | }
88 |
89 | scope.dispatchEvent( { type: 'drag', object: _selected } );
90 |
91 | return;
92 |
93 | }
94 |
95 | // hover support
96 |
97 | if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) {
98 |
99 | _intersections.length = 0;
100 |
101 | _raycaster.setFromCamera( _pointer, _camera );
102 | _raycaster.intersectObjects( _objects, true, _intersections );
103 |
104 | if ( _intersections.length > 0 ) {
105 |
106 | const object = _intersections[ 0 ].object;
107 |
108 | _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
109 |
110 | if ( _hovered !== object && _hovered !== null ) {
111 |
112 | scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
113 |
114 | _domElement.style.cursor = 'auto';
115 | _hovered = null;
116 |
117 | }
118 |
119 | if ( _hovered !== object ) {
120 |
121 | scope.dispatchEvent( { type: 'hoveron', object: object } );
122 |
123 | _domElement.style.cursor = 'pointer';
124 | _hovered = object;
125 |
126 | }
127 |
128 | } else {
129 |
130 | if ( _hovered !== null ) {
131 |
132 | scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
133 |
134 | _domElement.style.cursor = 'auto';
135 | _hovered = null;
136 |
137 | }
138 |
139 | }
140 |
141 | }
142 |
143 | }
144 |
145 | function onPointerDown( event ) {
146 |
147 | if ( scope.enabled === false ) return;
148 |
149 | updatePointer( event );
150 |
151 | _intersections.length = 0;
152 |
153 | _raycaster.setFromCamera( _pointer, _camera );
154 | _raycaster.intersectObjects( _objects, true, _intersections );
155 |
156 | if ( _intersections.length > 0 ) {
157 |
158 | _selected = ( scope.transformGroup === true ) ? _objects[ 0 ] : _intersections[ 0 ].object;
159 |
160 | _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
161 |
162 | if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
163 |
164 | _inverseMatrix.copy( _selected.parent.matrixWorld ).invert();
165 | _offset.copy( _intersection ).sub( _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
166 |
167 | }
168 |
169 | _domElement.style.cursor = 'move';
170 |
171 | scope.dispatchEvent( { type: 'dragstart', object: _selected } );
172 |
173 | }
174 |
175 |
176 | }
177 |
178 | function onPointerCancel() {
179 |
180 | if ( scope.enabled === false ) return;
181 |
182 | if ( _selected ) {
183 |
184 | scope.dispatchEvent( { type: 'dragend', object: _selected } );
185 |
186 | _selected = null;
187 |
188 | }
189 |
190 | _domElement.style.cursor = _hovered ? 'pointer' : 'auto';
191 |
192 | }
193 |
194 | function updatePointer( event ) {
195 |
196 | const rect = _domElement.getBoundingClientRect();
197 |
198 | _pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1;
199 | _pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1;
200 |
201 | }
202 |
203 | activate();
204 |
205 | // API
206 |
207 | this.enabled = true;
208 | this.transformGroup = false;
209 |
210 | this.activate = activate;
211 | this.deactivate = deactivate;
212 | this.dispose = dispose;
213 | this.getObjects = getObjects;
214 | this.getRaycaster = getRaycaster;
215 |
216 | }
217 |
218 | }
219 |
220 | export { DragControls };
221 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@zalo/mujoco_wasm",
3 | "version": "0.0.2",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "three": {
8 | "version": "0.150.1",
9 | "resolved": "https://registry.npmjs.org/three/-/three-0.150.1.tgz",
10 | "integrity": "sha512-5C1MqKUWaHYo13BX0Q64qcdwImgnnjSOFgBscOzAo8MYCzEtqfQqorEKMcajnA3FHy1yVlIe9AmaMQ0OQracNA=="
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mujoco_wasm",
3 | "version": "0.0.2",
4 | "description": "Run MuJoCo simulations in browser",
5 | "main": "dist/mujoco_wasm.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/zalo/mujoco_wasm.git"
15 | },
16 | "keywords": [
17 | "mujoco",
18 | "wasm"
19 | ],
20 | "author": "Sergei Surovtsev and Johnathon Selstad",
21 | "license": "ISC",
22 | "bugs": {
23 | "url": "https://github.com/zalo/mujoco_wasm/issues"
24 | },
25 | "homepage": "https://github.com/zalo/mujoco_wasm#readme",
26 | "dependencies": {
27 | "three": "^0.150.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 | project(mujoco_wasm)
3 |
4 | set(SOURCE_FILES main.genned.cc)
5 | add_compile_options(-pthread)
6 | set(EMCC_LINKER_FLAGS "-s ASSERTIONS=1 --bind -s ALLOW_MEMORY_GROWTH=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s FORCE_FILESYSTEM=1 -s EXPORTED_RUNTIME_METHODS=['FS','MEMFS'] -s EXPORT_NAME=load_mujoco -s EXCEPTION_CATCHING_ALLOWED=['load_from_xml']")
7 | set(CMAKE_REQUIRED_FLAGS "${EMCC_LINKER_FLAGS}")
8 | add_executable(mujoco_wasm ${SOURCE_FILES})
9 | set_target_properties(mujoco_wasm PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS}")
10 |
11 | target_link_libraries(mujoco_wasm ccd elasticity lodepng mujoco tinyxml2 qhullstatic_r)
12 | install(TARGETS mujoco_wasm DESTINATION ${DIVISIBLE_INSTALL_BIN_DIR})
13 |
--------------------------------------------------------------------------------
/src/ast_nodes.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 DeepMind Technologies Limited
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | # ==============================================================================
15 | """Classes that roughly correspond to Clang AST node types."""
16 |
17 | import collections
18 | import dataclasses
19 | import re
20 | from typing import Dict, Optional, Sequence, Tuple, Union
21 |
22 | # We are relying on Clang to do the actual source parsing and are only doing
23 | # a little bit of extra parsing of function parameter type declarations here.
24 | # These patterns are here for sanity checking rather than actual parsing.
25 | VALID_TYPE_NAME_PATTERN = re.compile('[A-Za-z_][A-Za-z0-9_]*')
26 | C_INVALID_TYPE_NAMES = frozenset([
27 | 'auto', 'break', 'case', 'const', 'continue', 'default', 'do', 'else',
28 | 'enum', 'extern', 'for', 'goto', 'if', 'inline', 'register', 'restrict',
29 | 'return', 'sizeof', 'static', 'struct', 'switch', 'typedef', 'union',
30 | 'volatile', 'while', '_Alignas', '_Atomic', '_Generic', '_Imaginary',
31 | '_Noreturn', '_Static_assert', '_Thread_local', '__attribute__', '_Pragma'])
32 |
33 |
34 | def _is_valid_integral_type(type_str: str):
35 | """Checks if a string is a valid integral type."""
36 | parts = re.split(r'\s+', type_str)
37 | counter = collections.defaultdict(lambda: 0)
38 | wildcard_counter = 0
39 | for part in parts:
40 | if part in ('signed', 'unsigned', 'short', 'long', 'int', 'char'):
41 | counter[part] += 1
42 | elif VALID_TYPE_NAME_PATTERN.fullmatch(part):
43 | # a non-keyword can be a typedef for int
44 | wildcard_counter += 1
45 | else:
46 | return False
47 |
48 | if (counter['signed'] + counter['unsigned'] > 1 or
49 | counter['short'] > 1 or counter['long'] > 2 or
50 | (counter['short'] and counter['long']) or
51 | ((counter['short'] or counter['long']) and counter['char']) or
52 | counter['char'] + counter['int'] + wildcard_counter > 1):
53 | return False
54 | else:
55 | return True
56 |
57 |
58 | @dataclasses.dataclass
59 | class ValueType:
60 | """Represents a C type that is neither a pointer type nor an array type."""
61 |
62 | name: str
63 | is_const: bool = False
64 | is_volatile: bool = False
65 |
66 | def __init__(self, name: str, is_const: bool = False,
67 | is_volatile: bool = False):
68 | is_valid_type_name = (
69 | VALID_TYPE_NAME_PATTERN.fullmatch(name) or
70 | _is_valid_integral_type(name)) and name not in C_INVALID_TYPE_NAMES
71 | if not is_valid_type_name:
72 | raise ValueError(f'{name!r} is not a valid value type name')
73 | self.name = name
74 | self.is_const = is_const
75 | self.is_volatile = is_volatile
76 |
77 | def decl(self, name_or_decl: Optional[str] = None) -> str:
78 | parts = []
79 | if self.is_const:
80 | parts.append('const')
81 | if self.is_volatile:
82 | parts.append('volatile')
83 | parts.append(self.name)
84 | if name_or_decl:
85 | parts.append(name_or_decl)
86 | return ' '.join(parts)
87 |
88 | def __str__(self):
89 | return self.decl()
90 |
91 |
92 | @dataclasses.dataclass
93 | class ArrayType:
94 | """Represents a C array type."""
95 |
96 | inner_type: Union[ValueType, 'PointerType']
97 | extents: Tuple[int]
98 |
99 | def __init__(self, inner_type: Union[ValueType, 'PointerType'],
100 | extents: Sequence[int]):
101 | self.inner_type = inner_type
102 | self.extents = tuple(extents)
103 |
104 | @property
105 | def _extents_str(self) -> str:
106 | return ''.join(f'[{n}]' for n in self.extents)
107 |
108 | def decl(self, name_or_decl: Optional[str] = None) -> str:
109 | name_or_decl = name_or_decl or ''
110 | return self.inner_type.decl(f'{name_or_decl}{self._extents_str}')
111 |
112 | def __str__(self):
113 | return self.decl()
114 |
115 |
116 | @dataclasses.dataclass
117 | class PointerType:
118 | """Represents a C pointer type."""
119 |
120 | inner_type: Union[ValueType, ArrayType, 'PointerType']
121 | is_const: bool = False
122 | is_volatile: bool = False
123 | is_restrict: bool = False
124 |
125 | def decl(self, name_or_decl: Optional[str] = None) -> str:
126 | """Creates a string that declares an object of this type."""
127 | parts = ['*']
128 | if self.is_const:
129 | parts.append('const')
130 | if self.is_volatile:
131 | parts.append('volatile')
132 | if self.is_restrict:
133 | parts.append('restrict')
134 | if name_or_decl:
135 | parts.append(name_or_decl)
136 | ptr_decl = ' '.join(parts)
137 | if isinstance(self.inner_type, ArrayType):
138 | ptr_decl = f'({ptr_decl})'
139 | return self.inner_type.decl(ptr_decl)
140 |
141 | def __str__(self):
142 | return self.decl()
143 |
144 |
145 | @dataclasses.dataclass
146 | class FunctionParameterDecl:
147 | """Represents a parameter in a function declaration.
148 |
149 | Note that according to the C language rule, a function parameter of array
150 | type undergoes array-to-pointer decay, and therefore appears as a pointer
151 | parameter in an actual C AST. We retain the arrayness of a parameter here
152 | since the array's extents are informative.
153 | """
154 |
155 | name: str
156 | type: Union[ValueType, ArrayType, PointerType]
157 |
158 | def __str__(self):
159 | return self.type.decl(self.name)
160 |
161 | @property
162 | def decltype(self) -> str:
163 | return self.type.decl()
164 |
165 |
166 | @dataclasses.dataclass
167 | class FunctionDecl:
168 | """Represents a function declaration."""
169 |
170 | name: str
171 | return_type: Union[ValueType, ArrayType, PointerType]
172 | parameters: Tuple[FunctionParameterDecl]
173 | doc: str
174 |
175 | def __init__(self, name: str,
176 | return_type: Union[ValueType, ArrayType, PointerType],
177 | parameters: Sequence[FunctionParameterDecl],
178 | doc: str):
179 | self.name = name
180 | self.return_type = return_type
181 | self.parameters = tuple(parameters)
182 | self.doc = doc
183 |
184 | def __str__(self):
185 | param_str = ', '.join(str(p) for p in self.parameters)
186 | return f'{self.return_type} {self.name}({param_str})'
187 |
188 | @property
189 | def decltype(self) -> str:
190 | param_str = ', '.join(str(p.decltype) for p in self.parameters)
191 | return f'{self.return_type} ({param_str})'
192 |
193 |
194 | class _EnumDeclValues(Dict[str, int]):
195 | """A dict with modified stringified representation.
196 |
197 | The __repr__ method of this class adds a trailing comma to the list of values.
198 | This is done as a hint for code formatters to place one item per line when
199 | the stringified OrderedDict is used in generated Python code.
200 | """
201 |
202 | def __repr__(self):
203 | out = super().__repr__()
204 | if self:
205 | out = re.sub(r'\(\[(.+)\]\)\Z', r'([\1,])', out)
206 | return re.sub(r'\A_EnumDeclValues', 'dict', out)
207 |
208 |
209 | @dataclasses.dataclass
210 | class EnumDecl:
211 | """Represents an enum declaration."""
212 |
213 | name: str
214 | declname: str
215 | values: Dict[str, int]
216 |
217 | def __init__(self, name: str, declname: str, values: Dict[str, int]):
218 | self.name = name
219 | self.declname = declname
220 | self.values = _EnumDeclValues(values)
221 |
--------------------------------------------------------------------------------
/src/main.template.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "mujoco/mujoco.h"
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | using namespace emscripten;
16 |
17 | int finish(const char *msg = NULL, mjModel *m = NULL) {
18 | if (m ) { mj_deleteModel(m); }
19 | if (msg) { std::printf("%s\n", msg); }
20 | return 0;
21 | }
22 |
23 | class Model {
24 | public:
25 | Model() { m = NULL; }
26 | Model(const std::string filename) {
27 | if(0 == filename.compare(filename.length() - 3, 3, "mjb")){
28 | char error[1000] = "Could not load mjb model";
29 | m = mj_loadModel(filename.c_str(), 0);
30 | if (!m) { finish(error, m); }
31 | } else {
32 | char error[1000] = "Could not load xml model";
33 | m = mj_loadXML(filename.c_str(), 0, error, 1000);
34 | if (!m) { finish(error, m); }
35 | }
36 | }
37 |
38 | static Model load_from_xml(const std::string filename) { return Model(filename); }
39 | static Model load_from_mjb(const std::string filename) { return Model(filename); }
40 |
41 | mjModel *ptr () { return m; }
42 | mjModel getVal () { return *m; }
43 | mjOption getOptions() { return (*m).opt; }
44 | void free () { return mju_free(m); }
45 |
46 | // MJMODEL_DEFINITIONS
47 |
48 | private:
49 | mjModel *m;
50 | };
51 |
52 | class State {
53 | public:
54 | State(Model m) { d = mj_makeData(m.ptr()); }
55 | mjData *ptr () { return d; }
56 | mjData getVal() { return *d; }
57 | void free () { return mju_free(d); }
58 |
59 | private:
60 | mjData *d;
61 | };
62 |
63 | class Simulation {
64 | public:
65 | Simulation(Model *m, State *s) {
66 | _model = m;
67 | _state = s;
68 | }
69 |
70 | State *state() { return _state; }
71 | Model *model() { return _model; }
72 | void free() { mju_free(_state); mju_free(_model); }
73 |
74 | void applyForce(
75 | mjtNum fx, mjtNum fy, mjtNum fz,
76 | mjtNum tx, mjtNum ty, mjtNum tz,
77 | mjtNum px, mjtNum py, mjtNum pz, int body) {
78 | mjtNum force [3] = {fx, fy, fz};
79 | mjtNum torque[3] = {tx, ty, tz};
80 | mjtNum point [3] = {px, py, pz};
81 | mj_applyFT(_model->ptr(), _state->ptr(),
82 | force, torque, point, body,
83 | _state->ptr()->qfrc_applied);
84 | }
85 |
86 | // copied from the source of mjv_applyPerturbPose
87 | // sets perturb pos,quat in d->mocap when selected body is mocap, and in d->qpos otherwise
88 | // d->qpos written only if flg_paused and subtree root for selected body has free joint
89 | void applyPose(int bodyID,
90 | mjtNum refPosX, mjtNum refPosY, mjtNum refPosZ,
91 | mjtNum refQuat1, mjtNum refQuat2, mjtNum refQuat3, mjtNum refQuat4,
92 | int flg_paused) {
93 | int rootid = 0, sel = bodyID;//pert->select;
94 | mjtNum pos1[3], quat1[4], pos2[3], quat2[4], refpos[3], refquat[4];
95 | mjtNum *Rpos, *Rquat, *Cpos, *Cquat;
96 | mjtNum inrefpos [3] = { refPosX , refPosY , refPosZ };
97 | mjtNum inrefquat[4] = { refQuat1, refQuat2, refQuat3, refQuat4 };
98 | mjModel *m = _model->ptr();
99 | mjData *d = _state->ptr();
100 |
101 | // exit if nothing to do
102 | //if (sel<=0 || sel>=m->nbody || !(pert->active | pert->active2)) { return; }
103 |
104 | // get rootid above selected body
105 | rootid = m->body_rootid[sel];
106 |
107 | // transform refpos,refquat from I-frame to X-frame of body[sel]
108 | mju_negPose(pos1, quat1, m->body_ipos+3*sel, m->body_iquat+4*sel);
109 | mju_mulPose(refpos, refquat, inrefpos, inrefquat, pos1, quat1);
110 |
111 | // mocap body
112 | if (m->body_mocapid[sel]>=0) {
113 | // copy ref pose into mocap pose
114 | mju_copy3(d->mocap_pos + 3*m->body_mocapid[sel], refpos);
115 | mju_copy4(d->mocap_quat + 4*m->body_mocapid[sel], refquat);
116 | }
117 |
118 | // floating body, paused
119 | else if (flg_paused && m->body_jntnum[sel]==1 &&
120 | m->jnt_type[m->body_jntadr[sel]]==mjJNT_FREE) {
121 | // copy ref pose into qpos
122 | mju_copy3(d->qpos + m->jnt_qposadr[m->body_jntadr[sel]], refpos);
123 | mju_copy4(d->qpos + m->jnt_qposadr[m->body_jntadr[sel]] + 3, refquat);
124 | }
125 |
126 | // child of floating body, paused
127 | else if (flg_paused && m->body_jntnum[rootid]==1 &&
128 | m->jnt_type[m->body_jntadr[rootid]]==mjJNT_FREE) {
129 | // get pointers to root
130 | Rpos = d->qpos + m->jnt_qposadr[m->body_jntadr[rootid]];
131 | Rquat = Rpos + 3;
132 |
133 | // get pointers to child
134 | Cpos = d->xpos + 3*sel;
135 | Cquat = d->xquat + 4*sel;
136 |
137 | // set root <- ref*neg(child)*root
138 | mju_negPose(pos1, quat1, Cpos, Cquat); // neg(child)
139 | mju_mulPose(pos2, quat2, pos1, quat1, Rpos, Rquat); // neg(child)*root
140 | mju_mulPose(Rpos, Rquat, refpos, refquat, pos2, quat2); // ref*neg(child)*root
141 | }
142 | }
143 |
144 | // MJDATA_DEFINITIONS
145 |
146 |
147 | private:
148 | Model *_model;
149 | State *_state;
150 | };
151 |
152 | // main function
153 | int main(int argc, char **argv) {
154 | std::printf("MuJoCo version: %d\n\n", mj_version());
155 | return 0;
156 | }
157 |
158 | EMSCRIPTEN_BINDINGS(mujoco_wasm) {
159 |
160 | // MODEL_ENUMS
161 |
162 |
163 | class_("Model")
164 | .constructor<>(&Model::load_from_xml)
165 | .class_function("load_from_xml", &Model::load_from_xml)
166 | .class_function("load_from_mjb", &Model::load_from_mjb)
167 | .function("ptr", &Model::ptr, allow_raw_pointers())
168 | .function("free" , &Model::free )
169 | .function("getVal" , &Model::getVal )
170 | .function("getOptions" , &Model::getOptions )
171 | // MJMODEL_BINDINGS
172 | ;
173 |
174 | class_("State")
175 | .constructor()
176 | .function("ptr" , &State::ptr, allow_raw_pointers())
177 | .function("free" , &State::free )
178 | .function("getVal", &State::getVal);
179 |
180 | class_("Simulation")
181 | .constructor()
182 | .function("state" , &Simulation::state, allow_raw_pointers())
183 | .function("model" , &Simulation::model, allow_raw_pointers())
184 | .function("free" , &Simulation::free )
185 | .function("applyForce", &Simulation::applyForce)
186 | .function("applyPose" , &Simulation::applyPose )
187 | // MJDATA_BINDINGS
188 | ;
189 |
190 | value_object("mjModel")
191 | .field("ngeom" , &mjModel::ngeom)
192 | .field("nq" , &mjModel::nq)
193 | .field("na" , &mjModel::na)
194 | .field("nv" , &mjModel::nv)
195 | .field("nu" , &mjModel::nu)
196 | .field("nbody" , &mjModel::nbody)
197 | .field("nsensordata", &mjModel::nsensordata)
198 | //.field("body_rootid", &mjModel::body_rootid, allow_raw_pointers())
199 | .field("nmesh" , &mjModel::nmesh)
200 | .field("nmeshvert" , &mjModel::nmeshvert)
201 | .field("nmeshface" , &mjModel::nmeshface);
202 |
203 | value_object("mjvPerturb")
204 | .field("select" , &mjvPerturb::select) // selected body id; non-positive: none
205 | .field("skinselect", &mjvPerturb::skinselect) // selected skin id; negative: none
206 | .field("active" , &mjvPerturb::active) // perturbation bitmask (mjtPertBit)
207 | .field("active2" , &mjvPerturb::active2) // secondary perturbation bitmask (mjtPertBit)
208 | .field("refpos" , &mjvPerturb::refpos) // desired position for selected object
209 | .field("refquat" , &mjvPerturb::refquat) // desired orientation for selected object
210 | .field("localpos" , &mjvPerturb::localpos) // selection point in object coordinates
211 | .field("scale" , &mjvPerturb::scale) // relative mouse motion-to-space scaling (set by initPerturb)
212 | ;
213 |
214 | value_object("mjContact")
215 | .field("dist" , &mjContact::dist) // distance between nearest points; neg: penetration
216 | .field("pos" , &mjContact::pos) // position of contact point: midpoint between geoms
217 | .field("frame" , &mjContact::frame) // normal is in [0-2]
218 | .field("includemargin", &mjContact::includemargin) // include if dist("mjLROpt")
231 | .field("mode" , &mjLROpt::mode)
232 | .field("useexisting", &mjLROpt::useexisting)
233 | .field("uselimit" , &mjLROpt::uselimit)
234 | .field("accel" , &mjLROpt::accel) // target acceleration used to compute force
235 | .field("maxforce" , &mjLROpt::maxforce) // maximum force; 0: no limit
236 | .field("timeconst" , &mjLROpt::timeconst) // time constant for velocity reduction; min 0.01
237 | .field("timestep" , &mjLROpt::timestep) // simulation timestep; 0: use mjOption.timestep
238 | .field("inttotal" , &mjLROpt::inttotal) // total simulation time interval
239 | .field("inteval" , &mjLROpt::inteval) // evaluation time interval (at the end)
240 | .field("tolrange" , &mjLROpt::tolrange); // convergence tolerance (relative to range)
241 |
242 | value_object("mjOption")
243 | .field("timestep" , &mjOption::timestep) // timestep
244 | .field("apirate" , &mjOption::apirate) // update rate for remote API (Hz)
245 | .field("impratio" , &mjOption::impratio) // ratio of friction-to-normal contact impedance
246 | .field("tolerance" , &mjOption::tolerance) // main solver tolerance
247 | .field("noslip_tolerance" , &mjOption::noslip_tolerance) // noslip solver tolerance
248 | .field("mpr_tolerance" , &mjOption::mpr_tolerance) // MPR solver tolerance
249 | //.field("gravity" , &mjOption::gravity) // gravitational acceleration
250 | //.field("wind" , &mjOption::wind) // wind (for lift, drag and viscosity)
251 | //.field("magnetic" , &mjOption::magnetic) // global magnetic flux
252 | .field("density" , &mjOption::density) // density of medium
253 | .field("viscosity" , &mjOption::viscosity) // viscosity of medium
254 | .field("o_margin" , &mjOption::o_margin) // margin
255 | //.field("o_solref" , &mjOption::o_solref) // solref
256 | //.field("o_solimp" , &mjOption::o_solimp) // solimp
257 | .field("integrator" , &mjOption::integrator) // integration mode (mjtIntegrator)
258 | .field("collision" , &mjOption::collision) // collision mode (mjtCollision)
259 | .field("cone" , &mjOption::cone) // type of friction cone (mjtCone)
260 | .field("jacobian" , &mjOption::jacobian) // type of Jacobian (mjtJacobian)
261 | .field("solver" , &mjOption::solver) // solver algorithm (mjtSolver)
262 | .field("iterations" , &mjOption::iterations) // maximum number of main solver iterations
263 | .field("noslip_iterations" , &mjOption::noslip_iterations) // maximum number of noslip solver iterations
264 | .field("mpr_iterations" , &mjOption::mpr_iterations) // maximum number of MPR solver iterations
265 | .field("disableflags" , &mjOption::disableflags) // bit flags for disabling standard features
266 | .field("enableflags" , &mjOption::enableflags); // bit flags for enabling optional features
267 |
268 | register_vector("vector");
269 | }
270 |
--------------------------------------------------------------------------------
/src/mujoco_wasm.template.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for Emscripten 1.39.16
2 | // Project: https://emscripten.org
3 | // Definitions by: Kensuke Matsuzaki
4 | // Periklis Tsirakidis
5 | // Bumsik Kim
6 | // Louis DeScioli
7 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts
8 | // TypeScript Version: 2.2
9 |
10 | /** Other WebAssembly declarations, for compatibility with older versions of Typescript */
11 | declare namespace WebAssembly {
12 | interface Module {}
13 | }
14 |
15 | declare namespace Emscripten {
16 | interface FileSystemType {}
17 | type EnvironmentType = 'WEB' | 'NODE' | 'SHELL' | 'WORKER';
18 |
19 | type JSType = 'number' | 'string' | 'array' | 'boolean';
20 | type TypeCompatibleWithC = number | string | any[] | boolean;
21 |
22 | type CIntType = 'i8' | 'i16' | 'i32' | 'i64';
23 | type CFloatType = 'float' | 'double';
24 | type CPointerType = 'i8*' | 'i16*' | 'i32*' | 'i64*' | 'float*' | 'double*' | '*';
25 | type CType = CIntType | CFloatType | CPointerType;
26 |
27 | type WebAssemblyImports = Array<{
28 | name: string;
29 | kind: string;
30 | }>;
31 |
32 | type WebAssemblyExports = Array<{
33 | module: string;
34 | name: string;
35 | kind: string;
36 | }>;
37 |
38 | interface CCallOpts {
39 | async?: boolean | undefined;
40 | }
41 | }
42 |
43 | interface EmscriptenModule {
44 | print(str: string): void;
45 | printErr(str: string): void;
46 | arguments: string[];
47 | environment: Emscripten.EnvironmentType;
48 | preInit: Array<{ (): void }>;
49 | preRun: Array<{ (): void }>;
50 | postRun: Array<{ (): void }>;
51 | onAbort: { (what: any): void };
52 | onRuntimeInitialized: { (): void };
53 | preinitializedWebGLContext: WebGLRenderingContext;
54 | noInitialRun: boolean;
55 | noExitRuntime: boolean;
56 | logReadFiles: boolean;
57 | filePackagePrefixURL: string;
58 | wasmBinary: ArrayBuffer;
59 |
60 | destroy(object: object): void;
61 | getPreloadedPackage(remotePackageName: string, remotePackageSize: number): ArrayBuffer;
62 | instantiateWasm(
63 | imports: Emscripten.WebAssemblyImports,
64 | successCallback: (module: WebAssembly.Module) => void,
65 | ): Emscripten.WebAssemblyExports;
66 | locateFile(url: string, scriptDirectory: string): string;
67 | onCustomMessage(event: MessageEvent): void;
68 |
69 | // USE_TYPED_ARRAYS == 1
70 | HEAP: Int32Array;
71 | IHEAP: Int32Array;
72 | FHEAP: Float64Array;
73 |
74 | // USE_TYPED_ARRAYS == 2
75 | HEAP8: Int8Array;
76 | HEAP16: Int16Array;
77 | HEAP32: Int32Array;
78 | HEAPU8: Uint8Array;
79 | HEAPU16: Uint16Array;
80 | HEAPU32: Uint32Array;
81 | HEAPF32: Float32Array;
82 | HEAPF64: Float64Array;
83 |
84 | TOTAL_STACK: number;
85 | TOTAL_MEMORY: number;
86 | FAST_MEMORY: number;
87 |
88 | addOnPreRun(cb: () => any): void;
89 | addOnInit(cb: () => any): void;
90 | addOnPreMain(cb: () => any): void;
91 | addOnExit(cb: () => any): void;
92 | addOnPostRun(cb: () => any): void;
93 |
94 | preloadedImages: any;
95 | preloadedAudios: any;
96 |
97 | _malloc(size: number): number;
98 | _free(ptr: number): void;
99 | }
100 |
101 | /**
102 | * A factory function is generated when setting the `MODULARIZE` build option
103 | * to `1` in your Emscripten build. It return a Promise that resolves to an
104 | * initialized, ready-to-call `EmscriptenModule` instance.
105 | *
106 | * By default, the factory function will be named `Module`. It's recommended to
107 | * use the `EXPORT_ES6` option, in which the factory function will be the
108 | * default export. If used without `EXPORT_ES6`, the factory function will be a
109 | * global variable. You can rename the variable using the `EXPORT_NAME` build
110 | * option. It's left to you to declare any global variables as needed in your
111 | * application's types.
112 | * @param moduleOverrides Default properties for the initialized module.
113 | */
114 | type EmscriptenModuleFactory = (
115 | moduleOverrides?: Partial,
116 | ) => Promise;
117 |
118 | declare namespace FS {
119 | interface Lookup {
120 | path: string;
121 | node: FSNode;
122 | }
123 |
124 | interface FSStream {}
125 | interface FSNode {}
126 | interface ErrnoError {}
127 |
128 | let ignorePermissions: boolean;
129 | let trackingDelegate: any;
130 | let tracking: any;
131 | let genericErrors: any;
132 |
133 | //
134 | // paths
135 | //
136 | function lookupPath(path: string, opts: any): Lookup;
137 | function getPath(node: FSNode): string;
138 |
139 | //
140 | // nodes
141 | //
142 | function isFile(mode: number): boolean;
143 | function isDir(mode: number): boolean;
144 | function isLink(mode: number): boolean;
145 | function isChrdev(mode: number): boolean;
146 | function isBlkdev(mode: number): boolean;
147 | function isFIFO(mode: number): boolean;
148 | function isSocket(mode: number): boolean;
149 |
150 | //
151 | // devices
152 | //
153 | function major(dev: number): number;
154 | function minor(dev: number): number;
155 | function makedev(ma: number, mi: number): number;
156 | function registerDevice(dev: number, ops: any): void;
157 |
158 | //
159 | // core
160 | //
161 | function syncfs(populate: boolean, callback: (e: any) => any): void;
162 | function syncfs(callback: (e: any) => any, populate?: boolean): void;
163 | function mount(type: Emscripten.FileSystemType, opts: any, mountpoint: string): any;
164 | function unmount(mountpoint: string): void;
165 |
166 | function mkdir(path: string, mode?: number): any;
167 | function mkdev(path: string, mode?: number, dev?: number): any;
168 | function symlink(oldpath: string, newpath: string): any;
169 | function rename(old_path: string, new_path: string): void;
170 | function rmdir(path: string): void;
171 | function readdir(path: string): any;
172 | function unlink(path: string): void;
173 | function readlink(path: string): string;
174 | function stat(path: string, dontFollow?: boolean): any;
175 | function lstat(path: string): any;
176 | function chmod(path: string, mode: number, dontFollow?: boolean): void;
177 | function lchmod(path: string, mode: number): void;
178 | function fchmod(fd: number, mode: number): void;
179 | function chown(path: string, uid: number, gid: number, dontFollow?: boolean): void;
180 | function lchown(path: string, uid: number, gid: number): void;
181 | function fchown(fd: number, uid: number, gid: number): void;
182 | function truncate(path: string, len: number): void;
183 | function ftruncate(fd: number, len: number): void;
184 | function utime(path: string, atime: number, mtime: number): void;
185 | function open(path: string, flags: string, mode?: number, fd_start?: number, fd_end?: number): FSStream;
186 | function close(stream: FSStream): void;
187 | function llseek(stream: FSStream, offset: number, whence: number): any;
188 | function read(stream: FSStream, buffer: ArrayBufferView, offset: number, length: number, position?: number): number;
189 | function write(
190 | stream: FSStream,
191 | buffer: ArrayBufferView,
192 | offset: number,
193 | length: number,
194 | position?: number,
195 | canOwn?: boolean,
196 | ): number;
197 | function allocate(stream: FSStream, offset: number, length: number): void;
198 | function mmap(
199 | stream: FSStream,
200 | buffer: ArrayBufferView,
201 | offset: number,
202 | length: number,
203 | position: number,
204 | prot: number,
205 | flags: number,
206 | ): any;
207 | function ioctl(stream: FSStream, cmd: any, arg: any): any;
208 | function readFile(path: string, opts: { encoding: 'binary'; flags?: string | undefined }): Uint8Array;
209 | function readFile(path: string, opts: { encoding: 'utf8'; flags?: string | undefined }): string;
210 | function readFile(path: string, opts?: { flags?: string | undefined }): Uint8Array;
211 | function writeFile(path: string, data: string | ArrayBufferView, opts?: { flags?: string | undefined }): void;
212 |
213 | //
214 | // module-level FS code
215 | //
216 | function cwd(): string;
217 | function chdir(path: string): void;
218 | function init(
219 | input: null | (() => number | null),
220 | output: null | ((c: number) => any),
221 | error: null | ((c: number) => any),
222 | ): void;
223 |
224 | function createLazyFile(
225 | parent: string | FSNode,
226 | name: string,
227 | url: string,
228 | canRead: boolean,
229 | canWrite: boolean,
230 | ): FSNode;
231 | function createPreloadedFile(
232 | parent: string | FSNode,
233 | name: string,
234 | url: string,
235 | canRead: boolean,
236 | canWrite: boolean,
237 | onload?: () => void,
238 | onerror?: () => void,
239 | dontCreateFile?: boolean,
240 | canOwn?: boolean,
241 | ): void;
242 | function createDataFile(
243 | parent: string | FSNode,
244 | name: string,
245 | data: ArrayBufferView,
246 | canRead: boolean,
247 | canWrite: boolean,
248 | canOwn: boolean,
249 | ): FSNode;
250 | }
251 |
252 | declare var MEMFS: Emscripten.FileSystemType;
253 | declare var NODEFS: Emscripten.FileSystemType;
254 | declare var IDBFS: Emscripten.FileSystemType;
255 |
256 | // https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html
257 | type StringToType = R extends Emscripten.JSType
258 | ? {
259 | number: number;
260 | string: string;
261 | array: number[] | string[] | boolean[] | Uint8Array | Int8Array;
262 | boolean: boolean;
263 | null: null;
264 | }[R]
265 | : never;
266 |
267 | type ArgsToType> = Extract<
268 | {
269 | [P in keyof T]: StringToType;
270 | },
271 | any[]
272 | >;
273 |
274 | type ReturnToType = R extends null
275 | ? null
276 | : StringToType>;
277 |
278 | // ENUMS
279 |
280 | export interface Model {
281 | new (filename : string) : Model;
282 | load_from_xml(str: string): Model;
283 | /** Free the memory associated with the model */
284 | free(): void;
285 | /** Retrive various parameters of the current simulation */
286 | getOptions(): any;
287 | // MODEL_INTERFACE
288 | }
289 |
290 | export interface State {
291 | new (model : Model) : State;
292 | /** Free the memory associated with the state */
293 | free(): void;
294 | }
295 |
296 | export interface Simulation {
297 | new (model : Model, state : State) : Simulation;
298 | state() : State;
299 | model() : Model;
300 | /** Free the memory associated with both the model and the state in the simulation */
301 | free() : void;
302 | /** Apply cartesian force and torque (outside xfrc_applied mechanism) */
303 | applyForce(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number, px: number, py: number, pz: number, body_id: number): void;
304 |
305 | /** sets perturb pos,quat in d->mocap when selected body is mocap, and in d->qpos otherwise
306 | * d->qpos written only if flg_paused and subtree root for selected body has free joint */
307 | applyPose(bodyID: number,
308 | refPosX : number, refPosY : number, refPosZ : number,
309 | refQuat1: number, refQuat2: number, refQuat3: number, refQuat4: number,
310 | flg_paused: number): void;
311 | // DATA_INTERFACE
312 | }
313 |
314 | export interface mujoco extends EmscriptenModule {
315 | FS : typeof FS;
316 | MEMFS : typeof MEMFS;
317 | Model : Model;
318 | State : State;
319 | Simulation : Simulation;
320 | }
321 | declare var load_mujoco: EmscriptenModuleFactory;
322 | export default load_mujoco;
323 |
--------------------------------------------------------------------------------
/src/old/parse_headers.py:
--------------------------------------------------------------------------------
1 | import json
2 | import dataclasses
3 | from cxxheaderparser.types import Array, Pointer
4 | from cxxheaderparser.simple import parse_string
5 |
6 | prefix = """// THIS FILE IS AUTO GENERATED - SEE parse_headers.py FOR HOW IT GETS GENERATED!
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "mujoco/mujoco.h"
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | using namespace emscripten;
22 |
23 | """
24 |
25 | class_definitions = ""
26 | emscripten_bindings = "\n\nEMSCRIPTEN_BINDINGS(mujoco_wasm) {\n\n"
27 | typescript_definitions = ""
28 |
29 | with open("include/mujoco/mjmodel.h") as f:
30 | content = f.read()
31 | parsed_data = parse_string(content)
32 |
33 | with open("parsed_json.json", mode='w') as j:
34 | json.dump(dataclasses.asdict(parsed_data), j, indent=2)
35 |
36 | for data in parsed_data.namespace.classes:
37 | if data.class_decl.classkey == "struct":
38 | struct_name = data.class_decl.typename.segments[0].name
39 | if struct_name.endswith("_"):
40 | struct_name = struct_name[:-1]
41 | print("Struct Name:", struct_name)
42 | class_definitions += "class "+struct_name[2:]+" {\npublic:\n "+struct_name[2:]+'() { m = NULL; }\n\n '+struct_name+' *ptr () { return m; }\n '+struct_name+' getVal() { return *m; }\n\n'
43 | emscripten_bindings += ' class_<'+struct_name[2:]+'>("'+struct_name[2:].ljust(22)+'")\n .constructor<>()\n'
44 | for field in data.fields:
45 | field_name = field.name
46 | if field.access == "public" and not "Visual" in struct_name:
47 | emscripten_bindings += ' .function('+('"'+field_name+'"').ljust(22)+', &'+struct_name[2:]+'::'+field_name.ljust(22)+')\n'
48 | #print(field.type)
49 | field_type = "void"
50 | if isinstance(field.type, Array):
51 | if isinstance(field.type.array_of, Array):
52 | field_type = "Array of Array of " + field.type.array_of.array_of.typename.segments[0].name
53 | elif isinstance(field.type.array_of, Pointer):
54 | field_type = "Pointer of " + field.type.array_of.ptr_to.typename.segments[0].name
55 | else:
56 | field_type = "Array of " + field.type.array_of.typename.segments[0].name
57 | else:
58 | if isinstance(field.type, Pointer):
59 | field_type = "Pointer of " + field.type.ptr_to.typename.segments[0].name
60 | class_definitions += ' val '+field_name.ljust(22)+'() { return val(typed_memory_view(m->nmesh, m->'+field_name.ljust(22)+' )); } ' + field.doxygen +"\n"
61 | elif field.type.typename:
62 | field_type = field.type.typename.segments[0].name
63 | field_type = field_type.replace("mjtNum", "double")
64 | class_definitions += ' '+field_type.ljust(6)+' '+field_name.ljust(22)+'() { return m->'+field_name.ljust(22)+'; } ' + field.doxygen +"\n"
65 | print(" Field Name:", field_name, ", Field Type:", field_type, field.doxygen)
66 | class_definitions += 'private:\n '+struct_name+' *m;\n};\n'
67 | emscripten_bindings += ";\n\n"
68 | emscripten_bindings += "}\n"
69 |
70 | full_cc = prefix + class_definitions + emscripten_bindings
71 | with open("main-genned.cc", mode="w") as f:
72 | f.write(full_cc)
73 |
--------------------------------------------------------------------------------
/src/parse_mjxmacro.py:
--------------------------------------------------------------------------------
1 | auto_gen_lines = {
2 | "model_definitions": [],
3 | "model_bindings" : [],
4 | "model_typescript" : [],
5 | "model_enums" : [],
6 | "data_definitions" : [],
7 | "data_bindings" : [],
8 | "data_typescript" : [],
9 | "enums_typescript" : [],
10 |
11 | }
12 | parse_mode = (None, None)
13 | types_to_array_types = {"int":"Int32Array", "mjtNum":"Float64Array", "float": "Float32Array", "mjtByte": "Uint8Array", "char": "Uint8Array", "uintptr_t":"BigUint64Array"}
14 |
15 | def parse_pointer_line(line:str, header_lines:list[str], mj_definitions:list[str], emscripten_bindings:list[str], typescript_definitions:list[str]):
16 | elements = line.strip(" X(").split(""")""")[0].strip().split(",")
17 | elements = [e.strip() for e in elements]
18 |
19 | model_ptr = "m" if parse_mode[1] == "model" else "_model->ptr()"
20 | if elements[3].startswith("MJ_M("):
21 | elements[3] = model_ptr+"->"+elements[3][5:]
22 | if parse_mode[1] == "model":
23 | mj_definitions .append(' val '+elements[1].ljust(22)+' () const { return val(typed_memory_view(m->'+elements[2].ljust(15)+' * '+elements[3].ljust(9)+', m->'+elements[1].ljust(22)+' )); }')
24 | else:
25 | mj_definitions .append(' val '+elements[1].ljust(22)+' () const { return val(typed_memory_view(_model->ptr()->'+elements[2].ljust(15)+' * '+elements[3].ljust(9)+', _state->ptr()->'+elements[1].ljust(22)+' )); }')
26 | emscripten_bindings.append(' .property('+('"'+elements[1]+'"').ljust(24)+', &'+("Model" if parse_mode[1] == "model" else "Simulation")+'::'+elements[1].ljust(22)+')')
27 | # Iterate through the original header file looking for comments
28 | for model_line in header_lines:
29 | if elements[0]+"* " in model_line and elements[1]+";" in model_line:
30 | comment = model_line.split("//")[1].strip()
31 | typescript_definitions.append(" /** "+ comment +"*/")
32 | break
33 | typescript_definitions.append(' '+elements[1].ljust(22)+': '+types_to_array_types[elements[0]].rjust(12)+';')
34 |
35 | def parse_int_line(line:str, header_lines:list[str], mj_definitions:list[str], emscripten_bindings:list[str], typescript_definitions:list[str]):
36 | name = line.strip(" X(").split(""")""")[0].strip()
37 | mj_definitions .append(' int '+name.ljust(14)+'() const { return m->'+name.ljust(14)+'; }')
38 | emscripten_bindings.append(' .property('+('"'+name+'"').ljust(24)+', &Model::'+name.ljust(22)+')')
39 |
40 | # Iterate through the file looking for comments
41 | for model_line in header_lines:
42 | if "int " in model_line and name+";" in model_line:
43 | comment = model_line.split("//")[1].strip()
44 | typescript_definitions.append(" /** "+ comment +"*/")
45 | break
46 |
47 | typescript_definitions.append(' '+name.ljust(22)+': '+('number').rjust(12)+';')
48 |
49 |
50 | with open("include/mujoco/mjmodel.h") as f:
51 | model_lines = f.readlines()
52 |
53 | with open("include/mujoco/mjdata.h") as f:
54 | data_lines = f.readlines()
55 |
56 |
57 | # Parse mjx Macro to get the emscripten bindings and typescript definitions
58 | with open("include/mujoco/mjxmacro.h") as f:
59 | lines = f.readlines()
60 |
61 | for line in lines:
62 | if parse_mode[0] != None:
63 | if parse_mode[0] == "pointers":
64 | if line.strip().startswith("X("):
65 | parse_pointer_line(line,
66 | model_lines if parse_mode[1] == "model" else data_lines,
67 | auto_gen_lines[parse_mode[1]+"_definitions"],
68 | auto_gen_lines[parse_mode[1]+"_bindings"],
69 | auto_gen_lines[parse_mode[1]+"_typescript"])
70 | else:
71 | parse_mode = (None, None)
72 |
73 | if parse_mode[0] == "ints":
74 | if line.strip().startswith("X("):
75 | parse_int_line(line,
76 | model_lines if parse_mode[1] == "model" else data_lines,
77 | auto_gen_lines[parse_mode[1]+"_definitions"],
78 | auto_gen_lines[parse_mode[1]+"_bindings"],
79 | auto_gen_lines[parse_mode[1]+"_typescript"])
80 | else:
81 | parse_mode = (None, None)
82 |
83 | if "#define MJMODEL_INTS" in line:
84 | parse_mode = ("ints", "model")
85 | if "#define MJMODEL_POINTERS" in line:
86 | parse_mode = ("pointers", "model")
87 | if "#define MJDATA_POINTERS" in line:
88 | parse_mode = ("pointers", "data")
89 |
90 | import functions
91 | from ast_nodes import ValueType
92 | for function in functions.FUNCTIONS:
93 | #print("Function:", function)
94 | param_types = [param.decltype for param in functions.FUNCTIONS[function].parameters]
95 | name = function[3:] if function != "mj_crb" else function[3:] + "Calculate"
96 | function_def = " void "+name.ljust(22)+"() { "+function.ljust(28)+"("
97 | def_args = []
98 | def_params = []
99 | def_typescript = []
100 | need_raw_pinters = False
101 | return_decl = functions.FUNCTIONS[function].return_type.decl()
102 | valid_function = return_decl == "const char *" or (not ("*" in return_decl) and not ("[" in return_decl))
103 | for param in functions.FUNCTIONS[function].parameters:
104 | param_type = param.type.decl()
105 | if(param.decltype == "const mjModel *"):
106 | def_params.append("_model->ptr()")
107 | elif(param.decltype == "mjData *"):
108 | def_params.append("_state->ptr()")
109 | elif(param.decltype == "const char *"):
110 | def_args .append("std::string "+param.name)
111 | def_params.append(param.name+".c_str()")
112 | def_typescript.append(param.name + " : string")
113 | elif("mjtNum *" in param.decltype):
114 | def_args .append("val "+param.name)#(str(param)) # UNTESTED, WE DON'T KNOW IF THIS WORKS
115 | #def_params.append(param.name +'["buffer"].as()')
116 | #def_params.append('reinterpret_cast('+param.name +')') #.global("byteOffset").as()
117 | def_params.append('reinterpret_cast('+param.name+'["byteOffset"].as())') #.global("byteOffset").as()
118 | def_typescript.append(param.name + " : Float64Array")
119 | need_raw_pinters = True
120 | elif (not ("*" in param_type) and not ("[" in param_type) and not (param_type == "mjfPluginLibraryLoadCallback")):
121 | def_args .append(str(param))
122 | def_params.append(param.name)
123 | param_type = param_type.replace("mjtNum","number").replace("int","number").replace("float","number").replace("size_t", "number").replace("unsigned char", "string")
124 | def_typescript.append(param.name + " : " + param_type)
125 | else:
126 | valid_function = False
127 | if valid_function:
128 | is_string = False
129 | to_return = function.ljust(28)+"("+(", ".join(def_params)).ljust(20)
130 | if return_decl == "const char *":
131 | return_decl = "std::string"
132 | to_return = "std::string(" + to_return + ")"
133 | auto_gen_lines["data_definitions"].append(" "+return_decl.ljust(6)+" "+name.ljust(20)+"("+(", ".join(def_args)).ljust(20)+") { return "+to_return+"); }")
134 | auto_gen_lines["data_bindings" ].append(' .function('+('"'+name+'"').ljust(23)+' , &Simulation::'+name.ljust(22)+(')'if not need_raw_pinters else ', allow_raw_pointers())')) #>
135 | auto_gen_lines["data_typescript" ].append(" /** "+ functions.FUNCTIONS[function].doc + (" [Only works with MuJoCo Allocated Arrays!]" if need_raw_pinters else "") +"*/")
136 | returnType = functions.FUNCTIONS[function].return_type
137 | returnType = returnType.inner_type.name if "*" in returnType.decl() else returnType.name
138 | returnType = returnType.replace("mjtNum","number").replace("int","number").replace("float","number").replace("char", "string")
139 | auto_gen_lines["data_typescript" ].append(' '+name.ljust(22)+'('+", ".join(def_typescript)+'): '+returnType+';')
140 |
141 |
142 | # Parse mjmodel.h for enums
143 | cur_enum_name = None
144 | for line in model_lines:
145 | line = line.strip()
146 |
147 | if cur_enum_name is not None and line.startswith("}"):
148 | cur_enum_name = None
149 | auto_gen_lines["model_enums"].append(' ;')
150 | auto_gen_lines["enums_typescript"].append( "}")
151 |
152 | if cur_enum_name is not None and len(line) > 0:
153 | parts = line.split("//")
154 | parts = [part.strip() for part in parts]
155 | if len(parts[0]) > 0 and len(parts[0].split(" ")) > 0:
156 | meat = parts[0].split(" ")[0].split(",")[0]; potatos = parts[1]
157 | auto_gen_lines["model_enums"].append(' .value('+('"'+meat+'"').ljust(25)+', '+cur_enum_name.ljust(25)+'::'+meat.ljust(25)+')')
158 | auto_gen_lines["enums_typescript"].append(" /** "+potatos.ljust(40)+" */")
159 | auto_gen_lines["enums_typescript"].append(" "+meat.ljust(25)+",")
160 |
161 |
162 | if line.startswith("typedef enum"):
163 | cur_enum_name = line.split(" ")[2][:-1]
164 | auto_gen_lines["model_enums"].append(' enum_<'+cur_enum_name+'>("'+cur_enum_name+'")')
165 | if len(line.split("//")) > 1:
166 | auto_gen_lines["enums_typescript"].append("/** "+line.split("//")[1].ljust(40)+" */")
167 | auto_gen_lines["enums_typescript"].append("export enum "+cur_enum_name +" {")
168 |
169 | # Insert our auto-generated bindings into our template files
170 | with open("src/main.template.cc") as f:
171 | content = f.read()
172 | content = content.replace("// MJMODEL_DEFINITIONS", "// MJMODEL_DEFINITIONS\n"+"\n".join(auto_gen_lines["model_definitions"]))
173 | content = content.replace("// MJMODEL_BINDINGS" , "// MJMODEL_BINDINGS\n" +"\n".join(auto_gen_lines["model_bindings"]))
174 |
175 | content = content.replace("// MJDATA_DEFINITIONS", "// MJDATA_DEFINITIONS\n"+"\n".join(auto_gen_lines["data_definitions"]))
176 | content = content.replace("// MJDATA_BINDINGS" , "// MJDATA_BINDINGS\n"+"\n".join(auto_gen_lines["data_bindings"]))
177 |
178 | content = content.replace("// MODEL_ENUMS", "// MODEL_ENUMS\n"+"\n".join(auto_gen_lines["model_enums"]))
179 |
180 | with open("src/main.genned.cc", mode="w") as f:
181 | f.write(content)
182 |
183 | with open("src/mujoco_wasm.template.d.ts") as f:
184 | content = f.read()
185 | content = content.replace("// MODEL_INTERFACE", "// MODEL_INTERFACE\n"+"\n".join(auto_gen_lines["model_typescript"]))
186 | content = content.replace("// DATA_INTERFACE" , "// DATA_INTERFACE\n" +"\n".join(auto_gen_lines[ "data_typescript"]))
187 | content = content.replace("// ENUMS" , "// ENUMS\n" +"\n".join(auto_gen_lines[ "enums_typescript"]))
188 | with open("dist/mujoco_wasm.d.ts", mode="w") as f:
189 | f.write(content)
190 |
--------------------------------------------------------------------------------