├── .github └── workflows │ └── main.yml ├── .gitignore ├── .nojekyll ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build_windows.bat ├── dist ├── mujoco_wasm.d.ts ├── mujoco_wasm.js └── mujoco_wasm.wasm ├── examples ├── MuJoCoBanner.png ├── MuJoCoWasmLogo.png ├── favicon.png ├── main.js ├── mujocoUtils.js ├── scenes │ ├── 22_humanoids.xml │ ├── adhesion.xml │ ├── agility_cassie │ │ ├── LICENSE │ │ ├── README.md │ │ ├── assets │ │ │ ├── achilles-rod.obj │ │ │ ├── cassie-texture.png │ │ │ ├── foot-crank.obj │ │ │ ├── foot.obj │ │ │ ├── heel-spring.obj │ │ │ ├── hip-pitch.obj │ │ │ ├── hip-roll.obj │ │ │ ├── hip-yaw.obj │ │ │ ├── knee-spring.obj │ │ │ ├── knee.obj │ │ │ ├── pelvis.obj │ │ │ ├── plantar-rod.obj │ │ │ ├── shin.obj │ │ │ └── tarsus.obj │ │ ├── cassie.xml │ │ └── scene.xml │ ├── arm26.xml │ ├── balloons.xml │ ├── flag.xml │ ├── generate_index.py │ ├── hammock.xml │ ├── humanoid.xml │ ├── humanoid_body.xml │ ├── index.json │ ├── model_with_tendon.xml │ ├── mug.obj │ ├── mug.png │ ├── mug.xml │ ├── scene.xml │ ├── shadow_hand │ │ ├── LICENSE │ │ ├── README.md │ │ ├── assets │ │ │ ├── f_distal_pst.obj │ │ │ ├── f_knuckle.obj │ │ │ ├── f_middle.obj │ │ │ ├── f_proximal.obj │ │ │ ├── forearm_0.obj │ │ │ ├── forearm_1.obj │ │ │ ├── forearm_collision.obj │ │ │ ├── lf_metacarpal.obj │ │ │ ├── mounting_plate.obj │ │ │ ├── palm.obj │ │ │ ├── th_distal_pst.obj │ │ │ ├── th_middle.obj │ │ │ ├── th_proximal.obj │ │ │ └── wrist.obj │ │ ├── left_hand.xml │ │ ├── right_hand.xml │ │ ├── scene_left.xml │ │ └── scene_right.xml │ ├── simple.xml │ └── slider_crank.xml └── utils │ ├── Debug.js │ ├── DragStateManager.js │ └── Reflector.js ├── include └── mujoco │ ├── mjdata.h │ ├── mjexport.h │ ├── mjmodel.h │ ├── mjplugin.h │ ├── mjrender.h │ ├── mjtnum.h │ ├── mjui.h │ ├── mjvisualize.h │ ├── mjxmacro.h │ └── mujoco.h ├── index.html ├── lib ├── libccd.a ├── libelasticity.a ├── liblodepng.a ├── libmujoco.a ├── libqhullstatic_r.a ├── libtinyobjloader.a └── libtinyxml2.a ├── node_modules └── three │ ├── build │ ├── three.cjs │ ├── three.js │ ├── three.min.js │ └── three.module.js │ └── examples │ └── jsm │ ├── controls │ ├── DragControls.js │ └── OrbitControls.js │ └── libs │ └── lil-gui.module.min.js ├── package-lock.json ├── package.json └── src ├── CMakeLists.txt ├── ast_nodes.py ├── functions.py ├── main.genned.cc ├── main.template.cc ├── mujoco_wasm.template.d.ts ├── old ├── main-genned.cc ├── main.cc └── parse_headers.py └── parse_mjxmacro.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build mujoco_wasm 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | Build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - uses: mymindstorm/setup-emsdk@v14 15 | 16 | - name: Verify Emscripten is Installed 17 | run: emcc -v 18 | 19 | - name: Linux - Build Base Binary 20 | if: runner.os == 'Linux' 21 | run: | 22 | mkdir build 23 | cd build 24 | emcmake cmake .. 25 | make 26 | 27 | - name: Linux - Upload Build 28 | uses: actions/upload-artifact@v4 29 | if: runner.os == 'Linux' 30 | with: 31 | name: mujoco_wasm 32 | path: | 33 | ./README.md 34 | ./build 35 | ./dist 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | **/.DS_Store 3 | *.slo 4 | *.lo 5 | *.o 6 | *.pyc 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | *.dll 16 | 17 | # Fortran module files 18 | *.mod 19 | *.smod 20 | 21 | # Compiled Static libraries 22 | *.lai 23 | *.la 24 | *.a 25 | *.lib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | 32 | **/cmake-build-debug 33 | **/CMakeCache.txt 34 | **/cmake_install.cmake 35 | **/install_manifest.txt 36 | **/CMakeFiles/ 37 | **/CTestTestfile.cmake 38 | **/Makefile 39 | **/*.cbp 40 | **/CMakeScripts 41 | **/compile_commands.json 42 | 43 | include/divisible/* 44 | 45 | 46 | ## Local 47 | 48 | .idea/*.xml 49 | 50 | build/**/* 51 | 52 | include/* 53 | lib/* 54 | bin/* 55 | test/test_runner 56 | .vscode 57 | .cache 58 | .fiveserverrc 59 | 60 | # Dependency directories 61 | node_modules/**/* 62 | jspm_packages/ 63 | 64 | # Three.js Build 65 | !node_modules/three/ 66 | !node_modules/three/*/ 67 | !node_modules/three/build/* 68 | # Three.js Controls 69 | !node_modules/three/examples/*/ 70 | !node_modules/three/examples/jsm/ 71 | !node_modules/three/examples/jsm/*/ 72 | !node_modules/three/examples/jsm/controls/ 73 | !node_modules/three/examples/jsm/controls/OrbitControls.js 74 | !node_modules/three/examples/jsm/controls/DragControls.js 75 | !node_modules/three/examples/jsm/libs/ 76 | !node_modules/three/examples/jsm/libs/lil-gui.module.min.js 77 | #!node_modules/three/examples/jsm/utils/ 78 | #!node_modules/three/examples/jsm/utils/* 79 | #!node_modules/three/examples/jsm/loaders/ 80 | #!node_modules/three/examples/jsm/loaders/* -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zalo/mujoco_wasm/afbc4c0810553f0b36dcec06d831123692d6b81b/.nojekyll -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | option(JS_ONLY "Compiles to native JS (No WASM)" OFF) 3 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/dist") 4 | 5 | project(mujoco_wasm) 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3") 9 | 10 | set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) 11 | 12 | set(MUJOCO_INSTALL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) 13 | set(MUJOCO_INSTALL_BIN_DIR ${PROJECT_SOURCE_DIR}/bin) 14 | set(MUJOCO_INSTALL_LIB_DIR ${PROJECT_SOURCE_DIR}/lib) 15 | 16 | include_directories(${MUJOCO_INSTALL_INCLUDE_DIR}) 17 | link_directories(${MUJOCO_INSTALL_LIB_DIR}) 18 | 19 | add_subdirectory(src) 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Konstantin Gredeskoul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | 6 | 7 | 9 | 11 | 12 | 13 | 14 | 15 |

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 | 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 | 119 | -------------------------------------------------------------------------------- /examples/scenes/balloons.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 64 | -------------------------------------------------------------------------------- /examples/scenes/humanoid.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 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 | --------------------------------------------------------------------------------