diff --git a/doc/APIreference/functions.rst b/doc/APIreference/functions.rst index 19167361..bc379660 100644 --- a/doc/APIreference/functions.rst +++ b/doc/APIreference/functions.rst @@ -2623,6 +2623,15 @@ Set perturb force,torque in d->xfrc_applied, if selected body is dynamic. Return the average of two OpenGL cameras. +.. _mjv_camera2GLCamera: + +`mjv_camera2GLCamera <#mjv_camera2GLCamera>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mjv_camera2GLCamera + +Converts a mjvCamera to a mjvGLCamera. + .. _mjv_select: `mjv_select <#mjv_select>`__ diff --git a/doc/includes/references.h b/doc/includes/references.h index d3902c53..e1a6d88b 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -3696,6 +3696,8 @@ void mjv_applyPerturbPose(const mjModel* m, mjData* d, const mjvPerturb* pert, int flg_paused); void mjv_applyPerturbForce(const mjModel* m, mjData* d, const mjvPerturb* pert); mjvGLCamera mjv_averageCamera(const mjvGLCamera* cam1, const mjvGLCamera* cam2); +mjvGLCamera mjv_camera2GLCamera(const mjModel* model, const mjData* data, + const mjvCamera* mjv_camera); int mjv_select(const mjModel* m, const mjData* d, const mjvOption* vopt, mjtNum aspectratio, mjtNum relx, mjtNum rely, const mjvScene* scn, mjtNum selpnt[3], diff --git a/include/mujoco/mujoco.h b/include/mujoco/mujoco.h index 44b2bbfa..27c33712 100644 --- a/include/mujoco/mujoco.h +++ b/include/mujoco/mujoco.h @@ -788,6 +788,10 @@ MJAPI void mjv_applyPerturbForce(const mjModel* m, mjData* d, const mjvPerturb* // Return the average of two OpenGL cameras. MJAPI mjvGLCamera mjv_averageCamera(const mjvGLCamera* cam1, const mjvGLCamera* cam2); +// Converts a mjvCamera to a mjvGLCamera. +MJAPI mjvGLCamera mjv_camera2GLCamera(const mjModel* model, const mjData* data, + const mjvCamera* mjv_camera); + // Select geom, flex or skin with mouse; return bodyid; -1: none selected. // Nullable: geomid, flexid, skinid MJAPI int mjv_select(const mjModel* m, const mjData* d, const mjvOption* vopt, diff --git a/python/mujoco/functions.cc b/python/mujoco/functions.cc index b48ecb5d..c07bc60c 100644 --- a/python/mujoco/functions.cc +++ b/python/mujoco/functions.cc @@ -854,6 +854,7 @@ PYBIND11_MODULE(_functions, pymodule, pybind11::mod_gil_not_used()) { Def(pymodule); Def(pymodule); // Skipped: mjv_averageCamera (defined in structs.cc due to the return type) + // Skipped: mjv_camera2GLCamera (defined in structs.cc due to the return type) Def(pymodule); // Visualization diff --git a/python/mujoco/introspect/functions.py b/python/mujoco/introspect/functions.py index 050d0f66..00d0d670 100644 --- a/python/mujoco/introspect/functions.py +++ b/python/mujoco/introspect/functions.py @@ -4972,6 +4972,32 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([ ), doc='Return the average of two OpenGL cameras.', )), + ('mjv_camera2GLCamera', + FunctionDecl( + name='mjv_camera2GLCamera', + return_type=ValueType(name='mjvGLCamera'), + parameters=( + FunctionParameterDecl( + name='model', + type=PointerType( + inner_type=ValueType(name='mjModel', is_const=True), + ), + ), + FunctionParameterDecl( + name='data', + type=PointerType( + inner_type=ValueType(name='mjData', is_const=True), + ), + ), + FunctionParameterDecl( + name='mjv_camera', + type=PointerType( + inner_type=ValueType(name='mjvCamera', is_const=True), + ), + ), + ), + doc='Converts a mjvCamera to a mjvGLCamera.', + )), ('mjv_select', FunctionDecl( name='mjv_select', diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index f8d05c59..be329afe 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -1421,9 +1421,10 @@ This is useful for example when the MJB is not available as a file on disk.)")); mjvFigure.def_readonly("linename", &MjvFigureWrapper::linename); - // mjv_averageCamera returns an mjvGLCamera and we need to call the wrapper's - // constructor on the return value. Defining the binding for this function - // in this file to avoid symbol dependency across modules. + // mjv_averageCamera and mjv_camera2GLCamera both return an mjvGLCamera. + // We need to call the wrapper's constructor on the return value. Defining the + // binding for these functions in this file to avoid symbol dependency across + // modules. m.def( "mjv_averageCamera", [](const MjvGLCameraWrapper& cam1, const MjvGLCameraWrapper& cam2) { @@ -1435,6 +1436,19 @@ This is useful for example when the MJB is not available as a file on disk.)")); py::arg("cam1"), py::arg("cam2"), py::doc(python_traits::mjv_averageCamera::doc)); + m.def( + "mjv_camera2GLCamera", + [](const MjModelWrapper& m, const MjDataWrapper& d, + const MjvCameraWrapper& cam) { + return MjvGLCameraWrapper([&m, &d, &cam]() { + py::gil_scoped_release no_gil; + return InterceptMjErrors(mjv_camera2GLCamera)(m.get(), d.get(), + cam.get()); + }()); + }, + py::arg("m"), py::arg("d"), py::arg("cam"), + py::doc(python_traits::mjv_camera2GLCamera::doc)); + m.def("_recompile_spec_addr", [](uintptr_t spec_addr, const MjModelWrapper& m, const MjDataWrapper& d) { return RecompileSpec(reinterpret_cast(spec_addr), m, d); diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 57bed634..9bdc4725 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -7225,6 +7225,9 @@ public static unsafe extern void mjv_applyPerturbForce(mjModel_* m, mjData_* d, [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern mjvGLCamera_ mjv_averageCamera(mjvGLCamera_* cam1, mjvGLCamera_* cam2); +[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] +public static unsafe extern mjvGLCamera_ mjv_camera2GLCamera(mjModel_* model, mjData_* data, mjvCamera_* mjv_camera); + [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int mjv_select(mjModel_* m, mjData_* d, mjvOption_* vopt, double aspectratio, double relx, double rely, mjvScene_* scn, double* selpnt, int* geomid, int* flexid, int* skinid); diff --git a/wasm/codegen/generated/bindings.cc b/wasm/codegen/generated/bindings.cc index 861be173..790b7aee 100644 --- a/wasm/codegen/generated/bindings.cc +++ b/wasm/codegen/generated/bindings.cc @@ -3732,6 +3732,12 @@ void mjv_applyPerturbPose_wrapper(const MjModel& m, MjData& d, const MjvPerturb& mjv_applyPerturbPose(m.get(), d.get(), pert.get(), flg_paused); } +MjvGLCamera mjv_camera2GLCamera_wrapper(const MjModel& model, const MjData& data, const MjvCamera& mjv_camera) { + MjvGLCamera result; + *result.get() = mjv_camera2GLCamera(model.get(), data.get(), mjv_camera.get()); + return result; +} + void mjv_cameraFrame_wrapper(const val& headpos, const val& forward, const val& up, const val& right, const MjData& d, const MjvCamera& cam) { UNPACK_NULLABLE_VALUE(mjtNum, headpos); UNPACK_NULLABLE_VALUE(mjtNum, forward); @@ -6629,6 +6635,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { function("mjv_alignToCamera", &mjv_alignToCamera_wrapper); function("mjv_applyPerturbForce", &mjv_applyPerturbForce_wrapper); function("mjv_applyPerturbPose", &mjv_applyPerturbPose_wrapper); + function("mjv_camera2GLCamera", &mjv_camera2GLCamera_wrapper); function("mjv_cameraFrame", &mjv_cameraFrame_wrapper); function("mjv_cameraFrustum", &mjv_cameraFrustum_wrapper); function("mjv_cameraInModel", &mjv_cameraInModel_wrapper);