Version 2.1.4: Switch to GLAD, minor improvements to simulate.

PiperOrigin-RevId: 439277749
Change-Id: I741d1c499ae88753338fcc6d141a65e92e13023e
This commit is contained in:
Saran Tunyasuvunakool
2022-04-04 13:53:21 +01:00
parent 3c71720d83
commit 90dea1bdfb
23 changed files with 270 additions and 298 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ function(add_mujoco_shell_test TEST_NAME TARGET_BINARY)
set_property(
TEST "${TEST_NAME}"
APPEND
PROPERTY ENVIRONMENT "MUJOCO_DLL_DIR=$<TARGET_FILE_DIR:mujoco_nogl>"
PROPERTY ENVIRONMENT "MUJOCO_DLL_DIR=$<TARGET_FILE_DIR:mujoco>"
)
endif()
endif()
+14 -14
View File
@@ -2437,7 +2437,7 @@ mjrContext
int charHeightBig; // character heights: big
// capabilities
int glewInitialized; // is glew initialized
int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer
@@ -2905,11 +2905,11 @@ mjcb_control
fields, their values do not correspond to the current time step.
| The control callback is called from within :ref:`mj_forward` and :ref:`mj_step`, just before the controls and applied
forces are needed. When using the RK integrator, it will be called 4 times per step. The alternative way of specifying
controls and applied forces is to set them before mj_step, or use mj_step1 and mj_step2. The latter approach allows
setting the controls after the position and velocity computations have been performed by mj_step1, allowing these
results to be utilized in computing the control (similar to using mjcb_control). However, the only way to change the
controls between sub-steps of the RK integrator is to define the control callback.
forces are needed. When using the RK integrator, it will be called 4 times per step. The alternative way of specifying
controls and applied forces is to set them before ``mj_step``, or use ``mj_step1`` and ``mj_step2``. The latter approach
allows setting the controls after the position and velocity computations have been performed by ``mj_step1``, allowing
these results to be utilized in computing the control (similar to using mjcb_control). However, the only way to change
the controls between sub-steps of the RK integrator is to define the control callback.
.. _mjcb_contactfilter:
@@ -3411,15 +3411,15 @@ Print internal XML schema as plain text or HTML, with style-padding or ``&nbsp;`
Main simulation
^^^^^^^^^^^^^^^
| These are the main entry points to the simulator. Most users will only need to call mj_step, which computes everything
and advanced the simulation state by one time step. Controls and applied forces must either be set in advance (in
mjData.ctrl, qfrc_applied and xfrc_applied), or a control callback mjcb_control must be installed which will be called
just before the controls and applied forces are needed. Alternatively, one can use mj_step1 and mj_step2 which break
down the simulation pipeline into computations that are executed before and after the controls are needed; in this way
one can set controls that depend on the results from mj_step1. Keep in mind though that the RK4 solver does not work
with mj_step1/2.
| These are the main entry points to the simulator. Most users will only need to call ``mj_step``, which computes
everything and advanced the simulation state by one time step. Controls and applied forces must either be set in advance
(in mjData.ctrl, qfrc_applied and xfrc_applied), or a control callback mjcb_control must be installed which will be
called just before the controls and applied forces are needed. Alternatively, one can use ``mj_step1`` and ``mj_step2``
which break down the simulation pipeline into computations that are executed before and after the controls are needed;
in this way one can set controls that depend on the results from ``mj_step1``. Keep in mind though that the RK4 solver
does not work with mj_step1/2.
| mj_forward performs the same computations as mj_step but without the integration. It is useful after loading or
| mj_forward performs the same computations as ``mj_step`` but without the integration. It is useful after loading or
resetting a model (to put the entire mjData in a valid state), and also for out-of-order computations that involve
sampling or finite-difference approximations.
+43
View File
@@ -2,6 +2,49 @@
Changelog
=========
Version 2.1.4 (Apr. 4, 2022)
-----------------------------
General
^^^^^^^
1. MuJoCo now uses GLAD to manage OpenGL API access instead of GLEW. On Linux, there is no longer a need to link against
different GL wrangling libraries depending on whether GLX, EGL, or OSMesa is being used. Instead, users can simply
use GLX, EGL, or OSMesa to create a GL context and ``mjr_makeContext`` will detect which one is being used.
#. Add visualisation for contact frames. This is useful when writing or modifying collision functions, when the actual
direction of the x and y axes of a contact can be important.
Binary build
^^^^^^^^^^^^
3. The ``_nogl`` dynamic library is no longer provided on Linux and Windows. The switch to GLAD allows us to resolve
OpenGL symbols when ``mjr_makeContext`` is called rather than when the library is loaded. As a result, the MuJoCo
library no longer has an explicit dynamic dependency on OpenGL, and can be used on system where OpenGL is not
present.
Simulate
^^^^^^^^
4. Fix a bug in simulate where pressing '[' or ']' when a model is not loaded causes a crash.
#. Contact frame visualisation is added to the Simulate GUI.
#. Rename "set key", "reset to key" to "save key" and "load key", respectively.
#. Change bindings of F6 and F7 from the not very useful "vertical sync" and "busy wait" to the more useful cycling of
frames and labels.
Bug fixes
^^^^^^^^^
8. ``mj_resetData`` zeroes out the ``solver_nnz`` field.
#. Remove a special branch in ``mju_quat2mat`` for unit quaternions. Previously, ``mju_quat2mat`` skipped all
computation if the real part of the quaternion equals 1.0. For very small angles (e.g. when finite differencing), the
cosine can evaluate to exactly 1.0 at double precision while the sine is still nonzero.
Version 2.1.3 (Mar. 23, 2022)
-----------------------------
+21 -72
View File
@@ -12,29 +12,16 @@ be used in C++ programs.
MuJoCo is a free product currently distributed as a pre-built dynamic library and will soon be made available as an
open-source project. The software distribution contains a compiled version of GLFW which is used in the code samples to
create an OpenGL window and direct user input to it. The Linux distribution also contains compiled versions of GLEW
which is used for OpenGL symbol loading and allow the user to choose between X11, EGL or MESA. For projects where
rendering is not needed, there is a smaller "nogl" library which does not have a dependence on OpenGL. This is suitable
for running on headless servers without video drivers installed. The distribution for each platform contains the
following dynamic libraries:
create an OpenGL window and direct user input to it. The distribution for each platform contains the following dynamic
library:
.. code-block:: Text
Windows: mujoco210.dll (stub library: mujoco210.lib)
mujoco210nogl.dll (stub library: mujoco210nogl.lib)
glfw3.dll (stub library: glfw3.lib)
Windows: mujoco.dll (stub library: mujoco.lib)
Linux: mujoco210.so
mujoco210nogl.so
glewXXX.so
glfw.so.3
Linux: mujoco.so.2.1.4
macOS: mujoco210.dylib
mujoco210nogl.dylib
glfw.3.dylib
Note that the software :ref:`version <inVersion>` number is contained in the library name (and obviously changes with
every release), so for example ``mujoco210`` means version 2.1.
macOS: mujoco.2.1.4.dylib
Even though MuJoCo is a single dynamic library with unified C API, it contains several modules, some of which are
implemented in C++. We have taken advantage of the convenience of C++ for functionality that is used before the
@@ -154,11 +141,6 @@ API. While we encourage users to upgrade to the latest version, we recognize tha
especially when other developers release software that relies on MuJoCo. Therefore we have introduced simple
mechanisms to help avoid version conflicts, as follows.
As noted above, the version number is contained in the name of the dynamic library, e.g. mujoco210.dll for version 2.1.
Thus if an executable was compiled and linked with version 2.1 and the currently installed MuJoCo version is different,
the dynamic library will not be found. Please avoid the temptation to rename the library so as to fool the dynamic
linker; this is never a good idea. Instead you should obtain the required version of the library.
The situation is more subtle if existing code was developed with a certain version of MuJoCo, and is now being
compiled and linked with a different version. If the definitions of the API functions used in that code have changed,
either the compiler or the linker will generate errors. But even if the function definitions have not changed, it may
@@ -224,55 +206,22 @@ mjcb\_
Using OpenGL
~~~~~~~~~~~~
The use of MuJoCo's native OpenGL renderer will be explained in :ref:`Rendering`. Here we only cover issues
related to external libraries and resolving dependencies. For projects that do not need rendering, one can use the
"nogl" version of the MuJoCo library.
The use of MuJoCo's native OpenGL renderer will be explained in :ref:`Rendering`. For rendering, MuJoCo uses OpenGL 1.5
in the compatibility profile with the ``ARB_framebuffer_object`` and ``ARB_vertex_buffer_object`` extensions. OpenGL
symbols are loaded via `GLAD <https://github.com/Dav1dde/glad>`_ the first time the :ref:`mjr_makeContext` function
is called. This means that the MuJoCo library itself does not have an explicit dependency on OpenGL and can be used
on systems without OpenGL support, as long as ``mjr_`` functions are not called.
For rendering MuJoCo uses OpenGL 1.5 with the ARB_framebuffer_object extension (provided by all modern drivers.) It
also uses GLEW 2.0.0 for loading OpenGL symbols. On Windows and macOS, both GLEW and the OpenGL library (OpenGL32.lib
or OpenGL.framework respectively) are linked with MuJoCo. On these platforms the user does not have to take additional
steps to resolve dependencies.
Applications that use MuJoCo's built-in rendering functionalities are responsible for linking against an appropriate
OpenGL context creation library and for ensuring that there is an OpenGL context that is made current on the running
thread. On Windows and macOS, there is a canonical OpenGL library provided by the operating system. On Linux, MuJoCo
currently supports GLX for rendering to an X11 window, OSMesa for headless software rendering, and EGL for hardware
accelerated headless rendering.
On Linux the situation is more complex, because there are multiple OpenGL implementations and ways to load symbols.
The renderer and linking process are organized so as to allow multiple use cases shown below. libmujoco210.so calls
GLEW and OpenGL functions without linking the corresponding libraries. Users must resolve the dependencies by linking
whatever flavor of GLEW and OpenGL are suitable for their needs. For illustration, see how
:ref:`record.cc <saRecord>` on Linux is compiled and linked in three different ways (makefile in the sample
directory).
No OpenGL: link with **libmujoco210nogl**.so
This version of the MuJoCo library is compiled without the renderer, so it does not make any calls to OpenGL or GLEW.
It can be used on compute servers where graphics drivers are not installed. The main header file mujoco.h still
declares the rendering functions (mjr_XXX), but the library does not implement them, therefore calling these
functions from user code will result in unresolved symbols at link time. In the code samples, we use this version of
the library in text-only applications.
X11 OpenGL: link with **libmujoco210**.so, **libglew**.so, **libGL**.so
This is the most common way of using OpenGL on Linux desktop, with X11 for context creation and symbol loading.
OSMESA OpenGL: link with **libmujoco210**.so, **libglewosmesa**.so, **libOSMesa**.so
This can be used for software rendering with the OSMesa library. Note that we are linking a different version of GLEW
here, built with OSMesa support instead of the standard GLX. Ideally users will find a way to avoid software
rendering and use hardware acceleration. But OSMesa is a convenient fall-back option when all else fails.
EGL OpenGL: link with **libmujoco210**.so, **libEGL**.so, **libglewegl**.so, **libOpenGL**.so
This is the key feature for headless rendering. It enables hardware-accelerated OpenGL on servers without X11. User
code must use EGL for context creation, as illustrated in :ref:`record.cc <saRecord>`. libglewegl.so uses EGL to
load OpenGL symbols instead of using GLX. libOpenGL.so is the vendor-independent library which exposes only OpenGL
functionality without introducing a dependence on X11 (as opposed to libGL.so which depends on libGLX.so). NVidia's
drivers provide libOpenGL.so when installed with the "--install-libglvnd" option. libEGL.so can be obtained from Mesa
and is driver-independent (sudo apt-get install libegl1-mesa-dev).
Finally, instead of using the compiled libglew we have provided, users can compile their own, or link glew.c statically
in their project (it is a single C file). Static linking requires the GLEW_STATIC symbol to be defined. In addition, the
following symbols must be defined when building GLEW 2.0.0 for different use cases:
::
libglew.so: GLEW_NO_GLU
libglewegl.so: GLEW_NO_GLU GLEW_EGL
libgleweomesa.so: GLEW_NO_GLU GLEW_OSMESA
For headless rendering to work, it is essential to eliminate the dependence on GLU, because otherwise a dependence on
X11 will be introduced via libGLU.so. Note that GLEW can also be built for Mir and Wayland. We have not tested these,
but in theory they should work.
Before version 2.1.4, MuJoCo used GLEW rather than GLAD to manage OpenGL symbols, which required linking against
different GLEW libraries at build time depending on the GL implementation used. In order to avoid having manage OpenGL
dependency when no rendering was required, "nogl" builds of the library was made available. Since OpenGL symbols are
now lazily resolved at runtime after the switch to GLAD, the "nogl" libraries are no longer provided.
.. _Sample:
@@ -641,7 +590,7 @@ but these are finer points).
Instead of relying on a control callback, we could set the control vector ``mjData.ctrl`` directly. Alternatively we
could set applied forces as explained in :ref:`state and control <siStateControl>`. If we could compute these control-
related quantities before mj_step is called, then the simulation loop for the controlled dynamics (without using a
related quantities before ``mj_step`` is called, then the simulation loop for the controlled dynamics (without using a
control callback) would become
.. code-block:: C
@@ -652,7 +601,7 @@ control callback) would become
mj_step(m, d);
}
Why would we not be able to compute the controls before mj_step is called? After all, isn't this what causality means?
Why would we not be able to compute the controls before ``mj_step`` is called? After all, isn't this what causality means?
The answer is subtle but important, and has to do with the fact that we are simulating in discrete time. The top-level
simulation function ``mj_step`` basically does two things: compute the :ref:`forward dynamics <siForward>` in continuous
time, and then integrate over a time period specified by ``mjModel.opt.timestep``. Forward dynamics computes the
+17
View File
@@ -101,6 +101,23 @@ Functions
This allows for some thread-based parallelism, however users should bear in mind that the GIL is only released for the
duration of the MuJoCo C function itself, and not during the execution of any other Python code.
.. note::
One place where the bindings do offer added functionality is the top-level :ref:`mj_step` function. Since it is
often called in a loop, we have added an additional ``nstep`` argument, indicating how many times the underlying
:ref:`mj_step` should be called. If not specified, ``nstep`` takes the default value of 1. The following two code
snippets perform the same computation, but the first one does so without acquiring the GIL in between subsequent
physics steps:
.. code-block:: python
mj_step(model, data, nstep=20)
.. code-block:: python
for _ in range(20):
mj_step(model, data)
Enums and constants
===================
+2 -2
View File
@@ -29,14 +29,14 @@ _____
The MuJoCo app needs to be run at least once before the native library can be used, in order to register the library as
a trusted binary. Then, copy the dynamic library file from
``/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.framework/Versions/Current/libmujoco.2.1.1.dylib`` (it can be
``/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.framework/Versions/Current/libmujoco.2.1.4.dylib`` (it can be
found by browsing the contents of ``MuJoCo.app``) and rename it as ``mujoco.dylib``.
Linux
_____
Expand the ``tar.gz`` archive to ``~/.mujoco``. Then copy the dynamic library from
``~/.mujoco/mujoco-2.1.1/lib/libmujoco_nogl.so.2.1.1`` (note the ``_nogl`` suffix) and rename it as ``libmujoco.so``.
``~/.mujoco/mujoco-2.1.4/lib/libmujoco.so.2.1.4`` and rename it as ``libmujoco.so``.
Windows
_______
+1 -1
View File
@@ -141,7 +141,7 @@ struct mjrContext_ { // custom OpenGL context
int charHeightBig; // character heights: big
// capabilities
int glewInitialized; // is glew initialized
int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer
+1
View File
@@ -88,6 +88,7 @@ typedef enum mjtFrame_ { // frame visualization
mjFRAME_SITE, // site frames
mjFRAME_CAMERA, // camera frames
mjFRAME_LIGHT, // light frames
mjFRAME_CONTACT, // contact frames
mjFRAME_WORLD, // world frame
mjNFRAME // number of visualization frames
+11 -11
View File
@@ -24,7 +24,7 @@ extern "C" {
#endif
// header version; should match the library version as returned by mj_version()
#define mjVERSION_HEADER 213
#define mjVERSION_HEADER 214
// needed to define size_t, fabs and log10
#include "stdlib.h"
@@ -79,21 +79,12 @@ MJAPI extern const char* mjVISSTRING[mjNVISFLAG][3];
MJAPI extern const char* mjRNDSTRING[mjNRNDFLAG][3];
//---------------------------------- Activation ----------------------------------------------------
// Return 1 (for backward compatibility).
MJAPI int mj_activate(const char* filename);
// Do nothing (for backward compatibility).
MJAPI void mj_deactivate(void);
//---------------------------------- Virtual file system -------------------------------------------
// Initialize VFS to empty (no deallocation).
MJAPI void mj_defaultVFS(mjVFS* vfs);
// Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: not found on disk.
// Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load.
MJAPI int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename);
// Make empty file in VFS, return 0: success, 1: full, 2: repeated name.
@@ -768,6 +759,15 @@ MJAPI void mj_warning(mjData* d, int warning, int info);
MJAPI void mju_writeLog(const char* type, const char* msg);
//---------------------------------- Activation ----------------------------------------------------
// Return 1 (for backward compatibility).
MJAPI int mj_activate(const char* filename);
// Do nothing (for backward compatibility).
MJAPI void mj_deactivate(void);
//---------------------------------- Standard math -------------------------------------------------
#define mjMAX(a,b) (((a) > (b)) ? (a) : (b))
+3 -2
View File
@@ -569,8 +569,9 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjFRAME_SITE', 3),
('mjFRAME_CAMERA', 4),
('mjFRAME_LIGHT', 5),
('mjFRAME_WORLD', 6),
('mjNFRAME', 7),
('mjFRAME_CONTACT', 6),
('mjFRAME_WORLD', 7),
('mjNFRAME', 8),
]),
)),
('mjtVisFlag',
+22 -22
View File
@@ -26,27 +26,6 @@ from .ast_nodes import PointerType
from .ast_nodes import ValueType
FUNCTIONS: Mapping[str, FunctionDecl] = dict([
('mj_activate',
FunctionDecl(
name='mj_activate',
return_type=ValueType(name='int'),
parameters=(
FunctionParameterDecl(
name='filename',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
),
doc='Return 1 (for backward compatibility).',
)),
('mj_deactivate',
FunctionDecl(
name='mj_deactivate',
return_type=ValueType(name='void'),
parameters=(),
doc='Do nothing (for backward compatibility).',
)),
('mj_defaultVFS',
FunctionDecl(
name='mj_defaultVFS',
@@ -85,7 +64,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
),
),
),
doc='Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: not found on disk.', # pylint: disable=line-too-long
doc='Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load.', # pylint: disable=line-too-long
)),
('mj_makeEmptyFileVFS',
FunctionDecl(
@@ -4738,6 +4717,27 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
),
doc='Write [datetime, type: message] to MUJOCO_LOG.TXT.',
)),
('mj_activate',
FunctionDecl(
name='mj_activate',
return_type=ValueType(name='int'),
parameters=(
FunctionParameterDecl(
name='filename',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
),
doc='Return 1 (for backward compatibility).',
)),
('mj_deactivate',
FunctionDecl(
name='mj_deactivate',
return_type=ValueType(name='void'),
parameters=(),
doc='Do nothing (for backward compatibility).',
)),
('mju_zero3',
FunctionDecl(
name='mju_zero3',
+3 -19
View File
@@ -55,7 +55,7 @@ include(FindOrFetch)
# ==================== MUJOCO LIBRARY ==========================================
if(NOT TARGET mujoco)
find_library(MUJOCO_LIBRARY mujoco mujoco.2.1.3 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED)
find_library(MUJOCO_LIBRARY mujoco mujoco.2.1.4 HINTS ${MUJOCO_LIBRARY_DIR} REQUIRED)
find_path(MUJOCO_INCLUDE mujoco.h HINTS ${MUJOCO_INCLUDE_DIR} REQUIRED)
message("MuJoCo is at ${MUJOCO_LIBRARY}")
message("MuJoCo headers are at ${MUJOCO_INCLUDE}")
@@ -152,7 +152,7 @@ else()
GIT_REPO
https://github.com/pybind/pybind11
GIT_TAG
08ea85b0ac0d4d46ac081ff24f481b41322d7159
a8f1a5567608f346bdba293b3d062a288ee16cd4
TARGETS
pybind11::pybind11_headers
EXCLUDE_FROM_ALL
@@ -257,12 +257,7 @@ macro(mujoco_pybind11_module name)
@rpath/$<TARGET_FILE_NAME:mujoco> -add_rpath @loader_path $<TARGET_FILE:${name}>
)
elseif(NOT WIN32)
add_custom_command(
TARGET ${name}
POST_BUILD
COMMAND patchelf --remove-needed $<TARGET_SONAME_FILE_NAME:mujoco>
$<TARGET_FILE_NAME:${name}>
)
set_target_properties(${name} PROPERTIES INSTALL_RPATH $ORIGIN BUILD_WITH_INSTALL_RPATH TRUE)
endif()
endmacro()
@@ -347,17 +342,6 @@ set(LIBRARIES_FOR_WHEEL
"$<TARGET_FILE:_structs>"
"$<TARGET_FILE:mujoco>"
)
if(NOT APPLE)
set(LIBRARIES_FOR_WHEEL ${LIBRARIES_FOR_WHEEL} $<TARGET_FILE:mujoco_nogl>)
endif()
if(NOT (APPLE OR WIN32))
set(LIBRARIES_FOR_WHEEL
${LIBRARIES_FOR_WHEEL}
"$<TARGET_FILE:glew>"
"$<TARGET_FILE:glewegl>"
"$<TARGET_FILE:glewosmesa>"
)
endif()
if(MUJOCO_PYTHON_MAKE_WHEEL)
add_custom_target(
+24 -49
View File
@@ -15,69 +15,44 @@
"""Python bindings for MuJoCo."""
import ctypes
import ctypes.util
import os
import platform
import subprocess
HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include')
_MUJOCO_GL_ENABLE = ('enable', 'enabled', 'on', 'true', '1' , '')
_MUJOCO_GL_DISABLE = ('disable', 'disabled', 'off', 'false', '0')
_MUJOCO_GL = os.environ.get('MUJOCO_GL', '').lower().strip()
_MUJOCO_GL_IS_VALID = True
_SYSTEM = platform.system()
if _SYSTEM == 'Linux':
libglew_name = None
if _MUJOCO_GL in _MUJOCO_GL_ENABLE + ('glfw', 'glx'):
libglew_name = 'libglew.so'
elif _MUJOCO_GL == 'egl':
libglew_name = 'libglewegl.so'
elif _MUJOCO_GL == 'osmesa':
libglew_name = 'libglewosmesa.so'
elif _MUJOCO_GL not in _MUJOCO_GL_DISABLE:
_MUJOCO_GL_IS_VALID = False
if libglew_name is not None:
ctypes.CDLL(os.path.join(os.path.dirname(__file__), libglew_name),
ctypes.RTLD_GLOBAL)
ctypes.CDLL(
os.path.join(os.path.dirname(__file__), 'libmujoco.so.2.1.3'),
ctypes.RTLD_GLOBAL)
else:
ctypes.CDLL(
os.path.join(os.path.dirname(__file__), 'libmujoco_nogl.so.2.1.3'),
ctypes.RTLD_GLOBAL)
elif _SYSTEM == 'Windows':
if _MUJOCO_GL in _MUJOCO_GL_ENABLE + ('glfw', 'wgl'):
ctypes.WinDLL(os.path.join(os.path.dirname(__file__), 'mujoco.dll'))
elif _MUJOCO_GL in _MUJOCO_GL_DISABLE:
ctypes.WinDLL(os.path.join(os.path.dirname(__file__), 'mujoco_nogl.dll'))
else:
_MUJOCO_GL_IS_VALID = False
if not _MUJOCO_GL_IS_VALID:
raise RuntimeError(
f'invalid value for environment variable MUJOCO_GL: {_MUJOCO_GL}')
if _SYSTEM == 'Windows':
ctypes.WinDLL(os.path.join(os.path.dirname(__file__), 'mujoco.dll'))
from mujoco._callbacks import *
from mujoco._constants import *
from mujoco._enums import *
from mujoco._errors import *
from mujoco._functions import *
from mujoco._render import *
from mujoco._structs import *
# pylint: disable=g-import-not-at-top
if _MUJOCO_GL not in _MUJOCO_GL_DISABLE:
from mujoco._render import *
if _SYSTEM != 'Linux':
from mujoco.glfw import GLContext
_MUJOCO_GL = os.environ.get('MUJOCO_GL', '').lower().strip()
if _MUJOCO_GL not in ('disable', 'disabled', 'off', 'false', '0'):
_VALID_MUJOCO_GL = ('enable', 'enabled', 'on', 'true', '1' , 'glfw', '')
if _SYSTEM == 'Linux':
_VALID_MUJOCO_GL += ('glx', 'egl', 'osmesa')
elif _SYSTEM == 'Windows':
_VALID_MUJOCO_GL += ('wgl',)
elif _SYSTEM == 'Darwin':
_VALID_MUJOCO_GL += ('cgl',)
if _MUJOCO_GL not in _VALID_MUJOCO_GL:
raise RuntimeError(
f'invalid value for environment variable MUJOCO_GL: {_MUJOCO_GL}')
if _SYSTEM == 'Linux' and _MUJOCO_GL == 'osmesa':
from mujoco.osmesa import GLContext
elif _SYSTEM == 'Linux' and _MUJOCO_GL == 'egl':
from mujoco.egl import GLContext
else:
_dl_handle = ctypes.CDLL(None)
if hasattr(_dl_handle, 'OSMesaCreateContextExt'):
from mujoco.osmesa import GLContext
elif hasattr(_dl_handle, 'eglCreateContext'):
from mujoco.egl import GLContext
else:
from mujoco.glfw import GLContext
from mujoco.glfw import GLContext
HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include')
__version__ = mj_versionString() # pylint: disable=undefined-variable
+66 -64
View File
@@ -665,7 +665,7 @@ Euler integrator, semi-implicit in velocity.
def test_enum_as_index(self):
x = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
self.assertEqual(x[mujoco.mjtFrame.mjNFRAME], 'h')
self.assertEqual(x[mujoco.mjtFrame.mjFRAME_WORLD], 'h')
self.assertEqual(
x[mujoco.mjtFrame.mjFRAME_GEOM:mujoco.mjtFrame.mjFRAME_CAMERA],
['c', 'd'])
@@ -673,83 +673,85 @@ Euler integrator, semi-implicit in velocity.
def test_enum_ops(self):
# Note: when modifying this test, make sure the enum value is an odd number
# so that the division tests are correctly exercised.
self.assertEqual(mujoco.mjtFrame.mjNFRAME, 7)
self.assertEqual(mujoco.mjtFrame.mjNFRAME, 7.0)
self.assertEqual(7, mujoco.mjtFrame.mjNFRAME)
self.assertEqual(7.0, mujoco.mjtFrame.mjNFRAME)
self.assertEqual(mujoco.mjtFrame.mjNFRAME, mujoco.mjtFrame.mjNFRAME)
self.assertNotEqual(mujoco.mjtFrame.mjNFRAME, mujoco.mjtFrame.mjFRAME_NONE)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD, 7)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD, 7.0)
self.assertEqual(7, mujoco.mjtFrame.mjFRAME_WORLD)
self.assertEqual(7.0, mujoco.mjtFrame.mjFRAME_WORLD)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD,
mujoco.mjtFrame.mjFRAME_WORLD)
self.assertNotEqual(mujoco.mjtFrame.mjFRAME_WORLD,
mujoco.mjtFrame.mjFRAME_NONE)
self.assertEqual(-mujoco.mjtFrame.mjNFRAME, -7)
self.assertIsInstance(-mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(-mujoco.mjtFrame.mjFRAME_WORLD, -7)
self.assertIsInstance(-mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME + 1, 8)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME + 1, int)
self.assertEqual(2 + mujoco.mjtFrame.mjNFRAME, 9)
self.assertIsInstance(2 + mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME + 1.75, 8.75)
self.assertEqual(2.75 + mujoco.mjtFrame.mjNFRAME, 9.75)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD + 1, 8)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD + 1, int)
self.assertEqual(2 + mujoco.mjtFrame.mjFRAME_WORLD, 9)
self.assertIsInstance(2 + mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD + 1.75, 8.75)
self.assertEqual(2.75 + mujoco.mjtFrame.mjFRAME_WORLD, 9.75)
self.assertEqual(mujoco.mjtFrame.mjNFRAME - 2, 5)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME - 2, int)
self.assertEqual(8 - mujoco.mjtFrame.mjNFRAME, 1)
self.assertIsInstance(8 - mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME - 2.25, 4.75)
self.assertEqual(8.25 - mujoco.mjtFrame.mjNFRAME, 1.25)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD - 2, 5)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD - 2, int)
self.assertEqual(8 - mujoco.mjtFrame.mjFRAME_WORLD, 1)
self.assertIsInstance(8 - mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD - 2.25, 4.75)
self.assertEqual(8.25 - mujoco.mjtFrame.mjFRAME_WORLD, 1.25)
self.assertEqual(mujoco.mjtFrame.mjNFRAME * 3, 21)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME * 3, int)
self.assertEqual(3 * mujoco.mjtFrame.mjNFRAME, 21)
self.assertIsInstance(3 * mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME * 3.5, 24.5)
self.assertEqual(3.5 * mujoco.mjtFrame.mjNFRAME, 24.5)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD * 3, 21)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD * 3, int)
self.assertEqual(3 * mujoco.mjtFrame.mjFRAME_WORLD, 21)
self.assertIsInstance(3 * mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD * 3.5, 24.5)
self.assertEqual(3.5 * mujoco.mjtFrame.mjFRAME_WORLD, 24.5)
self.assertEqual(mujoco.mjtFrame.mjNFRAME / 2, 3.5)
self.assertEqual(17.5 / mujoco.mjtFrame.mjNFRAME, 2.5)
self.assertEqual(mujoco.mjtFrame.mjNFRAME // 2, 3)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME // 2, int)
self.assertEqual(-mujoco.mjtFrame.mjNFRAME // 2, -4)
self.assertIsInstance(-mujoco.mjtFrame.mjNFRAME // 2, int)
self.assertEqual(20 // mujoco.mjtFrame.mjNFRAME, 2)
self.assertIsInstance(20 // mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(-20 // mujoco.mjtFrame.mjNFRAME, -3)
self.assertIsInstance(-20 // mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME // 2.0, 3)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME // 2.0, float)
self.assertEqual(-mujoco.mjtFrame.mjNFRAME // 2.0, -4)
self.assertIsInstance(-mujoco.mjtFrame.mjNFRAME // 2.0, float)
self.assertEqual(20.0 // mujoco.mjtFrame.mjNFRAME, 2)
self.assertIsInstance(20.0 // mujoco.mjtFrame.mjNFRAME, float)
self.assertEqual(-20 // mujoco.mjtFrame.mjNFRAME, -3)
self.assertIsInstance(-20.0 // mujoco.mjtFrame.mjNFRAME, float)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD / 2, 3.5)
self.assertEqual(17.5 / mujoco.mjtFrame.mjFRAME_WORLD, 2.5)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD // 2, 3)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD // 2, int)
self.assertEqual(-mujoco.mjtFrame.mjFRAME_WORLD // 2, -4)
self.assertIsInstance(-mujoco.mjtFrame.mjFRAME_WORLD // 2, int)
self.assertEqual(20 // mujoco.mjtFrame.mjFRAME_WORLD, 2)
self.assertIsInstance(20 // mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(-20 // mujoco.mjtFrame.mjFRAME_WORLD, -3)
self.assertIsInstance(-20 // mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD // 2.0, 3)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD // 2.0, float)
self.assertEqual(-mujoco.mjtFrame.mjFRAME_WORLD // 2.0, -4)
self.assertIsInstance(-mujoco.mjtFrame.mjFRAME_WORLD // 2.0, float)
self.assertEqual(20.0 // mujoco.mjtFrame.mjFRAME_WORLD, 2)
self.assertIsInstance(20.0 // mujoco.mjtFrame.mjFRAME_WORLD, float)
self.assertEqual(-20 // mujoco.mjtFrame.mjFRAME_WORLD, -3)
self.assertIsInstance(-20.0 // mujoco.mjtFrame.mjFRAME_WORLD, float)
self.assertEqual(mujoco.mjtFrame.mjNFRAME % 4, 3)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME % 4, int)
self.assertEqual(-mujoco.mjtFrame.mjNFRAME % -4, -3)
self.assertIsInstance(-mujoco.mjtFrame.mjNFRAME % -4, int)
self.assertEqual(-mujoco.mjtFrame.mjNFRAME % 4, 1)
self.assertIsInstance(-mujoco.mjtFrame.mjNFRAME % 4, int)
self.assertEqual(mujoco.mjtFrame.mjNFRAME % -4, -1)
self.assertIsInstance(mujoco.mjtFrame.mjNFRAME % -4, int)
self.assertEqual(9 % mujoco.mjtFrame.mjNFRAME, 2)
self.assertIsInstance(9 % mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(-9 % -mujoco.mjtFrame.mjNFRAME, -2)
self.assertIsInstance(-9 % -mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(-9 % mujoco.mjtFrame.mjNFRAME, 5)
self.assertIsInstance(-9 % mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(9 % -mujoco.mjtFrame.mjNFRAME, -5)
self.assertIsInstance(9 % -mujoco.mjtFrame.mjNFRAME, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD % 4, 3)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD % 4, int)
self.assertEqual(-mujoco.mjtFrame.mjFRAME_WORLD % -4, -3)
self.assertIsInstance(-mujoco.mjtFrame.mjFRAME_WORLD % -4, int)
self.assertEqual(-mujoco.mjtFrame.mjFRAME_WORLD % 4, 1)
self.assertIsInstance(-mujoco.mjtFrame.mjFRAME_WORLD % 4, int)
self.assertEqual(mujoco.mjtFrame.mjFRAME_WORLD % -4, -1)
self.assertIsInstance(mujoco.mjtFrame.mjFRAME_WORLD % -4, int)
self.assertEqual(9 % mujoco.mjtFrame.mjFRAME_WORLD, 2)
self.assertIsInstance(9 % mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(-9 % -mujoco.mjtFrame.mjFRAME_WORLD, -2)
self.assertIsInstance(-9 % -mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(-9 % mujoco.mjtFrame.mjFRAME_WORLD, 5)
self.assertIsInstance(-9 % mujoco.mjtFrame.mjFRAME_WORLD, int)
self.assertEqual(9 % -mujoco.mjtFrame.mjFRAME_WORLD, -5)
self.assertIsInstance(9 % -mujoco.mjtFrame.mjFRAME_WORLD, int)
with self.assertRaises(ZeroDivisionError):
_ = mujoco.mjtFrame.mjNFRAME / 0
_ = mujoco.mjtFrame.mjFRAME_WORLD / 0
with self.assertRaises(ZeroDivisionError):
_ = 1 / mujoco.mjtFrame.mjFRAME_NONE
with self.assertRaises(ZeroDivisionError):
_ = mujoco.mjtFrame.mjNFRAME // 0
_ = mujoco.mjtFrame.mjFRAME_WORLD // 0
with self.assertRaises(ZeroDivisionError):
_ = 1 // mujoco.mjtFrame.mjFRAME_NONE
with self.assertRaises(ZeroDivisionError):
_ = mujoco.mjtFrame.mjNFRAME % 0
_ = mujoco.mjtFrame.mjFRAME_WORLD % 0
with self.assertRaises(ZeroDivisionError):
_ = 1 % mujoco.mjtFrame.mjFRAME_NONE
+1 -1
View File
@@ -206,7 +206,7 @@ PYBIND11_MODULE(_render, pymodule) {
X(nskin);
X(charHeight);
X(charHeightBig);
X(glewInitialized);
X(glInitialized);
X(windowAvailable);
X(windowSamples);
X(windowStereo);
+1 -1
View File
@@ -19,7 +19,7 @@ import mujoco
import numpy as np
@absltest.skipUnless(hasattr(mujoco, 'mjr_render'),
@absltest.skipUnless(hasattr(mujoco, 'GLContext'),
'MuJoCo rendering is disabled')
class MuJoCoRenderTest(absltest.TestCase):
+11 -13
View File
@@ -30,7 +30,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command import build_ext
__version__ = '2.1.3'
__version__ = '2.1.4'
MUJOCO_CMAKE = 'MUJOCO_CMAKE'
MUJOCO_CMAKE_ARGS = 'MUJOCO_CMAKE_ARGS'
@@ -54,20 +54,20 @@ def get_long_description():
def get_mujoco_lib_pattern():
if platform.system() == 'Windows':
return 'mujoco*.lib'
return 'mujoco.lib'
elif platform.system() == 'Darwin':
return 'libmujoco*.dylib'
return 'libmujoco.*.dylib'
else:
return 'libmujoco*.so*'
return 'libmujoco.so.*'
def get_external_lib_patterns():
if platform.system() == 'Windows':
return ['mujoco*.dll']
return ['mujoco.dll']
elif platform.system() == 'Darwin':
return ['libmujoco*.dylib']
return ['libmujoco.*.dylib']
else:
return ['libmujoco*.so*', 'libglew*.so']
return ['libmujoco.so.*']
def start_and_end(iterable):
@@ -290,12 +290,10 @@ setup(
find_data_files(
package_dir='mujoco',
patterns=[
'libmujoco*.dylib',
'libmujoco*.so*',
'mujoco*.dll',
'libglew*.so*',
'mujoco.h',
'mj*.h',
'libmujoco.*.dylib',
'libmujoco*.so.*',
'mujoco.dll',
'include/*.h',
]),
},
)
+7 -7
View File
@@ -5,12 +5,12 @@
COMMON=-O2 -I../include -L../lib -std=c++11 -pthread -Wl,-rpath,'$$ORIGIN'/../lib
all:
$(CXX) $(COMMON) testxml.cc -lmujoco_nogl -o ../bin/testxml
$(CXX) $(COMMON) testspeed.cc -lmujoco_nogl -o ../bin/testspeed
$(CXX) $(COMMON) compile.cc -lmujoco_nogl -o ../bin/compile
$(CXX) $(COMMON) derivative.cc -lmujoco_nogl -fopenmp -o ../bin/derivative
$(CXX) $(COMMON) basic.cc -lmujoco -lGL -lglew -lglfw -o ../bin/basic
$(CXX) $(COMMON) record.cc -lmujoco -lGL -lglew -lglfw -o ../bin/record
$(CXX) $(COMMON) testxml.cc -lmujoco -o ../bin/testxml
$(CXX) $(COMMON) testspeed.cc -lmujoco -o ../bin/testspeed
$(CXX) $(COMMON) compile.cc -lmujoco -o ../bin/compile
$(CXX) $(COMMON) derivative.cc -lmujoco -fopenmp -o ../bin/derivative
$(CXX) $(COMMON) basic.cc -lmujoco -lGL -lglfw -o ../bin/basic
$(CXX) $(COMMON) record.cc -lmujoco -lGL -lglfw -o ../bin/record
$(CC) -c -O2 -I../include uitools.c
$(CXX) $(COMMON) uitools.o simulate.cc -lmujoco -lGL -lglew -lglfw -o ../bin/simulate
$(CXX) $(COMMON) uitools.o simulate.cc -lmujoco -lGL -lglfw -o ../bin/simulate
rm *.o
+12 -10
View File
@@ -2,20 +2,22 @@
# packages are installed in /usr/local. If your setup is different, you will
# need to adjust the HOMEBREW variable accordingly.
# This Makefile also assumes that MuJoCo.app is present in /Applications.
HOMEBREW?=/usr/local
MUJOCO_LIBDIR=../MuJoCo.Framework/Versions/A
MUJOCO_INCLUDEDIR=../MuJoCo.Framework/Versions/A/Headers
MUJOCO_LIBDIR=/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.Framework/Versions/A
MUJOCO_INCLUDEDIR=/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.Framework/Versions/A/Headers
CFLAGS=-O2 -I$(MUJOCO_INCLUDEDIR) -I$(HOMEBREW)/include -pthread
ALLFLAGS=$(CFLAGS) -L$(MUJOCO_LIBDIR) -L$(HOMEBREW)/lib -std=c++11 -stdlib=libc++
ALLFLAGS=$(CFLAGS) -L$(MUJOCO_LIBDIR) -L$(HOMEBREW)/lib -std=c++11 -stdlib=libc++ -Wl,-rpath,/Applications/MuJoCo.app/Contents/Frameworks
all:
clang++ $(ALLFLAGS) testxml.cc -lmujoco.2.1.3 -o testxml
clang++ $(ALLFLAGS) testspeed.cc -lmujoco.2.1.3 -o testspeed
clang++ $(ALLFLAGS) compile.cc -lmujoco.2.1.3 -o compile
clang++ $(ALLFLAGS) derivative.cc -lmujoco.2.1.3 -o derivative
clang++ $(ALLFLAGS) basic.cc -lmujoco.2.1.3 -lglfw -o basic
clang++ $(ALLFLAGS) record.cc -lmujoco.2.1.3 -lglfw -o record
clang++ $(ALLFLAGS) testxml.cc -lmujoco.2.1.4 -o testxml
clang++ $(ALLFLAGS) testspeed.cc -lmujoco.2.1.4 -o testspeed
clang++ $(ALLFLAGS) compile.cc -lmujoco.2.1.4 -o compile
clang++ $(ALLFLAGS) derivative.cc -lmujoco.2.1.4 -o derivative
clang++ $(ALLFLAGS) basic.cc -lmujoco.2.1.4 -lglfw -o basic
clang++ $(ALLFLAGS) record.cc -lmujoco.2.1.4 -lglfw -o record
clang -c $(CFLAGS) uitools.c
clang++ $(ALLFLAGS) uitools.o simulate.cc -lmujoco.2.1.3 -lglfw -o simulate
clang++ $(ALLFLAGS) uitools.o simulate.cc -lmujoco.2.1.4 -lglfw -o simulate
rm *.o
+4 -4
View File
@@ -9,10 +9,10 @@
COMMON=/O2 /MT /EHsc /arch:AVX /I../include /Fe../bin/
all:
cl $(COMMON) testxml.cc ../lib/mujoco_nogl.lib
cl $(COMMON) testspeed.cc ../lib/mujoco_nogl.lib
cl $(COMMON) compile.cc ../lib/mujoco_nogl.lib
cl $(COMMON) derivative.cc /openmp ../lib/mujoco_nogl.lib
cl $(COMMON) testxml.cc ../lib/mujoco.lib
cl $(COMMON) testspeed.cc ../lib/mujoco.lib
cl $(COMMON) compile.cc ../lib/mujoco.lib
cl $(COMMON) derivative.cc /openmp ../lib/mujoco.lib
cl $(COMMON) basic.cc ../lib/glfw3.lib ../lib/mujoco.lib
cl $(COMMON) record.cc ../lib/glfw3.lib ../lib/mujoco.lib
cl $(COMMON) simulate.cc uitools.c ../lib/glfw3.lib ../lib/mujoco.lib
+1 -1
View File
@@ -762,7 +762,7 @@ void makerendering(int oldstate) {
"Frame",
2,
&(vopt.frame),
"None\nBody\nGeom\nSite\nCamera\nLight\nWorld"
"None\nBody\nGeom\nSite\nCamera\nLight\nContact\nWorld"
},
{
mjITEM_BUTTON,
@@ -35,7 +35,7 @@ public class MujocoBinaryRetriever {
if (AssetDatabase.LoadMainAssetAtPath(mujocoPath + "/mujoco.dylib") == null) {
File.Copy(
"/Applications/MuJoCo.app/Contents/Frameworks" +
"/MuJoCo.framework/Versions/Current/libmujoco.2.1.3.dylib",
"/MuJoCo.framework/Versions/Current/libmujoco.2.1.4.dylib",
mujocoPath + "/mujoco.dylib");
AssetDatabase.Refresh();
}
@@ -43,7 +43,7 @@ public class MujocoBinaryRetriever {
if (AssetDatabase.LoadMainAssetAtPath(mujocoPath + "/libmujoco.so") == null) {
File.Copy(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) +
"/.mujoco/mujoco-2.1.3/lib/libmujoco_nogl.so.2.1.3",
"/.mujoco/mujoco-2.1.4/lib/libmujoco.so.2.1.4",
mujocoPath + "/libmujoco.so");
AssetDatabase.Refresh();
}
+2 -2
View File
@@ -83,7 +83,7 @@ public const int mjMAXOVERLAY = 500;
public const int mjMAXLINE = 100;
public const int mjMAXLINEPNT = 1000;
public const int mjMAXPLANEGRID = 200;
public const int mjVERSION_HEADER = 213;
public const int mjVERSION_HEADER = 214;
// ------------------------------------Enums------------------------------------
@@ -2201,7 +2201,7 @@ public unsafe struct mjrContext_ {
public fixed int charWidthBig[127];
public int charHeight;
public int charHeightBig;
public int glewInitialized;
public int glInitialized;
public int windowAvailable;
public int windowSamples;
public int windowStereo;