diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61f877c2158..f8576df315e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,7 @@ jobs: if: contains(matrix.os, 'windows') shell: bash -l {0} run: | - bash_vc_install=${VCToolsInstallDir//\\//} + bash_vc_install=${VCToolsInstallDir//\\//} compiler_path=${bash_vc_install}bin/Hostx64/x64/cl.exe echo "CC=${compiler_path}" >> $GITHUB_ENV echo "CXX=${compiler_path}" >> $GITHUB_ENV @@ -182,7 +182,7 @@ jobs: apt-get -y update apt-get -y install \ git build-essential cmake libace-dev coinor-libipopt-dev libeigen3-dev swig \ - libxml2-dev liboctave-dev python3-dev python3-numpy valgrind libassimp-dev libirrlicht-dev curl unzip + libxml2-dev liboctave-dev python3-dev python3-numpy valgrind libassimp-dev libirrlicht-dev curl unzip libglfw3-dev - name: Install files to enable compilation of mex files [apt] run: | diff --git a/.github/workflows/matlab.yml b/.github/workflows/matlab.yml index 29ef82390d7..502f5c63cb2 100644 --- a/.github/workflows/matlab.yml +++ b/.github/workflows/matlab.yml @@ -5,11 +5,11 @@ on: pull_request: schedule: # * is a special character in YAML so you have to quote this string - # Execute a "nightly" build at 2 AM UTC + # Execute a "nightly" build at 2 AM UTC - cron: '0 2 * * *' - + jobs: - build-matlab-tests: + build-matlab-tests: name: '[matlab:${{ matrix.matlab_version }}:${{ matrix.os }}]' runs-on: ${{ matrix.os }} defaults: @@ -56,14 +56,14 @@ jobs: run: | # Workaround for https://github.com/conda-incubator/setup-miniconda/issues/186 conda config --remove channels defaults - # Compilation related dependencies + # Compilation related dependencies mamba install cmake compilers make ninja pkg-config # Actual dependencies - mamba install eigen libxml2 assimp ipopt irrlicht osqp-eigen + mamba install eigen libxml2 assimp ipopt irrlicht osqp-eigen glfw # Additional dependencies useful only on Linux - name: Dependencies [Conda/Linux] - if: contains(matrix.os, 'ubuntu') + if: contains(matrix.os, 'ubuntu') run: | # Additional dependencies only useful on Linux # See https://github.com/robotology/robotology-superbuild/issues/477 @@ -71,7 +71,7 @@ jobs: # Additional dependencies useful only on Windows - name: Dependencies [Conda/Windows] - if: contains(matrix.os, 'windows') + if: contains(matrix.os, 'windows') run: | # Additional dependencies only useful on Windows # See https://github.com/robotology/robotology-superbuild/issues/477 @@ -120,8 +120,8 @@ jobs: run: | cd build # Only run matlab tests as the rest of tests are already run by other jobs - ctest --output-on-failure -C ${{ matrix.build_type }} -R "matlab" -VV . - + ctest --output-on-failure -C ${{ matrix.build_type }} -R "matlab" -VV . + - name: Install [Conda] run: | cd build diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index e83dcfbc719..f1f62de4816 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -46,7 +46,8 @@ jobs: swig \ libxml2-dev \ libassimp-dev \ - libirrlicht-dev + libirrlicht-dev \ + libglfw3-dev pip install build - name: Build sdist diff --git a/CHANGELOG.md b/CHANGELOG.md index eb712e613ee..3452370e2fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [8.999.0] - 2023-03-05 +## [8.999.0] - YYYY-MM-DD ### Fixed - Fix export of `iDynTree::PrismaticJoint` in `iDynTree::getRandomModel` (https://github.com/robotology/idyntree/pull/1057). @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Binary wheels available on PyPI now target `manylinux_2_28`, and the options `IDYNTREE_USES_ASSIMP`, `IDYNTREE_USES_IPOPT` and `IDYNTREE_USES_IRRLICHT` are disable in binary wheels on PyPI. If you need these options enabled, please use conda-forge binaries or build iDynTree from source (https://github.com/robotology/idyntree/pull/1068). +- Compilation with `IDYNTREE_USES_IRRLICHT` set to `ON` now requires `glfw` library. Furthermore, now `IDYNTREE_USES_IRRLICHT` on Windows requires irrlicht to be compiled with SDL support. This changes have been done to support resizable visualizer windows on Windows (https://github.com/robotology/idyntree/issues/1070, https://github.com/robotology/idyntree/pull/1071). - Use iDynTree::InverseKinematicsRotationParametrizationRollPitchYaw as default parametrization in iDynTree::InverseKinematics (https://github.com/robotology/idyntree/pull/1058). #### URDF XML parser change diff --git a/ci_env.yml b/ci_env.yml index 17708ca19a7..4deadbae125 100644 --- a/ci_env.yml +++ b/ci_env.yml @@ -13,6 +13,7 @@ dependencies: - assimp - ipopt - irrlicht + - glfw - swig - pybind11 - python diff --git a/src/visualization/CMakeLists.txt b/src/visualization/CMakeLists.txt index ba4972665af..662c9e643a7 100644 --- a/src/visualization/CMakeLists.txt +++ b/src/visualization/CMakeLists.txt @@ -72,8 +72,9 @@ target_compile_options(${libraryname} PRIVATE ${IDYNTREE_WARNING_FLAGS}) if(IDYNTREE_USES_IRRLICHT) find_package(OpenGL) find_package(Irrlicht REQUIRED) + find_package(glfw3 REQUIRED) - target_link_libraries(${libraryname} PRIVATE Irrlicht::Irrlicht) + target_link_libraries(${libraryname} PRIVATE Irrlicht::Irrlicht glfw) if(TARGET OpenGL::GL) target_link_libraries(${libraryname} PRIVATE OpenGL::GL) endif() diff --git a/src/visualization/src/Camera.cpp b/src/visualization/src/Camera.cpp index d6412761613..fd8c1fc3482 100644 --- a/src/visualization/src/Camera.cpp +++ b/src/visualization/src/Camera.cpp @@ -51,6 +51,12 @@ void Camera::setAspectRatio(double aspectRatio) } } +void Camera::setWindowDimensions(unsigned int width, unsigned int height) +{ + setAspectRatio(width/ (float)height); + m_animator->setWindowDimensions(width, height); +} + void Camera::setIrrlichtCamera(irr::scene::ICameraSceneNode* cam) { m_irrCamera = cam; diff --git a/src/visualization/src/Camera.h b/src/visualization/src/Camera.h index ab68f1848c9..61e47488e3a 100644 --- a/src/visualization/src/Camera.h +++ b/src/visualization/src/Camera.h @@ -36,6 +36,8 @@ class Camera: public ICamera void setAspectRatio(double aspectRatio); + void setWindowDimensions(unsigned int width, unsigned int height); + virtual void setPosition(const Position& cameraPos); virtual void setTarget(const Position& targetPos); virtual void setUpVector(const Direction& upVector); diff --git a/src/visualization/src/CameraAnimator.cpp b/src/visualization/src/CameraAnimator.cpp index 85d049a57d1..942674235a7 100644 --- a/src/visualization/src/CameraAnimator.cpp +++ b/src/visualization/src/CameraAnimator.cpp @@ -16,22 +16,17 @@ namespace iDynTree { //! constructor -CameraAnimator::CameraAnimator(irr::gui::ICursorControl* cursor, irr::scene::ISceneNode *cameraAxis, +CameraAnimator::CameraAnimator(irr::scene::ISceneNode *cameraAxis, unsigned int windowWidth, unsigned int windowHeight, double rotateSpeed, double zoomSpeed, double translateSpeed) - : m_cursorControl(cursor), m_mousePos(0.5f, 0.5f), m_initialMousePosition(m_mousePos), + : m_mousePos(0.5f, 0.5f), m_initialMousePosition(m_mousePos), m_zoomSpeed(zoomSpeed), m_rotateSpeed(rotateSpeed), m_translateSpeed(translateSpeed), - m_zooming(false), m_rotating(false), m_movingUp(false), m_translating(false), m_isEnabled(false) + m_zooming(false), m_rotating(false), m_movingUp(false), m_translating(false), m_isEnabled(false), + m_width(windowWidth), m_height(windowHeight) { #ifdef _DEBUG setDebugName("iDynTreeCameraAnimator"); #endif - if (m_cursorControl) - { - m_cursorControl->grab(); - m_mousePos = m_cursorControl->getRelativePosition(); - } - allKeysUp(); m_cameraAxis = cameraAxis; @@ -41,8 +36,13 @@ CameraAnimator::CameraAnimator(irr::gui::ICursorControl* cursor, irr::scene::ISc //! destructor CameraAnimator::~CameraAnimator() { - if (m_cursorControl) - m_cursorControl->drop(); + +} + +void CameraAnimator::setWindowDimensions(unsigned int width, unsigned int height) +{ + m_width = width; + m_height = height; } @@ -60,11 +60,11 @@ bool CameraAnimator::OnEvent(const irr::SEvent& event) { case irr::EMIE_LMOUSE_PRESSED_DOWN: m_mouseKeys[0] = true; - m_initialMousePosition = m_cursorControl->getRelativePosition(); + m_initialMousePosition = m_mousePos; break; case irr::EMIE_RMOUSE_PRESSED_DOWN: m_mouseKeys[2] = true; - m_initialMousePosition = m_cursorControl->getRelativePosition(); + m_initialMousePosition = m_mousePos; break; case irr::EMIE_MMOUSE_PRESSED_DOWN: m_mouseKeys[1] = true; @@ -79,7 +79,7 @@ bool CameraAnimator::OnEvent(const irr::SEvent& event) m_mouseKeys[1] = false; break; case irr::EMIE_MOUSE_MOVED: - m_mousePos = m_cursorControl->getRelativePosition(); + m_mousePos.set(static_cast(event.MouseInput.X) / m_width, static_cast(event.MouseInput.Y) / m_height); break; case irr::EMIE_MOUSE_WHEEL: m_wheelMoving = true; @@ -328,7 +328,7 @@ double CameraAnimator::getZoomSpeed() const irr::scene::ISceneNodeAnimator* CameraAnimator::createClone(irr::scene::ISceneNode* /*node*/, irr::scene::ISceneManager* /*newManager*/) { CameraAnimator * newAnimator = - new CameraAnimator(m_cursorControl, m_cameraAxis->clone(), m_rotateSpeed, m_zoomSpeed, m_translateSpeed); + new CameraAnimator(m_cameraAxis->clone(), m_width, m_height, m_rotateSpeed, m_zoomSpeed, m_translateSpeed); return newAnimator; } diff --git a/src/visualization/src/CameraAnimator.h b/src/visualization/src/CameraAnimator.h index ce8d32392db..d2dc3748a4b 100644 --- a/src/visualization/src/CameraAnimator.h +++ b/src/visualization/src/CameraAnimator.h @@ -21,12 +21,14 @@ namespace iDynTree { public: //! Constructor - CameraAnimator(irr::gui::ICursorControl* cursor, irr::scene::ISceneNode *cameraAxis, double rotateSpeed = 10.0f, + CameraAnimator(irr::scene::ISceneNode *cameraAxis, unsigned int windowWidth, unsigned int windowHeight, double rotateSpeed = 10.0f, double zoomSpeed = 0.5f, double translationSpeed = 10.0f); //! Destructor virtual ~CameraAnimator(); + void setWindowDimensions(unsigned int width, unsigned int height); + //! Animates the scene node, currently only works on cameras virtual void animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs) override; @@ -78,7 +80,6 @@ namespace iDynTree bool m_wheelMoving; irr::f32 m_wheelDirection; - irr::gui::ICursorControl *m_cursorControl; irr::scene::ISceneNode *m_cameraAxis; irr::core::position2df m_mousePos; irr::core::position2df m_initialMousePosition; @@ -90,6 +91,8 @@ namespace iDynTree bool m_movingUp; bool m_translating; bool m_isEnabled; + unsigned int m_width; + unsigned int m_height; }; } // end namespace irr diff --git a/src/visualization/src/Visualizer.cpp b/src/visualization/src/Visualizer.cpp index 6234e7d6534..188f345ec7b 100644 --- a/src/visualization/src/Visualizer.cpp +++ b/src/visualization/src/Visualizer.cpp @@ -24,6 +24,20 @@ #include "CameraAnimator.h" #include "Label.h" +#if defined(_WIN32) + #define GLFW_EXPOSE_NATIVE_WIN32 + #define GLFW_EXPOSE_NATIVE_WGL +#elif defined(__APPLE__) + #define GLFW_EXPOSE_NATIVE_COCOA + #define GLFW_EXPOSE_NATIVE_NSGL +#elif defined(__linux__) + #define GLFW_EXPOSE_NATIVE_X11 + #define GLFW_EXPOSE_NATIVE_GLX +#endif + +#include +#include + #if defined(_WIN32) && defined(_IRR_COMPILE_WITH_SDL_DEVICE_) // Required by SetEnvironmentVariableA, _putenv is not unsetting // correctly the variables @@ -118,6 +132,22 @@ struct Visualizer::VisualizerPimpl int lastFPS; #ifdef IDYNTREE_USES_IRRLICHT + + /** + * Custom window object + */ + GLFWwindow* m_window{nullptr}; + + static unsigned int m_glfwInstances; + +#if defined(_WIN32) + HWND m_windowId; +#elif defined(__APPLE__) + id m_windowId; +#elif defined(__linux__) + Window m_windowId; +#endif + /** * Collection of model visualization. */ @@ -214,6 +244,145 @@ struct Visualizer::VisualizerPimpl m_palette["meshcat"].zAxis = irr::video::SColor(alphaLev,66,133,244); m_palette["meshcat"].vector = irr::video::SColor(255,253,98,2); } + + void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos) + { + if (window != m_window) + { + return; + } + + if (!m_isInitialized) + { + return; + } + + GLint ww, wh; + glfwGetWindowSize(window, &ww, &wh); + + irr::SEvent::SMouseInput mouseEvent; + + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_MOUSE_MOVED; + mouseEvent.X = xpos; + mouseEvent.Y = ypos; + + irr::SEvent event; + event.EventType = irr::EEVENT_TYPE::EET_MOUSE_INPUT_EVENT; + event.MouseInput = mouseEvent; + + m_irrDevice->postEventFromUser(event); + } + + void mouseButtonCallback(GLFWwindow* window, int button, int action, int) + { + if (window != m_window) + { + return; + } + + if (!m_isInitialized) + { + return; + } + + irr::SEvent::SMouseInput mouseEvent; + + if (button == GLFW_MOUSE_BUTTON_RIGHT) + { + if (action == GLFW_PRESS) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_RMOUSE_PRESSED_DOWN; + } + else if (action == GLFW_RELEASE) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_RMOUSE_LEFT_UP; + } + else + { + return; + } + } + else if (button == GLFW_MOUSE_BUTTON_LEFT) + { + if (action == GLFW_PRESS) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_LMOUSE_PRESSED_DOWN; + } + else if (action == GLFW_RELEASE) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_LMOUSE_LEFT_UP; + } + else + { + return; + } + } + else if (button == GLFW_MOUSE_BUTTON_MIDDLE) + { + if (action == GLFW_PRESS) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_MMOUSE_PRESSED_DOWN; + } + else if (action == GLFW_RELEASE) + { + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_MMOUSE_LEFT_UP; + } + else + { + return; + } + } + else + { + return; + } + + irr::SEvent event; + event.EventType = irr::EEVENT_TYPE::EET_MOUSE_INPUT_EVENT; + event.MouseInput = mouseEvent; + + m_irrDevice->postEventFromUser(event); + } + + void scrollCallback(GLFWwindow* window, double, double yoffset) + { + if (window != m_window) + { + return; + } + + if (!m_isInitialized) + { + return; + } + + irr::SEvent::SMouseInput mouseEvent; + + mouseEvent.Event = irr::EMOUSE_INPUT_EVENT::EMIE_MOUSE_WHEEL; + mouseEvent.Wheel = yoffset; + + irr::SEvent event; + event.EventType = irr::EEVENT_TYPE::EET_MOUSE_INPUT_EVENT; + event.MouseInput = mouseEvent; + + m_irrDevice->postEventFromUser(event); + } + + static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) + { + static_cast(glfwGetWindowUserPointer(window))->cursorPositionCallback(window, xpos, ypos); + } + + static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) + { + static_cast(glfwGetWindowUserPointer(window))->mouseButtonCallback(window, button, action, mods); + } + + static void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) + { + static_cast(glfwGetWindowUserPointer(window))->scrollCallback(window, xoffset, yoffset); + } + #else DummyCamera m_camera; DummyEnvironment m_environment; @@ -237,6 +406,11 @@ struct Visualizer::VisualizerPimpl } }; +#ifdef IDYNTREE_USES_IRRLICHT + +unsigned int Visualizer::VisualizerPimpl::m_glfwInstances = 0; + +#endif Visualizer::Visualizer(const Visualizer& /*other*/) { @@ -274,19 +448,53 @@ bool Visualizer::init(const VisualizerOptions &visualizerOptions) // initialize the color palette pimpl->initializePalette(); + if (pimpl->m_glfwInstances == 0) + { + if (!glfwInit()) { + reportError("Visualizer", "init", "Unable to initialize GLFW"); + return false; + } + + glfwWindowHint(GLFW_SAMPLES, 4); //Antialiasing + } + pimpl->m_glfwInstances++; + + pimpl->m_window = glfwCreateWindow(visualizerOptions.winWidth, visualizerOptions.winHeight, "iDynTree Visualizer", nullptr, nullptr); + if (!pimpl->m_window) { + reportError("Visualizer","init","Could not create window"); + return false; + } + + glfwMakeContextCurrent(pimpl->m_window); + glfwSwapInterval(1); + irr::SIrrlichtCreationParameters irrDevParams; -// If we are on Windows and the SDL backend of Irrlicht is available, -// let's use it to avoid spurios WM_QUIT signal being raised in the -// close() method, see https://github.com/robotology/idyntree/issues/975 -#if defined(_WIN32) && defined(_IRR_COMPILE_WITH_SDL_DEVICE_) +// If we are on Windows, only SDL works with the external window +#if defined(_WIN32) +#ifndef _IRR_COMPILE_WITH_SDL_DEVICE_ +#error "On Windows it is necessary to use Irrlicht with SDL" +#endif irrDevParams.DeviceType = irr::EIDT_SDL; #endif + irrDevParams.DriverType = irr::video::EDT_OPENGL; irrDevParams.WindowSize = irr::core::dimension2d(visualizerOptions.winWidth, visualizerOptions.winHeight); irrDevParams.WithAlphaChannel = true; irrDevParams.AntiAlias = 4; +#if defined(_WIN32) + pimpl->m_windowId = glfwGetWin32Window(pimpl->m_window); + irrDevParams.WindowId = (void*)(pimpl->m_windowId); +#elif defined(__APPLE__) + pimpl->m_windowId = glfwGetCocoaWindow(pimpl->m_window); + irrDevParams.WindowId = (void*)(pimpl->m_windowId); +#elif defined(__linux__) + pimpl->m_windowId = glfwGetX11Window(pimpl->m_window); + irrDevParams.WindowId = (void*)(pimpl->m_windowId); +#endif + + if( visualizerOptions.verbose ) { reportWarning("Visualizer","init","verbose flag found, enabling verbose output in Visualizer"); @@ -346,8 +554,7 @@ bool Visualizer::init(const VisualizerOptions &visualizerOptions) pimpl->m_environment.init(pimpl->m_irrSmgr, pimpl->rootFrameArrowsDimension); pimpl->m_camera.setIrrlichtCamera(addVizCamera(pimpl->m_irrSmgr)); - pimpl->m_camera.setCameraAnimator(new CameraAnimator(pimpl->m_irrDevice->getCursorControl(), - addFrameAxes(pimpl->m_irrSmgr, 0, 0.1))); + pimpl->m_camera.setCameraAnimator(new CameraAnimator(addFrameAxes(pimpl->m_irrSmgr, 0, 0.1), visualizerOptions.winWidth, visualizerOptions.winHeight)); pimpl->m_vectors.init(pimpl->m_irrSmgr); @@ -355,6 +562,11 @@ bool Visualizer::init(const VisualizerOptions &visualizerOptions) pimpl->m_textures.init(pimpl->m_irrDriver, pimpl->m_irrSmgr); + glfwSetWindowUserPointer(pimpl->m_window, pimpl); + glfwSetCursorPosCallback(pimpl->m_window, VisualizerPimpl::cursor_position_callback); + glfwSetMouseButtonCallback(pimpl->m_window, VisualizerPimpl::mouse_button_callback); + glfwSetScrollCallback(pimpl->m_window, VisualizerPimpl::scroll_callback); + pimpl->m_isInitialized = true; pimpl->lastFPS = -1; @@ -462,13 +674,17 @@ void Visualizer::draw() return; } + glfwMakeContextCurrent(pimpl->m_window); + pimpl->m_irrDriver->beginScene(true,true, pimpl->m_environment.m_backgroundColor.toSColor(), pimpl->m_irrVideoData); pimpl->m_irrDriver->setViewPort(irr::core::rect(0, 0, winWidth, winHeight)); + pimpl->m_irrDriver->OnResize(irr::core::dimension2d(winWidth, winHeight)); + pimpl->m_textures.draw(pimpl->m_environment, pimpl->m_camera, true); - pimpl->m_camera.setAspectRatio(winWidth/ (float)winHeight); + pimpl->m_camera.setWindowDimensions(winWidth, winHeight); pimpl->m_irrSmgr->drawAll(); } @@ -476,6 +692,10 @@ void Visualizer::draw() pimpl->m_irrDriver->endScene(); pimpl->m_subDrawStarted = false; + glfwSwapBuffers(pimpl->m_window); + + glfwPollEvents(); + int fps = pimpl->m_irrDriver->getFPS(); if (pimpl->lastFPS != fps) @@ -485,8 +705,10 @@ void Visualizer::draw() str += "] FPS:"; str += fps; str += " "; + irr::core::stringc strc(str); pimpl->m_irrDevice->setWindowCaption(str.c_str()); + glfwSetWindowTitle(pimpl->m_window, strc.c_str()); pimpl->lastFPS = fps; } @@ -524,6 +746,7 @@ void Visualizer::subDraw(int xOffsetFromTopLeft, int yOffsetFromTopLeft, int sub bool clearTextureBuffers = false; if (!pimpl->m_subDrawStarted) { + glfwMakeContextCurrent(pimpl->m_window); pimpl->m_irrDriver->beginScene(true,true, pimpl->m_environment.m_backgroundColor.toSColor(), pimpl->m_irrVideoData); pimpl->m_subDrawStarted = true; clearTextureBuffers = true; @@ -533,7 +756,10 @@ void Visualizer::subDraw(int xOffsetFromTopLeft, int yOffsetFromTopLeft, int sub pimpl->m_camera.setAspectRatio(subImageWidth/ (float)subImageHeight); - pimpl->m_irrDriver->setViewPort(irr::core::rect(0, 0, width(), height())); //workaround for http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=47004 + int winWidth = width(); + int winHeight = height(); + pimpl->m_irrDriver->OnResize(irr::core::dimension2d(winWidth, winHeight)); + pimpl->m_irrDriver->setViewPort(irr::core::rect(0, 0, winWidth, winHeight)); //workaround for http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=47004 pimpl->m_irrDriver->setViewPort(irr::core::rect(xOffsetFromTopLeft, yOffsetFromTopLeft, xOffsetFromTopLeft + subImageWidth, yOffsetFromTopLeft + subImageHeight)); @@ -689,8 +915,10 @@ int Visualizer::width() const return 0; } - auto winDimensions = pimpl->m_irrDriver->getScreenSize(); - return winDimensions.Width; + GLint ww, wh; + glfwGetWindowSize(pimpl->m_window, &ww, &wh); + + return ww; #else return 0; #endif @@ -705,8 +933,9 @@ int Visualizer::height() const return 0; } - auto winDimensions = pimpl->m_irrDriver->getScreenSize(); - return winDimensions.Height; + GLint ww, wh; + glfwGetWindowSize(pimpl->m_window, &ww, &wh); + return wh; #else return 0; #endif @@ -721,7 +950,7 @@ bool Visualizer::run() return false; } - return pimpl->m_irrDevice->run(); + return pimpl->m_irrDevice->run() && !glfwWindowShouldClose(pimpl->m_window); #else reportError("Visualizer","run","Impossible to use iDynTree::Visualizer, as iDynTree has been compiled without Irrlicht."); return false; @@ -735,6 +964,7 @@ void Visualizer::close() { return; } + glfwMakeContextCurrent(pimpl->m_window); pimpl->m_vectors.close(); pimpl->m_frames.close(); @@ -756,6 +986,20 @@ void Visualizer::close() pimpl->m_modelViz.resize(0); + if (pimpl->m_window) + { + glfwMakeContextCurrent(pimpl->m_window); + glfwDestroyWindow(pimpl->m_window); + + pimpl->m_glfwInstances--; + if (pimpl->m_glfwInstances == 0) + { + glfwTerminate(); + } + + pimpl->m_window = nullptr; + } + return; #endif } diff --git a/src/visualization/tests/VisualizerUnitTest.cpp b/src/visualization/tests/VisualizerUnitTest.cpp index 7e6ee62f7ef..5627e337ff9 100644 --- a/src/visualization/tests/VisualizerUnitTest.cpp +++ b/src/visualization/tests/VisualizerUnitTest.cpp @@ -280,6 +280,9 @@ void checkDoubleViz() viz1.draw(); viz2.draw(); } + + viz1.close(); + viz2.close(); } int main()