From 306de580835123d8e92e241b1f547b46ad26770c Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Sun, 7 Feb 2021 10:39:51 +0100 Subject: [PATCH] add cross-platform CI with conda packages --- .github/ci_env.yml | 48 +++++++++ .github/workflows/ci.yml | 97 +++++++++++++++++++ CMakeLists.txt | 18 ++-- ogre_media/fonts/ogre1.10.fontdef | 9 ++ src/python_bindings/CMakeLists.txt | 8 +- src/rviz/default_plugin/camera_display.cpp | 27 +++++- src/rviz/default_plugin/camera_display.h | 4 + src/rviz/default_plugin/image_display.cpp | 24 ++++- src/rviz/default_plugin/image_display.h | 8 +- .../interactive_marker_control.h | 5 + src/rviz/default_plugin/marker_display.cpp | 4 + src/rviz/default_plugin/marker_utils.cpp | 4 + src/rviz/ogre_helpers/render_system.cpp | 16 ++- src/rviz/render_panel.cpp | 7 ++ src/rviz/render_panel.h | 2 + src/rviz/yaml_config_writer.cpp | 2 + 16 files changed, 256 insertions(+), 27 deletions(-) create mode 100644 .github/ci_env.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/ci_env.yml b/.github/ci_env.yml new file mode 100644 index 0000000000..b8d9254da7 --- /dev/null +++ b/.github/ci_env.yml @@ -0,0 +1,48 @@ +name: test +channels: + - robostack + - conda-forge +dependencies: + # build deps + - compilers + - ninja + - cmake + - catkin_pkg + # Other deps + - assimp + - eigen + - ogre 1.10.* + - python 3.8.* + - qt 5.12.* + - ros-distro-mutex 0.1 noetic + - ros-noetic-catkin + - ros-noetic-cmake-modules + - ros-noetic-geometry-msgs + - ros-noetic-image-transport + - ros-noetic-interactive-markers + - ros-noetic-laser-geometry + - ros-noetic-map-msgs + - ros-noetic-message-filters + - ros-noetic-message-generation + - ros-noetic-nav-msgs + - ros-noetic-pluginlib + - ros-noetic-python-qt-binding + - ros-noetic-resource-retriever + - ros-noetic-rosbag + - ros-noetic-rosconsole + - ros-noetic-roscpp + - ros-noetic-roslib + - ros-noetic-rospy + - ros-noetic-rostest + - ros-noetic-rosunit + - ros-noetic-sensor-msgs + - ros-noetic-std-msgs + - ros-noetic-std-srvs + - ros-noetic-tf2-geometry-msgs + - ros-noetic-tf2-ros + - ros-noetic-urdf + - ros-noetic-visualization-msgs + - tinyxml2 + - urdfdom 1.0.* + - urdfdom_headers 1.0.* + - yaml-cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..a496b2f60e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,97 @@ +name: Build RViz on all platforms + +on: push + +jobs: + run_rviz_compilation: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + steps: + - uses: actions/checkout@v2 + - name: Set up Dependencies + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: .github/ci_env.yml + - name: Install System Dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get install libglew-dev mesa-utils xvfb libgl1-mesa-glx libgl1-mesa-dev libglu1-mesa libglu1-mesa-dev \ + libselinux1 libxdamage1 libxfixes3 libxxf86vm1 + + - name: Build RViz on Unix + if: runner.os == 'Linux' || runner.os == 'macOS' + shell: bash -l -eo pipefail {0} + run: | + if [[ `uname -s` == "Linux" ]]; then + CDT="-cos6-x86_64" + micromamba install -y mesa-libgl-devel$CDT mesa-dri-drivers$CDT \ + libselinux$CDT libxdamage$CDT libxxf86vm$CDT \ + libxext$CDT libxfixes$CDT -c conda-forge + fi + + export CTEST_OUTPUT_ON_FAILURE=1 + + mkdir build + cd build + + cmake .. -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ + -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ + -DCMAKE_BUILD_TYPE=Release \ + -DCATKIN_SKIP_TESTING=OFF \ + -G "Ninja" + + ninja + ninja run_tests + + - name: Build RViz on Windows + if: runner.os == 'Windows' + shell: powershell + run: | + micromamba shell hook -s cmd.exe -p C:\Users\runneradmin\micromamba + Get-Content -Path C:\Users\runneradmin\micromamba\condabin\mamba_hook.bat + + - name: Build RViz on Windows + if: runner.os == 'Windows' + shell: cmd + run: | + + echo "Remove unnecessary / colliding things from PATH" + + set "PATH=%PATH:C:\ProgramData\Chocolatey\bin;=%" + set "PATH=%PATH:C:\Program Files (x86)\sbt\bin;=%" + set "PATH=%PATH:C:\Rust\.cargo\bin;=%" + set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%" + set "PATH=%PATH:C:\Program Files\Git\cmd;=%" + set "PATH=%PATH:C:\Program Files\Git\mingw64\bin;=%" + set "PATH=%PATH:C:\Program Files (x86)\Subversion\bin;=%" + set "PATH=%PATH:C:\Program Files\CMake\bin;=%" + set "PATH=%PATH:C:\Program Files\OpenSSL\bin;=%" + set "PATH=%PATH:C:\Strawberry\c\bin;=%" + set "PATH=%PATH:C:\Strawberry\perl\bin;=%" + set "PATH=%PATH:C:\Strawberry\perl\site\bin;=%" + set "PATH=%PATH:c:\tools\php;=%" + :: Make paths like C:\\hostedtoolcache\\windows\\Ruby\\2.5.7\\x64\\bin garbage + set "PATH=%PATH:ostedtoolcache=%" + + echo "Activate environment, and compile" + + call C:\Users\runneradmin\micromamba\condabin\micromamba.bat activate test + + SET "PYTHONPATH=%CONDA_PREFIX%\Library\lib\site-packages" + + mkdir build + cd build + SET "CTEST_OUTPUT_ON_FAILURE=1" + + cmake .. -DCMAKE_PREFIX_PATH="%CONDA_PREFIX%\Library" ^ + -DCMAKE_INSTALL_PREFIX="%CONDA_PREFIX%\Library" ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DCATKIN_SKIP_TESTING=OFF ^ + -DBoost_USE_STATIC_LIBS=OFF ^ + -G "Ninja" + + ninja + ninja run_tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 23719c1b44..1b7e6f93db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,13 +24,7 @@ find_package(Boost REQUIRED ) find_package(urdfdom_headers REQUIRED) - -set(CMAKE_POLICY_DEFAULT_CMP0012 NEW) # required due to a bug in assimp 5.0 -find_package(ASSIMP REQUIRED) -if(NOT DEFINED ASSIMP_LIBRARIES AND TARGET assimp::assimp) - # ASSIMP >= 5.0 no longer defines ASSIMP_LIBRARIES - set(ASSIMP_LIBRARIES assimp::assimp) -endif() +find_package(assimp REQUIRED) find_package(OGRE QUIET COMPONENTS Overlay) if(OGRE_FOUND) @@ -102,10 +96,10 @@ if(APPLE) endif() # Prefer newer vender-specific OpenGL library -if (POLICY CMP0072) - cmake_policy(SET CMP0072 NEW) -endif() -find_package(OpenGL REQUIRED) +# if (POLICY CMP0072) +# cmake_policy(SET CMP0072 NEW) +# endif() +# find_package(OpenGL REQUIRED) set(CMAKE_AUTOMOC ON) @@ -219,7 +213,7 @@ catkin_package( #catkin_lint: ignore_once external_directory include_directories(src ${EXPORT_HEADER_DIR}) -include_directories(SYSTEM +include_directories( ${EIGEN3_INCLUDE_DIRS} ${OGRE_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} diff --git a/ogre_media/fonts/ogre1.10.fontdef b/ogre_media/fonts/ogre1.10.fontdef index 4b3c5b82a6..e714db0f13 100644 --- a/ogre_media/fonts/ogre1.10.fontdef +++ b/ogre_media/fonts/ogre1.10.fontdef @@ -1,3 +1,12 @@ +Liberation Sans +{ + type truetype + source liberation-sans/LiberationSans-Regular.ttf + size 18 + resolution 96 +} + +# Ogre >= 1.10 has changed the format font "Liberation Sans" { type truetype diff --git a/src/python_bindings/CMakeLists.txt b/src/python_bindings/CMakeLists.txt index aedb7ad06b..1f5d1a0872 100644 --- a/src/python_bindings/CMakeLists.txt +++ b/src/python_bindings/CMakeLists.txt @@ -2,9 +2,9 @@ set(rviz_BINDINGS "") # TODO(wjwwood): re-enabled PySide2 support when it is fixed. # add_subdirectory(shiboken) -add_subdirectory(sip) +# add_subdirectory(sip) message(STATUS "Python binding generators: ${rviz_BINDINGS}") -if(NOT rviz_BINDINGS) - message(FATAL_ERROR "No Python binding generator found.") -endif() +# if(NOT rviz_BINDINGS) +# message(FATAL_ERROR "No Python binding generator found.") +# endif() diff --git a/src/rviz/default_plugin/camera_display.cpp b/src/rviz/default_plugin/camera_display.cpp index 49abcfea8f..8afa2b158b 100644 --- a/src/rviz/default_plugin/camera_display.cpp +++ b/src/rviz/default_plugin/camera_display.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,8 @@ CameraDisplay::CameraDisplay() SLOT(forceRender())); zoom_property_->setMin(0.00001); zoom_property_->setMax(100000); + + has_run_once_ = false; } CameraDisplay::~CameraDisplay() @@ -127,8 +130,15 @@ void CameraDisplay::onInitialize() { ImageDisplayBase::onInitialize(); - bg_scene_node_ = scene_node_->createChildSceneNode(); - fg_scene_node_ = scene_node_->createChildSceneNode(); + { + static uint32_t count = 0; + std::stringstream ss; + ss << "CameraDisplay" << count++; + camera_scene_manager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC, ss.str()); + } + + bg_scene_node_ = camera_scene_manager_->getRootSceneNode()->createChildSceneNode(); + fg_scene_node_ = camera_scene_manager_->getRootSceneNode()->createChildSceneNode(); { static int count = 0; @@ -189,6 +199,7 @@ void CameraDisplay::onInitialize() render_panel_->getRenderWindow()->setActive(false); render_panel_->resize(640, 480); render_panel_->initialize(context_->getSceneManager(), context_); + // render_panel_->initialize(camera_scene_manager_, context_); setAssociatedWidget(render_panel_); @@ -212,8 +223,16 @@ void CameraDisplay::onInitialize() void CameraDisplay::preRenderTargetUpdate(const Ogre::RenderTargetEvent& /*evt*/) { QString image_position = image_position_property_->getString(); - bg_scene_node_->setVisible(caminfo_ok_ && (image_position == BACKGROUND || image_position == BOTH)); - fg_scene_node_->setVisible(caminfo_ok_ && (image_position == OVERLAY || image_position == BOTH)); + + if (has_run_once_) + { + fg_scene_node_->setVisible(caminfo_ok_ && (image_position == OVERLAY || image_position == BOTH)); + bg_scene_node_->setVisible(caminfo_ok_ && (image_position == BACKGROUND || image_position == BOTH)); + } + else + { + has_run_once_ = true; + } // set view flags on all displays visibility_property_->update(); diff --git a/src/rviz/default_plugin/camera_display.h b/src/rviz/default_plugin/camera_display.h index 175a3a2402..ccd4d6f3e9 100644 --- a/src/rviz/default_plugin/camera_display.h +++ b/src/rviz/default_plugin/camera_display.h @@ -96,6 +96,8 @@ class CameraDisplay : public ImageDisplayBase, public Ogre::RenderTargetListener ROSImageTexture texture_; RenderPanel* render_panel_; + Ogre::SceneManager* camera_scene_manager_; + private Q_SLOTS: void forceRender(); void updateAlpha(); @@ -135,6 +137,8 @@ private Q_SLOTS: bool force_render_; uint32_t vis_bit_; + + bool has_run_once_; }; } // namespace rviz diff --git a/src/rviz/default_plugin/image_display.cpp b/src/rviz/default_plugin/image_display.cpp index 3b5d50ceac..e424ea68aa 100644 --- a/src/rviz/default_plugin/image_display.cpp +++ b/src/rviz/default_plugin/image_display.cpp @@ -72,6 +72,7 @@ ImageDisplay::ImageDisplay() : ImageDisplayBase(), texture_() this, SLOT(updateNormalizeOptions())); got_float_image_ = false; + has_run_once_ = false; } void ImageDisplay::onInitialize() @@ -114,12 +115,13 @@ void ImageDisplay::onInitialize() screen_rect_->setBoundingBox(aabInf); setMaterial(*screen_rect_, material_); img_scene_node_->attachObject(screen_rect_); + img_scene_node_->setVisible(false); } render_panel_ = new RenderPanel(); + render_panel_->getRenderWindow()->addListener(this); render_panel_->getRenderWindow()->setAutoUpdated(false); render_panel_->getRenderWindow()->setActive(false); - render_panel_->resize(640, 480); render_panel_->initialize(img_scene_manager_, context_); @@ -136,12 +138,32 @@ ImageDisplay::~ImageDisplay() { if (initialized()) { + render_panel_->getRenderWindow()->removeListener(this); + delete render_panel_; delete screen_rect_; removeAndDestroyChildNode(img_scene_node_->getParentSceneNode(), img_scene_node_); } } +void ImageDisplay::preRenderTargetUpdate(const Ogre::RenderTargetEvent& /*evt*/) +{ + if (has_run_once_) + { + img_scene_node_->setVisible(true); + } + else + { + has_run_once_ = true; + img_scene_node_->setVisible(false); + } +} + +void ImageDisplay::postRenderTargetUpdate(const Ogre::RenderTargetEvent& /*evt*/) +{ + img_scene_node_->setVisible(false); +} + void ImageDisplay::onEnable() { ImageDisplayBase::subscribe(); diff --git a/src/rviz/default_plugin/image_display.h b/src/rviz/default_plugin/image_display.h index 88492c191e..e5b1335bf7 100644 --- a/src/rviz/default_plugin/image_display.h +++ b/src/rviz/default_plugin/image_display.h @@ -59,7 +59,7 @@ namespace rviz * \class ImageDisplay * */ -class ImageDisplay : public ImageDisplayBase +class ImageDisplay : public ImageDisplayBase, public Ogre::RenderTargetListener { Q_OBJECT public: @@ -71,6 +71,10 @@ class ImageDisplay : public ImageDisplayBase void update(float wall_dt, float ros_dt) override; void reset() override; + // Overrides from Ogre::RenderTargetListener + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) override; + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) override; + public Q_SLOTS: virtual void updateNormalizeOptions(); @@ -98,6 +102,8 @@ public Q_SLOTS: FloatProperty* max_property_; IntProperty* median_buffer_size_property_; bool got_float_image_; + + bool has_run_once_; }; } // namespace rviz diff --git a/src/rviz/default_plugin/interactive_markers/interactive_marker_control.h b/src/rviz/default_plugin/interactive_markers/interactive_marker_control.h index 7f8cfbb248..9cc6aff56e 100644 --- a/src/rviz/default_plugin/interactive_markers/interactive_marker_control.h +++ b/src/rviz/default_plugin/interactive_markers/interactive_marker_control.h @@ -32,6 +32,11 @@ #ifndef Q_MOC_RUN +#ifdef _WIN32 +#undef ERROR +#undef DELETE +#endif + #include #include diff --git a/src/rviz/default_plugin/marker_display.cpp b/src/rviz/default_plugin/marker_display.cpp index 79edefd7eb..4bcf7eef99 100644 --- a/src/rviz/default_plugin/marker_display.cpp +++ b/src/rviz/default_plugin/marker_display.cpp @@ -43,6 +43,10 @@ #include +#ifdef DELETE +#undef DELETE +#endif + namespace rviz { //////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/rviz/default_plugin/marker_utils.cpp b/src/rviz/default_plugin/marker_utils.cpp index f543b49b4e..288ef6f34f 100644 --- a/src/rviz/default_plugin/marker_utils.cpp +++ b/src/rviz/default_plugin/marker_utils.cpp @@ -45,6 +45,10 @@ #include #include +#ifdef DELETE +#undef DELETE +#endif + namespace rviz { MarkerBase* diff --git a/src/rviz/ogre_helpers/render_system.cpp b/src/rviz/ogre_helpers/render_system.cpp index e8eb9a91d7..25f2dc508a 100644 --- a/src/rviz/ogre_helpers/render_system.cpp +++ b/src/rviz/ogre_helpers/render_system.cpp @@ -40,6 +40,10 @@ #include #endif +#if defined(Q_OS_MAC) +#include +#endif + // X.h #defines CursorShape to be "0". Qt uses CursorShape in normal // C++ way. This wasn't an issue until ogre_logging.h (below) // introduced a #include of . @@ -155,10 +159,7 @@ void RenderSystem::setupDummyWindowId() void RenderSystem::loadOgrePlugins() { - std::string plugin_prefix = get_ogre_plugin_path() + "/"; -#ifdef Q_OS_MAC - plugin_prefix += "lib"; -#endif + std::string plugin_prefix = std::string(std::getenv("CONDA_PREFIX")) + "/lib/OGRE/"; ogre_root_->loadPlugin(plugin_prefix + "RenderSystem_GL"); ogre_root_->loadPlugin(plugin_prefix + "Plugin_OctreeSceneManager"); ogre_root_->loadPlugin(plugin_prefix + "Plugin_ParticleFX"); @@ -183,8 +184,12 @@ void RenderSystem::detectGlVersion() int minor = caps->getDriverVersion().minor; gl_version_ = major * 100 + minor * 10; +#ifdef __linux__ std::string gl_version_string = (const char*)glGetString(GL_VERSION); mesa_workaround = gl_version_string.find("Mesa 20.") != std::string::npos && gl_version_ >= 320; +#else + mesa_workaround = false; +#endif } switch (gl_version_) @@ -435,7 +440,7 @@ Ogre::RenderWindow* RenderSystem::makeRenderWindow(WindowIDType window_id, // Created a non-stereo window. Discard it and try again (below) // without the stereo parameter. ogre_root_->detachRenderTarget(window); - window->destroy(); + ogre_root_->destroyRenderTarget(window); window = nullptr; stream << "x"; is_stereo = false; @@ -492,6 +497,7 @@ Ogre::RenderWindow* RenderSystem::tryMakeRenderWindow(const std::string& name, if (x_baddrawable_error) { ogre_root_->detachRenderTarget(window); + ogre_root_->destroyRenderTarget(window); window = nullptr; x_baddrawable_error = false; } diff --git a/src/rviz/render_panel.cpp b/src/rviz/render_panel.cpp index 5532741d4e..10fc63314b 100644 --- a/src/rviz/render_panel.cpp +++ b/src/rviz/render_panel.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -100,6 +101,12 @@ void RenderPanel::leaveEvent(QEvent* /*event*/) } } +void RenderPanel::resizeEvent(QResizeEvent* event) +{ + QWidget::resizeEvent(event); + render_window_->windowMovedOrResized(); +} + void RenderPanel::onRenderWindowMouseEvents(QMouseEvent* event) { int last_x = mouse_x_; diff --git a/src/rviz/render_panel.h b/src/rviz/render_panel.h index 2ce29c6f87..e1ef904e98 100644 --- a/src/rviz/render_panel.h +++ b/src/rviz/render_panel.h @@ -118,6 +118,8 @@ class RenderPanel : public QtOgreRenderWindow, public Ogre::SceneManager::Listen /// Called when any mouse event happens inside the render window void onRenderWindowMouseEvents(QMouseEvent* event); + void resizeEvent(QResizeEvent* event) override; + // QWidget mouse events all get sent to onRenderWindowMouseEvents(). // QMouseEvent.type() distinguishes them later. void mouseMoveEvent(QMouseEvent* event) override diff --git a/src/rviz/yaml_config_writer.cpp b/src/rviz/yaml_config_writer.cpp index 7fc0715420..33682f5cfc 100644 --- a/src/rviz/yaml_config_writer.cpp +++ b/src/rviz/yaml_config_writer.cpp @@ -152,7 +152,9 @@ void YamlConfigWriter::writeConfigNode(const Config& config, YAML::Emitter& emit break; } default: + #ifndef _WIN32 emitter << YAML::Null; + #endif break; } }