Expose a handle for the Python viewer.

This change also requires user scripts to explicitly synchronize changes to physics state to the viewer. The Simulate class was reconfigured so that certain UI events are handled during this sync operation, outside of the render loop on the main thread. These correspond to operations that require access to the full mjModel/mjData.

To support other, more interactive operations (e.g. camera movements), a new mjvSceneState struct is introduced which captures only the portion of the physics state required for scene re-rendering. The mjvSceneState is updated from mjModel/mjData during the viewer sync operation, and is significantly cheaper than a full mj_copyModel and mj_copyData.

Fixes https://github.com/deepmind/mujoco/issues/796

PiperOrigin-RevId: 525723636
Change-Id: Id08d0210a2c067d5afe85e2bf104f276aeddd75e
This commit is contained in:
Saran Tunyasuvunakool
2023-04-20 05:58:32 -07:00
committed by Copybara-Service
parent 4f5da9c554
commit b362cb4972
34 changed files with 4644 additions and 1088 deletions
+11
View File
@@ -814,6 +814,17 @@ This structure contains everything needed to render the 3D scene in OpenGL.
.. mujoco-include:: mjvScene .. mujoco-include:: mjvScene
.. _mjvSceneState:
mjvSceneState
~~~~~~~~~~~~~
This structure contains the portions of :ref:`mjModel` and :ref:`mjData` that are required for
various ``mjv_*`` functions.
.. mujoco-include:: mjvScene
.. _mjvFigure: .. _mjvFigure:
mjvFigure mjvFigure
+72
View File
@@ -1332,6 +1332,15 @@ mjv_moveCamera
Move camera with mouse; action is mjtMouse. Move camera with mouse; action is mjtMouse.
.. _mjv_moveCameraFromState:
mjv_moveCameraFromState
~~~~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_moveCameraFromState
Move camera with mouse given a scene state; action is mjtMouse.
.. _mjv_movePerturb: .. _mjv_movePerturb:
mjv_movePerturb mjv_movePerturb
@@ -1341,6 +1350,15 @@ mjv_movePerturb
Move perturb object with mouse; action is mjtMouse. Move perturb object with mouse; action is mjtMouse.
.. _mjv_movePerturbFromState:
mjv_movePerturbFromState
~~~~~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_movePerturbFromState
Move perturb object with mouse given a scene state; action is mjtMouse.
.. _mjv_moveModel: .. _mjv_moveModel:
mjv_moveModel mjv_moveModel
@@ -1483,6 +1501,51 @@ mjv_updateScene
Update entire scene given model state. Update entire scene given model state.
.. _mjv_updateSceneFromState:
mjv_updateSceneFromState
~~~~~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_updateSceneFromState
Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.
.. _mjv_defaultSceneState:
mjv_defaultSceneState
~~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_defaultSceneState
Set default scene state.
.. _mjv_makeSceneState:
mjv_makeSceneState
~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_makeSceneState
Allocate resources and initialize a scene state object.
.. _mjv_freeSceneState:
mjv_freeSceneState
~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_freeSceneState
Free scene state.
.. _mjv_updateSceneState:
mjv_updateSceneState
~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjv_updateSceneState
Update a scene state from model and data.
.. _mjv_addGeoms: .. _mjv_addGeoms:
mjv_addGeoms mjv_addGeoms
@@ -1572,6 +1635,15 @@ mjr_freeContext
Free resources in custom OpenGL context, set to default. Free resources in custom OpenGL context, set to default.
.. _mjr_resizeOffscreen:
mjr_resizeOffscreen
~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjr_resizeOffscreen
Resize offscreen buffers.
.. _mjr_uploadTexture: .. _mjr_uploadTexture:
mjr_uploadTexture mjr_uploadTexture
+5 -1
View File
@@ -35,6 +35,10 @@ Python bindings
state concurrently with the internal ``mj_forward``, resulting in e.g. state concurrently with the internal ``mj_forward``, resulting in e.g.
`MuJoCo stack overflow error <https://github.com/deepmind/mujoco/issues/783>`_ `MuJoCo stack overflow error <https://github.com/deepmind/mujoco/issues/783>`_
or `segmentation fault <https://github.com/deepmind/mujoco/issues/790>`_. or `segmentation fault <https://github.com/deepmind/mujoco/issues/790>`_.
- The ``viewer.launch_passive`` function now returns a handle which can be used to interact with the viewer. The passive
viewer now also requires an explicit call to ``sync`` on its handle to pick up any update to the physics state. This
is to avoid race conditions that can result in visual artifacts. See :ref:`documentation<PyViewer>` for details.
- The ``viewer.launch_repl`` function has been removed since its functionality is superceded by ``launch_passive``.
- Added a small number of missing struct fields discovered through the new ``introspect`` metadata. - Added a small number of missing struct fields discovered through the new ``introspect`` metadata.
Bug fixes Bug fixes
@@ -102,7 +106,7 @@ Python bindings
#. Added ``viewer.launch_passive`` which launches the interactive viewer in a passive, non-blocking mode. Calls to #. Added ``viewer.launch_passive`` which launches the interactive viewer in a passive, non-blocking mode. Calls to
``launch_passive`` return immediately, allowing user code to continue execution, with the viewer automatically ``launch_passive`` return immediately, allowing user code to continue execution, with the viewer automatically
reflecting any changes to the physics state. (Note that this functionality is currently in experimental/beta stage, reflecting any changes to the physics state. (Note that this functionality is currently in experimental/beta stage,
and is not yet described in our :ref:`viewer documentation<PyViewer>`.) and is not yet described in our :ref:`viewer documentation<PyViewer>`.)
#. Added the ``mjpython`` launcher for macOS, which is required for ``viewer.launch_passive`` to function there. #. Added the ``mjpython`` launcher for macOS, which is required for ``viewer.launch_passive`` to function there.
#. Removed ``efc_`` fields from joint indexers. Since the introduction of arena memory, these fields now have dynamic #. Removed ``efc_`` fields from joint indexers. Since the introduction of arena memory, these fields now have dynamic
sizes that change between time steps depending on the number of active constraints, breaking strict correspondence sizes that change between time steps depending on the number of active constraints, breaking strict correspondence
+229 -1
View File
@@ -673,7 +673,6 @@ struct mjVisual_ { // visualization options
float realtime; // initial real-time factor (1: real time) float realtime; // initial real-time factor (1: real time)
int offwidth; // width of offscreen buffer int offwidth; // width of offscreen buffer
int offheight; // height of offscreen buffer int offheight; // height of offscreen buffer
int treedepth; // depth of the bounding volume hierarchy
int ellipsoidinertia; // geom for inertia visualization (0: box, 1: ellipsoid) int ellipsoidinertia; // geom for inertia visualization (0: box, 1: ellipsoid)
} global; } global;
@@ -1779,6 +1778,7 @@ struct mjvOption_ { // abstract visualization options
mjtByte actuatorgroup[mjNGROUP]; // actuator visualization by group mjtByte actuatorgroup[mjNGROUP]; // actuator visualization by group
mjtByte skingroup[mjNGROUP]; // skin visualization by group mjtByte skingroup[mjNGROUP]; // skin visualization by group
mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag) mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag)
int bvh_depth; // depth of the bounding volume hierarchy to be visualized
}; };
typedef struct mjvOption_ mjvOption; typedef struct mjvOption_ mjvOption;
struct mjvScene_ { // abstract scene passed to OpenGL renderer struct mjvScene_ { // abstract scene passed to OpenGL renderer
@@ -1865,6 +1865,219 @@ struct mjvFigure_ { // abstract 2D figure passed to OpenGL rendere
float yaxisdata[2]; // range of y-axis in data units float yaxisdata[2]; // range of y-axis in data units
}; };
typedef struct mjvFigure_ mjvFigure; typedef struct mjvFigure_ mjvFigure;
struct mjvSceneState_ {
int nbuffer; // size of the buffer in bytes
void* buffer; // heap-allocated memory for all arrays in this struct
int maxgeom; // maximum number of mjvGeom supported by this state object
mjvScene plugincache; // scratch space for vis geoms inserted by plugins
// fields in mjModel that are necessary to re-render a scene
struct {
int nu;
int na;
int nbody;
int nbvh;
int njnt;
int ngeom;
int nsite;
int ncam;
int nlight;
int nmesh;
int nskin;
int nskinvert;
int nskinface;
int nskinbone;
int nskinbonevert;
int nmat;
int neq;
int ntendon;
int nwrap;
int nsensor;
int nnames;
int nsensordata;
mjOption opt;
mjVisual vis;
mjStatistic stat;
int* body_parentid;
int* body_rootid;
int* body_weldid;
int* body_mocapid;
int* body_jntnum;
int* body_jntadr;
int* body_geomnum;
int* body_geomadr;
mjtNum* body_iquat;
mjtNum* body_mass;
mjtNum* body_inertia;
int* body_bvhadr;
int* body_bvhnum;
int* bvh_depth;
int* bvh_child;
int* bvh_geomid;
mjtNum* bvh_aabb;
int* jnt_type;
int* jnt_bodyid;
int* jnt_group;
int* geom_type;
int* geom_bodyid;
int* geom_dataid;
int* geom_matid;
int* geom_group;
mjtNum* geom_size;
mjtNum* geom_aabb;
mjtNum* geom_rbound;
float* geom_rgba;
int* site_type;
int* site_bodyid;
int* site_matid;
int* site_group;
mjtNum* site_size;
float* site_rgba;
mjtNum* cam_fovy;
mjtNum* cam_ipd;
mjtByte* light_directional;
mjtByte* light_castshadow;
mjtByte* light_active;
float* light_attenuation;
float* light_cutoff;
float* light_exponent;
float* light_ambient;
float* light_diffuse;
float* light_specular;
int* mesh_texcoordadr;
int* mesh_graphadr;
int* skin_matid;
int* skin_group;
float* skin_rgba;
float* skin_inflate;
int* skin_vertadr;
int* skin_vertnum;
int* skin_texcoordadr;
int* skin_faceadr;
int* skin_facenum;
int* skin_boneadr;
int* skin_bonenum;
float* skin_vert;
int* skin_face;
int* skin_bonevertadr;
int* skin_bonevertnum;
float* skin_bonebindpos;
float* skin_bonebindquat;
int* skin_bonebodyid;
int* skin_bonevertid;
float* skin_bonevertweight;
int* mat_texid;
mjtByte* mat_texuniform;
float* mat_texrepeat;
float* mat_emission;
float* mat_specular;
float* mat_shininess;
float* mat_reflectance;
float* mat_rgba;
int* eq_type;
int* eq_obj1id;
int* eq_obj2id;
mjtByte* eq_active;
mjtNum* eq_data;
int* tendon_num;
int* tendon_matid;
int* tendon_group;
mjtByte* tendon_limited;
mjtNum* tendon_width;
mjtNum* tendon_range;
mjtNum* tendon_stiffness;
mjtNum* tendon_damping;
mjtNum* tendon_frictionloss;
mjtNum* tendon_lengthspring;
float* tendon_rgba;
int* actuator_trntype;
int* actuator_dyntype;
int* actuator_trnid;
int* actuator_actadr;
int* actuator_actnum;
int* actuator_group;
mjtByte* actuator_ctrllimited;
mjtByte* actuator_actlimited;
mjtNum* actuator_ctrlrange;
mjtNum* actuator_actrange;
mjtNum* actuator_cranklength;
int* sensor_type;
int* sensor_objid;
int* sensor_adr;
int* name_bodyadr;
int* name_jntadr;
int* name_geomadr;
int* name_siteadr;
int* name_camadr;
int* name_lightadr;
int* name_eqadr;
int* name_tendonadr;
int* name_actuatoradr;
char* names;
} model;
// fields in mjData that are necessary to re-render a scene
struct {
mjWarningStat warning[mjNWARNING];
int nefc;
int ncon;
mjtNum time;
mjtNum* act;
mjtNum* ctrl;
mjtNum* xfrc_applied;
mjtNum* sensordata;
mjtNum* xpos;
mjtNum* xquat;
mjtNum* xmat;
mjtNum* xipos;
mjtNum* ximat;
mjtNum* xanchor;
mjtNum* xaxis;
mjtNum* geom_xpos;
mjtNum* geom_xmat;
mjtNum* site_xpos;
mjtNum* site_xmat;
mjtNum* cam_xpos;
mjtNum* cam_xmat;
mjtNum* light_xpos;
mjtNum* light_xdir;
mjtNum* subtree_com;
int* ten_wrapadr;
int* ten_wrapnum;
int* wrap_obj;
mjtNum* wrap_xpos;
mjtByte* bvh_active;
mjContact* contact;
mjtNum* efc_force;
} data;
};
typedef struct mjvSceneState_ mjvSceneState;
//----------------------------- MJAPI FUNCTIONS -------------------------------- //----------------------------- MJAPI FUNCTIONS --------------------------------
void mj_defaultVFS(mjVFS* vfs); void mj_defaultVFS(mjVFS* vfs);
@@ -2020,8 +2233,14 @@ mjtNum mjv_frustumHeight(const mjvScene* scn);
void mjv_alignToCamera(mjtNum res[3], const mjtNum vec[3], const mjtNum forward[3]); void mjv_alignToCamera(mjtNum res[3], const mjtNum vec[3], const mjtNum forward[3]);
void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy, void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam); const mjvScene* scn, mjvCamera* cam);
void mjv_moveCameraFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam);
void mjv_movePerturb(const mjModel* m, const mjData* d, int action, mjtNum reldx, void mjv_movePerturb(const mjModel* m, const mjData* d, int action, mjtNum reldx,
mjtNum reldy, const mjvScene* scn, mjvPerturb* pert); mjtNum reldy, const mjvScene* scn, mjvPerturb* pert);
void mjv_movePerturbFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvPerturb* pert);
void mjv_moveModel(const mjModel* m, int action, mjtNum reldx, mjtNum reldy, void mjv_moveModel(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
const mjtNum roomup[3], mjvScene* scn); const mjtNum roomup[3], mjvScene* scn);
void mjv_initPerturb(const mjModel* m, mjData* d, const mjvScene* scn, mjvPerturb* pert); void mjv_initPerturb(const mjModel* m, mjData* d, const mjvScene* scn, mjvPerturb* pert);
@@ -2044,6 +2263,14 @@ void mjv_makeScene(const mjModel* m, mjvScene* scn, int maxgeom);
void mjv_freeScene(mjvScene* scn); void mjv_freeScene(mjvScene* scn);
void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt, void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn); const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn);
int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask,
mjvScene* scn);
void mjv_defaultSceneState(mjvSceneState* scnstate);
void mjv_makeSceneState(const mjModel* m, const mjData* d,
mjvSceneState* scnstate, int maxgeom);
void mjv_freeSceneState(mjvSceneState* scnstate);
void mjv_updateSceneState(const mjModel* m, mjData* d, mjvSceneState* scnstate);
void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt, void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, int catmask, mjvScene* scn); const mjvPerturb* pert, int catmask, mjvScene* scn);
void mjv_makeLights(const mjModel* m, mjData* d, mjvScene* scn); void mjv_makeLights(const mjModel* m, mjData* d, mjvScene* scn);
@@ -2054,6 +2281,7 @@ void mjr_makeContext(const mjModel* m, mjrContext* con, int fontscale);
void mjr_changeFont(int fontscale, mjrContext* con); void mjr_changeFont(int fontscale, mjrContext* con);
void mjr_addAux(int index, int width, int height, int samples, mjrContext* con); void mjr_addAux(int index, int width, int height, int samples, mjrContext* con);
void mjr_freeContext(mjrContext* con); void mjr_freeContext(mjrContext* con);
void mjr_resizeOffscreen(int width, int height, mjrContext* con);
void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid); void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid);
void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid); void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid);
void mjr_uploadHField(const mjModel* m, const mjrContext* con, int hfieldid); void mjr_uploadHField(const mjModel* m, const mjrContext* con, int hfieldid);
+78 -12
View File
@@ -117,19 +117,19 @@ As a reference, a working build configuration can be found in MuJoCo's
Interactive viewer Interactive viewer
================== ==================
An interactive GUI viewer is available as part of the Python package. (This is the same viewer as the ``simulate`` An interactive GUI viewer is provided as part of the Python package in the ``mujoco.viewer`` module. This is the same
application that ships with the MuJoCo binary releases.) viewer as the ``simulate`` application that ships with the MuJoCo binary releases.
Three distinct use cases are supported: Three distinct use cases are supported:
#. Launching as a standalone application: #. As a **standalone application**:
- ``python -m mujoco.viewer`` launches an empty visualization session, where a model can be loaded by drag-and-drop. - ``python -m mujoco.viewer`` launches an empty visualization session, where a model can be loaded by drag-and-drop.
- ``python -m mujoco.viewer --mjcf=/path/to/some/mjcf.xml`` launches a visualization session for the specified - ``python -m mujoco.viewer --mjcf=/path/to/some/mjcf.xml`` launches a visualization session for the specified
model file. model file.
#. Launching from a Python program/script -- import the module via ``from mujoco import viewer`` and launch the GUI #. As a **fully managed viewer** in a Python program/script, through the function ``viewer.launch``. This function
using one of the following invocations: **blocks the user's script completely** to take care of running and timing a physics loop.
- ``viewer.launch()`` launches an empty visualization session, where a model can be loaded by drag-and-drop. - ``viewer.launch()`` launches an empty visualization session, where a model can be loaded by drag-and-drop.
- ``viewer.launch(model)`` launches a visualization session for the given ``mjModel`` where the visualizer - ``viewer.launch(model)`` launches a visualization session for the given ``mjModel`` where the visualizer
@@ -137,13 +137,79 @@ Three distinct use cases are supported:
- ``viewer.launch(model, data)`` is the same as above, except that the visualizer operates directly on the given - ``viewer.launch(model, data)`` is the same as above, except that the visualizer operates directly on the given
``mjData`` instance -- upon exit the ``data`` object will have been modified. ``mjData`` instance -- upon exit the ``data`` object will have been modified.
#. Launching from an interactive Python session (aka REPL): when working interactively either in a ``python`` or #. As a **passive viewer**, by calling ``viewer.launch_passive(model, data)``. This function **does not block**,
``ipython`` shell, the visualizer can be launched in a "passive" mode via ``viewer.launch_repl(model, data)``, where allowing the user script to continue execution. In this mode, the user's script is responsible for timing and
the user remains in full control of modifying or stepping the physics. In this mode, the user can interact with the advancing the physics state, and mouse-drag perturbations will not work unless the user explicitly handles incoming
visualizer using the mouse and keyboard as usual, however the physics will be frozen unless the user explicitly calls events.
``mj_step`` (or perform any other modification of the ``mjData`` or ``mjModel``) in the REPL terminal. Note that since
the visualizer does not modify ``mjData`` in this mode, mouse-drag perturbations will not work unless the user .. warning::
explicitly handles incoming GUI perturbation events in the REPL session. On macOS, ``launch_passive`` requires that the user script is executed via a special ``mjpython`` launcher.
The ``mjpython`` command is installed as part of the ``mujoco`` package, and can be used as a drop-in replacement
for the usual ``python`` command and supports an identical set of command line flags and arguments. For example,
a script can be executed via ``mjpython my_script.py``, and an IPython shell can be launched via
``mjpython -m IPython``.
The ``launch_passive`` function returns a handle which can be used to interact with the viewer. It has the following
attributes:
- ``scn``, ``cam``, ``opt``, and ``pert`` properties: correspond to :ref:`mjvScene`, :ref:`mjvCamera`,
:ref:`mjvOption`, and :ref:`mjvPerturb` structs, respectively.
- ``lock()``: provides a mutex lock for the viewer as a context manager. Since the viewer operates its own
thread, user code must ensure that it is holding the viewer lock before modifying any physics or visualization
state. These include the ``mjModel`` and ``mjData`` instance passed to ``launch_passive``, and also the ``scn``,
``cam``, ``opt``, and ``pert`` properties of the viewer handle.
- ``sync()``: synchronizes state between ``mjModel``, ``mjData``, and GUI user inputs since the previous call to
``sync``. In order to allow user scripts to make arbitrary modifications to ``mjModel`` and ``mjData`` without
needing to hold the viewer lock, the passive viewer does not access or modify these structs outside of ``sync``
calls.
User scripts must call ``sync`` in order for the viewer to reflect physics state changes. The ``sync`` function
also transfers user inputs from the GUI back into ``mjOption`` (inside ``mjModel``) and ``mjData``, including
enable/disable flags, control inputs, and mouse perturbations.
- ``close()``: programmatically closes the viewer window. This method can be safely called without locking.
- ``is_running()``: returns ``True`` if the viewer window is running and ``False`` if it is closed.
This method can be safely called without locking.
The viewer handle can also be used as a context manager which calls ``close()`` automatically upon exit. A minimal
example of a user script that uses ``launch_passive`` might look like the following. (Note that example is a simple
illustrative example that does **not** necessarily keep the physics ticking at the correct wallclock rate.)
.. code-block:: python
import time
import mujoco
import mujoco.viewer
m = mujoco.MjModel.from_xml_path('/path/to/mjcf.xml')
d = mujoco.MjData(m)
with mujoco.viewer.launch_passive(m, d) as viewer:
# Close the viewer automatically after 30 seconds.
start = time.time()
while viewer.is_running() and time.time() - start < 30:
step_start = time.time()
# The mj_step call can be replaced with a user-defined function that evaluates
# a policy, applies a control signal, and steps an environment.
mujoco.mj_step(m, d)
# Example of modifying a viewer option: toggle contact points every second.
with viewer.lock():
viewer.opt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTPOINT] = int(d.time % 2)
# Synchronize so that the viewer picks up changes to the physics state.
viewer.sync()
# Rudimentary time keeping, doesn't attempt to catch up if physics stepping
# takes too long.
time_until_next_step = m.opt.timestep - (time.time() - step_start)
if time_until_next_step > 0:
time.sleep(time_until_next_step)
.. _PyUsage: .. _PyUsage:
-1
View File
@@ -447,7 +447,6 @@ struct mjVisual_ { // visualization options
float realtime; // initial real-time factor (1: real time) float realtime; // initial real-time factor (1: real time)
int offwidth; // width of offscreen buffer int offwidth; // width of offscreen buffer
int offheight; // height of offscreen buffer int offheight; // height of offscreen buffer
int treedepth; // depth of the bounding volume hierarchy
int ellipsoidinertia; // geom for inertia visualization (0: box, 1: ellipsoid) int ellipsoidinertia; // geom for inertia visualization (0: box, 1: ellipsoid)
} global; } global;
+220
View File
@@ -15,6 +15,8 @@
#ifndef MUJOCO_MJVISUALIZE_H_ #ifndef MUJOCO_MJVISUALIZE_H_
#define MUJOCO_MJVISUALIZE_H_ #define MUJOCO_MJVISUALIZE_H_
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h> #include <mujoco/mjtnum.h>
@@ -265,6 +267,7 @@ struct mjvOption_ { // abstract visualization options
mjtByte actuatorgroup[mjNGROUP]; // actuator visualization by group mjtByte actuatorgroup[mjNGROUP]; // actuator visualization by group
mjtByte skingroup[mjNGROUP]; // skin visualization by group mjtByte skingroup[mjNGROUP]; // skin visualization by group
mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag) mjtByte flags[mjNVISFLAG]; // visualization flags (indexed by mjtVisFlag)
int bvh_depth; // depth of the bounding volume hierarchy to be visualized
}; };
typedef struct mjvOption_ mjvOption; typedef struct mjvOption_ mjvOption;
@@ -360,4 +363,221 @@ struct mjvFigure_ { // abstract 2D figure passed to OpenGL rendere
}; };
typedef struct mjvFigure_ mjvFigure; typedef struct mjvFigure_ mjvFigure;
//---------------------------------- mjvSceneState -------------------------------------------------
struct mjvSceneState_ {
int nbuffer; // size of the buffer in bytes
void* buffer; // heap-allocated memory for all arrays in this struct
int maxgeom; // maximum number of mjvGeom supported by this state object
mjvScene plugincache; // scratch space for vis geoms inserted by plugins
// fields in mjModel that are necessary to re-render a scene
struct {
int nu;
int na;
int nbody;
int nbvh;
int njnt;
int ngeom;
int nsite;
int ncam;
int nlight;
int nmesh;
int nskin;
int nskinvert;
int nskinface;
int nskinbone;
int nskinbonevert;
int nmat;
int neq;
int ntendon;
int nwrap;
int nsensor;
int nnames;
int nsensordata;
mjOption opt;
mjVisual vis;
mjStatistic stat;
int* body_parentid;
int* body_rootid;
int* body_weldid;
int* body_mocapid;
int* body_jntnum;
int* body_jntadr;
int* body_geomnum;
int* body_geomadr;
mjtNum* body_iquat;
mjtNum* body_mass;
mjtNum* body_inertia;
int* body_bvhadr;
int* body_bvhnum;
int* bvh_depth;
int* bvh_child;
int* bvh_geomid;
mjtNum* bvh_aabb;
int* jnt_type;
int* jnt_bodyid;
int* jnt_group;
int* geom_type;
int* geom_bodyid;
int* geom_dataid;
int* geom_matid;
int* geom_group;
mjtNum* geom_size;
mjtNum* geom_aabb;
mjtNum* geom_rbound;
float* geom_rgba;
int* site_type;
int* site_bodyid;
int* site_matid;
int* site_group;
mjtNum* site_size;
float* site_rgba;
mjtNum* cam_fovy;
mjtNum* cam_ipd;
mjtByte* light_directional;
mjtByte* light_castshadow;
mjtByte* light_active;
float* light_attenuation;
float* light_cutoff;
float* light_exponent;
float* light_ambient;
float* light_diffuse;
float* light_specular;
int* mesh_texcoordadr;
int* mesh_graphadr;
int* skin_matid;
int* skin_group;
float* skin_rgba;
float* skin_inflate;
int* skin_vertadr;
int* skin_vertnum;
int* skin_texcoordadr;
int* skin_faceadr;
int* skin_facenum;
int* skin_boneadr;
int* skin_bonenum;
float* skin_vert;
int* skin_face;
int* skin_bonevertadr;
int* skin_bonevertnum;
float* skin_bonebindpos;
float* skin_bonebindquat;
int* skin_bonebodyid;
int* skin_bonevertid;
float* skin_bonevertweight;
int* mat_texid;
mjtByte* mat_texuniform;
float* mat_texrepeat;
float* mat_emission;
float* mat_specular;
float* mat_shininess;
float* mat_reflectance;
float* mat_rgba;
int* eq_type;
int* eq_obj1id;
int* eq_obj2id;
mjtByte* eq_active;
mjtNum* eq_data;
int* tendon_num;
int* tendon_matid;
int* tendon_group;
mjtByte* tendon_limited;
mjtNum* tendon_width;
mjtNum* tendon_range;
mjtNum* tendon_stiffness;
mjtNum* tendon_damping;
mjtNum* tendon_frictionloss;
mjtNum* tendon_lengthspring;
float* tendon_rgba;
int* actuator_trntype;
int* actuator_dyntype;
int* actuator_trnid;
int* actuator_actadr;
int* actuator_actnum;
int* actuator_group;
mjtByte* actuator_ctrllimited;
mjtByte* actuator_actlimited;
mjtNum* actuator_ctrlrange;
mjtNum* actuator_actrange;
mjtNum* actuator_cranklength;
int* sensor_type;
int* sensor_objid;
int* sensor_adr;
int* name_bodyadr;
int* name_jntadr;
int* name_geomadr;
int* name_siteadr;
int* name_camadr;
int* name_lightadr;
int* name_eqadr;
int* name_tendonadr;
int* name_actuatoradr;
char* names;
} model;
// fields in mjData that are necessary to re-render a scene
struct {
mjWarningStat warning[mjNWARNING];
int nefc;
int ncon;
mjtNum time;
mjtNum* act;
mjtNum* ctrl;
mjtNum* xfrc_applied;
mjtNum* sensordata;
mjtNum* xpos;
mjtNum* xquat;
mjtNum* xmat;
mjtNum* xipos;
mjtNum* ximat;
mjtNum* xanchor;
mjtNum* xaxis;
mjtNum* geom_xpos;
mjtNum* geom_xmat;
mjtNum* site_xpos;
mjtNum* site_xmat;
mjtNum* cam_xpos;
mjtNum* cam_xmat;
mjtNum* light_xpos;
mjtNum* light_xdir;
mjtNum* subtree_com;
int* ten_wrapadr;
int* ten_wrapnum;
int* wrap_obj;
mjtNum* wrap_xpos;
mjtByte* bvh_active;
mjContact* contact;
mjtNum* efc_force;
} data;
};
typedef struct mjvSceneState_ mjvSceneState;
#endif // MUJOCO_MJVISUALIZE_H_ #endif // MUJOCO_MJVISUALIZE_H_
+451 -442
View File
@@ -62,71 +62,71 @@
// int fields of mjModel // int fields of mjModel
#define MJMODEL_INTS \ #define MJMODEL_INTS \
X( nq ) \ X ( nq ) \
X( nv ) \ X ( nv ) \
X( nu ) \ XMJV( nu ) \
X( na ) \ XMJV( na ) \
X( nbody ) \ XMJV( nbody ) \
X( nbvh ) \ XMJV( nbvh ) \
X( njnt ) \ XMJV( njnt ) \
X( ngeom ) \ XMJV( ngeom ) \
X( nsite ) \ XMJV( nsite ) \
X( ncam ) \ XMJV( ncam ) \
X( nlight ) \ XMJV( nlight ) \
X( nmesh ) \ XMJV( nmesh ) \
X( nmeshvert ) \ X ( nmeshvert ) \
X( nmeshnormal ) \ X ( nmeshnormal ) \
X( nmeshtexcoord ) \ X ( nmeshtexcoord ) \
X( nmeshface ) \ X ( nmeshface ) \
X( nmeshgraph ) \ X ( nmeshgraph ) \
X( nskin ) \ XMJV( nskin ) \
X( nskinvert ) \ XMJV( nskinvert ) \
X( nskintexvert ) \ X ( nskintexvert ) \
X( nskinface ) \ XMJV( nskinface ) \
X( nskinbone ) \ XMJV( nskinbone ) \
X( nskinbonevert ) \ XMJV( nskinbonevert ) \
X( nhfield ) \ X ( nhfield ) \
X( nhfielddata ) \ X ( nhfielddata ) \
X( ntex ) \ X ( ntex ) \
X( ntexdata ) \ X ( ntexdata ) \
X( nmat ) \ XMJV( nmat ) \
X( npair ) \ X ( npair ) \
X( nexclude ) \ X ( nexclude ) \
X( neq ) \ XMJV( neq ) \
X( ntendon ) \ XMJV( ntendon ) \
X( nwrap ) \ XMJV( nwrap ) \
X( nsensor ) \ XMJV( nsensor ) \
X( nnumeric ) \ X ( nnumeric ) \
X( nnumericdata ) \ X ( nnumericdata ) \
X( ntext ) \ X ( ntext ) \
X( ntextdata ) \ X ( ntextdata ) \
X( ntuple ) \ X ( ntuple ) \
X( ntupledata ) \ X ( ntupledata ) \
X( nkey ) \ X ( nkey ) \
X( nmocap ) \ X ( nmocap ) \
X( nplugin ) \ X ( nplugin ) \
X( npluginattr ) \ X ( npluginattr ) \
X( nuser_body ) \ X ( nuser_body ) \
X( nuser_jnt ) \ X ( nuser_jnt ) \
X( nuser_geom ) \ X ( nuser_geom ) \
X( nuser_site ) \ X ( nuser_site ) \
X( nuser_cam ) \ X ( nuser_cam ) \
X( nuser_tendon ) \ X ( nuser_tendon ) \
X( nuser_actuator ) \ X ( nuser_actuator ) \
X( nuser_sensor ) \ X ( nuser_sensor ) \
X( nnames ) \ XMJV( nnames ) \
X( nnames_map ) \ X ( nnames_map ) \
X( nM ) \ X ( nM ) \
X( nD ) \ X ( nD ) \
X( nB ) \ X ( nB ) \
X( nemax ) \ X ( nemax ) \
X( njmax ) \ X ( njmax ) \
X( nconmax ) \ X ( nconmax ) \
X( nstack ) \ X ( nstack ) \
X( nuserdata ) \ X ( nuserdata ) \
X( nsensordata ) \ XMJV( nsensordata ) \
X( npluginstate ) \ X ( npluginstate ) \
X( nbuffer ) X ( nbuffer )
// define symbols needed in MJMODEL_POINTERS (corresponding to number of columns) // define symbols needed in MJMODEL_POINTERS (corresponding to number of columns)
@@ -151,305 +151,307 @@
// pointer fields of mjModel // pointer fields of mjModel
// XMJV means that the field is required to construct mjvScene
// (by default we define XMJV to be the same as X)
#define MJMODEL_POINTERS \ #define MJMODEL_POINTERS \
X( mjtNum, qpos0, nq, 1 ) \ X ( mjtNum, qpos0, nq, 1 ) \
X( mjtNum, qpos_spring, nq, 1 ) \ X ( mjtNum, qpos_spring, nq, 1 ) \
X( int, body_parentid, nbody, 1 ) \ XMJV( int, body_parentid, nbody, 1 ) \
X( int, body_rootid, nbody, 1 ) \ XMJV( int, body_rootid, nbody, 1 ) \
X( int, body_weldid, nbody, 1 ) \ XMJV( int, body_weldid, nbody, 1 ) \
X( int, body_mocapid, nbody, 1 ) \ XMJV( int, body_mocapid, nbody, 1 ) \
X( int, body_jntnum, nbody, 1 ) \ XMJV( int, body_jntnum, nbody, 1 ) \
X( int, body_jntadr, nbody, 1 ) \ XMJV( int, body_jntadr, nbody, 1 ) \
X( int, body_dofnum, nbody, 1 ) \ X ( int, body_dofnum, nbody, 1 ) \
X( int, body_dofadr, nbody, 1 ) \ X ( int, body_dofadr, nbody, 1 ) \
X( int, body_geomnum, nbody, 1 ) \ XMJV( int, body_geomnum, nbody, 1 ) \
X( int, body_geomadr, nbody, 1 ) \ XMJV( int, body_geomadr, nbody, 1 ) \
X( mjtByte, body_simple, nbody, 1 ) \ X ( mjtByte, body_simple, nbody, 1 ) \
X( mjtByte, body_sameframe, nbody, 1 ) \ X ( mjtByte, body_sameframe, nbody, 1 ) \
X( mjtNum, body_pos, nbody, 3 ) \ X ( mjtNum, body_pos, nbody, 3 ) \
X( mjtNum, body_quat, nbody, 4 ) \ X ( mjtNum, body_quat, nbody, 4 ) \
X( mjtNum, body_ipos, nbody, 3 ) \ X ( mjtNum, body_ipos, nbody, 3 ) \
X( mjtNum, body_iquat, nbody, 4 ) \ XMJV( mjtNum, body_iquat, nbody, 4 ) \
X( mjtNum, body_mass, nbody, 1 ) \ XMJV( mjtNum, body_mass, nbody, 1 ) \
X( mjtNum, body_subtreemass, nbody, 1 ) \ X ( mjtNum, body_subtreemass, nbody, 1 ) \
X( mjtNum, body_inertia, nbody, 3 ) \ XMJV( mjtNum, body_inertia, nbody, 3 ) \
X( mjtNum, body_invweight0, nbody, 2 ) \ X ( mjtNum, body_invweight0, nbody, 2 ) \
X( mjtNum, body_gravcomp, nbody, 1 ) \ X ( mjtNum, body_gravcomp, nbody, 1 ) \
X( mjtNum, body_user, nbody, MJ_M(nuser_body) ) \ X ( mjtNum, body_user, nbody, MJ_M(nuser_body) ) \
X( int, body_plugin, nbody, 1 ) \ X ( int, body_plugin, nbody, 1 ) \
X( int, body_bvhadr, nbody, 1 ) \ XMJV( int, body_bvhadr, nbody, 1 ) \
X( int, body_bvhnum, nbody, 1 ) \ XMJV( int, body_bvhnum, nbody, 1 ) \
X( int, bvh_depth, nbvh, 1 ) \ XMJV( int, bvh_depth, nbvh, 1 ) \
X( int, bvh_child, nbvh, 2 ) \ XMJV( int, bvh_child, nbvh, 2 ) \
X( int, bvh_geomid, nbvh, 1 ) \ XMJV( int, bvh_geomid, nbvh, 1 ) \
X( mjtNum, bvh_aabb, nbvh, 6 ) \ XMJV( mjtNum, bvh_aabb, nbvh, 6 ) \
X( int, jnt_type, njnt, 1 ) \ XMJV( int, jnt_type, njnt, 1 ) \
X( int, jnt_qposadr, njnt, 1 ) \ X ( int, jnt_qposadr, njnt, 1 ) \
X( int, jnt_dofadr, njnt, 1 ) \ X ( int, jnt_dofadr, njnt, 1 ) \
X( int, jnt_bodyid, njnt, 1 ) \ XMJV( int, jnt_bodyid, njnt, 1 ) \
X( int, jnt_group, njnt, 1 ) \ XMJV( int, jnt_group, njnt, 1 ) \
X( mjtByte, jnt_limited, njnt, 1 ) \ X ( mjtByte, jnt_limited, njnt, 1 ) \
X( mjtNum, jnt_solref, njnt, mjNREF ) \ X ( mjtNum, jnt_solref, njnt, mjNREF ) \
X( mjtNum, jnt_solimp, njnt, mjNIMP ) \ X ( mjtNum, jnt_solimp, njnt, mjNIMP ) \
X( mjtNum, jnt_pos, njnt, 3 ) \ X ( mjtNum, jnt_pos, njnt, 3 ) \
X( mjtNum, jnt_axis, njnt, 3 ) \ X ( mjtNum, jnt_axis, njnt, 3 ) \
X( mjtNum, jnt_stiffness, njnt, 1 ) \ X ( mjtNum, jnt_stiffness, njnt, 1 ) \
X( mjtNum, jnt_range, njnt, 2 ) \ X ( mjtNum, jnt_range, njnt, 2 ) \
X( mjtNum, jnt_margin, njnt, 1 ) \ X ( mjtNum, jnt_margin, njnt, 1 ) \
X( mjtNum, jnt_user, njnt, MJ_M(nuser_jnt) ) \ X ( mjtNum, jnt_user, njnt, MJ_M(nuser_jnt) ) \
X( int, dof_bodyid, nv, 1 ) \ X ( int, dof_bodyid, nv, 1 ) \
X( int, dof_jntid, nv, 1 ) \ X ( int, dof_jntid, nv, 1 ) \
X( int, dof_parentid, nv, 1 ) \ X ( int, dof_parentid, nv, 1 ) \
X( int, dof_Madr, nv, 1 ) \ X ( int, dof_Madr, nv, 1 ) \
X( int, dof_simplenum, nv, 1 ) \ X ( int, dof_simplenum, nv, 1 ) \
X( mjtNum, dof_solref, nv, mjNREF ) \ X ( mjtNum, dof_solref, nv, mjNREF ) \
X( mjtNum, dof_solimp, nv, mjNIMP ) \ X ( mjtNum, dof_solimp, nv, mjNIMP ) \
X( mjtNum, dof_frictionloss, nv, 1 ) \ X ( mjtNum, dof_frictionloss, nv, 1 ) \
X( mjtNum, dof_armature, nv, 1 ) \ X ( mjtNum, dof_armature, nv, 1 ) \
X( mjtNum, dof_damping, nv, 1 ) \ X ( mjtNum, dof_damping, nv, 1 ) \
X( mjtNum, dof_invweight0, nv, 1 ) \ X ( mjtNum, dof_invweight0, nv, 1 ) \
X( mjtNum, dof_M0, nv, 1 ) \ X ( mjtNum, dof_M0, nv, 1 ) \
X( int, geom_type, ngeom, 1 ) \ XMJV( int, geom_type, ngeom, 1 ) \
X( int, geom_contype, ngeom, 1 ) \ X ( int, geom_contype, ngeom, 1 ) \
X( int, geom_conaffinity, ngeom, 1 ) \ X ( int, geom_conaffinity, ngeom, 1 ) \
X( int, geom_condim, ngeom, 1 ) \ X ( int, geom_condim, ngeom, 1 ) \
X( int, geom_bodyid, ngeom, 1 ) \ XMJV( int, geom_bodyid, ngeom, 1 ) \
X( int, geom_dataid, ngeom, 1 ) \ XMJV( int, geom_dataid, ngeom, 1 ) \
X( int, geom_matid, ngeom, 1 ) \ XMJV( int, geom_matid, ngeom, 1 ) \
X( int, geom_group, ngeom, 1 ) \ XMJV( int, geom_group, ngeom, 1 ) \
X( int, geom_priority, ngeom, 1 ) \ X ( int, geom_priority, ngeom, 1 ) \
X( mjtByte, geom_sameframe, ngeom, 1 ) \ X ( mjtByte, geom_sameframe, ngeom, 1 ) \
X( mjtNum, geom_solmix, ngeom, 1 ) \ X ( mjtNum, geom_solmix, ngeom, 1 ) \
X( mjtNum, geom_solref, ngeom, mjNREF ) \ X ( mjtNum, geom_solref, ngeom, mjNREF ) \
X( mjtNum, geom_solimp, ngeom, mjNIMP ) \ X ( mjtNum, geom_solimp, ngeom, mjNIMP ) \
X( mjtNum, geom_size, ngeom, 3 ) \ XMJV( mjtNum, geom_size, ngeom, 3 ) \
X( mjtNum, geom_aabb, ngeom, 6 ) \ XMJV( mjtNum, geom_aabb, ngeom, 6 ) \
X( mjtNum, geom_rbound, ngeom, 1 ) \ XMJV( mjtNum, geom_rbound, ngeom, 1 ) \
X( mjtNum, geom_pos, ngeom, 3 ) \ X ( mjtNum, geom_pos, ngeom, 3 ) \
X( mjtNum, geom_quat, ngeom, 4 ) \ X ( mjtNum, geom_quat, ngeom, 4 ) \
X( mjtNum, geom_friction, ngeom, 3 ) \ X ( mjtNum, geom_friction, ngeom, 3 ) \
X( mjtNum, geom_margin, ngeom, 1 ) \ X ( mjtNum, geom_margin, ngeom, 1 ) \
X( mjtNum, geom_gap, ngeom, 1 ) \ X ( mjtNum, geom_gap, ngeom, 1 ) \
X( mjtNum, geom_fluid, ngeom, mjNFLUID ) \ X ( mjtNum, geom_fluid, ngeom, mjNFLUID ) \
X( mjtNum, geom_user, ngeom, MJ_M(nuser_geom) ) \ X ( mjtNum, geom_user, ngeom, MJ_M(nuser_geom) ) \
X( float, geom_rgba, ngeom, 4 ) \ XMJV( float, geom_rgba, ngeom, 4 ) \
X( int, site_type, nsite, 1 ) \ XMJV( int, site_type, nsite, 1 ) \
X( int, site_bodyid, nsite, 1 ) \ XMJV( int, site_bodyid, nsite, 1 ) \
X( int, site_matid, nsite, 1 ) \ XMJV( int, site_matid, nsite, 1 ) \
X( int, site_group, nsite, 1 ) \ XMJV( int, site_group, nsite, 1 ) \
X( mjtByte, site_sameframe, nsite, 1 ) \ X ( mjtByte, site_sameframe, nsite, 1 ) \
X( mjtNum, site_size, nsite, 3 ) \ XMJV( mjtNum, site_size, nsite, 3 ) \
X( mjtNum, site_pos, nsite, 3 ) \ X ( mjtNum, site_pos, nsite, 3 ) \
X( mjtNum, site_quat, nsite, 4 ) \ X ( mjtNum, site_quat, nsite, 4 ) \
X( mjtNum, site_user, nsite, MJ_M(nuser_site) ) \ X ( mjtNum, site_user, nsite, MJ_M(nuser_site) ) \
X( float, site_rgba, nsite, 4 ) \ XMJV( float, site_rgba, nsite, 4 ) \
X( int, cam_mode, ncam, 1 ) \ X ( int, cam_mode, ncam, 1 ) \
X( int, cam_bodyid, ncam, 1 ) \ X ( int, cam_bodyid, ncam, 1 ) \
X( int, cam_targetbodyid, ncam, 1 ) \ X ( int, cam_targetbodyid, ncam, 1 ) \
X( mjtNum, cam_pos, ncam, 3 ) \ X ( mjtNum, cam_pos, ncam, 3 ) \
X( mjtNum, cam_quat, ncam, 4 ) \ X ( mjtNum, cam_quat, ncam, 4 ) \
X( mjtNum, cam_poscom0, ncam, 3 ) \ X ( mjtNum, cam_poscom0, ncam, 3 ) \
X( mjtNum, cam_pos0, ncam, 3 ) \ X ( mjtNum, cam_pos0, ncam, 3 ) \
X( mjtNum, cam_mat0, ncam, 9 ) \ X ( mjtNum, cam_mat0, ncam, 9 ) \
X( mjtNum, cam_fovy, ncam, 1 ) \ XMJV( mjtNum, cam_fovy, ncam, 1 ) \
X( mjtNum, cam_ipd, ncam, 1 ) \ XMJV( mjtNum, cam_ipd, ncam, 1 ) \
X( mjtNum, cam_user, ncam, MJ_M(nuser_cam) ) \ X ( mjtNum, cam_user, ncam, MJ_M(nuser_cam) ) \
X( int, light_mode, nlight, 1 ) \ X ( int, light_mode, nlight, 1 ) \
X( int, light_bodyid, nlight, 1 ) \ X ( int, light_bodyid, nlight, 1 ) \
X( int, light_targetbodyid, nlight, 1 ) \ X ( int, light_targetbodyid, nlight, 1 ) \
X( mjtByte, light_directional, nlight, 1 ) \ XMJV( mjtByte, light_directional, nlight, 1 ) \
X( mjtByte, light_castshadow, nlight, 1 ) \ XMJV( mjtByte, light_castshadow, nlight, 1 ) \
X( mjtByte, light_active, nlight, 1 ) \ XMJV( mjtByte, light_active, nlight, 1 ) \
X( mjtNum, light_pos, nlight, 3 ) \ X ( mjtNum, light_pos, nlight, 3 ) \
X( mjtNum, light_dir, nlight, 3 ) \ X ( mjtNum, light_dir, nlight, 3 ) \
X( mjtNum, light_poscom0, nlight, 3 ) \ X ( mjtNum, light_poscom0, nlight, 3 ) \
X( mjtNum, light_pos0, nlight, 3 ) \ X ( mjtNum, light_pos0, nlight, 3 ) \
X( mjtNum, light_dir0, nlight, 3 ) \ X ( mjtNum, light_dir0, nlight, 3 ) \
X( float, light_attenuation, nlight, 3 ) \ XMJV( float, light_attenuation, nlight, 3 ) \
X( float, light_cutoff, nlight, 1 ) \ XMJV( float, light_cutoff, nlight, 1 ) \
X( float, light_exponent, nlight, 1 ) \ XMJV( float, light_exponent, nlight, 1 ) \
X( float, light_ambient, nlight, 3 ) \ XMJV( float, light_ambient, nlight, 3 ) \
X( float, light_diffuse, nlight, 3 ) \ XMJV( float, light_diffuse, nlight, 3 ) \
X( float, light_specular, nlight, 3 ) \ XMJV( float, light_specular, nlight, 3 ) \
X( int, mesh_vertadr, nmesh, 1 ) \ X ( int, mesh_vertadr, nmesh, 1 ) \
X( int, mesh_vertnum, nmesh, 1 ) \ X ( int, mesh_vertnum, nmesh, 1 ) \
X( int, mesh_normaladr, nmesh, 1 ) \ X ( int, mesh_normaladr, nmesh, 1 ) \
X( int, mesh_normalnum, nmesh, 1 ) \ X ( int, mesh_normalnum, nmesh, 1 ) \
X( int, mesh_texcoordadr, nmesh, 1 ) \ XMJV( int, mesh_texcoordadr, nmesh, 1 ) \
X( int, mesh_texcoordnum, nmesh, 1 ) \ X ( int, mesh_texcoordnum, nmesh, 1 ) \
X( int, mesh_faceadr, nmesh, 1 ) \ X ( int, mesh_faceadr, nmesh, 1 ) \
X( int, mesh_facenum, nmesh, 1 ) \ X ( int, mesh_facenum, nmesh, 1 ) \
X( int, mesh_graphadr, nmesh, 1 ) \ XMJV( int, mesh_graphadr, nmesh, 1 ) \
X( float, mesh_vert, nmeshvert, 3 ) \ X ( float, mesh_vert, nmeshvert, 3 ) \
X( float, mesh_normal, nmeshnormal, 3 ) \ X ( float, mesh_normal, nmeshnormal, 3 ) \
X( float, mesh_texcoord, nmeshtexcoord, 2 ) \ X ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
X( int, mesh_face, nmeshface, 3 ) \ X ( int, mesh_face, nmeshface, 3 ) \
X( int, mesh_facenormal, nmeshface, 3 ) \ X ( int, mesh_facenormal, nmeshface, 3 ) \
X( int, mesh_facetexcoord, nmeshface, 3 ) \ X ( int, mesh_facetexcoord, nmeshface, 3 ) \
X( int, mesh_graph, nmeshgraph, 1 ) \ X ( int, mesh_graph, nmeshgraph, 1 ) \
X( int, skin_matid, nskin, 1 ) \ XMJV( int, skin_matid, nskin, 1 ) \
X( int, skin_group, nskin, 1 ) \ XMJV( int, skin_group, nskin, 1 ) \
X( float, skin_rgba, nskin, 4 ) \ XMJV( float, skin_rgba, nskin, 4 ) \
X( float, skin_inflate, nskin, 1 ) \ XMJV( float, skin_inflate, nskin, 1 ) \
X( int, skin_vertadr, nskin, 1 ) \ XMJV( int, skin_vertadr, nskin, 1 ) \
X( int, skin_vertnum, nskin, 1 ) \ XMJV( int, skin_vertnum, nskin, 1 ) \
X( int, skin_texcoordadr, nskin, 1 ) \ XMJV( int, skin_texcoordadr, nskin, 1 ) \
X( int, skin_faceadr, nskin, 1 ) \ XMJV( int, skin_faceadr, nskin, 1 ) \
X( int, skin_facenum, nskin, 1 ) \ XMJV( int, skin_facenum, nskin, 1 ) \
X( int, skin_boneadr, nskin, 1 ) \ XMJV( int, skin_boneadr, nskin, 1 ) \
X( int, skin_bonenum, nskin, 1 ) \ XMJV( int, skin_bonenum, nskin, 1 ) \
X( float, skin_vert, nskinvert, 3 ) \ XMJV( float, skin_vert, nskinvert, 3 ) \
X( float, skin_texcoord, nskintexvert, 2 ) \ X ( float, skin_texcoord, nskintexvert, 2 ) \
X( int, skin_face, nskinface, 3 ) \ XMJV( int, skin_face, nskinface, 3 ) \
X( int, skin_bonevertadr, nskinbone, 1 ) \ XMJV( int, skin_bonevertadr, nskinbone, 1 ) \
X( int, skin_bonevertnum, nskinbone, 1 ) \ XMJV( int, skin_bonevertnum, nskinbone, 1 ) \
X( float, skin_bonebindpos, nskinbone, 3 ) \ XMJV( float, skin_bonebindpos, nskinbone, 3 ) \
X( float, skin_bonebindquat, nskinbone, 4 ) \ XMJV( float, skin_bonebindquat, nskinbone, 4 ) \
X( int, skin_bonebodyid, nskinbone, 1 ) \ XMJV( int, skin_bonebodyid, nskinbone, 1 ) \
X( int, skin_bonevertid, nskinbonevert, 1 ) \ XMJV( int, skin_bonevertid, nskinbonevert, 1 ) \
X( float, skin_bonevertweight, nskinbonevert, 1 ) \ XMJV( float, skin_bonevertweight, nskinbonevert, 1 ) \
X( mjtNum, hfield_size, nhfield, 4 ) \ X ( mjtNum, hfield_size, nhfield, 4 ) \
X( int, hfield_nrow, nhfield, 1 ) \ X ( int, hfield_nrow, nhfield, 1 ) \
X( int, hfield_ncol, nhfield, 1 ) \ X ( int, hfield_ncol, nhfield, 1 ) \
X( int, hfield_adr, nhfield, 1 ) \ X ( int, hfield_adr, nhfield, 1 ) \
X( float, hfield_data, nhfielddata, 1 ) \ X ( float, hfield_data, nhfielddata, 1 ) \
X( int, tex_type, ntex, 1 ) \ X ( int, tex_type, ntex, 1 ) \
X( int, tex_height, ntex, 1 ) \ X ( int, tex_height, ntex, 1 ) \
X( int, tex_width, ntex, 1 ) \ X ( int, tex_width, ntex, 1 ) \
X( int, tex_adr, ntex, 1 ) \ X ( int, tex_adr, ntex, 1 ) \
X( mjtByte, tex_rgb, ntexdata, 1 ) \ X ( mjtByte, tex_rgb, ntexdata, 1 ) \
X( int, mat_texid, nmat, 1 ) \ XMJV( int, mat_texid, nmat, 1 ) \
X( mjtByte, mat_texuniform, nmat, 1 ) \ XMJV( mjtByte, mat_texuniform, nmat, 1 ) \
X( float, mat_texrepeat, nmat, 2 ) \ XMJV( float, mat_texrepeat, nmat, 2 ) \
X( float, mat_emission, nmat, 1 ) \ XMJV( float, mat_emission, nmat, 1 ) \
X( float, mat_specular, nmat, 1 ) \ XMJV( float, mat_specular, nmat, 1 ) \
X( float, mat_shininess, nmat, 1 ) \ XMJV( float, mat_shininess, nmat, 1 ) \
X( float, mat_reflectance, nmat, 1 ) \ XMJV( float, mat_reflectance, nmat, 1 ) \
X( float, mat_rgba, nmat, 4 ) \ XMJV( float, mat_rgba, nmat, 4 ) \
X( int, pair_dim, npair, 1 ) \ X ( int, pair_dim, npair, 1 ) \
X( int, pair_geom1, npair, 1 ) \ X ( int, pair_geom1, npair, 1 ) \
X( int, pair_geom2, npair, 1 ) \ X ( int, pair_geom2, npair, 1 ) \
X( int, pair_signature, npair, 1 ) \ X ( int, pair_signature, npair, 1 ) \
X( mjtNum, pair_solref, npair, mjNREF ) \ X ( mjtNum, pair_solref, npair, mjNREF ) \
X( mjtNum, pair_solimp, npair, mjNIMP ) \ X ( mjtNum, pair_solimp, npair, mjNIMP ) \
X( mjtNum, pair_margin, npair, 1 ) \ X ( mjtNum, pair_margin, npair, 1 ) \
X( mjtNum, pair_gap, npair, 1 ) \ X ( mjtNum, pair_gap, npair, 1 ) \
X( mjtNum, pair_friction, npair, 5 ) \ X ( mjtNum, pair_friction, npair, 5 ) \
X( int, exclude_signature, nexclude, 1 ) \ X ( int, exclude_signature, nexclude, 1 ) \
X( int, eq_type, neq, 1 ) \ XMJV( int, eq_type, neq, 1 ) \
X( int, eq_obj1id, neq, 1 ) \ XMJV( int, eq_obj1id, neq, 1 ) \
X( int, eq_obj2id, neq, 1 ) \ XMJV( int, eq_obj2id, neq, 1 ) \
X( mjtByte, eq_active, neq, 1 ) \ XMJV( mjtByte, eq_active, neq, 1 ) \
X( mjtNum, eq_solref, neq, mjNREF ) \ X ( mjtNum, eq_solref, neq, mjNREF ) \
X( mjtNum, eq_solimp, neq, mjNIMP ) \ X ( mjtNum, eq_solimp, neq, mjNIMP ) \
X( mjtNum, eq_data, neq, mjNEQDATA ) \ XMJV( mjtNum, eq_data, neq, mjNEQDATA ) \
X( int, tendon_adr, ntendon, 1 ) \ X ( int, tendon_adr, ntendon, 1 ) \
X( int, tendon_num, ntendon, 1 ) \ XMJV( int, tendon_num, ntendon, 1 ) \
X( int, tendon_matid, ntendon, 1 ) \ XMJV( int, tendon_matid, ntendon, 1 ) \
X( int, tendon_group, ntendon, 1 ) \ XMJV( int, tendon_group, ntendon, 1 ) \
X( mjtByte, tendon_limited, ntendon, 1 ) \ XMJV( mjtByte, tendon_limited, ntendon, 1 ) \
X( mjtNum, tendon_width, ntendon, 1 ) \ XMJV( mjtNum, tendon_width, ntendon, 1 ) \
X( mjtNum, tendon_solref_lim, ntendon, mjNREF ) \ X ( mjtNum, tendon_solref_lim, ntendon, mjNREF ) \
X( mjtNum, tendon_solimp_lim, ntendon, mjNIMP ) \ X ( mjtNum, tendon_solimp_lim, ntendon, mjNIMP ) \
X( mjtNum, tendon_solref_fri, ntendon, mjNREF ) \ X ( mjtNum, tendon_solref_fri, ntendon, mjNREF ) \
X( mjtNum, tendon_solimp_fri, ntendon, mjNIMP ) \ X ( mjtNum, tendon_solimp_fri, ntendon, mjNIMP ) \
X( mjtNum, tendon_range, ntendon, 2 ) \ XMJV( mjtNum, tendon_range, ntendon, 2 ) \
X( mjtNum, tendon_margin, ntendon, 1 ) \ X ( mjtNum, tendon_margin, ntendon, 1 ) \
X( mjtNum, tendon_stiffness, ntendon, 1 ) \ XMJV( mjtNum, tendon_stiffness, ntendon, 1 ) \
X( mjtNum, tendon_damping, ntendon, 1 ) \ XMJV( mjtNum, tendon_damping, ntendon, 1 ) \
X( mjtNum, tendon_frictionloss, ntendon, 1 ) \ XMJV( mjtNum, tendon_frictionloss, ntendon, 1 ) \
X( mjtNum, tendon_lengthspring, ntendon, 2 ) \ XMJV( mjtNum, tendon_lengthspring, ntendon, 2 ) \
X( mjtNum, tendon_length0, ntendon, 1 ) \ X ( mjtNum, tendon_length0, ntendon, 1 ) \
X( mjtNum, tendon_invweight0, ntendon, 1 ) \ X ( mjtNum, tendon_invweight0, ntendon, 1 ) \
X( mjtNum, tendon_user, ntendon, MJ_M(nuser_tendon) ) \ X ( mjtNum, tendon_user, ntendon, MJ_M(nuser_tendon) ) \
X( float, tendon_rgba, ntendon, 4 ) \ XMJV( float, tendon_rgba, ntendon, 4 ) \
X( int, wrap_type, nwrap, 1 ) \ X ( int, wrap_type, nwrap, 1 ) \
X( int, wrap_objid, nwrap, 1 ) \ X ( int, wrap_objid, nwrap, 1 ) \
X( mjtNum, wrap_prm, nwrap, 1 ) \ X ( mjtNum, wrap_prm, nwrap, 1 ) \
X( int, actuator_trntype, nu, 1 ) \ XMJV( int, actuator_trntype, nu, 1 ) \
X( int, actuator_dyntype, nu, 1 ) \ XMJV( int, actuator_dyntype, nu, 1 ) \
X( int, actuator_gaintype, nu, 1 ) \ X ( int, actuator_gaintype, nu, 1 ) \
X( int, actuator_biastype, nu, 1 ) \ X ( int, actuator_biastype, nu, 1 ) \
X( int, actuator_trnid, nu, 2 ) \ XMJV( int, actuator_trnid, nu, 2 ) \
X( int, actuator_actadr, nu, 1 ) \ XMJV( int, actuator_actadr, nu, 1 ) \
X( int, actuator_actnum, nu, 1 ) \ XMJV( int, actuator_actnum, nu, 1 ) \
X( int, actuator_group, nu, 1 ) \ XMJV( int, actuator_group, nu, 1 ) \
X( mjtByte, actuator_ctrllimited, nu, 1 ) \ XMJV( mjtByte, actuator_ctrllimited, nu, 1 ) \
X( mjtByte, actuator_forcelimited, nu, 1 ) \ X ( mjtByte, actuator_forcelimited, nu, 1 ) \
X( mjtByte, actuator_actlimited, nu, 1 ) \ XMJV( mjtByte, actuator_actlimited, nu, 1 ) \
X( mjtNum, actuator_dynprm, nu, mjNDYN ) \ X ( mjtNum, actuator_dynprm, nu, mjNDYN ) \
X( mjtNum, actuator_gainprm, nu, mjNGAIN ) \ X ( mjtNum, actuator_gainprm, nu, mjNGAIN ) \
X( mjtNum, actuator_biasprm, nu, mjNBIAS ) \ X ( mjtNum, actuator_biasprm, nu, mjNBIAS ) \
X( mjtNum, actuator_ctrlrange, nu, 2 ) \ XMJV( mjtNum, actuator_ctrlrange, nu, 2 ) \
X( mjtNum, actuator_forcerange, nu, 2 ) \ X ( mjtNum, actuator_forcerange, nu, 2 ) \
X( mjtNum, actuator_actrange, nu, 2 ) \ XMJV( mjtNum, actuator_actrange, nu, 2 ) \
X( mjtNum, actuator_gear, nu, 6 ) \ X ( mjtNum, actuator_gear, nu, 6 ) \
X( mjtNum, actuator_cranklength, nu, 1 ) \ XMJV( mjtNum, actuator_cranklength, nu, 1 ) \
X( mjtNum, actuator_acc0, nu, 1 ) \ X ( mjtNum, actuator_acc0, nu, 1 ) \
X( mjtNum, actuator_length0, nu, 1 ) \ X ( mjtNum, actuator_length0, nu, 1 ) \
X( mjtNum, actuator_lengthrange, nu, 2 ) \ X ( mjtNum, actuator_lengthrange, nu, 2 ) \
X( mjtNum, actuator_user, nu, MJ_M(nuser_actuator) ) \ X ( mjtNum, actuator_user, nu, MJ_M(nuser_actuator) ) \
X( int, actuator_plugin, nu, 1 ) \ X ( int, actuator_plugin, nu, 1 ) \
X( int, sensor_type, nsensor, 1 ) \ XMJV( int, sensor_type, nsensor, 1 ) \
X( int, sensor_datatype, nsensor, 1 ) \ X ( int, sensor_datatype, nsensor, 1 ) \
X( int, sensor_needstage, nsensor, 1 ) \ X ( int, sensor_needstage, nsensor, 1 ) \
X( int, sensor_objtype, nsensor, 1 ) \ X ( int, sensor_objtype, nsensor, 1 ) \
X( int, sensor_objid, nsensor, 1 ) \ XMJV( int, sensor_objid, nsensor, 1 ) \
X( int, sensor_reftype, nsensor, 1 ) \ X ( int, sensor_reftype, nsensor, 1 ) \
X( int, sensor_refid, nsensor, 1 ) \ X ( int, sensor_refid, nsensor, 1 ) \
X( int, sensor_dim, nsensor, 1 ) \ X ( int, sensor_dim, nsensor, 1 ) \
X( int, sensor_adr, nsensor, 1 ) \ XMJV( int, sensor_adr, nsensor, 1 ) \
X( mjtNum, sensor_cutoff, nsensor, 1 ) \ X ( mjtNum, sensor_cutoff, nsensor, 1 ) \
X( mjtNum, sensor_noise, nsensor, 1 ) \ X ( mjtNum, sensor_noise, nsensor, 1 ) \
X( mjtNum, sensor_user, nsensor, MJ_M(nuser_sensor) ) \ X ( mjtNum, sensor_user, nsensor, MJ_M(nuser_sensor) ) \
X( int, sensor_plugin, nsensor, 1 ) \ X ( int, sensor_plugin, nsensor, 1 ) \
X( int, plugin, nplugin, 1 ) \ X ( int, plugin, nplugin, 1 ) \
X( int, plugin_stateadr, nplugin, 1 ) \ X ( int, plugin_stateadr, nplugin, 1 ) \
X( int, plugin_statenum, nplugin, 1 ) \ X ( int, plugin_statenum, nplugin, 1 ) \
X( char, plugin_attr, npluginattr, 1 ) \ X ( char, plugin_attr, npluginattr, 1 ) \
X( int, plugin_attradr, nplugin, 1 ) \ X ( int, plugin_attradr, nplugin, 1 ) \
X( int, numeric_adr, nnumeric, 1 ) \ X ( int, numeric_adr, nnumeric, 1 ) \
X( int, numeric_size, nnumeric, 1 ) \ X ( int, numeric_size, nnumeric, 1 ) \
X( mjtNum, numeric_data, nnumericdata, 1 ) \ X ( mjtNum, numeric_data, nnumericdata, 1 ) \
X( int, text_adr, ntext, 1 ) \ X ( int, text_adr, ntext, 1 ) \
X( int, text_size, ntext, 1 ) \ X ( int, text_size, ntext, 1 ) \
X( char, text_data, ntextdata, 1 ) \ X ( char, text_data, ntextdata, 1 ) \
X( int, tuple_adr, ntuple, 1 ) \ X ( int, tuple_adr, ntuple, 1 ) \
X( int, tuple_size, ntuple, 1 ) \ X ( int, tuple_size, ntuple, 1 ) \
X( int, tuple_objtype, ntupledata, 1 ) \ X ( int, tuple_objtype, ntupledata, 1 ) \
X( int, tuple_objid, ntupledata, 1 ) \ X ( int, tuple_objid, ntupledata, 1 ) \
X( mjtNum, tuple_objprm, ntupledata, 1 ) \ X ( mjtNum, tuple_objprm, ntupledata, 1 ) \
X( mjtNum, key_time, nkey, 1 ) \ X ( mjtNum, key_time, nkey, 1 ) \
X( mjtNum, key_qpos, nkey, MJ_M(nq) ) \ X ( mjtNum, key_qpos, nkey, MJ_M(nq) ) \
X( mjtNum, key_qvel, nkey, MJ_M(nv) ) \ X ( mjtNum, key_qvel, nkey, MJ_M(nv) ) \
X( mjtNum, key_act, nkey, MJ_M(na) ) \ X ( mjtNum, key_act, nkey, MJ_M(na) ) \
X( mjtNum, key_mpos, nkey, MJ_M(nmocap)*3 ) \ X ( mjtNum, key_mpos, nkey, MJ_M(nmocap)*3 ) \
X( mjtNum, key_mquat, nkey, MJ_M(nmocap)*4 ) \ X ( mjtNum, key_mquat, nkey, MJ_M(nmocap)*4 ) \
X( mjtNum, key_ctrl, nkey, MJ_M(nu) ) \ X ( mjtNum, key_ctrl, nkey, MJ_M(nu) ) \
X( int, name_bodyadr, nbody, 1 ) \ XMJV( int, name_bodyadr, nbody, 1 ) \
X( int, name_jntadr, njnt, 1 ) \ XMJV( int, name_jntadr, njnt, 1 ) \
X( int, name_geomadr, ngeom, 1 ) \ XMJV( int, name_geomadr, ngeom, 1 ) \
X( int, name_siteadr, nsite, 1 ) \ XMJV( int, name_siteadr, nsite, 1 ) \
X( int, name_camadr, ncam, 1 ) \ XMJV( int, name_camadr, ncam, 1 ) \
X( int, name_lightadr, nlight, 1 ) \ XMJV( int, name_lightadr, nlight, 1 ) \
X( int, name_meshadr, nmesh, 1 ) \ X ( int, name_meshadr, nmesh, 1 ) \
X( int, name_skinadr, nskin, 1 ) \ X ( int, name_skinadr, nskin, 1 ) \
X( int, name_hfieldadr, nhfield, 1 ) \ X ( int, name_hfieldadr, nhfield, 1 ) \
X( int, name_texadr, ntex, 1 ) \ X ( int, name_texadr, ntex, 1 ) \
X( int, name_matadr, nmat, 1 ) \ X ( int, name_matadr, nmat, 1 ) \
X( int, name_pairadr, npair, 1 ) \ X ( int, name_pairadr, npair, 1 ) \
X( int, name_excludeadr, nexclude, 1 ) \ X ( int, name_excludeadr, nexclude, 1 ) \
X( int, name_eqadr, neq, 1 ) \ XMJV( int, name_eqadr, neq, 1 ) \
X( int, name_tendonadr, ntendon, 1 ) \ XMJV( int, name_tendonadr, ntendon, 1 ) \
X( int, name_actuatoradr, nu, 1 ) \ XMJV( int, name_actuatoradr, nu, 1 ) \
X( int, name_sensoradr, nsensor, 1 ) \ X ( int, name_sensoradr, nsensor, 1 ) \
X( int, name_numericadr, nnumeric, 1 ) \ X ( int, name_numericadr, nnumeric, 1 ) \
X( int, name_textadr, ntext, 1 ) \ X ( int, name_textadr, ntext, 1 ) \
X( int, name_tupleadr, ntuple, 1 ) \ X ( int, name_tupleadr, ntuple, 1 ) \
X( int, name_keyadr, nkey, 1 ) \ X ( int, name_keyadr, nkey, 1 ) \
X( int, name_pluginadr, nplugin, 1 ) \ X ( int, name_pluginadr, nplugin, 1 ) \
X( char, names, nnames, 1 ) \ XMJV( char, names, nnames, 1 ) \
X( int, names_map, nnames_map, 1 ) \ X ( int, names_map, nnames_map, 1 ) \
//-------------------------------- mjData ---------------------------------------------------------- //-------------------------------- mjData ----------------------------------------------------------
@@ -459,85 +461,87 @@
// pointer fields of mjData // pointer fields of mjData
#define MJDATA_POINTERS \ // XMJV means that the field is required to construct mjvScene
X( mjtNum, qpos, nq, 1 ) \ // (by default we define XMJV to be the same as X)
X( mjtNum, qvel, nv, 1 ) \ #define MJDATA_POINTERS \
X( mjtNum, act, na, 1 ) \ X ( mjtNum, qpos, nq, 1 ) \
X( mjtNum, qacc_warmstart, nv, 1 ) \ X ( mjtNum, qvel, nv, 1 ) \
X( mjtNum, plugin_state, npluginstate, 1 ) \ XMJV( mjtNum, act, na, 1 ) \
X( mjtNum, ctrl, nu, 1 ) \ X ( mjtNum, qacc_warmstart, nv, 1 ) \
X( mjtNum, qfrc_applied, nv, 1 ) \ X ( mjtNum, plugin_state, npluginstate, 1 ) \
X( mjtNum, xfrc_applied, nbody, 6 ) \ XMJV( mjtNum, ctrl, nu, 1 ) \
X( mjtNum, mocap_pos, nmocap, 3 ) \ X ( mjtNum, qfrc_applied, nv, 1 ) \
X( mjtNum, mocap_quat, nmocap, 4 ) \ XMJV( mjtNum, xfrc_applied, nbody, 6 ) \
X( mjtNum, qacc, nv, 1 ) \ X ( mjtNum, mocap_pos, nmocap, 3 ) \
X( mjtNum, act_dot, na, 1 ) \ X ( mjtNum, mocap_quat, nmocap, 4 ) \
X( mjtNum, userdata, nuserdata, 1 ) \ X ( mjtNum, qacc, nv, 1 ) \
X( mjtNum, sensordata, nsensordata, 1 ) \ X ( mjtNum, act_dot, na, 1 ) \
X( int, plugin, nplugin, 1 ) \ X ( mjtNum, userdata, nuserdata, 1 ) \
X( uintptr_t, plugin_data, nplugin, 1 ) \ XMJV( mjtNum, sensordata, nsensordata, 1 ) \
X( mjtNum, xpos, nbody, 3 ) \ X ( int, plugin, nplugin, 1 ) \
X( mjtNum, xquat, nbody, 4 ) \ X ( uintptr_t, plugin_data, nplugin, 1 ) \
X( mjtNum, xmat, nbody, 9 ) \ XMJV( mjtNum, xpos, nbody, 3 ) \
X( mjtNum, xipos, nbody, 3 ) \ XMJV( mjtNum, xquat, nbody, 4 ) \
X( mjtNum, ximat, nbody, 9 ) \ XMJV( mjtNum, xmat, nbody, 9 ) \
X( mjtNum, xanchor, njnt, 3 ) \ XMJV( mjtNum, xipos, nbody, 3 ) \
X( mjtNum, xaxis, njnt, 3 ) \ XMJV( mjtNum, ximat, nbody, 9 ) \
X( mjtNum, geom_xpos, ngeom, 3 ) \ XMJV( mjtNum, xanchor, njnt, 3 ) \
X( mjtNum, geom_xmat, ngeom, 9 ) \ XMJV( mjtNum, xaxis, njnt, 3 ) \
X( mjtNum, site_xpos, nsite, 3 ) \ XMJV( mjtNum, geom_xpos, ngeom, 3 ) \
X( mjtNum, site_xmat, nsite, 9 ) \ XMJV( mjtNum, geom_xmat, ngeom, 9 ) \
X( mjtNum, cam_xpos, ncam, 3 ) \ XMJV( mjtNum, site_xpos, nsite, 3 ) \
X( mjtNum, cam_xmat, ncam, 9 ) \ XMJV( mjtNum, site_xmat, nsite, 9 ) \
X( mjtNum, light_xpos, nlight, 3 ) \ XMJV( mjtNum, cam_xpos, ncam, 3 ) \
X( mjtNum, light_xdir, nlight, 3 ) \ XMJV( mjtNum, cam_xmat, ncam, 9 ) \
X( mjtNum, subtree_com, nbody, 3 ) \ XMJV( mjtNum, light_xpos, nlight, 3 ) \
X( mjtNum, cdof, nv, 6 ) \ XMJV( mjtNum, light_xdir, nlight, 3 ) \
X( mjtNum, cinert, nbody, 10 ) \ XMJV( mjtNum, subtree_com, nbody, 3 ) \
X( int, ten_wrapadr, ntendon, 1 ) \ X ( mjtNum, cdof, nv, 6 ) \
X( int, ten_wrapnum, ntendon, 1 ) \ X ( mjtNum, cinert, nbody, 10 ) \
X( int, ten_J_rownnz, ntendon, 1 ) \ XMJV( int, ten_wrapadr, ntendon, 1 ) \
X( int, ten_J_rowadr, ntendon, 1 ) \ XMJV( int, ten_wrapnum, ntendon, 1 ) \
X( int, ten_J_colind, ntendon, MJ_M(nv) ) \ X ( int, ten_J_rownnz, ntendon, 1 ) \
X( mjtNum, ten_length, ntendon, 1 ) \ X ( int, ten_J_rowadr, ntendon, 1 ) \
X( mjtNum, ten_J, ntendon, MJ_M(nv) ) \ X ( int, ten_J_colind, ntendon, MJ_M(nv) ) \
X( int, wrap_obj, nwrap, 2 ) \ X ( mjtNum, ten_length, ntendon, 1 ) \
X( mjtNum, wrap_xpos, nwrap, 6 ) \ X ( mjtNum, ten_J, ntendon, MJ_M(nv) ) \
X( mjtNum, actuator_length, nu, 1 ) \ XMJV( int, wrap_obj, nwrap, 2 ) \
X( mjtNum, actuator_moment, nu, MJ_M(nv) ) \ XMJV( mjtNum, wrap_xpos, nwrap, 6 ) \
X( mjtNum, crb, nbody, 10 ) \ X ( mjtNum, actuator_length, nu, 1 ) \
X( mjtNum, qM, nM, 1 ) \ X ( mjtNum, actuator_moment, nu, MJ_M(nv) ) \
X( mjtNum, qLD, nM, 1 ) \ X ( mjtNum, crb, nbody, 10 ) \
X( mjtNum, qLDiagInv, nv, 1 ) \ X ( mjtNum, qM, nM, 1 ) \
X( mjtNum, qLDiagSqrtInv, nv, 1 ) \ X ( mjtNum, qLD, nM, 1 ) \
X( mjtByte, bvh_active, nbvh, 1 ) \ X ( mjtNum, qLDiagInv, nv, 1 ) \
X( mjtNum, ten_velocity, ntendon, 1 ) \ X ( mjtNum, qLDiagSqrtInv, nv, 1 ) \
X( mjtNum, actuator_velocity, nu, 1 ) \ XMJV( mjtByte, bvh_active, nbvh, 1 ) \
X( mjtNum, cvel, nbody, 6 ) \ X ( mjtNum, ten_velocity, ntendon, 1 ) \
X( mjtNum, cdof_dot, nv, 6 ) \ X ( mjtNum, actuator_velocity, nu, 1 ) \
X( mjtNum, qfrc_bias, nv, 1 ) \ X ( mjtNum, cvel, nbody, 6 ) \
X( mjtNum, qfrc_passive, nv, 1 ) \ X ( mjtNum, cdof_dot, nv, 6 ) \
X( mjtNum, subtree_linvel, nbody, 3 ) \ X ( mjtNum, qfrc_bias, nv, 1 ) \
X( mjtNum, subtree_angmom, nbody, 3 ) \ X ( mjtNum, qfrc_passive, nv, 1 ) \
X( mjtNum, qH, nM, 1 ) \ X ( mjtNum, subtree_linvel, nbody, 3 ) \
X( mjtNum, qHDiagInv, nv, 1 ) \ X ( mjtNum, subtree_angmom, nbody, 3 ) \
X( int, D_rownnz, nv, 1 ) \ X ( mjtNum, qH, nM, 1 ) \
X( int, D_rowadr, nv, 1 ) \ X ( mjtNum, qHDiagInv, nv, 1 ) \
X( int, D_colind, nD, 1 ) \ X ( int, D_rownnz, nv, 1 ) \
X( int, B_rownnz, nbody, 1 ) \ X ( int, D_rowadr, nv, 1 ) \
X( int, B_rowadr, nbody, 1 ) \ X ( int, D_colind, nD, 1 ) \
X( int, B_colind, nB, 1 ) \ X ( int, B_rownnz, nbody, 1 ) \
X( mjtNum, qDeriv, nD, 1 ) \ X ( int, B_rowadr, nbody, 1 ) \
X( mjtNum, qLU, nD, 1 ) \ X ( int, B_colind, nB, 1 ) \
X( mjtNum, actuator_force, nu, 1 ) \ X ( mjtNum, qDeriv, nD, 1 ) \
X( mjtNum, qfrc_actuator, nv, 1 ) \ X ( mjtNum, qLU, nD, 1 ) \
X( mjtNum, qfrc_smooth, nv, 1 ) \ X ( mjtNum, actuator_force, nu, 1 ) \
X( mjtNum, qacc_smooth, nv, 1 ) \ X ( mjtNum, qfrc_actuator, nv, 1 ) \
X( mjtNum, qfrc_constraint, nv, 1 ) \ X ( mjtNum, qfrc_smooth, nv, 1 ) \
X( mjtNum, qfrc_inverse, nv, 1 ) \ X ( mjtNum, qacc_smooth, nv, 1 ) \
X( mjtNum, cacc, nbody, 6 ) \ X ( mjtNum, qfrc_constraint, nv, 1 ) \
X( mjtNum, cfrc_int, nbody, 6 ) \ X ( mjtNum, qfrc_inverse, nv, 1 ) \
X( mjtNum, cfrc_ext, nbody, 6 ) X ( mjtNum, cacc, nbody, 6 ) \
X ( mjtNum, cfrc_int, nbody, 6 ) \
X ( mjtNum, cfrc_ext, nbody, 6 )
// macro for annotating that an array size in an X macro is a member of mjData // macro for annotating that an array size in an X macro is a member of mjData
@@ -623,4 +627,9 @@
X( mjtNum, energy, 2, 1 ) X( mjtNum, energy, 2, 1 )
// alias XMJV to be the same as X
// to obtain only X macros for fields that are relevant for mjvScene creation,
// redefine X to expand to nothing, and XMJV to do what's required
#define XMJV X
#endif // MUJOCO_MJXMACRO_H_ #endif // MUJOCO_MJXMACRO_H_
+31
View File
@@ -546,10 +546,20 @@ MJAPI void mjv_alignToCamera(mjtNum res[3], const mjtNum vec[3], const mjtNum fo
MJAPI void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy, MJAPI void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam); const mjvScene* scn, mjvCamera* cam);
// Move camera with mouse given a scene state; action is mjtMouse.
MJAPI void mjv_moveCameraFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam);
// Move perturb object with mouse; action is mjtMouse. // Move perturb object with mouse; action is mjtMouse.
MJAPI void mjv_movePerturb(const mjModel* m, const mjData* d, int action, mjtNum reldx, MJAPI void mjv_movePerturb(const mjModel* m, const mjData* d, int action, mjtNum reldx,
mjtNum reldy, const mjvScene* scn, mjvPerturb* pert); mjtNum reldy, const mjvScene* scn, mjvPerturb* pert);
// Move perturb object with mouse given a scene state; action is mjtMouse.
MJAPI void mjv_movePerturbFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvPerturb* pert);
// Move model with mouse; action is mjtMouse. // Move model with mouse; action is mjtMouse.
MJAPI void mjv_moveModel(const mjModel* m, int action, mjtNum reldx, mjtNum reldy, MJAPI void mjv_moveModel(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
const mjtNum roomup[3], mjvScene* scn); const mjtNum roomup[3], mjvScene* scn);
@@ -606,6 +616,24 @@ MJAPI void mjv_freeScene(mjvScene* scn);
MJAPI void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt, MJAPI void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn); const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn);
// Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.
MJAPI int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask,
mjvScene* scn);
// Set default scene state.
MJAPI void mjv_defaultSceneState(mjvSceneState* scnstate);
// Allocate resources and initialize a scene state object.
MJAPI void mjv_makeSceneState(const mjModel* m, const mjData* d,
mjvSceneState* scnstate, int maxgeom);
// Free scene state.
MJAPI void mjv_freeSceneState(mjvSceneState* scnstate);
// Update a scene state from model and data.
MJAPI void mjv_updateSceneState(const mjModel* m, mjData* d, mjvSceneState* scnstate);
// Add geoms from selected categories. // Add geoms from selected categories.
MJAPI void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt, MJAPI void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, int catmask, mjvScene* scn); const mjvPerturb* pert, int catmask, mjvScene* scn);
@@ -637,6 +665,9 @@ MJAPI void mjr_addAux(int index, int width, int height, int samples, mjrContext*
// Free resources in custom OpenGL context, set to default. // Free resources in custom OpenGL context, set to default.
MJAPI void mjr_freeContext(mjrContext* con); MJAPI void mjr_freeContext(mjrContext* con);
// Resize offscreen buffers.
MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con);
// Upload texture to GPU, overwriting previous upload if any. // Upload texture to GPU, overwriting previous upload if any.
MJAPI void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid); MJAPI void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid);
+224
View File
@@ -3276,6 +3276,44 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Move camera with mouse; action is mjtMouse.', doc='Move camera with mouse; action is mjtMouse.',
)), )),
('mjv_moveCameraFromState',
FunctionDecl(
name='mjv_moveCameraFromState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState', is_const=True),
),
),
FunctionParameterDecl(
name='action',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='reldx',
type=ValueType(name='mjtNum'),
),
FunctionParameterDecl(
name='reldy',
type=ValueType(name='mjtNum'),
),
FunctionParameterDecl(
name='scn',
type=PointerType(
inner_type=ValueType(name='mjvScene', is_const=True),
),
),
FunctionParameterDecl(
name='cam',
type=PointerType(
inner_type=ValueType(name='mjvCamera'),
),
),
),
doc='Move camera with mouse given a scene state; action is mjtMouse.',
)),
('mjv_movePerturb', ('mjv_movePerturb',
FunctionDecl( FunctionDecl(
name='mjv_movePerturb', name='mjv_movePerturb',
@@ -3320,6 +3358,44 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Move perturb object with mouse; action is mjtMouse.', doc='Move perturb object with mouse; action is mjtMouse.',
)), )),
('mjv_movePerturbFromState',
FunctionDecl(
name='mjv_movePerturbFromState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState', is_const=True),
),
),
FunctionParameterDecl(
name='action',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='reldx',
type=ValueType(name='mjtNum'),
),
FunctionParameterDecl(
name='reldy',
type=ValueType(name='mjtNum'),
),
FunctionParameterDecl(
name='scn',
type=PointerType(
inner_type=ValueType(name='mjvScene', is_const=True),
),
),
FunctionParameterDecl(
name='pert',
type=PointerType(
inner_type=ValueType(name='mjvPerturb'),
),
),
),
doc='Move perturb object with mouse given a scene state; action is mjtMouse.', # pylint: disable=line-too-long
)),
('mjv_moveModel', ('mjv_moveModel',
FunctionDecl( FunctionDecl(
name='mjv_moveModel', name='mjv_moveModel',
@@ -3752,6 +3828,132 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Update entire scene given model state.', doc='Update entire scene given model state.',
)), )),
('mjv_updateSceneFromState',
FunctionDecl(
name='mjv_updateSceneFromState',
return_type=ValueType(name='int'),
parameters=(
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState', is_const=True),
),
),
FunctionParameterDecl(
name='opt',
type=PointerType(
inner_type=ValueType(name='mjvOption', is_const=True),
),
),
FunctionParameterDecl(
name='pert',
type=PointerType(
inner_type=ValueType(name='mjvPerturb', is_const=True),
),
),
FunctionParameterDecl(
name='cam',
type=PointerType(
inner_type=ValueType(name='mjvCamera'),
),
),
FunctionParameterDecl(
name='catmask',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='scn',
type=PointerType(
inner_type=ValueType(name='mjvScene'),
),
),
),
doc='Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.', # pylint: disable=line-too-long
)),
('mjv_defaultSceneState',
FunctionDecl(
name='mjv_defaultSceneState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState'),
),
),
),
doc='Set default scene state.',
)),
('mjv_makeSceneState',
FunctionDecl(
name='mjv_makeSceneState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='m',
type=PointerType(
inner_type=ValueType(name='mjModel', is_const=True),
),
),
FunctionParameterDecl(
name='d',
type=PointerType(
inner_type=ValueType(name='mjData', is_const=True),
),
),
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState'),
),
),
FunctionParameterDecl(
name='maxgeom',
type=ValueType(name='int'),
),
),
doc='Allocate resources and initialize a scene state object.',
)),
('mjv_freeSceneState',
FunctionDecl(
name='mjv_freeSceneState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState'),
),
),
),
doc='Free scene state.',
)),
('mjv_updateSceneState',
FunctionDecl(
name='mjv_updateSceneState',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='m',
type=PointerType(
inner_type=ValueType(name='mjModel', is_const=True),
),
),
FunctionParameterDecl(
name='d',
type=PointerType(
inner_type=ValueType(name='mjData'),
),
),
FunctionParameterDecl(
name='scnstate',
type=PointerType(
inner_type=ValueType(name='mjvSceneState'),
),
),
),
doc='Update a scene state from model and data.',
)),
('mjv_addGeoms', ('mjv_addGeoms',
FunctionDecl( FunctionDecl(
name='mjv_addGeoms', name='mjv_addGeoms',
@@ -3978,6 +4180,28 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Free resources in custom OpenGL context, set to default.', doc='Free resources in custom OpenGL context, set to default.',
)), )),
('mjr_resizeOffscreen',
FunctionDecl(
name='mjr_resizeOffscreen',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='width',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='height',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='con',
type=PointerType(
inner_type=ValueType(name='mjrContext'),
),
),
),
doc='Resize offscreen buffers.',
)),
('mjr_uploadTexture', ('mjr_uploadTexture',
FunctionDecl( FunctionDecl(
name='mjr_uploadTexture', name='mjr_uploadTexture',
+1199 -5
View File
File diff suppressed because it is too large Load Diff
+29 -20
View File
@@ -52,24 +52,28 @@ struct {
#define CPYTHON_FN(fname) decltype(&::fname) fname #define CPYTHON_FN(fname) decltype(&::fname) fname
#if PY_MINOR_VERSION >= 8 #if PY_MINOR_VERSION >= 8
CPYTHON_FN(Py_InitializeFromConfig); // go/keep-sorted start
CPYTHON_FN(Py_RunMain);
CPYTHON_FN(PyConfig_Clear); CPYTHON_FN(PyConfig_Clear);
CPYTHON_FN(PyConfig_InitPythonConfig); CPYTHON_FN(PyConfig_InitPythonConfig);
CPYTHON_FN(PyConfig_SetBytesArgv); CPYTHON_FN(PyConfig_SetBytesArgv);
CPYTHON_FN(Py_InitializeFromConfig);
CPYTHON_FN(Py_RunMain);
// go/keep-sorted end
#else #else
// go/keep-sorted start
CPYTHON_FN(PyMem_RawFree);
CPYTHON_FN(Py_DecodeLocale); CPYTHON_FN(Py_DecodeLocale);
CPYTHON_FN(Py_Initialize); CPYTHON_FN(Py_Initialize);
CPYTHON_FN(Py_Main); CPYTHON_FN(Py_Main);
CPYTHON_FN(PyMem_RawFree);
CPYTHON_FN(Py_SetProgramName); CPYTHON_FN(Py_SetProgramName);
// go/keep-sorted end
#endif #endif
// go/keep-sorted start // go/keep-sorted start
CPYTHON_FN(Py_FinalizeEx);
CPYTHON_FN(PyGILState_Ensure); CPYTHON_FN(PyGILState_Ensure);
CPYTHON_FN(PyGILState_Release); CPYTHON_FN(PyGILState_Release);
CPYTHON_FN(PyRun_SimpleStringFlags); CPYTHON_FN(PyRun_SimpleStringFlags);
CPYTHON_FN(Py_FinalizeEx);
// go/keep-sorted end // go/keep-sorted end
#undef CPYTHON_FN #undef CPYTHON_FN
@@ -131,16 +135,16 @@ class _MjPythonImpl(mujoco.viewer._MjPythonBase):
def __init__(self): def __init__(self):
self._cond = threading.Condition() self._cond = threading.Condition()
self._model_data = None self._task = None
self._termination = self.__class__.NOT_TERMINATED self._termination = self.__class__.NOT_TERMINATED
self._busy = False self._busy = False
def launch_on_ui_thread(self, model, data): def launch_on_ui_thread(self, model, data, handle_return):
with self._cond: with self._cond:
if self._busy or self._model_data is not None: if self._busy or self._task is not None:
raise RuntimeError('another MuJoCo viewer is already open') raise RuntimeError('another MuJoCo viewer is already open')
else: else:
self._model_data = (model, data) self._task = (model, data, handle_return)
self._cond.notify() self._cond.notify()
def terminate(self): def terminate(self):
@@ -153,17 +157,17 @@ class _MjPythonImpl(mujoco.viewer._MjPythonBase):
def get(self): def get(self):
with self._cond: with self._cond:
self._cond.wait_for( self._cond.wait_for(
lambda: self._model_data is not None or self._termination) lambda: self._task is not None or self._termination)
if self._termination: if self._termination:
if self._termination == self.__class__.TERMINATION_REQUESTED: if self._termination == self.__class__.TERMINATION_REQUESTED:
self._termination = self.__class__.TERMINATION_ACCEPTED self._termination = self.__class__.TERMINATION_ACCEPTED
return None return None
model_data = self._model_data task = self._task
self._busy = True self._busy = True
self._model_data = None self._task = None
return model_data return task
def done(self): def done(self):
with self._cond: with self._cond:
@@ -257,24 +261,28 @@ int main(int argc, char** argv) {
} }
#if PY_MINOR_VERSION >= 8 #if PY_MINOR_VERSION >= 8
CPYTHON_INITFN(Py_InitializeFromConfig); // go/keep-sorted start
CPYTHON_INITFN(Py_RunMain);
CPYTHON_INITFN(PyConfig_Clear); CPYTHON_INITFN(PyConfig_Clear);
CPYTHON_INITFN(PyConfig_InitPythonConfig); CPYTHON_INITFN(PyConfig_InitPythonConfig);
CPYTHON_INITFN(PyConfig_SetBytesArgv); CPYTHON_INITFN(PyConfig_SetBytesArgv);
CPYTHON_INITFN(Py_InitializeFromConfig);
CPYTHON_INITFN(Py_RunMain);
// go/keep-sorted end
#else #else
// go/keep-sorted start
CPYTHON_INITFN(PyMem_RawFree);
CPYTHON_INITFN(Py_DecodeLocale); CPYTHON_INITFN(Py_DecodeLocale);
CPYTHON_INITFN(Py_Initialize); CPYTHON_INITFN(Py_Initialize);
CPYTHON_INITFN(Py_Main); CPYTHON_INITFN(Py_Main);
CPYTHON_INITFN(PyMem_RawFree);
CPYTHON_INITFN(Py_SetProgramName); CPYTHON_INITFN(Py_SetProgramName);
// go/keep-sorted end
#endif #endif
// go/keep-sorted start // go/keep-sorted start
CPYTHON_INITFN(Py_FinalizeEx);
CPYTHON_INITFN(PyGILState_Ensure); CPYTHON_INITFN(PyGILState_Ensure);
CPYTHON_INITFN(PyGILState_Release); CPYTHON_INITFN(PyGILState_Release);
CPYTHON_INITFN(PyRun_SimpleStringFlags); CPYTHON_INITFN(PyRun_SimpleStringFlags);
CPYTHON_INITFN(Py_FinalizeEx);
// go/keep-sorted end // go/keep-sorted end
#undef CPYTHON_INITFN #undef CPYTHON_INITFN
@@ -327,17 +335,18 @@ with cond:
while True: while True:
try: try:
# Wait for an incoming payload. # Wait for an incoming payload.
payload = mujoco.viewer._MJPYTHON.get() task = mujoco.viewer._MJPYTHON.get()
# None means that we are exiting. # None means that we are exiting.
if payload is None: if task is None:
glfw.terminate() glfw.terminate()
break break
# Otherwise, launch the viewer. # Otherwise, launch the viewer.
model, data = payload model, data, handle_return = task
ctypes.CDLL(None).mjpython_show_dock_icon() ctypes.CDLL(None).mjpython_show_dock_icon()
mujoco.viewer._launch_internal(model, data, run_physics_thread=False) mujoco.viewer._launch_internal(
model, data, run_physics_thread=False, handle_return=handle_return)
ctypes.CDLL(None).mjpython_hide_dock_icon() ctypes.CDLL(None).mjpython_hide_dock_icon()
finally: finally:
+1
View File
@@ -250,6 +250,7 @@ PYBIND11_MODULE(_render, pymodule) {
Def<traits::mjr_changeFont>(pymodule); Def<traits::mjr_changeFont>(pymodule);
Def<traits::mjr_addAux>(pymodule); Def<traits::mjr_addAux>(pymodule);
// Skipped: mjr_freeContext (have MjrContext.__del__) // Skipped: mjr_freeContext (have MjrContext.__del__)
Def<traits::mjr_resizeOffscreen>(pymodule);
Def<traits::mjr_uploadTexture>(pymodule); Def<traits::mjr_uploadTexture>(pymodule);
Def<traits::mjr_uploadMesh>(pymodule); Def<traits::mjr_uploadMesh>(pymodule);
Def<traits::mjr_uploadHField>(pymodule); Def<traits::mjr_uploadHField>(pymodule);
+77 -39
View File
@@ -12,29 +12,76 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cstdint> #include <atomic>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <glfw_adapter.h> #include <glfw_adapter.h>
#include <glfw_dispatch.h> #include <glfw_dispatch.h>
#include <simulate.h> #include <simulate.h>
#include "structs.h" #include "structs.h"
#include <pybind11/gil.h>
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
namespace mujoco::python { namespace mujoco::python {
namespace { namespace {
namespace py = ::pybind11;
template <typename T, int N> template <typename T, int N>
constexpr inline std::size_t sizeof_arr(const T(&arr)[N]) { constexpr inline std::size_t sizeof_arr(const T(&arr)[N]) {
return sizeof(arr); return sizeof(arr);
} }
PYBIND11_MODULE(_simulate, pymodule) { class SimulateWrapper : public mujoco::Simulate {
namespace py = ::pybind11; public:
using SimulateMutex = decltype(mujoco::Simulate::mtx); SimulateWrapper(std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
py::object scn, py::object cam,
py::object opt, py::object pert, bool fully_managed)
: Simulate(std::move(platform_ui_adapter),
scn.cast<MjvSceneWrapper&>().get(),
cam.cast<MjvCameraWrapper&>().get(),
opt.cast<MjvOptionWrapper&>().get(),
pert.cast<MjvPerturbWrapper&>().get(),
fully_managed),
m_(py::none()),
d_(py::none()),
scn_(scn),
cam_(cam),
opt_(opt),
pert_(pert) {}
py::class_<SimulateMutex>(pymodule, "SimulateMutex") void Load(py::object m, py::object d, const std::string& path) {
mjModel* m_raw = m.cast<MjModelWrapper&>().get();
mjData* d_raw = d.cast<MjDataWrapper&>().get();
{
py::gil_scoped_release no_gil;
Simulate::Load(m_raw, d_raw, path.c_str());
}
m_ = m;
d_ = d;
m_raw_ = m_raw;
d_raw_ = d_raw;
}
private:
// Hold references to keep these Python objects alive for as long as the
// simulate object.
py::object m_;
py::object d_;
py::object scn_;
py::object cam_;
py::object opt_;
py::object pert_;
mjModel* m_raw_ = nullptr;
mjData* d_raw_ = nullptr;
};
PYBIND11_MODULE(_simulate, pymodule) {
py::class_<SimulateMutex>(pymodule, "Mutex")
.def( .def(
"__enter__", [](SimulateMutex& mtx) { mtx.lock(); }, "__enter__", [](SimulateMutex& mtx) { mtx.lock(); },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
@@ -45,36 +92,29 @@ PYBIND11_MODULE(_simulate, pymodule) {
}, },
py::call_guard<py::gil_scoped_release>()); py::call_guard<py::gil_scoped_release>());
py::class_<mujoco::Simulate>(pymodule, "Simulate") py::class_<SimulateWrapper>(pymodule, "Simulate")
.def(py::init([]() { .def_readonly_static("MAX_GEOM", &mujoco::Simulate::kMaxGeom)
return std::make_unique<mujoco::Simulate>( .def(py::init([](py::object scn, py::object cam, py::object opt,
std::make_unique<mujoco::GlfwAdapter>()); py::object pert, bool fully_managed) {
return std::make_unique<SimulateWrapper>(
std::make_unique<mujoco::GlfwAdapter>(), scn, cam, opt, pert,
fully_managed);
})) }))
.def( .def("load", &SimulateWrapper::Load)
"render_loop", .def("sync", &mujoco::Simulate::Sync,
[](mujoco::Simulate& simulate) { simulate.RenderLoop(); },
py::call_guard<py::gil_scoped_release>())
.def(
"load",
[](mujoco::Simulate& simulate, MjModelWrapper& m, MjDataWrapper& d,
const std::string& path) {
simulate.Load(m.get(), d.get(), path.c_str());
},
py::call_guard<py::gil_scoped_release>())
.def("apply_pose_perturbations",
&mujoco::Simulate::ApplyPosePerturbations,
py::call_guard<py::gil_scoped_release>())
.def("apply_force_perturbations",
&mujoco::Simulate::ApplyForcePerturbations,
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def(
"render_loop",
[](SimulateWrapper& simulate) { simulate.RenderLoop(); },
py::call_guard<py::gil_scoped_release>())
.def( .def(
"lock", "lock",
[](mujoco::Simulate& simulate) -> SimulateMutex& { [](SimulateWrapper& simulate) -> SimulateMutex& {
return simulate.mtx; return simulate.mtx;
}, },
py::call_guard<py::gil_scoped_release>(), py::call_guard<py::gil_scoped_release>(),
py::return_value_policy::reference) py::return_value_policy::reference_internal)
.def_readonly("ctrl_noise_std", &mujoco::Simulate::ctrl_noise_std, .def_readonly("ctrl_noise_std", &mujoco::Simulate::ctrl_noise_std,
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_readonly("ctrl_noise_rate", &mujoco::Simulate::ctrl_noise_rate, .def_readonly("ctrl_noise_rate", &mujoco::Simulate::ctrl_noise_rate,
@@ -96,54 +136,52 @@ PYBIND11_MODULE(_simulate, pymodule) {
.def_property( .def_property(
"exitrequest", "exitrequest",
[](mujoco::Simulate& simulate) { [](SimulateWrapper& simulate) { return simulate.exitrequest.load(); },
return simulate.exitrequest.load(); [](SimulateWrapper& simulate, int exitrequest) {
},
[](mujoco::Simulate& simulate, bool exitrequest) {
simulate.exitrequest.store(exitrequest); simulate.exitrequest.store(exitrequest);
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_property_readonly( .def_property_readonly(
"uiloadrequest", "uiloadrequest",
[](mujoco::Simulate& simulate) { [](SimulateWrapper& simulate) {
return simulate.uiloadrequest.load(); return simulate.uiloadrequest.load();
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def( .def(
"uiloadrequest_decrement", "uiloadrequest_decrement",
[](mujoco::Simulate& simulate) { [](SimulateWrapper& simulate) {
simulate.uiloadrequest.fetch_sub(1); simulate.uiloadrequest.fetch_sub(1);
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_property( .def_property(
"droploadrequest", "droploadrequest",
[](mujoco::Simulate& simulate) { [](SimulateWrapper& simulate) {
return simulate.droploadrequest.load(); return simulate.droploadrequest.load();
}, },
[](mujoco::Simulate& simulate, bool droploadrequest) { [](SimulateWrapper& simulate, bool droploadrequest) {
simulate.droploadrequest.store(droploadrequest); simulate.droploadrequest.store(droploadrequest);
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_property_readonly( .def_property_readonly(
"dropfilename", "dropfilename",
[](mujoco::Simulate& simulate) -> std::string { [](SimulateWrapper& simulate) -> std::string {
return simulate.dropfilename; return simulate.dropfilename;
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_property_readonly( .def_property_readonly(
"filename", "filename",
[](mujoco::Simulate& simulate) -> std::string { [](SimulateWrapper& simulate) -> std::string {
return simulate.filename; return simulate.filename;
}, },
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
.def_property( .def_property(
"load_error", "load_error",
[](mujoco::Simulate& simulate) -> std::string { [](SimulateWrapper& simulate) -> std::string {
return simulate.load_error; return simulate.load_error;
}, },
[](mujoco::Simulate& simulate, const std::string& error) { [](SimulateWrapper& simulate, const std::string& error) {
const auto max_length = sizeof_arr(simulate.load_error); const auto max_length = sizeof_arr(simulate.load_error);
std::strncpy(simulate.load_error, error.c_str(), max_length - 1); std::strncpy(simulate.load_error, error.c_str(), max_length - 1);
simulate.load_error[max_length - 1] = '\0'; simulate.load_error[max_length - 1] = '\0';
+1 -1
View File
@@ -1305,7 +1305,6 @@ PYBIND11_MODULE(_structs, m) {
X(realtime); X(realtime);
X(offwidth); X(offwidth);
X(offheight); X(offheight);
X(treedepth);
X(ellipsoidinertia); X(ellipsoidinertia);
#undef X #undef X
@@ -2134,6 +2133,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
}) })
X(label); X(label);
X(frame); X(frame);
X(bvh_depth);
#undef X #undef X
#define X(var) DefinePyArray(mjvOption, #var, &MjvOptionWrapper::var) #define X(var) DefinePyArray(mjvOption, #var, &MjvOptionWrapper::var)
+104 -111
View File
@@ -16,14 +16,15 @@
import abc import abc
import atexit import atexit
import code import contextlib
import inspect
import math import math
import os import os
import queue
import sys import sys
import threading import threading
import time import time
from typing import Callable, Optional, Tuple, Union from typing import Callable, Optional, Tuple, Union
import weakref
import glfw import glfw
import mujoco import mujoco
@@ -56,7 +57,70 @@ LoaderType = Callable[[], Tuple[mujoco.MjModel, mujoco.MjData]]
_LoaderWithPathType = Callable[[], Tuple[mujoco.MjModel, mujoco.MjData, str]] _LoaderWithPathType = Callable[[], Tuple[mujoco.MjModel, mujoco.MjData, str]]
_InternalLoaderType = Union[LoaderType, _LoaderWithPathType] _InternalLoaderType = Union[LoaderType, _LoaderWithPathType]
Simulate = _simulate.Simulate _Simulate = _simulate.Simulate
class Handle:
"""A handle for interacting with a MuJoCo viewer."""
def __init__(
self,
sim: _Simulate,
scn: mujoco.MjvScene,
cam: mujoco.MjvCamera,
opt: mujoco.MjvOption,
pert: mujoco.MjvPerturb,
):
self._sim = weakref.ref(sim)
self._scn = scn
self._cam = cam
self._opt = opt
self._pert = pert
@property
def scn(self):
return self._scn
@property
def cam(self):
return self._cam
@property
def opt(self):
return self._opt
@property
def perturb(self):
return self._pert
def close(self):
sim = self._sim()
if sim is not None:
sim.exitrequest = 1
def is_running(self) -> bool:
sim = self._sim()
if sim is not None:
return sim.exitrequest < 2
return False
def lock(self):
sim = self._sim()
if sim is not None:
return sim.lock()
return contextlib.nullcontext()
def sync(self):
sim = self._sim()
if sim is not None:
with sim.lock():
sim.sync()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
# Abstract base dispatcher class for systems that require UI calls to be made # Abstract base dispatcher class for systems that require UI calls to be made
@@ -83,7 +147,8 @@ def _file_loader(path: str) -> _LoaderWithPathType:
def _reload( def _reload(
simulate: Simulate, loader: _InternalLoaderType simulate: _Simulate, loader: _InternalLoaderType,
notify_loaded: Optional[Callable[[], None]] = None
) -> Optional[Tuple[mujoco.MjModel, mujoco.MjData]]: ) -> Optional[Tuple[mujoco.MjModel, mujoco.MjData]]:
"""Internal function for reloading a model in the viewer.""" """Internal function for reloading a model in the viewer."""
try: try:
@@ -102,10 +167,13 @@ def _reload(
path = load_tuple[2] if len(load_tuple) == 3 else '' path = load_tuple[2] if len(load_tuple) == 3 else ''
simulate.load(m, d, path) simulate.load(m, d, path)
if notify_loaded:
notify_loaded()
return m, d return m, d
def _physics_loop(simulate: Simulate, loader: Optional[_InternalLoaderType]): def _physics_loop(simulate: _Simulate, loader: Optional[_InternalLoaderType]):
"""Physics loop for the GUI, to be run in a separate thread.""" """Physics loop for the GUI, to be run in a separate thread."""
m: mujoco.MjModel = None m: mujoco.MjModel = None
d: mujoco.MjData = None d: mujoco.MjData = None
@@ -181,11 +249,6 @@ def _physics_loop(simulate: Simulate, loader: Optional[_InternalLoaderType]):
syncsim = d.time syncsim = d.time
simulate.speed_changed = False simulate.speed_changed = False
# Clear old perturbations, apply new.
d.xfrc_applied[:, :] = 0
simulate.apply_pose_perturbations(0) # Move mocap bodies only.
simulate.apply_force_perturbations()
# Run single step, let next iteration deal with timing. # Run single step, let next iteration deal with timing.
mujoco.mj_step(m, d) mujoco.mj_step(m, d)
@@ -203,11 +266,6 @@ def _physics_loop(simulate: Simulate, loader: Optional[_InternalLoaderType]):
simulate.measured_slowdown = elapsedcpu / elapsedsim simulate.measured_slowdown = elapsedcpu / elapsedsim
measured = True measured = True
# Clear old perturbations, apply new.
d.xfrc_applied[:, :] = 0
simulate.applyposepertubations(0) # Move mocap bodies only.
simulate.applyforceperturbations()
# Call mj_step. # Call mj_step.
mujoco.mj_step(m, d) mujoco.mj_step(m, d)
@@ -215,19 +273,19 @@ def _physics_loop(simulate: Simulate, loader: Optional[_InternalLoaderType]):
if d.time < prevsim: if d.time < prevsim:
break break
else: # simulate.run is False: GUI is paused. else: # simulate.run is False: GUI is paused.
# Apply pose perturbation.
simulate.applyposepertubations(1) # Move mocap and dynamic bodies.
# Run mj_forward, to update rendering and joint sliders. # Run mj_forward, to update rendering and joint sliders.
mujoco.mj_forward(m, d) mujoco.mj_forward(m, d)
def _launch_internal(model: Optional[mujoco.MjModel] = None, def _launch_internal(
data: Optional[mujoco.MjData] = None, model: Optional[mujoco.MjModel] = None,
*, data: Optional[mujoco.MjData] = None,
run_physics_thread: bool = True, *,
loader: Optional[_InternalLoaderType] = None, run_physics_thread: bool,
simulate: Optional[Simulate] = None) -> None: loader: Optional[_InternalLoaderType] = None,
handle_return: Optional['queue.Queue[Handle]'] = None,
) -> None:
"""Internal API, so that the public API has more readable type annotations.""" """Internal API, so that the public API has more readable type annotations."""
if model is None and data is not None: if model is None and data is not None:
raise ValueError('mjData is specified but mjModel is not') raise ValueError('mjData is specified but mjModel is not')
@@ -236,6 +294,8 @@ def _launch_internal(model: Optional[mujoco.MjModel] = None,
'mjData should not be specified when an mjModel loader is used') 'mjData should not be specified when an mjModel loader is used')
elif loader is not None and model is not None: elif loader is not None and model is not None:
raise ValueError('model and loader are both specified') raise ValueError('model and loader are both specified')
elif run_physics_thread and handle_return is not None:
raise ValueError('run_physics_thread and handle_return are both specified')
if loader is None and model is not None: if loader is None and model is not None:
@@ -246,9 +306,14 @@ def _launch_internal(model: Optional[mujoco.MjModel] = None,
loader = _loader loader = _loader
# The simulate object encapsulates the UI. if model and not run_physics_thread:
if simulate is None: scn = mujoco.MjvScene(model, _Simulate.MAX_GEOM)
simulate = Simulate() else:
scn = mujoco.MjvScene()
cam = mujoco.MjvCamera()
opt = mujoco.MjvOption()
pert = mujoco.MjvPerturb()
simulate = _Simulate(scn, cam, opt, pert, run_physics_thread)
# Initialize GLFW if not using mjpython. # Initialize GLFW if not using mjpython.
if _MJPYTHON is None: if _MJPYTHON is None:
@@ -256,13 +321,18 @@ def _launch_internal(model: Optional[mujoco.MjModel] = None,
raise mujoco.FatalError('could not initialize GLFW') raise mujoco.FatalError('could not initialize GLFW')
atexit.register(glfw.terminate) atexit.register(glfw.terminate)
notify_loaded = None
if handle_return:
notify_loaded = (
lambda: handle_return.put_nowait(Handle(simulate, scn, cam, opt, pert)))
side_thread = None side_thread = None
if run_physics_thread: if run_physics_thread:
side_thread = threading.Thread( side_thread = threading.Thread(
target=_physics_loop, args=(simulate, loader)) target=_physics_loop, args=(simulate, loader))
else: else:
side_thread = threading.Thread( side_thread = threading.Thread(
target=_reload, args=(simulate, loader)) target=_reload, args=(simulate, loader, notify_loaded))
def make_exit_requester(simulate): def make_exit_requester(simulate):
def exit_requester(): def exit_requester():
@@ -281,18 +351,15 @@ def _launch_internal(model: Optional[mujoco.MjModel] = None,
def launch(model: Optional[mujoco.MjModel] = None, def launch(model: Optional[mujoco.MjModel] = None,
data: Optional[mujoco.MjData] = None, data: Optional[mujoco.MjData] = None,
*, *,
run_physics_thread: bool = True,
loader: Optional[LoaderType] = None) -> None: loader: Optional[LoaderType] = None) -> None:
"""Launches the Simulate GUI.""" """Launches the Simulate GUI."""
if not run_physics_thread:
mujoco.mj_forward(model, data)
_launch_internal( _launch_internal(
model, data, run_physics_thread=run_physics_thread, loader=loader) model, data, run_physics_thread=True, loader=loader)
def launch_from_path(path: str) -> None: def launch_from_path(path: str) -> None:
"""Launches the Simulate GUI from file path.""" """Launches the Simulate GUI from file path."""
_launch_internal(loader=_file_loader(path)) _launch_internal(run_physics_thread=True, loader=_file_loader(path))
def launch_passive(model: mujoco.MjModel, data: mujoco.MjData) -> None: def launch_passive(model: mujoco.MjModel, data: mujoco.MjData) -> None:
@@ -303,12 +370,13 @@ def launch_passive(model: mujoco.MjModel, data: mujoco.MjData) -> None:
raise ValueError(f'`data` is not a mujoco.MjData: got {data!r}') raise ValueError(f'`data` is not a mujoco.MjData: got {data!r}')
mujoco.mj_forward(model, data) mujoco.mj_forward(model, data)
handle_return = queue.Queue(1)
if sys.platform != 'darwin': if sys.platform != 'darwin':
thread = threading.Thread( thread = threading.Thread(
target=_launch_internal, target=_launch_internal,
args=(model, data), args=(model, data),
kwargs=dict(run_physics_thread=False), kwargs=dict(run_physics_thread=False, handle_return=handle_return),
) )
thread.daemon = True thread.daemon = True
thread.start() thread.start()
@@ -316,85 +384,10 @@ def launch_passive(model: mujoco.MjModel, data: mujoco.MjData) -> None:
if not isinstance(_MJPYTHON, _MjPythonBase): if not isinstance(_MJPYTHON, _MjPythonBase):
raise RuntimeError( raise RuntimeError(
'`launch_passive` requires that the Python script be run under ' '`launch_passive` requires that the Python script be run under '
'`mjpython`') '`mjpython` on macOS')
_MJPYTHON.launch_on_ui_thread(model, data) _MJPYTHON.launch_on_ui_thread(model, data, handle_return)
return handle_return.get()
def launch_repl(model: mujoco.MjModel, data: mujoco.MjData) -> None:
"""Launches the Simulate GUI in REPL mode."""
ipython_shell = None
try:
import IPython # pylint: disable=g-import-not-at-top
ipython_shell = IPython.get_ipython()
ipython_is_terminal_interactive_shell = isinstance(
ipython_shell,
IPython.terminal.interactiveshell.TerminalInteractiveShell)
except ImportError:
ipython_is_terminal_interactive_shell = False
simulate = Simulate()
viewer_is_running = True
def start_shell(global_variables):
if ipython_is_terminal_interactive_shell:
ipython_shell.execution_count += 1
# A SQLite connection can only be used on the same thread that opened it.
# We cache the existing connection and reopen on the current thread.
old_db = ipython_shell.history_manager.db
ipython_shell.history_manager.init_db()
ipython_shell.history_manager.new_session()
try:
# Replicate IPython main loop without exiting on keyboard interrupt,
# unless the viewer window has already been closed.
# (https://github.com/ipython/ipython/blob/8.9.0/IPython/terminal/interactiveshell.py#L701)
while viewer_is_running and ipython_shell.keep_running:
print(ipython_shell.separate_in, end='')
try:
c = ipython_shell.prompt_for_code()
except EOFError:
if not ipython_shell.confirm_exit or ipython_shell.ask_yes_no(
'Do you really want to exit ([y]/n)?', 'y', 'n'):
ipython_shell.ask_exit()
if not ipython_shell.keep_running and simulate is not None:
simulate.exitrequest = True
else:
if c:
ipython_shell.run_cell(c, store_history=True)
finally:
# Close the temporary history DB connection and restore the old one.
ipython_shell.history_manager.end_session()
ipython_shell.history_manager.db.close()
ipython_shell.history_manager.db = old_db
ipython_shell.execution_count -= 1
else:
code.InteractiveConsole(locals=global_variables).interact()
# End IPython history session on the main thread. We will need to open
# a new session in the REPL thread.
if ipython_is_terminal_interactive_shell:
ipython_shell.history_manager.end_session()
try:
# Continue the IPython REPL session in a separate thread.
repl_thread = threading.Thread(
target=start_shell, args=(inspect.stack()[1][0].f_globals,))
repl_thread.start()
# Launch the viewer on the main thread.
mujoco.mj_forward(model, data)
_launch_internal(
model, data, run_physics_thread=False, simulate=simulate)
simulate = None
# Wait until the REPL thread quits, then restore the IPython history
# DB session on the main thread.
viewer_is_running = False
repl_thread.join()
finally:
if ipython_is_terminal_interactive_shell:
ipython_shell.history_manager.new_session()
if __name__ == '__main__': if __name__ == '__main__':
+16 -15
View File
@@ -313,7 +313,7 @@ void PhysicsLoop(mj::Simulate& sim) {
{ {
// lock the sim mutex // lock the sim mutex
const std::lock_guard<std::mutex> lock(sim.mtx); const std::unique_lock<std::recursive_mutex> lock(sim.mtx);
// run only if model is present // run only if model is present
if (m) { if (m) {
@@ -356,11 +356,6 @@ void PhysicsLoop(mj::Simulate& sim) {
syncSim = d->time; syncSim = d->time;
sim.speed_changed = false; sim.speed_changed = false;
// clear old perturbations, apply new
mju_zero(d->xfrc_applied, 6*m->nbody);
sim.ApplyPosePerturbations(0); // move mocap bodies only
sim.ApplyForcePerturbations();
// run single step, let next iteration deal with timing // run single step, let next iteration deal with timing
mj_step(m, d); mj_step(m, d);
} }
@@ -382,11 +377,6 @@ void PhysicsLoop(mj::Simulate& sim) {
measured = true; measured = true;
} }
// clear old perturbations, apply new
mju_zero(d->xfrc_applied, 6*m->nbody);
sim.ApplyPosePerturbations(0); // move mocap bodies only
sim.ApplyForcePerturbations();
// call mj_step // call mj_step
mj_step(m, d); mj_step(m, d);
@@ -400,9 +390,6 @@ void PhysicsLoop(mj::Simulate& sim) {
// paused // paused
else { else {
// apply pose perturbation
sim.ApplyPosePerturbations(1); // move mocap and dynamic bodies
// run mj_forward, to update rendering and joint sliders // run mj_forward, to update rendering and joint sliders
mj_forward(m, d); mj_forward(m, d);
} }
@@ -468,9 +455,23 @@ int main(int argc, const char** argv) {
// scan for libraries in the plugin directory to load additional plugins // scan for libraries in the plugin directory to load additional plugins
scanPluginLibraries(); scanPluginLibraries();
mjvScene scn;
mjv_defaultScene(&scn);
mjvCamera cam;
mjv_defaultCamera(&cam);
mjvOption opt;
mjv_defaultOption(&opt);
mjvPerturb pert;
mjv_defaultPerturb(&pert);
// simulate object encapsulates the UI // simulate object encapsulates the UI
auto sim = std::make_unique<mj::Simulate>( auto sim = std::make_unique<mj::Simulate>(
std::make_unique<mj::GlfwAdapter>()); std::make_unique<mj::GlfwAdapter>(),
&scn, &cam, &opt, &pert, /* fully_managed = */ true
);
const char* filename = nullptr; const char* filename = nullptr;
if (argc > 1) { if (argc > 1) {
+4
View File
@@ -35,6 +35,10 @@ bool PlatformUIAdapter::RefreshMjrContext(const mjModel* m, int fontscale) {
return false; return false;
} }
bool PlatformUIAdapter::EnsureContextSize() {
return false;
}
void PlatformUIAdapter::OnFilesDrop(int count, const char** paths) { void PlatformUIAdapter::OnFilesDrop(int count, const char** paths) {
state_.type = mjEVENT_FILESDROP; state_.type = mjEVENT_FILESDROP;
state_.dropcount = count; state_.dropcount = count;
+2
View File
@@ -41,6 +41,8 @@ class PlatformUIAdapter {
// Optionally overrideable function to (re)create an mjrContext for an mjModel // Optionally overrideable function to (re)create an mjrContext for an mjModel
virtual bool RefreshMjrContext(const mjModel* m, int fontscale); virtual bool RefreshMjrContext(const mjModel* m, int fontscale);
virtual bool EnsureContextSize();
// Pure virtual functions to be implemented by individual adapters // Pure virtual functions to be implemented by individual adapters
virtual std::pair<double, double> GetCursorPosition() const = 0; virtual std::pair<double, double> GetCursorPosition() const = 0;
virtual double GetDisplayPixelsPerInch() const = 0; virtual double GetDisplayPixelsPerInch() const = 0;
+765 -395
View File
File diff suppressed because it is too large Load Diff
+92 -26
View File
@@ -20,15 +20,24 @@
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include <ratio> #include <ratio>
#include <thread> #include <utility>
#include <vector>
#include <mujoco/mjui.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "platform_ui_adapter.h" #include "platform_ui_adapter.h"
namespace mujoco { namespace mujoco {
//-------------------------------- global ----------------------------------------------- // The viewer itself doesn't require a reentrant mutex, however we use it in
// order to provide a Python sync API that doesn't require separate locking
// (since sync is by far the most common operation), but that also won't
// deadlock if called when a lock is already held by the user script on the
// same thread.
class SimulateMutex : public std::recursive_mutex {};
using MutexLock = std::unique_lock<std::recursive_mutex>;
// Simulate states not contained in MuJoCo structures // Simulate states not contained in MuJoCo structures
class Simulate { class Simulate {
@@ -36,14 +45,17 @@ class Simulate {
using Clock = std::chrono::steady_clock; using Clock = std::chrono::steady_clock;
static_assert(std::ratio_less_equal_v<Clock::period, std::milli>); static_assert(std::ratio_less_equal_v<Clock::period, std::milli>);
static constexpr int kMaxGeom = 20000;
// create object and initialize the simulate ui // create object and initialize the simulate ui
Simulate(std::unique_ptr<PlatformUIAdapter> platform_ui_adapter); Simulate(
std::unique_ptr<PlatformUIAdapter> platform_ui_adapter,
mjvScene* scn, mjvCamera* cam,
mjvOption* opt, mjvPerturb* pert, bool fully_managed);
// Apply UI pose perturbations to model and data // Synchronize mjModel and mjData state with UI inputs, and update
void ApplyPosePerturbations(int flg_paused); // visualization.
void Sync();
// Apply UI force perturbations to model and data
void ApplyForcePerturbations();
// Request that the Simulate UI thread render a new model // Request that the Simulate UI thread render a new model
// optionally delete the old model and data when done // optionally delete the old model and data when done
@@ -53,9 +65,6 @@ class Simulate {
// load mjb or xml model that has been requested by load() // load mjb or xml model that has been requested by load()
void LoadOnRenderThread(); void LoadOnRenderThread();
// prepare to render
void PrepareScene();
// render the ui to the window // render the ui to the window
void Render(); void Render();
@@ -65,14 +74,71 @@ class Simulate {
// constants // constants
static constexpr int kMaxFilenameLength = 1000; static constexpr int kMaxFilenameLength = 1000;
// model and data to be visualized // whether the viewer is operating in fully managed mode, where it can assume
mjModel* mnew = nullptr; // that it has exclusive access to mjModel, mjData, and various mjv objects
mjData* dnew = nullptr; bool fully_managed_ = true;
mjModel* m = nullptr; // model and data to be visualized
mjData* d = nullptr; mjModel* mnew_ = nullptr;
std::mutex mtx; mjData* dnew_ = nullptr;
std::condition_variable cond_loadrequest;
mjModel* m_ = nullptr;
mjData* d_ = nullptr;
int ncam_ = 0;
int nkey_ = 0;
std::vector<int> body_parentid_;
std::vector<int> jnt_type_;
std::vector<int> jnt_group_;
std::vector<int> jnt_qposadr_;
std::vector<std::optional<std::pair<mjtNum, mjtNum>>> jnt_range_;
std::vector<std::string> jnt_names_;
std::vector<int> actuator_group_;
std::vector<std::optional<std::pair<mjtNum, mjtNum>>> actuator_ctrlrange_;
std::vector<std::string> actuator_names_;
// mjModel and mjData fields that can be modified by the user through the GUI
std::vector<mjtNum> qpos_;
std::vector<mjtNum> qpos_prev_;
std::vector<mjtNum> ctrl_;
std::vector<mjtNum> ctrl_prev_;
mjvSceneState scnstate_;
mjOption mjopt_prev_;
mjvOption opt_prev_;
mjvCamera cam_prev_;
int warn_vgeomfull_prev_;
// pending GUI-driven actions, to be applied at the next call to Sync
struct {
std::optional<std::string> save_xml;
std::optional<std::string> save_mjb;
std::optional<std::string> print_model;
std::optional<std::string> print_data;
bool reset;
bool align;
bool copy_pose;
bool load_key;
bool save_key;
bool zero_ctrl;
int newperturb;
bool select;
mjuiState select_state;
bool full_ui_update;
bool ui_update_physics;
bool ui_update_joint;
bool ui_update_ctrl;
} pending_ = {};
SimulateMutex mtx;
std::condition_variable_any cond_loadrequest;
int frames_ = 0;
std::chrono::time_point<Clock> last_fps_update_;
double fps_ = 0;
// options // options
int spacing = 0; int spacing = 0;
@@ -140,10 +206,10 @@ class Simulate {
int camera = 0; int camera = 0;
// abstract visualization // abstract visualization
mjvScene scn = {}; mjvScene& scn;
mjvCamera cam = {}; mjvCamera& cam;
mjvOption opt = {}; mjvOption& opt;
mjvPerturb pert = {}; mjvPerturb& pert;
mjvFigure figconstraint = {}; mjvFigure figconstraint = {};
mjvFigure figcost = {}; mjvFigure figcost = {};
mjvFigure figtimer = {}; mjvFigure figtimer = {};
@@ -186,16 +252,16 @@ class Simulate {
// simulation section of UI // simulation section of UI
const mjuiDef def_simulation[12] = { const mjuiDef def_simulation[12] = {
{mjITEM_SECTION, "Simulation", 1, nullptr, "AS"}, {mjITEM_SECTION, "Simulation", 1, nullptr, "AS"},
{mjITEM_RADIO, "", 2, &this->run, "Pause\nRun"}, {mjITEM_RADIO, "", 5, &this->run, "Pause\nRun"},
{mjITEM_BUTTON, "Reset", 2, nullptr, " #259"}, {mjITEM_BUTTON, "Reset", 2, nullptr, " #259"},
{mjITEM_BUTTON, "Reload", 2, nullptr, "CL"}, {mjITEM_BUTTON, "Reload", 5, nullptr, "CL"},
{mjITEM_BUTTON, "Align", 2, nullptr, "CA"}, {mjITEM_BUTTON, "Align", 2, nullptr, "CA"},
{mjITEM_BUTTON, "Copy pose", 2, nullptr, "CC"}, {mjITEM_BUTTON, "Copy pose", 2, nullptr, "CC"},
{mjITEM_SLIDERINT, "Key", 3, &this->key, "0 0"}, {mjITEM_SLIDERINT, "Key", 3, &this->key, "0 0"},
{mjITEM_BUTTON, "Load key", 3}, {mjITEM_BUTTON, "Load key", 3},
{mjITEM_BUTTON, "Save key", 3}, {mjITEM_BUTTON, "Save key", 3},
{mjITEM_SLIDERNUM, "Noise scale", 2, &this->ctrl_noise_std, "0 2"}, {mjITEM_SLIDERNUM, "Noise scale", 5, &this->ctrl_noise_std, "0 2"},
{mjITEM_SLIDERNUM, "Noise rate", 2, &this->ctrl_noise_rate, "0 2"}, {mjITEM_SLIDERNUM, "Noise rate", 5, &this->ctrl_noise_rate, "0 2"},
{mjITEM_END} {mjITEM_END}
}; };
+2
View File
@@ -77,6 +77,8 @@ set(MUJOCO_ENGINE_SRCS
engine_vis_init.h engine_vis_init.h
engine_vis_interact.c engine_vis_interact.c
engine_vis_interact.h engine_vis_interact.h
engine_vis_state.c
engine_vis_state.h
engine_vis_visualize.c engine_vis_visualize.c
engine_vis_visualize.h engine_vis_visualize.h
) )
-1
View File
@@ -145,7 +145,6 @@ void mj_defaultVisual(mjVisual* vis) {
vis->global.offwidth = 640; vis->global.offwidth = 640;
vis->global.offheight = 480; vis->global.offheight = 480;
vis->global.realtime = 1.0; vis->global.realtime = 1.0;
vis->global.treedepth = 1;
vis->global.ellipsoidinertia = 0; vis->global.ellipsoidinertia = 0;
// rendering quality // rendering quality
+2
View File
@@ -226,6 +226,8 @@ void mjv_defaultOption(mjvOption* vopt) {
for (int i=0; i<mjNVISFLAG; i++) { for (int i=0; i<mjNVISFLAG; i++) {
vopt->flags[i] = (mjVISSTRING[i][1][0]=='1'); vopt->flags[i] = (mjVISSTRING[i][1][0]=='1');
} }
vopt->bvh_depth = 1;
} }
+339
View File
@@ -0,0 +1,339 @@
// Copyright 2023 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "engine/engine_vis_state.h"
#include <string.h>
#include <mujoco/mjdata.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mjxmacro.h>
#include "engine/engine_core_constraint.h"
#include "engine/engine_macro.h"
#include "engine/engine_plugin.h"
#include "engine/engine_support.h"
#include "engine/engine_util_errmem.h"
#include "engine/engine_vis_init.h"
#include "engine/engine_vis_interact.h"
#include "engine/engine_vis_visualize.h"
// this source file needs to treat XMJV differently from other X macros
#undef XMJV
// round size up to multiples of 64-byte cache lines
static inline size_t roundUpToCacheLine(size_t n) {
return 64 * ((n / 64) + (n % 64 ? 1 : 0));
}
// set default scene
void mjv_defaultSceneState(mjvSceneState* scnstate) {
memset(scnstate, 0, sizeof(mjvSceneState));
mjv_defaultScene(&scnstate->plugincache);
}
// allocate and init scene state
void mjv_makeSceneState(const mjModel* m, const mjData* d, mjvSceneState* scnstate, int maxgeom) {
mjv_freeScene(&scnstate->plugincache);
mju_free(scnstate->buffer);
#ifdef MEMORY_SANITIZER
__msan_allocated_memory(scnstate, sizeof(mjvSceneState));
mjv_defaultScene(&scnstate->plugincache);
#endif
scnstate->nbuffer = 0;
scnstate->maxgeom = maxgeom;
#define X(var)
#define XMJV(var) scnstate->model.var = m->var;
MJMODEL_INTS
#undef XMJV
#undef X
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
scnstate->nbuffer += roundUpToCacheLine(sizeof(dtype) * m->dim0 * dim1);
MJMODEL_POINTERS
#undef XMJV
#undef X
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
scnstate->nbuffer += roundUpToCacheLine(sizeof(dtype) * m->dim0 * dim1);
MJDATA_POINTERS
#undef XMJV
#undef X
int condimmax = mj_isPyramidal(m) ? 10 : 6;
scnstate->nbuffer += roundUpToCacheLine(sizeof(mjContact) * maxgeom);
scnstate->nbuffer += roundUpToCacheLine(sizeof(mjtNum) * maxgeom * condimmax);
scnstate->buffer = mju_malloc(scnstate->nbuffer);
char* ptr = scnstate->buffer;
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
scnstate->model.var = (dtype*)ptr; \
ptr += roundUpToCacheLine(sizeof(dtype) * m->dim0 * dim1);
MJMODEL_POINTERS
#undef XMJV
#undef X
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
scnstate->data.var = (dtype*)ptr; \
ptr += roundUpToCacheLine(sizeof(dtype) * m->dim0 * dim1);
MJDATA_POINTERS
#undef XMJV
#undef X
scnstate->data.contact = (mjContact*)ptr;
ptr += roundUpToCacheLine(sizeof(mjContact) * scnstate->maxgeom);
scnstate->data.efc_force = (mjtNum*)ptr;
ptr += roundUpToCacheLine(sizeof(mjtNum) * scnstate->maxgeom * condimmax);
// should not occur
if (ptr - (char*)scnstate->buffer != scnstate->nbuffer) {
mju_error("Unexpected error: mjvSceneState buffer is not fully used");
}
mjv_makeScene(m, &scnstate->plugincache, maxgeom);
}
// free scene state
void mjv_freeSceneState(mjvSceneState* scnstate) {
mjv_freeScene(&scnstate->plugincache);
mju_free(scnstate->buffer);
mjv_defaultSceneState(scnstate);
}
// shallow copy scene state into model and data for use with mjv functions
void mjv_assignFromSceneState(const mjvSceneState* scnstate, mjModel* m, mjData* d) {
if (m) {
memset(m, 0, sizeof(mjModel));
#ifdef MEMORY_SANITIZER
// Tell msan to treat the entire buffer as uninitialized
__msan_allocated_memory(m, sizeof(mjModel));
#endif
#define X(var)
#define XMJV(var) m->var = scnstate->model.var;
MJMODEL_INTS
#undef XMJV
#undef X
m->opt = scnstate->model.opt;
m->vis = scnstate->model.vis;
m->stat = scnstate->model.stat;
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) m->var = scnstate->model.var;
MJMODEL_POINTERS
#undef XMJV
#undef X
}
if (d) {
memset(d, 0, sizeof(mjData));
#ifdef MEMORY_SANITIZER
// Tell msan to treat the entire buffer as uninitialized
__msan_allocated_memory(d, sizeof(mjData));
#endif
memcpy(d->warning, scnstate->data.warning, sizeof(d->warning));
d->nefc = scnstate->data.nefc;
d->ncon = scnstate->data.ncon;
d->time = scnstate->data.time;
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) d->var = scnstate->data.var;
MJDATA_POINTERS
#undef XMJV
#undef X
d->contact = scnstate->data.contact;
d->efc_force = scnstate->data.efc_force;
}
}
// update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings
int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn) {
// shallow-copy scnstate pointers into mjModel and mjData
mjModel m;
mjData d;
mjv_assignFromSceneState(scnstate, &m, &d);
// save the number of mjWARN_VGEOMFULL warnings before the scene update
int warning_start = d.warning[mjWARN_VGEOMFULL].number;
// copy mjvGeoms added by plugins
int nplugingeom = scnstate->plugincache.ngeom;
if (nplugingeom > scn->maxgeom) {
mj_warning(&d, mjWARN_VGEOMFULL, scn->maxgeom);
scn->ngeom = scn->maxgeom;
} else {
scn->ngeom = nplugingeom;
}
memcpy(scn->geoms, scnstate->plugincache.geoms, sizeof(mjvGeom) * scn->ngeom);
// add all categories
mjv_addGeoms(&m, &d, opt, pert, catmask, scn);
// add lights
mjv_makeLights(&m, &d, scn);
// update camera
mjv_updateCamera(&m, &d, cam, scn);
// update skins
if (opt->flags[mjVIS_SKIN]) {
mjv_updateActiveSkin(&m, &d, scn, opt);
}
// return the number of new mjWARN_VGEOMFULL warnings generated
return d.warning[mjWARN_VGEOMFULL].number - warning_start;
}
// update a scene state from model and data
void mjv_updateSceneState(const mjModel* m, mjData* d, mjvSceneState* scnstate) {
// Check that mjModel sizes haven't changed.
#define X(var)
#define XMJV(var) \
if (scnstate->model.var != m->var) { \
mju_error("m->%s changed", #var); \
}
MJMODEL_INTS
#undef XMJV
#undef X
// Update plugin visualization cache.
scnstate->plugincache.ngeom = 0;
if (m->nplugin) {
const int nslot = mjp_pluginCount();
// iterate over plugins, call visualize if defined
for (int i=0; i<m->nplugin; i++) {
const int slot = m->plugin[i];
const mjpPlugin* plugin = mjp_getPluginAtSlotUnsafe(slot, nslot);
if (!plugin) {
mju_error("invalid plugin slot: %d", slot);
}
if (plugin->visualize) {
plugin->visualize(m, d, &scnstate->plugincache, i);
}
}
}
// Copy variable-sized arrays in mjModel.
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
memcpy(scnstate->model.var, m->var, sizeof(dtype) * m->dim0 * dim1);
MJMODEL_POINTERS
#undef XMJV
#undef X
scnstate->model.opt = m->opt;
scnstate->model.vis = m->vis;
scnstate->model.stat = m->stat;
// Copy mjData variables.
memcpy(scnstate->data.warning, d->warning, sizeof(d->warning));
scnstate->data.time = d->time;
// Copy variable-sized arrays in mjData.
#define X(dtype, var, dim0, dim1)
#define XMJV(dtype, var, dim0, dim1) \
memcpy(scnstate->data.var, d->var, sizeof(dtype) * m->dim0 * dim1);
MJDATA_POINTERS
#undef XMJV
#undef X
// Copy contacts.
{
if (d->ncon > scnstate->maxgeom) {
mj_warning(d, mjWARN_VGEOMFULL, scnstate->maxgeom);
scnstate->data.ncon = scnstate->maxgeom;
} else {
scnstate->data.ncon = d->ncon;
}
memcpy(scnstate->data.contact, d->contact, sizeof(mjContact) * scnstate->data.ncon);
}
// Copy only the entries in efc_force that correspond to contacts.
{
scnstate->data.nefc = 0;
for (int i = 0; i < scnstate->data.ncon; ++i) {
const mjContact* con = &d->contact[i];
scnstate->data.nefc += con->dim;
}
int efc_address = 0;
int ispyramid = mj_isPyramidal(m);
for (int i = 0; i < scnstate->data.ncon; ++i) {
mjContact* con = &scnstate->data.contact[i];
int dim = con->dim;
if (ispyramid && dim > 1){
dim = 2*(dim - 1);
}
for (int j = 0; j < dim; ++j) {
scnstate->data.efc_force[efc_address + j] = d->efc_force[con->efc_address + j];
}
con->efc_address = efc_address;
efc_address += dim;
}
}
}
// move camera with mouse given a scene state; action is mjtMouse
MJAPI void mjv_moveCameraFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam) {
mjModel m;
mjv_assignFromSceneState(scnstate, &m, NULL);
mjv_moveCamera(&m, action, reldx, reldy, scn, cam);
}
// move perturb object with mouse given a scene state; action is mjtMouse
MJAPI void mjv_movePerturbFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvPerturb* pert) {
mjModel m;
mjData d;
mjv_assignFromSceneState(scnstate, &m, &d);
mjv_movePerturb(&m, &d, action, reldx, reldy, scn, pert);
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2023 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_SRC_ENGINE_ENGINE_VIS_STATE_H_
#define MUJOCO_SRC_ENGINE_ENGINE_VIS_STATE_H_
#include <mujoco/mjdata.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjvisualize.h>
#ifdef __cplusplus
extern "C" {
#endif
// set default scene state
MJAPI void mjv_defaultSceneState(mjvSceneState* scnstate);
// allocate and init scene state
MJAPI void mjv_makeSceneState(const mjModel* m, const mjData* d,
mjvSceneState* scnstate, int maxgeom);
// free scene state
MJAPI void mjv_freeSceneState(mjvSceneState* scnstate);
// shallow copy scene state into model and data for use with mjv functions
void mjv_assignFromSceneState(const mjvSceneState* scnstate, mjModel* m, mjData* d);
// update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings
MJAPI int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask,
mjvScene* scn);
// update a scene state from model and data
MJAPI void mjv_updateSceneState(const mjModel* m, mjData* d, mjvSceneState* scnstate);
// move camera with mouse given a scene state; action is mjtMouse
MJAPI void mjv_moveCameraFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvCamera* cam);
// move perturb object with mouse given a scene state; action is mjtMouse
MJAPI void mjv_movePerturbFromState(const mjvSceneState* scnstate, int action,
mjtNum reldx, mjtNum reldy,
const mjvScene* scn, mjvPerturb* pert);
#ifdef __cplusplus
}
#endif
#endif // MUJOCO_SRC_ENGINE_ENGINE_VIS_STATE_H_
+19 -17
View File
@@ -460,7 +460,7 @@ static int bodycategory(const mjModel* m, int bodyid) {
// add abstract geoms // add abstract geoms
void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt, void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
const mjvPerturb* pert, int catmask, mjvScene* scn) { const mjvPerturb* pert, int catmask, mjvScene* scn) {
int objtype, category; int objtype, category;
mjtNum sz[3], mat[9], selpos[3]; mjtNum sz[3], mat[9], selpos[3];
mjtNum catenary[3*mjNCATENARY]; mjtNum catenary[3*mjNCATENARY];
@@ -527,8 +527,8 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
for (int i = 0; i < m->nbvh; i++) { for (int i = 0; i < m->nbvh; i++) {
int isleaf = m->bvh_child[2*i]==-1 && m->bvh_child[2*i+1]==-1; int isleaf = m->bvh_child[2*i]==-1 && m->bvh_child[2*i+1]==-1;
if (scn->ngeom >= scn->maxgeom) break; if (scn->ngeom >= scn->maxgeom) break;
if (m->bvh_depth[i] != m->vis.global.treedepth) { if (m->bvh_depth[i] != vopt->bvh_depth) {
if (!isleaf || m->bvh_depth[i] > m->vis.global.treedepth) { if (!isleaf || m->bvh_depth[i] > vopt->bvh_depth) {
continue; continue;
} }
} }
@@ -2057,22 +2057,10 @@ void mjv_updateActiveSkin(const mjModel* m, mjData* d, mjvScene* scn, const mjvO
// update entire scene // update entire scene
void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt, void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn) { const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn) {
// clear geoms and add all categories // clear geoms
scn->ngeom = 0; scn->ngeom = 0;
mjv_addGeoms(m, d, opt, pert, catmask, scn);
// add lights // trigger plugin visualization hooks
mjv_makeLights(m, d, scn);
// update camera
mjv_updateCamera(m, d, cam, scn);
// update skins
if (opt->flags[mjVIS_SKIN]) {
mjv_updateActiveSkin(m, d, scn, opt);
}
// update plugin
if (m->nplugin) { if (m->nplugin) {
const int nslot = mjp_pluginCount(); const int nslot = mjp_pluginCount();
// iterate over plugins, call visualize if defined // iterate over plugins, call visualize if defined
@@ -2087,6 +2075,20 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
} }
} }
} }
// add all categories
mjv_addGeoms(m, d, opt, pert, catmask, scn);
// add lights
mjv_makeLights(m, d, scn);
// update camera
mjv_updateCamera(m, d, cam, scn);
// update skins
if (opt->flags[mjVIS_SKIN]) {
mjv_updateActiveSkin(m, d, scn, opt);
}
} }
+45
View File
@@ -1798,3 +1798,48 @@ void mjr_freeContext(mjrContext* con) {
con->windowStereo = windowStereo; con->windowStereo = windowStereo;
con->windowDoublebuffer = windowDoublebuffer; con->windowDoublebuffer = windowDoublebuffer;
} }
// resize offscreen buffers
MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) {
if (con->offWidth == width && con->offHeight == height) {
return;
}
con->offWidth = width;
con->offHeight = height;
if (!width || !height) {
return;
}
if (!con->offFBO) {
makeOff(con);
return;
}
glBindRenderbuffer(GL_RENDERBUFFER, con->offColor);
if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_RGBA8,
con->offWidth, con->offHeight);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight);
}
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil);
if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH24_STENCIL8,
con->offWidth, con->offHeight);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight);
}
if (con->offSamples) {
glBindRenderbuffer(GL_RENDERBUFFER, con->offColor_r);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight);
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight);
}
}
+3
View File
@@ -53,6 +53,9 @@ MJAPI void mjr_addAux(int index, int width, int height, int samples, mjrContext*
// free resources in custom OpenGL context, set to default // free resources in custom OpenGL context, set to default
MJAPI void mjr_freeContext(mjrContext* con); MJAPI void mjr_freeContext(mjrContext* con);
// resize offscreen renderbuffer
MJAPI void mjr_resizeOffscreen(int offwidth, int offheight, mjrContext* con);
// (re) upload texture to GPU // (re) upload texture to GPU
MJAPI void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid); MJAPI void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid);
+3
View File
@@ -78,3 +78,6 @@ target_link_libraries(engine_util_spatial_test fixture gmock)
mujoco_test(engine_vfs_test) mujoco_test(engine_vfs_test)
target_link_libraries(engine_vfs_test fixture gmock) target_link_libraries(engine_vfs_test fixture gmock)
mujoco_test(engine_vis_state_test)
target_link_libraries(engine_vis_state_test fixture gmock)
+116
View File
@@ -0,0 +1,116 @@
// Copyright 2023 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstring>
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h>
#include "test/fixture.h"
namespace mujoco {
namespace {
using ::testing::NotNull;
using MjvSceneStateTest = MujocoTest;
constexpr int kMaxGeom = 10000;
TEST_F(MjvSceneStateTest, CanUpdateFromState) {
constexpr char path[] = "engine/testdata/hammock/hammock.xml";
const std::string xml_path = GetTestDataFilePath(path);
mjModel* model = mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
ASSERT_THAT(model, NotNull());
mjData* data = mj_makeData(model);
while (data->time < 2) {
mj_step(model, data);
}
ASSERT_GT(data->ncon, 10);
mjvScene scn1;
mjv_defaultScene(&scn1);
mjv_makeScene(model, &scn1, kMaxGeom);
mjvOption opt;
mjv_defaultOption(&opt);
mjvPerturb pert;
mjv_defaultPerturb(&pert);
mjvCamera cam;
mjv_defaultFreeCamera(model, &cam);
// Enable all flags to exercise all code paths
for (int i = 0; i < mjNVISFLAG; ++i) {
opt.flags[i] = 1;
}
mjv_updateScene(model, data, &opt, &pert, &cam, mjCAT_ALL, &scn1);
EXPECT_GT(scn1.ngeom, 0);
EXPECT_GT(scn1.nskin, 0);
EXPECT_GT(scn1.nlight, 0);
mjvSceneState scnstate;
mjv_defaultSceneState(&scnstate);
mjv_makeSceneState(model, data, &scnstate, kMaxGeom);
mjv_updateSceneState(model, data, &scnstate);
mjvScene scn2;
mjv_defaultScene(&scn2);
mjv_makeScene(model, &scn2, kMaxGeom);
mjv_updateSceneFromState(&scnstate, &opt, &pert, &cam, mjCAT_ALL, &scn2);
EXPECT_EQ(scn1.ngeom, scn2.ngeom);
for (int i = 0; i < scn1.ngeom; ++i) {
EXPECT_EQ(std::memcmp(&scn1.geoms[i], &scn2.geoms[i], sizeof(mjvGeom)), 0);
}
// NB: scn->geomorder is a scratch space for use by mjr_render, so we don't
// need to compare them here.
EXPECT_LE(scn1.nskin, scn2.nskin);
EXPECT_EQ(std::memcmp(scn1.skinfacenum, scn2.skinfacenum,
sizeof(*scn2.skinfacenum) * scn2.nskin),
0);
EXPECT_EQ(std::memcmp(scn1.skinvertadr, scn2.skinvertadr,
sizeof(*scn2.skinvertadr) * scn2.nskin),
0);
EXPECT_EQ(std::memcmp(scn1.skinvertnum, scn2.skinvertnum,
sizeof(*scn2.skinvertnum) * scn2.nskin),
0);
EXPECT_EQ(std::memcmp(scn1.skinvert, scn2.skinvert,
sizeof(*scn2.skinvert) * scn2.nskin),
0);
EXPECT_EQ(std::memcmp(scn1.skinnormal, scn2.skinnormal,
sizeof(*scn2.skinnormal) * scn2.nskin),
0);
auto scn1_cmp_begin = reinterpret_cast<char*>(&scn1.nlight);
auto scn2_cmp_begin = reinterpret_cast<char*>(&scn2.nlight);
auto cmp_bytes =
sizeof(mjvScene) - (scn2_cmp_begin - reinterpret_cast<char*>(&scn2));
EXPECT_EQ(std::memcmp(scn1_cmp_begin, scn2_cmp_begin, cmp_bytes), 0);
mjv_freeScene(&scn1);
mjv_freeScene(&scn2);
mjv_freeSceneState(&scnstate);
mj_deleteData(data);
mj_deleteModel(model);
}
} // namespace
} // namespace mujoco
+63
View File
@@ -0,0 +1,63 @@
<!-- Copyright 2021 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="Hammock">
<!-- Degree of Freedom: 312
Actuators: 21
Equality constraints: 178
Tendons: 178
Simple humanoid on a hammock, implemented as a 2D grid composite, pinned at the corners.
-->
<option timestep="0.005" solver="CG" iterations="30" tolerance="1e-6"/>
<size memory="20M"/>
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<quality shadowsize="2048"/>
<global offwidth="800" offheight="800"/>
</visual>
<asset>
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="512"/>
<texture name="plane" type="2d" builtin="checker" rgb1=".2 .3 .4" rgb2=".1 0.15 0.2"
width="512" height="512" mark="cross" markrgb=".8 .8 .8"/>
<texture name="hammock" type="2d" builtin="checker" rgb1=".1 .5 .1" rgb2=".5 .1 .1"
width="512" height="512" mark="edge" markrgb=".8 .8 .8"/>
<material name="plane" reflectance="0.3" texture="plane" texrepeat="1 1" texuniform="true"/>
<material name="hammock" texture="hammock"/>
</asset>
<include file="humanoid_body.xml"/>
<worldbody>
<geom name="floor" pos="0 0 -1" size="0 0 .25" type="plane" material="plane" condim="3"/>
<light directional="true" diffuse=".2 .2 .2" specular="0 0 0" pos="0 0 5" dir="0 0 -1" castshadow="false"/>
<light directional="false" diffuse=".8 .8 .8" specular="0.3 0.3 0.3" pos="0 0 4" dir="0 0 -1"/>
<composite type="grid" count="11 9 1" spacing="0.2" offset="0. 0. 0">
<skin texcoord="true" material="hammock" inflate="0.01" subgrid="3"/>
<pin coord="0 0"/>
<pin coord="10 0"/>
<pin coord="0 8"/>
<pin coord="10 8"/>
<geom size=".095"/>
<joint kind="main" damping="10"/>
</composite>
</worldbody>
</mujoco>
+157
View File
@@ -0,0 +1,157 @@
<!-- Copyright 2021 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="Humanoid body">
<!-- Degree of Freedom: 27
Actuators: 21
This simplified humanoid model, introduced in [1], is designed for bipedal locomotion
behaviours. While several variants of it exist in the wild, this version is based on the model
in the DeepMind Control Suite [2], which has fairly realistic actuator gains.
[1] Synthesis and Stabilization of Complex Behaviors through Online Trajectory Optimization.
https://doi.org/10.1109/IROS.2012.6386025
[2] DeepMind Control Suite, Tassa et al. https://arxiv.org/abs/1801.00690
-->
<asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
</asset>
<default>
<motor ctrlrange="-1 1" ctrllimited="true"/>
<default class="body">
<geom type="capsule" condim="1" friction=".7" solimp=".9 .99 .003" solref=".015 1" material="body"/>
<joint type="hinge" damping=".2" stiffness="1" armature=".01" limited="true" solimplimit="0 .99 .01"/>
<default class="big_joint">
<joint damping="5" stiffness="10"/>
<default class="big_stiff_joint">
<joint stiffness="20"/>
</default>
</default>
</default>
</default>
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<quality shadowsize="4096"/>
<global offwidth="800" offheight="800"/>
</visual>
<worldbody>
<body name="torso" pos="0 0 1.5" childclass="body">
<camera name="back" pos="-3 0 1" xyaxes="0 -1 0 1 0 2" mode="trackcom"/>
<camera name="side" pos="0 -3 1" xyaxes="1 0 0 0 1 2" mode="trackcom"/>
<freejoint name="root"/>
<geom name="torso" fromto="0 -.07 0 0 .07 0" size=".07"/>
<geom name="upper_waist" fromto="-.01 -.06 -.12 -.01 .06 -.12" size=".06"/>
<body name="head" pos="0 0 .19">
<geom name="head" type="sphere" size=".09"/>
<camera name="egocentric" pos=".09 0 0" xyaxes="0 -1 0 .1 0 1" fovy="80"/>
</body>
<body name="lower_waist" pos="-.01 0 -.26">
<geom name="lower_waist" fromto="0 -.06 0 0 .06 0" size=".06"/>
<joint name="abdomen_z" pos="0 0 .065" axis="0 0 1" range="-45 45" class="big_stiff_joint"/>
<joint name="abdomen_y" pos="0 0 .065" axis="0 1 0" range="-75 30" class="big_joint"/>
<body name="pelvis" pos="0 0 -.165">
<joint name="abdomen_x" pos="0 0 .1" axis="1 0 0" range="-35 35" class="big_joint"/>
<geom name="butt" fromto="-.02 -.07 0 -.02 .07 0" size=".09"/>
<body name="right_thigh" pos="0 -.1 -.04">
<joint name="right_hip_x" axis="1 0 0" range="-25 5" class="big_joint"/>
<joint name="right_hip_z" axis="0 0 1" range="-60 35" class="big_joint"/>
<joint name="right_hip_y" axis="0 1 0" range="-110 20" class="big_stiff_joint"/>
<geom name="right_thigh" fromto="0 0 0 0 .01 -.34" size=".06"/>
<body name="right_shin" pos="0 .01 -.403">
<joint name="right_knee" pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
<geom name="right_shin" fromto="0 0 0 0 0 -.3" size=".049"/>
<body name="right_foot" pos="0 0 -.39">
<joint name="right_ankle_y" pos="0 0 .08" axis="0 1 0" range="-50 50" stiffness="6"/>
<joint name="right_ankle_x" pos="0 0 .04" axis="1 0 .5" range="-50 50" stiffness="3"/>
<geom name="right_right_foot" fromto="-.07 -.02 0 .14 -.04 0" size=".027"/>
<geom name="left_right_foot" fromto="-.07 0 0 .14 .02 0" size=".027"/>
</body>
</body>
</body>
<body name="left_thigh" pos="0 .1 -.04">
<joint name="left_hip_x" axis="-1 0 0" range="-25 5" class="big_joint"/>
<joint name="left_hip_z" axis="0 0 -1" range="-60 35" class="big_joint"/>
<joint name="left_hip_y" axis="0 1 0" range="-110 20" class="big_stiff_joint"/>
<geom name="left_thigh" fromto="0 0 0 0 -.01 -.34" size=".06"/>
<body name="left_shin" pos="0 -.01 -.403">
<joint name="left_knee" pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
<geom name="left_shin" fromto="0 0 0 0 0 -.3" size=".049"/>
<body name="left_foot" pos="0 0 -.39">
<joint name="left_ankle_y" pos="0 0 .08" axis="0 1 0" range="-50 50" stiffness="6"/>
<joint name="left_ankle_x" pos="0 0 .04" axis="1 0 .5" range="-50 50" stiffness="3"/>
<geom name="left_left_foot" fromto="-.07 .02 0 .14 .04 0" size=".027"/>
<geom name="right_left_foot" fromto="-.07 0 0 .14 -.02 0" size=".027"/>
</body>
</body>
</body>
</body>
</body>
<body name="right_upper_arm" pos="0 -.17 .06">
<joint name="right_shoulder1" axis="2 1 1" range="-85 60"/>
<joint name="right_shoulder2" axis="0 -1 1" range="-85 60"/>
<geom name="right_upper_arm" fromto="0 0 0 .16 -.16 -.16" size=".04 .16"/>
<body name="right_lower_arm" pos=".18 -.18 -.18">
<joint name="right_elbow" axis="0 -1 1" range="-90 50" stiffness="0"/>
<geom name="right_lower_arm" fromto=".01 .01 .01 .17 .17 .17" size=".031"/>
<body name="right_hand" pos=".18 .18 .18">
<geom name="right_hand" type="sphere" size=".04" zaxis="1 1 1"/>
</body>
</body>
</body>
<body name="left_upper_arm" pos="0 .17 .06">
<joint name="left_shoulder1" axis="2 -1 1" range="-60 85"/>
<joint name="left_shoulder2" axis="0 1 1" range="-60 85"/>
<geom name="left_upper_arm" fromto="0 0 0 .16 .16 -.16" size=".04 .16"/>
<body name="left_lower_arm" pos=".18 .18 -.18">
<joint name="left_elbow" axis="0 -1 -1" range="-90 50" stiffness="0"/>
<geom name="left_lower_arm" fromto=".01 -.01 .01 .17 -.17 .17" size=".031"/>
<body name="left_hand" pos=".18 -.18 .18">
<geom name="left_hand" type="sphere" size=".04" zaxis="1 -1 1"/>
</body>
</body>
</body>
</body>
</worldbody>
<actuator>
<motor name="abdomen_y" gear="40" joint="abdomen_y"/>
<motor name="abdomen_z" gear="40" joint="abdomen_z"/>
<motor name="abdomen_x" gear="40" joint="abdomen_x"/>
<motor name="right_hip_x" gear="40" joint="right_hip_x"/>
<motor name="right_hip_z" gear="40" joint="right_hip_z"/>
<motor name="right_hip_y" gear="120" joint="right_hip_y"/>
<motor name="right_knee" gear="80" joint="right_knee"/>
<motor name="right_ankle_x" gear="20" joint="right_ankle_x"/>
<motor name="right_ankle_y" gear="20" joint="right_ankle_y"/>
<motor name="left_hip_x" gear="40" joint="left_hip_x"/>
<motor name="left_hip_z" gear="40" joint="left_hip_z"/>
<motor name="left_hip_y" gear="120" joint="left_hip_y"/>
<motor name="left_knee" gear="80" joint="left_knee"/>
<motor name="left_ankle_x" gear="20" joint="left_ankle_x"/>
<motor name="left_ankle_y" gear="20" joint="left_ankle_y"/>
<motor name="right_shoulder1" gear="20" joint="right_shoulder1"/>
<motor name="right_shoulder2" gear="20" joint="right_shoulder2"/>
<motor name="right_elbow" gear="40" joint="right_elbow"/>
<motor name="left_shoulder1" gear="20" joint="left_shoulder1"/>
<motor name="left_shoulder2" gear="20" joint="left_shoulder2"/>
<motor name="left_elbow" gear="40" joint="left_elbow"/>
</actuator>
</mujoco>
+222 -1
View File
@@ -1771,7 +1771,6 @@ public unsafe struct global {
public float realtime; public float realtime;
public int offwidth; public int offwidth;
public int offheight; public int offheight;
public int treedepth;
public int ellipsoidinertia; public int ellipsoidinertia;
} }
@@ -2576,6 +2575,7 @@ public unsafe struct mjvOption_ {
public fixed byte actuatorgroup[6]; public fixed byte actuatorgroup[6];
public fixed byte skingroup[6]; public fixed byte skingroup[6];
public fixed byte flags[24]; public fixed byte flags[24];
public int bvh_depth;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@@ -2738,6 +2738,203 @@ public unsafe struct mjvFigure_ {
public fixed int yaxispixel[2]; public fixed int yaxispixel[2];
public fixed float xaxisdata[2]; public fixed float xaxisdata[2];
public fixed float yaxisdata[2]; public fixed float yaxisdata[2];
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct model {
public int nu;
public int na;
public int nbody;
public int nbvh;
public int njnt;
public int ngeom;
public int nsite;
public int ncam;
public int nlight;
public int nmesh;
public int nskin;
public int nskinvert;
public int nskinface;
public int nskinbone;
public int nskinbonevert;
public int nmat;
public int neq;
public int ntendon;
public int nwrap;
public int nsensor;
public int nnames;
public int nsensordata;
public mjOption_ opt;
public mjVisual_ vis;
public mjStatistic_ stat;
public int* body_parentid;
public int* body_rootid;
public int* body_weldid;
public int* body_mocapid;
public int* body_jntnum;
public int* body_jntadr;
public int* body_geomnum;
public int* body_geomadr;
public double* body_iquat;
public double* body_mass;
public double* body_inertia;
public int* body_bvhadr;
public int* body_bvhnum;
public int* bvh_depth;
public int* bvh_child;
public int* bvh_geomid;
public double* bvh_aabb;
public int* jnt_type;
public int* jnt_bodyid;
public int* jnt_group;
public int* geom_type;
public int* geom_bodyid;
public int* geom_dataid;
public int* geom_matid;
public int* geom_group;
public double* geom_size;
public double* geom_aabb;
public double* geom_rbound;
public float* geom_rgba;
public int* site_type;
public int* site_bodyid;
public int* site_matid;
public int* site_group;
public double* site_size;
public float* site_rgba;
public double* cam_fovy;
public double* cam_ipd;
public byte* light_directional;
public byte* light_castshadow;
public byte* light_active;
public float* light_attenuation;
public float* light_cutoff;
public float* light_exponent;
public float* light_ambient;
public float* light_diffuse;
public float* light_specular;
public int* mesh_texcoordadr;
public int* mesh_graphadr;
public int* skin_matid;
public int* skin_group;
public float* skin_rgba;
public float* skin_inflate;
public int* skin_vertadr;
public int* skin_vertnum;
public int* skin_texcoordadr;
public int* skin_faceadr;
public int* skin_facenum;
public int* skin_boneadr;
public int* skin_bonenum;
public float* skin_vert;
public int* skin_face;
public int* skin_bonevertadr;
public int* skin_bonevertnum;
public float* skin_bonebindpos;
public float* skin_bonebindquat;
public int* skin_bonebodyid;
public int* skin_bonevertid;
public float* skin_bonevertweight;
public int* mat_texid;
public byte* mat_texuniform;
public float* mat_texrepeat;
public float* mat_emission;
public float* mat_specular;
public float* mat_shininess;
public float* mat_reflectance;
public float* mat_rgba;
public int* eq_type;
public int* eq_obj1id;
public int* eq_obj2id;
public byte* eq_active;
public double* eq_data;
public int* tendon_num;
public int* tendon_matid;
public int* tendon_group;
public byte* tendon_limited;
public double* tendon_width;
public double* tendon_range;
public double* tendon_stiffness;
public double* tendon_damping;
public double* tendon_frictionloss;
public double* tendon_lengthspring;
public float* tendon_rgba;
public int* actuator_trntype;
public int* actuator_dyntype;
public int* actuator_trnid;
public int* actuator_actadr;
public int* actuator_actnum;
public int* actuator_group;
public byte* actuator_ctrllimited;
public byte* actuator_actlimited;
public double* actuator_ctrlrange;
public double* actuator_actrange;
public double* actuator_cranklength;
public int* sensor_type;
public int* sensor_objid;
public int* sensor_adr;
public int* name_bodyadr;
public int* name_jntadr;
public int* name_geomadr;
public int* name_siteadr;
public int* name_camadr;
public int* name_lightadr;
public int* name_eqadr;
public int* name_tendonadr;
public int* name_actuatoradr;
public char* names;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct data {
public mjWarningStat_ warning0;
public mjWarningStat_ warning1;
public mjWarningStat_ warning2;
public mjWarningStat_ warning3;
public mjWarningStat_ warning4;
public mjWarningStat_ warning5;
public mjWarningStat_ warning6;
public mjWarningStat_ warning7;
public int nefc;
public int ncon;
public double time;
public double* act;
public double* ctrl;
public double* xfrc_applied;
public double* sensordata;
public double* xpos;
public double* xquat;
public double* xmat;
public double* xipos;
public double* ximat;
public double* xanchor;
public double* xaxis;
public double* geom_xpos;
public double* geom_xmat;
public double* site_xpos;
public double* site_xmat;
public double* cam_xpos;
public double* cam_xmat;
public double* light_xpos;
public double* light_xdir;
public double* subtree_com;
public int* ten_wrapadr;
public int* ten_wrapnum;
public int* wrap_obj;
public double* wrap_xpos;
public byte* bvh_active;
public mjContact_* contact;
public double* efc_force;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct mjvSceneState_ {
public int nbuffer;
public void* buffer;
public int maxgeom;
public mjvScene_ plugincache;
public model model;
public data data;
}public struct mjuiItem_ {}public struct mjfItemEnable {} }public struct mjuiItem_ {}public struct mjfItemEnable {}
// ----------------------------Function declarations---------------------------- // ----------------------------Function declarations----------------------------
@@ -3128,9 +3325,15 @@ public static unsafe extern void mjv_alignToCamera(double* res, double* vec, dou
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_moveCamera(mjModel_* m, int action, double reldx, double reldy, mjvScene_* scn, mjvCamera_* cam); public static unsafe extern void mjv_moveCamera(mjModel_* m, int action, double reldx, double reldy, mjvScene_* scn, mjvCamera_* cam);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_moveCameraFromState(mjvSceneState_* scnstate, int action, double reldx, double reldy, mjvScene_* scn, mjvCamera_* cam);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_movePerturb(mjModel_* m, mjData_* d, int action, double reldx, double reldy, mjvScene_* scn, mjvPerturb_* pert); public static unsafe extern void mjv_movePerturb(mjModel_* m, mjData_* d, int action, double reldx, double reldy, mjvScene_* scn, mjvPerturb_* pert);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_movePerturbFromState(mjvSceneState_* scnstate, int action, double reldx, double reldy, mjvScene_* scn, mjvPerturb_* pert);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_moveModel(mjModel_* m, int action, double reldx, double reldy, double* roomup, mjvScene_* scn); public static unsafe extern void mjv_moveModel(mjModel_* m, int action, double reldx, double reldy, double* roomup, mjvScene_* scn);
@@ -3173,6 +3376,21 @@ public static unsafe extern void mjv_freeScene(mjvScene_* scn);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_updateScene(mjModel_* m, mjData_* d, mjvOption_* opt, mjvPerturb_* pert, mjvCamera_* cam, int catmask, mjvScene_* scn); public static unsafe extern void mjv_updateScene(mjModel_* m, mjData_* d, mjvOption_* opt, mjvPerturb_* pert, mjvCamera_* cam, int catmask, mjvScene_* scn);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern int mjv_updateSceneFromState(mjvSceneState_* scnstate, mjvOption_* opt, mjvPerturb_* pert, mjvCamera_* cam, int catmask, mjvScene_* scn);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_defaultSceneState(mjvSceneState_* scnstate);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_makeSceneState(mjModel_* m, mjData_* d, mjvSceneState_* scnstate, int maxgeom);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_freeSceneState(mjvSceneState_* scnstate);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_updateSceneState(mjModel_* m, mjData_* d, mjvSceneState_* scnstate);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjv_addGeoms(mjModel_* m, mjData_* d, mjvOption_* opt, mjvPerturb_* pert, int catmask, mjvScene_* scn); public static unsafe extern void mjv_addGeoms(mjModel_* m, mjData_* d, mjvOption_* opt, mjvPerturb_* pert, int catmask, mjvScene_* scn);
@@ -3200,6 +3418,9 @@ public static unsafe extern void mjr_addAux(int index, int width, int height, in
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjr_freeContext(mjrContext_* con); public static unsafe extern void mjr_freeContext(mjrContext_* con);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjr_resizeOffscreen(int width, int height, mjrContext_* con);
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void mjr_uploadTexture(mjModel_* m, mjrContext_* con, int texid); public static unsafe extern void mjr_uploadTexture(mjModel_* m, mjrContext_* con, int texid);