Call GLFW functions via a dynamic dispatch table.
This allows us to use GLFW without needing to introduce a link-time dependency on the library, which in turn enables us to get GLFW through Python. PiperOrigin-RevId: 470100999 Change-Id: I27c84ad3310afdbebd582ab0033b6a963ba6307e
This commit is contained in:
committed by
Copybara-Service
parent
d26501c0f3
commit
3240596c3a
+16
-12
@@ -97,25 +97,29 @@ if(NOT TARGET lodepng)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# mjsimulate library
|
# Simulate library
|
||||||
add_library(mjsimulate STATIC)
|
add_library(libsimulate STATIC)
|
||||||
|
add_library(mujoco::libsimulate ALIAS libsimulate)
|
||||||
|
|
||||||
target_sources(
|
target_sources(
|
||||||
mjsimulate
|
libsimulate
|
||||||
PUBLIC simulate.h
|
PUBLIC simulate.h
|
||||||
array_safety.h
|
array_safety.h
|
||||||
|
glfw_dispatch.h
|
||||||
|
glfw_dispatch.cc
|
||||||
simulate.cc
|
simulate.cc
|
||||||
uitools.h
|
uitools.h
|
||||||
uitools.c
|
uitools.cc
|
||||||
)
|
)
|
||||||
target_include_directories(mjsimulate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(libsimulate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(mjsimulate PUBLIC MJSIMULATE_STATIC)
|
target_compile_definitions(libsimulate PUBLIC MJSIMULATE_STATIC)
|
||||||
target_compile_options(mjsimulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
|
target_compile_options(libsimulate PUBLIC ${MUJOCO_SIMULATE_COMPILE_OPTIONS})
|
||||||
target_link_libraries(mjsimulate PUBLIC glfw lodepng mujoco::mujoco)
|
target_link_libraries(libsimulate PUBLIC glfw lodepng mujoco::mujoco)
|
||||||
target_link_options(mjsimulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
target_link_options(libsimulate PRIVATE ${MUJOCO_SIMULATE_LINK_OPTIONS})
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_sources(mjsimulate PRIVATE macos_save.mm)
|
target_sources(libsimulate PRIVATE macos_save.mm)
|
||||||
target_link_libraries(mjsimulate PUBLIC "-framework Cocoa")
|
target_link_libraries(libsimulate PUBLIC "-framework Cocoa")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Build simulate executable
|
# Build simulate executable
|
||||||
@@ -142,7 +146,7 @@ endif()
|
|||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
simulate
|
simulate
|
||||||
mjsimulate
|
libsimulate
|
||||||
mujoco::mujoco
|
mujoco::mujoco
|
||||||
glfw
|
glfw
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2022 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 "glfw_dispatch.h"
|
||||||
|
|
||||||
|
#ifdef mjGLFW_DYNAMIC_SYMBOLS
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <windows.h>
|
||||||
|
#include <libloaderapi.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace mujoco {
|
||||||
|
const struct Glfw& Glfw(void* dlhandle) {
|
||||||
|
{
|
||||||
|
static const void* init_dlhandle = dlhandle;
|
||||||
|
if (dlhandle && dlhandle != init_dlhandle) {
|
||||||
|
std::cerr << "dlhandle is specified when GLFW dispatch table is already "
|
||||||
|
"initialized\n";
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct Glfw glfw = [&]() {
|
||||||
|
struct Glfw glfw;
|
||||||
|
|
||||||
|
#ifdef mjGLFW_DYNAMIC_SYMBOLS
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (!dlhandle) dlhandle = LoadLibraryA("glfw3.dll");
|
||||||
|
if (!dlhandle) {
|
||||||
|
std::cerr << "cannot obtain a shared object handle\n";
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#define mjGLFW_RESOLVE_SYMBOL(func) \
|
||||||
|
glfw.func = reinterpret_cast<decltype(glfw.func)>( \
|
||||||
|
GetProcAddress(reinterpret_cast<HMODULE>(dlhandle), #func))
|
||||||
|
#else
|
||||||
|
if (!dlhandle) dlhandle = dlopen("nullptr", RTLD_GLOBAL | RTLD_NOW);
|
||||||
|
if (!dlhandle) {
|
||||||
|
std::cerr << "cannot obtain a shared object handle\n";
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#define mjGLFW_RESOLVE_SYMBOL(func) \
|
||||||
|
glfw.func = reinterpret_cast<decltype(glfw.func)>(dlsym(dlhandle, #func))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define mjGLFW_RESOLVE_SYMBOL(func) glfw.func = &func
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define mjGLFW_INITIALIZE_SYMBOL(func) \
|
||||||
|
if (!(mjGLFW_RESOLVE_SYMBOL(func))) { \
|
||||||
|
std::cerr << "cannot dlsym " #func "\n"; \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// go/keep-sorted start
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwCreateWindow);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetCursorPos);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetFramebufferSize);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetKey);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetMonitorPhysicalSize);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetMouseButton);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetPrimaryMonitor);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetTime);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetVideoMode);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetWindowMonitor);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetWindowPos);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetWindowSize);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwGetWindowUserPointer);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwInit);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwMakeContextCurrent);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwPollEvents);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetClipboardString);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetCursorPosCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetDropCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetKeyCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetMouseButtonCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetScrollCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetWindowMonitor);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetWindowRefreshCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetWindowSizeCallback);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetWindowTitle);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSetWindowUserPointer);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSwapBuffers);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwSwapInterval);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwTerminate);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwWindowHint);
|
||||||
|
mjGLFW_INITIALIZE_SYMBOL(glfwWindowShouldClose);
|
||||||
|
// go/keep-sorted end
|
||||||
|
|
||||||
|
#undef mjGLFW_INITIALIZE_SYMBOL
|
||||||
|
|
||||||
|
#if defined(mjGLFW_DYNAMIC_SYMBOLS) && !defined(_MSC_VER)
|
||||||
|
dlclose(dlhandle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return glfw;
|
||||||
|
}();
|
||||||
|
return glfw;
|
||||||
|
}
|
||||||
|
} // namespace mujoco
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2022 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_SIMULATE_GLFW_DISPATCH_H_
|
||||||
|
#define MUJOCO_SIMULATE_GLFW_DISPATCH_H_
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
namespace mujoco {
|
||||||
|
// Dynamic dispatch table for GLFW functions required by Simulate.
|
||||||
|
// This allows us to use GLFW without introducing a link-time dependency on the
|
||||||
|
// library, which is useful e.g. when using GLFW via Python.
|
||||||
|
struct Glfw {
|
||||||
|
#define mjGLFW_DECLARE_SYMBOL(func) decltype(&func) func
|
||||||
|
// go/keep-sorted start
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwCreateWindow);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetCursorPos);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetFramebufferSize);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetKey);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetMonitorPhysicalSize);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetMouseButton);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetPrimaryMonitor);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetTime);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetVideoMode);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetWindowMonitor);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetWindowPos);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetWindowSize);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwGetWindowUserPointer);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwInit);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwMakeContextCurrent);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwPollEvents);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetClipboardString);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetCursorPosCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetDropCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetKeyCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetMouseButtonCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetScrollCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetWindowMonitor);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetWindowRefreshCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetWindowSizeCallback);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetWindowTitle);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSetWindowUserPointer);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSwapBuffers);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwSwapInterval);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwTerminate);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwWindowHint);
|
||||||
|
mjGLFW_DECLARE_SYMBOL(glfwWindowShouldClose);
|
||||||
|
// go/keep-sorted end
|
||||||
|
#undef mjGLFW_DECLARE_SYMBOL
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct Glfw& Glfw(void* dlhandle = nullptr);
|
||||||
|
} // namespace mujoco
|
||||||
|
|
||||||
|
#endif // MUJOCO_SIMULATE_GLFW_DISPATCH_H_
|
||||||
+8
-5
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
#include <mujoco/mjxmacro.h>
|
#include <mujoco/mjxmacro.h>
|
||||||
|
#include "glfw_dispatch.h"
|
||||||
#include "simulate.h"
|
#include "simulate.h"
|
||||||
#include "array_safety.h"
|
#include "array_safety.h"
|
||||||
|
|
||||||
@@ -30,6 +31,8 @@ namespace {
|
|||||||
namespace mj = ::mujoco;
|
namespace mj = ::mujoco;
|
||||||
namespace mju = ::mujoco::sample_util;
|
namespace mju = ::mujoco::sample_util;
|
||||||
|
|
||||||
|
using ::mujoco::Glfw;
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
const double syncmisalign = 0.1; // maximum time mis-alignment before re-sync
|
const double syncmisalign = 0.1; // maximum time mis-alignment before re-sync
|
||||||
const double refreshfactor = 0.7; // fraction of refresh available for simulation
|
const double refreshfactor = 0.7; // fraction of refresh available for simulation
|
||||||
@@ -158,7 +161,7 @@ void PhysicsLoop(mj::Simulate& sim) {
|
|||||||
// running
|
// running
|
||||||
if (sim.run) {
|
if (sim.run) {
|
||||||
// record cpu time at start of iteration
|
// record cpu time at start of iteration
|
||||||
double tmstart = glfwGetTime();
|
double tmstart = Glfw().glfwGetTime();
|
||||||
|
|
||||||
// inject noise
|
// inject noise
|
||||||
if (sim.ctrlnoisestd) {
|
if (sim.ctrlnoisestd) {
|
||||||
@@ -195,8 +198,8 @@ void PhysicsLoop(mj::Simulate& sim) {
|
|||||||
// in-sync
|
// in-sync
|
||||||
else {
|
else {
|
||||||
// step while simtime lags behind cputime, and within safefactor
|
// step while simtime lags behind cputime, and within safefactor
|
||||||
while ((d->time*sim.slow_down-simsync) < (glfwGetTime()-cpusync) &&
|
while ((d->time*sim.slow_down-simsync) < (Glfw().glfwGetTime()-cpusync) &&
|
||||||
(glfwGetTime()-tmstart) < refreshfactor/sim.vmode.refreshRate) {
|
(Glfw().glfwGetTime()-tmstart) < refreshfactor/sim.vmode.refreshRate) {
|
||||||
// clear old perturbations, apply new
|
// clear old perturbations, apply new
|
||||||
mju_zero(d->xfrc_applied, 6*m->nbody);
|
mju_zero(d->xfrc_applied, 6*m->nbody);
|
||||||
sim.applyposepertubations(0); // move mocap bodies only
|
sim.applyposepertubations(0); // move mocap bodies only
|
||||||
@@ -268,7 +271,7 @@ int main(int argc, const char** argv) {
|
|||||||
auto sim = std::make_unique<mj::Simulate>();
|
auto sim = std::make_unique<mj::Simulate>();
|
||||||
|
|
||||||
// init GLFW
|
// init GLFW
|
||||||
if (!glfwInit()) {
|
if (!Glfw().glfwInit()) {
|
||||||
mju_error("could not initialize GLFW");
|
mju_error("could not initialize GLFW");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +289,7 @@ int main(int argc, const char** argv) {
|
|||||||
|
|
||||||
// terminate GLFW (crashes with Linux NVidia drivers)
|
// terminate GLFW (crashes with Linux NVidia drivers)
|
||||||
#if defined(__APPLE__) || defined(_WIN32)
|
#if defined(__APPLE__) || defined(_WIN32)
|
||||||
glfwTerminate();
|
Glfw().glfwTerminate();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+34
-29
@@ -23,9 +23,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include "lodepng.h"
|
||||||
#include <mujoco/mjmodel.h>
|
#include <mujoco/mjmodel.h>
|
||||||
#include <mujoco/mjvisualize.h>
|
#include <mujoco/mjvisualize.h>
|
||||||
#include <mujoco/mjxmacro.h>
|
#include <mujoco/mjxmacro.h>
|
||||||
|
#include "glfw_dispatch.h"
|
||||||
#include "uitools.h"
|
#include "uitools.h"
|
||||||
#include "array_safety.h"
|
#include "array_safety.h"
|
||||||
|
|
||||||
@@ -46,6 +49,8 @@ namespace {
|
|||||||
namespace mj = ::mujoco;
|
namespace mj = ::mujoco;
|
||||||
namespace mju = ::mujoco::sample_util;
|
namespace mju = ::mujoco::sample_util;
|
||||||
|
|
||||||
|
using ::mujoco::Glfw;
|
||||||
|
|
||||||
//------------------------------------------- global -----------------------------------------------
|
//------------------------------------------- global -----------------------------------------------
|
||||||
|
|
||||||
const int maxgeom = 5000; // preallocated geom array in mjvScene
|
const int maxgeom = 5000; // preallocated geom array in mjvScene
|
||||||
@@ -925,12 +930,12 @@ void copykey(mj::Simulate* sim) {
|
|||||||
mju::strcat_arr(clipboard, "'/>");
|
mju::strcat_arr(clipboard, "'/>");
|
||||||
|
|
||||||
// copy to clipboard
|
// copy to clipboard
|
||||||
glfwSetClipboardString(sim->window, clipboard);
|
Glfw().glfwSetClipboardString(sim->window, clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// millisecond timer, for MuJoCo built-in profiler
|
// millisecond timer, for MuJoCo built-in profiler
|
||||||
mjtNum timer() {
|
mjtNum timer() {
|
||||||
return 1000*glfwGetTime();
|
return 1000*Glfw().glfwGetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear all times
|
// clear all times
|
||||||
@@ -965,7 +970,7 @@ void copycamera(mj::Simulate* sim) {
|
|||||||
camera[0].up[0], camera[0].up[1], camera[0].up[2]);
|
camera[0].up[0], camera[0].up[1], camera[0].up[2]);
|
||||||
|
|
||||||
// copy spec into clipboard
|
// copy spec into clipboard
|
||||||
glfwSetClipboardString(sim->window, clipboard);
|
Glfw().glfwSetClipboardString(sim->window, clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update UI 0 when MuJoCo structures change (except for joint sliders)
|
// update UI 0 when MuJoCo structures change (except for joint sliders)
|
||||||
@@ -1026,7 +1031,7 @@ void uiLayout(mjuiState* state) {
|
|||||||
// rect 0: entire framebuffer
|
// rect 0: entire framebuffer
|
||||||
rect[0].left = 0;
|
rect[0].left = 0;
|
||||||
rect[0].bottom = 0;
|
rect[0].bottom = 0;
|
||||||
glfwGetFramebufferSize(sim->window, &rect[0].width, &rect[0].height);
|
Glfw().glfwGetFramebufferSize(sim->window, &rect[0].width, &rect[0].height);
|
||||||
|
|
||||||
// rect 1: UI 0
|
// rect 1: UI 0
|
||||||
rect[1].left = 0;
|
rect[1].left = 0;
|
||||||
@@ -1119,29 +1124,29 @@ void uiEvent(mjuiState* state) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 9: // Full screen
|
case 9: // Full screen
|
||||||
if (glfwGetWindowMonitor(sim->window)) {
|
if (Glfw().glfwGetWindowMonitor(sim->window)) {
|
||||||
// restore window from saved data
|
// restore window from saved data
|
||||||
glfwSetWindowMonitor(sim->window, nullptr, sim->windowpos[0], sim->windowpos[1],
|
Glfw().glfwSetWindowMonitor(sim->window, nullptr, sim->windowpos[0], sim->windowpos[1],
|
||||||
sim->windowsize[0], sim->windowsize[1], 0);
|
sim->windowsize[0], sim->windowsize[1], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently windowed: switch to full screen
|
// currently windowed: switch to full screen
|
||||||
else {
|
else {
|
||||||
// save window data
|
// save window data
|
||||||
glfwGetWindowPos(sim->window, sim->windowpos, sim->windowpos+1);
|
Glfw().glfwGetWindowPos(sim->window, sim->windowpos, sim->windowpos+1);
|
||||||
glfwGetWindowSize(sim->window, sim->windowsize, sim->windowsize+1);
|
Glfw().glfwGetWindowSize(sim->window, sim->windowsize, sim->windowsize+1);
|
||||||
|
|
||||||
// switch
|
// switch
|
||||||
glfwSetWindowMonitor(sim->window, glfwGetPrimaryMonitor(), 0, 0,
|
Glfw().glfwSetWindowMonitor(sim->window, Glfw().glfwGetPrimaryMonitor(), 0, 0,
|
||||||
sim->vmode.width, sim->vmode.height, sim->vmode.refreshRate);
|
sim->vmode.width, sim->vmode.height, sim->vmode.refreshRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reinstante vsync, just in case
|
// reinstante vsync, just in case
|
||||||
glfwSwapInterval(sim->vsync);
|
Glfw().glfwSwapInterval(sim->vsync);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 10: // Vertical sync
|
case 10: // Vertical sync
|
||||||
glfwSwapInterval(sim->vsync);
|
Glfw().glfwSwapInterval(sim->vsync);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1617,7 +1622,7 @@ void Simulate::loadmodel() {
|
|||||||
if (this->window && this->m->names) {
|
if (this->window && this->m->names) {
|
||||||
char title[200] = "Simulate : ";
|
char title[200] = "Simulate : ";
|
||||||
mju::strcat_arr(title, this->m->names);
|
mju::strcat_arr(title, this->m->names);
|
||||||
glfwSetWindowTitle(this->window, title);
|
Glfw().glfwSetWindowTitle(this->window, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set keyframe range and divisions
|
// set keyframe range and divisions
|
||||||
@@ -1648,7 +1653,7 @@ void Simulate::prepare() {
|
|||||||
static double lastupdatetm = 0;
|
static double lastupdatetm = 0;
|
||||||
|
|
||||||
// update interval, save update time
|
// update interval, save update time
|
||||||
double tmnow = glfwGetTime();
|
double tmnow = Glfw().glfwGetTime();
|
||||||
double interval = tmnow - lastupdatetm;
|
double interval = tmnow - lastupdatetm;
|
||||||
interval = mjMIN(1, mjMAX(0.0001, interval));
|
interval = mjMIN(1, mjMAX(0.0001, interval));
|
||||||
lastupdatetm = tmnow;
|
lastupdatetm = tmnow;
|
||||||
@@ -1734,7 +1739,7 @@ void Simulate::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
glfwSwapBuffers(this->window);
|
Glfw().glfwSwapBuffers(this->window);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1822,7 +1827,7 @@ void Simulate::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
glfwSwapBuffers(this->window);
|
Glfw().glfwSwapBuffers(this->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1836,27 +1841,27 @@ void Simulate::renderloop() {
|
|||||||
mjcb_time = timer;
|
mjcb_time = timer;
|
||||||
|
|
||||||
// multisampling
|
// multisampling
|
||||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
Glfw().glfwWindowHint(GLFW_SAMPLES, 4);
|
||||||
glfwWindowHint(GLFW_VISIBLE, 1);
|
Glfw().glfwWindowHint(GLFW_VISIBLE, 1);
|
||||||
|
|
||||||
// get videomode and save
|
// get videomode and save
|
||||||
this->vmode = *glfwGetVideoMode(glfwGetPrimaryMonitor());
|
this->vmode = *Glfw().glfwGetVideoMode(Glfw().glfwGetPrimaryMonitor());
|
||||||
|
|
||||||
// create window
|
// create window
|
||||||
this->window = glfwCreateWindow((2*this->vmode.width)/3, (2*this->vmode.height)/3,
|
this->window = Glfw().glfwCreateWindow((2*this->vmode.width)/3, (2*this->vmode.height)/3,
|
||||||
"Simulate", nullptr, nullptr);
|
"Simulate", nullptr, nullptr);
|
||||||
if (!this->window) {
|
if (!this->window) {
|
||||||
glfwTerminate();
|
Glfw().glfwTerminate();
|
||||||
mju_error("could not create window");
|
mju_error("could not create window");
|
||||||
}
|
}
|
||||||
|
|
||||||
// save window position and size
|
// save window position and size
|
||||||
glfwGetWindowPos(this->window, this->windowpos, this->windowpos+1);
|
Glfw().glfwGetWindowPos(this->window, this->windowpos, this->windowpos+1);
|
||||||
glfwGetWindowSize(this->window, this->windowsize, this->windowsize+1);
|
Glfw().glfwGetWindowSize(this->window, this->windowsize, this->windowsize+1);
|
||||||
|
|
||||||
// make context current, set v-sync
|
// make context current, set v-sync
|
||||||
glfwMakeContextCurrent(this->window);
|
Glfw().glfwMakeContextCurrent(this->window);
|
||||||
glfwSwapInterval(this->vsync);
|
Glfw().glfwSwapInterval(this->vsync);
|
||||||
|
|
||||||
// init abstract visualization
|
// init abstract visualization
|
||||||
mjv_defaultCamera(&this->cam);
|
mjv_defaultCamera(&this->cam);
|
||||||
@@ -1906,7 +1911,7 @@ void Simulate::renderloop() {
|
|||||||
uiModify(this->window, &this->ui1, &this->uistate, &this->con);
|
uiModify(this->window, &this->ui1, &this->uistate, &this->con);
|
||||||
|
|
||||||
// run event loop
|
// run event loop
|
||||||
while (!glfwWindowShouldClose(this->window) && !this->exitrequest.load()) {
|
while (!Glfw().glfwWindowShouldClose(this->window) && !this->exitrequest.load()) {
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(this->mtx);
|
const std::lock_guard<std::mutex> lock(this->mtx);
|
||||||
|
|
||||||
@@ -1918,7 +1923,7 @@ void Simulate::renderloop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle events (calls all callbacks)
|
// handle events (calls all callbacks)
|
||||||
glfwPollEvents();
|
Glfw().glfwPollEvents();
|
||||||
|
|
||||||
// prepare to render
|
// prepare to render
|
||||||
this->prepare();
|
this->prepare();
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "lodepng.h"
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
|
|
||||||
|
|||||||
@@ -17,27 +17,33 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include "glfw_dispatch.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using ::mujoco::Glfw;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------ internal GLFW callbacks -------------------------------------
|
//------------------------------------ internal GLFW callbacks -------------------------------------
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
static void uiUpdateState(GLFWwindow* wnd) {
|
static void uiUpdateState(GLFWwindow* wnd) {
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// mouse buttons
|
// mouse buttons
|
||||||
state->left = (glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_LEFT)==GLFW_PRESS);
|
state->left = (Glfw().glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_LEFT)==GLFW_PRESS);
|
||||||
state->right = (glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_RIGHT)==GLFW_PRESS);
|
state->right = (Glfw().glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_RIGHT)==GLFW_PRESS);
|
||||||
state->middle = (glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_MIDDLE)==GLFW_PRESS);
|
state->middle = (Glfw().glfwGetMouseButton(wnd, GLFW_MOUSE_BUTTON_MIDDLE)==GLFW_PRESS);
|
||||||
|
|
||||||
// keyboard modifiers
|
// keyboard modifiers
|
||||||
state->control = (glfwGetKey(wnd, GLFW_KEY_LEFT_CONTROL)==GLFW_PRESS ||
|
state->control = (Glfw().glfwGetKey(wnd, GLFW_KEY_LEFT_CONTROL)==GLFW_PRESS ||
|
||||||
glfwGetKey(wnd, GLFW_KEY_RIGHT_CONTROL)==GLFW_PRESS);
|
Glfw().glfwGetKey(wnd, GLFW_KEY_RIGHT_CONTROL)==GLFW_PRESS);
|
||||||
state->shift = (glfwGetKey(wnd, GLFW_KEY_LEFT_SHIFT)==GLFW_PRESS ||
|
state->shift = (Glfw().glfwGetKey(wnd, GLFW_KEY_LEFT_SHIFT)==GLFW_PRESS ||
|
||||||
glfwGetKey(wnd, GLFW_KEY_RIGHT_SHIFT)==GLFW_PRESS);
|
Glfw().glfwGetKey(wnd, GLFW_KEY_RIGHT_SHIFT)==GLFW_PRESS);
|
||||||
state->alt = (glfwGetKey(wnd, GLFW_KEY_LEFT_ALT)==GLFW_PRESS ||
|
state->alt = (Glfw().glfwGetKey(wnd, GLFW_KEY_LEFT_ALT)==GLFW_PRESS ||
|
||||||
glfwGetKey(wnd, GLFW_KEY_RIGHT_ALT)==GLFW_PRESS);
|
Glfw().glfwGetKey(wnd, GLFW_KEY_RIGHT_ALT)==GLFW_PRESS);
|
||||||
|
|
||||||
// swap left and right if Alt
|
// swap left and right if Alt
|
||||||
if (state->alt) {
|
if (state->alt) {
|
||||||
@@ -48,7 +54,7 @@ static void uiUpdateState(GLFWwindow* wnd) {
|
|||||||
|
|
||||||
// get mouse position, scale by buffer-to-window ratio
|
// get mouse position, scale by buffer-to-window ratio
|
||||||
double x, y;
|
double x, y;
|
||||||
glfwGetCursorPos(wnd, &x, &y);
|
Glfw().glfwGetCursorPos(wnd, &x, &y);
|
||||||
x *= ptr->buffer2window;
|
x *= ptr->buffer2window;
|
||||||
y *= ptr->buffer2window;
|
y *= ptr->buffer2window;
|
||||||
|
|
||||||
@@ -75,7 +81,7 @@ static void uiKeyboard(GLFWwindow* wnd, int key, int scancode, int act, int mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
@@ -84,7 +90,7 @@ static void uiKeyboard(GLFWwindow* wnd, int key, int scancode, int act, int mods
|
|||||||
// set key info
|
// set key info
|
||||||
state->type = mjEVENT_KEY;
|
state->type = mjEVENT_KEY;
|
||||||
state->key = key;
|
state->key = key;
|
||||||
state->keytime = glfwGetTime();
|
state->keytime = Glfw().glfwGetTime();
|
||||||
|
|
||||||
// application-specific processing
|
// application-specific processing
|
||||||
ptr->uiEvent(state);
|
ptr->uiEvent(state);
|
||||||
@@ -95,7 +101,7 @@ static void uiKeyboard(GLFWwindow* wnd, int key, int scancode, int act, int mods
|
|||||||
// mouse button
|
// mouse button
|
||||||
static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
@@ -111,8 +117,8 @@ static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// swap left and right if Alt
|
// swap left and right if Alt
|
||||||
if (glfwGetKey(wnd, GLFW_KEY_LEFT_ALT)==GLFW_PRESS ||
|
if (Glfw().glfwGetKey(wnd, GLFW_KEY_LEFT_ALT)==GLFW_PRESS ||
|
||||||
glfwGetKey(wnd, GLFW_KEY_RIGHT_ALT)==GLFW_PRESS) {
|
Glfw().glfwGetKey(wnd, GLFW_KEY_RIGHT_ALT)==GLFW_PRESS) {
|
||||||
if (button==mjBUTTON_LEFT) {
|
if (button==mjBUTTON_LEFT) {
|
||||||
button = mjBUTTON_RIGHT;
|
button = mjBUTTON_RIGHT;
|
||||||
} else if (button==mjBUTTON_RIGHT) {
|
} else if (button==mjBUTTON_RIGHT) {
|
||||||
@@ -123,7 +129,7 @@ static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
|||||||
// press
|
// press
|
||||||
if (act==GLFW_PRESS) {
|
if (act==GLFW_PRESS) {
|
||||||
// detect doubleclick: 250 ms
|
// detect doubleclick: 250 ms
|
||||||
if (button==state->button && glfwGetTime()-state->buttontime<0.25) {
|
if (button==state->button && Glfw().glfwGetTime()-state->buttontime<0.25) {
|
||||||
state->doubleclick = 1;
|
state->doubleclick = 1;
|
||||||
} else {
|
} else {
|
||||||
state->doubleclick = 0;
|
state->doubleclick = 0;
|
||||||
@@ -132,7 +138,7 @@ static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
|||||||
// set info
|
// set info
|
||||||
state->type = mjEVENT_PRESS;
|
state->type = mjEVENT_PRESS;
|
||||||
state->button = button;
|
state->button = button;
|
||||||
state->buttontime = glfwGetTime();
|
state->buttontime = Glfw().glfwGetTime();
|
||||||
|
|
||||||
// start dragging
|
// start dragging
|
||||||
if (state->mouserect) {
|
if (state->mouserect) {
|
||||||
@@ -161,7 +167,7 @@ static void uiMouseButton(GLFWwindow* wnd, int button, int act, int mods) {
|
|||||||
// mouse move
|
// mouse move
|
||||||
static void uiMouseMove(GLFWwindow* wnd, double xpos, double ypos) {
|
static void uiMouseMove(GLFWwindow* wnd, double xpos, double ypos) {
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// no buttons down: nothing to do
|
// no buttons down: nothing to do
|
||||||
@@ -184,7 +190,7 @@ static void uiMouseMove(GLFWwindow* wnd, double xpos, double ypos) {
|
|||||||
// scroll
|
// scroll
|
||||||
static void uiScroll(GLFWwindow* wnd, double xoffset, double yoffset) {
|
static void uiScroll(GLFWwindow* wnd, double xoffset, double yoffset) {
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
@@ -204,7 +210,7 @@ static void uiScroll(GLFWwindow* wnd, double xoffset, double yoffset) {
|
|||||||
// resize
|
// resize
|
||||||
static void uiResize(GLFWwindow* wnd, int width, int height) {
|
static void uiResize(GLFWwindow* wnd, int width, int height) {
|
||||||
// extract data from user pointer
|
// extract data from user pointer
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
|
|
||||||
// set layout
|
// set layout
|
||||||
@@ -228,13 +234,13 @@ static void uiResize(GLFWwindow* wnd, int width, int height) {
|
|||||||
|
|
||||||
|
|
||||||
static void uiRender(GLFWwindow* wnd) {
|
static void uiRender(GLFWwindow* wnd) {
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
ptr->uiRender(state);
|
ptr->uiRender(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uiDrop(GLFWwindow* wnd, int count, const char** paths) {
|
static void uiDrop(GLFWwindow* wnd, int count, const char** paths) {
|
||||||
uiUserPointer* ptr = (uiUserPointer*)glfwGetWindowUserPointer(wnd);
|
uiUserPointer* ptr = (uiUserPointer*)Glfw().glfwGetWindowUserPointer(wnd);
|
||||||
mjuiState* state = ptr->state;
|
mjuiState* state = ptr->state;
|
||||||
ptr->uiDrop(state, count, paths);
|
ptr->uiDrop(state, count, paths);
|
||||||
}
|
}
|
||||||
@@ -245,14 +251,14 @@ static void uiDrop(GLFWwindow* wnd, int count, const char** paths) {
|
|||||||
int uiFontScale(GLFWwindow* wnd) {
|
int uiFontScale(GLFWwindow* wnd) {
|
||||||
// compute framebuffer-to-window ratio
|
// compute framebuffer-to-window ratio
|
||||||
int width_win, width_buf, height;
|
int width_win, width_buf, height;
|
||||||
glfwGetWindowSize(wnd, &width_win, &height);
|
Glfw().glfwGetWindowSize(wnd, &width_win, &height);
|
||||||
glfwGetFramebufferSize(wnd, &width_buf, &height);
|
Glfw().glfwGetFramebufferSize(wnd, &width_buf, &height);
|
||||||
double b2w = (double)width_buf / (double)width_win;
|
double b2w = (double)width_buf / (double)width_win;
|
||||||
|
|
||||||
// compute PPI
|
// compute PPI
|
||||||
int width_MM, height_MM;
|
int width_MM, height_MM;
|
||||||
glfwGetMonitorPhysicalSize(glfwGetPrimaryMonitor(), &width_MM, &height_MM);
|
Glfw().glfwGetMonitorPhysicalSize(Glfw().glfwGetPrimaryMonitor(), &width_MM, &height_MM);
|
||||||
int width_vmode = glfwGetVideoMode(glfwGetPrimaryMonitor())->width;
|
int width_vmode = Glfw().glfwGetVideoMode(Glfw().glfwGetPrimaryMonitor())->width;
|
||||||
double PPI = 25.4 * b2w * (double)width_vmode / (double)width_MM;
|
double PPI = 25.4 * b2w * (double)width_vmode / (double)width_MM;
|
||||||
|
|
||||||
// estimate font scaling, guard against unrealistic PPI
|
// estimate font scaling, guard against unrealistic PPI
|
||||||
@@ -283,22 +289,22 @@ void uiSetCallback(GLFWwindow* wnd, mjuiState* state,
|
|||||||
ptr->uiLayout = uiLayout;
|
ptr->uiLayout = uiLayout;
|
||||||
ptr->uiRender = uiUserRender;
|
ptr->uiRender = uiUserRender;
|
||||||
ptr->uiDrop = uiUserDrop;
|
ptr->uiDrop = uiUserDrop;
|
||||||
glfwSetWindowUserPointer(wnd, ptr);
|
Glfw().glfwSetWindowUserPointer(wnd, ptr);
|
||||||
|
|
||||||
// compute framebuffer-to-window pixel ratio
|
// compute framebuffer-to-window pixel ratio
|
||||||
int width_win, width_buf, height;
|
int width_win, width_buf, height;
|
||||||
glfwGetWindowSize(wnd, &width_win, &height);
|
Glfw().glfwGetWindowSize(wnd, &width_win, &height);
|
||||||
glfwGetFramebufferSize(wnd, &width_buf, &height);
|
Glfw().glfwGetFramebufferSize(wnd, &width_buf, &height);
|
||||||
ptr->buffer2window = (double)width_buf / (double)width_win;
|
ptr->buffer2window = (double)width_buf / (double)width_win;
|
||||||
|
|
||||||
// set internal callbacks
|
// set internal callbacks
|
||||||
glfwSetKeyCallback(wnd, uiKeyboard);
|
Glfw().glfwSetKeyCallback(wnd, uiKeyboard);
|
||||||
glfwSetCursorPosCallback(wnd, uiMouseMove);
|
Glfw().glfwSetCursorPosCallback(wnd, uiMouseMove);
|
||||||
glfwSetMouseButtonCallback(wnd, uiMouseButton);
|
Glfw().glfwSetMouseButtonCallback(wnd, uiMouseButton);
|
||||||
glfwSetScrollCallback(wnd, uiScroll);
|
Glfw().glfwSetScrollCallback(wnd, uiScroll);
|
||||||
glfwSetWindowSizeCallback(wnd, uiResize);
|
Glfw().glfwSetWindowSizeCallback(wnd, uiResize);
|
||||||
glfwSetWindowRefreshCallback(wnd, uiRender);
|
Glfw().glfwSetWindowRefreshCallback(wnd, uiRender);
|
||||||
glfwSetDropCallback(wnd, uiDrop);
|
Glfw().glfwSetDropCallback(wnd, uiDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -306,19 +312,19 @@ void uiSetCallback(GLFWwindow* wnd, mjuiState* state,
|
|||||||
// Clear UI callbacks in GLFW window.
|
// Clear UI callbacks in GLFW window.
|
||||||
void uiClearCallback(GLFWwindow* wnd) {
|
void uiClearCallback(GLFWwindow* wnd) {
|
||||||
// clear container
|
// clear container
|
||||||
if (glfwGetWindowUserPointer(wnd)) {
|
if (Glfw().glfwGetWindowUserPointer(wnd)) {
|
||||||
mju_free(glfwGetWindowUserPointer(wnd));
|
mju_free(Glfw().glfwGetWindowUserPointer(wnd));
|
||||||
glfwSetWindowUserPointer(wnd, NULL);
|
Glfw().glfwSetWindowUserPointer(wnd, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear internal callbacks
|
// clear internal callbacks
|
||||||
glfwSetKeyCallback(wnd, NULL);
|
Glfw().glfwSetKeyCallback(wnd, NULL);
|
||||||
glfwSetCursorPosCallback(wnd, NULL);
|
Glfw().glfwSetCursorPosCallback(wnd, NULL);
|
||||||
glfwSetMouseButtonCallback(wnd, NULL);
|
Glfw().glfwSetMouseButtonCallback(wnd, NULL);
|
||||||
glfwSetScrollCallback(wnd, NULL);
|
Glfw().glfwSetScrollCallback(wnd, NULL);
|
||||||
glfwSetWindowSizeCallback(wnd, NULL);
|
Glfw().glfwSetWindowSizeCallback(wnd, NULL);
|
||||||
glfwSetWindowRefreshCallback(wnd, NULL);
|
Glfw().glfwSetWindowRefreshCallback(wnd, NULL);
|
||||||
glfwSetDropCallback(wnd, NULL);
|
Glfw().glfwSetDropCallback(wnd, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user