From 27eb7bbe9f3c99783c46c0054f202a29c8a337b9 Mon Sep 17 00:00:00 2001 From: Stephen Hurd Date: Sat, 19 Aug 2023 03:45:27 -0400 Subject: [PATCH] Add spacenavd support (#1769) --- CMakeLists.txt | 14 ++++++ src/slic3r/CMakeLists.txt | 4 ++ src/slic3r/GUI/Mouse3DController.cpp | 74 +++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12f7e321b..fefcd598f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -568,6 +568,20 @@ else () "OpenVDB installation with the OPENVDB_FIND_MODULE_PATH cache variable.") endif () +find_path(SPNAV_INCLUDE_DIR spnav.h) +if (SPNAV_INCLUDE_DIR) + find_library(HAVE_SPNAV spnav) + if (HAVE_SPNAV) + add_definitions(-DHAVE_SPNAV) + add_library(libspnav SHARED IMPORTED) + target_link_libraries(libspnav INTERFACE spnav) + message(STATUS "SPNAV library found") + else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") + endif() +else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") +endif() set(TOP_LEVEL_PROJECT_DIR ${PROJECT_SOURCE_DIR}) function(orcaslicer_copy_dlls target config postfix output_dlls) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 7fa6cf8d5..6763a0dba 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -528,6 +528,10 @@ if (SLIC3R_STATIC) target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0) endif() +if (HAVE_SPNAV) + target_link_libraries(libslic3r_gui spnav) +endif() + if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL AND UNIX AND NOT APPLE) target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE) endif () diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 3ef0b096b..3c2f08c5e 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -17,7 +17,9 @@ #include //unofficial linux lib -//#include +#ifdef HAVE_SPNAV +#include +#endif // WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules @@ -773,6 +775,31 @@ void Mouse3DController::shutdown() // Main routine of the worker thread. void Mouse3DController::run() { +#ifdef HAVE_SPNAV + if (spnav_open() == -1) { + // Give up. + BOOST_LOG_TRIVIAL(error) << "Unable to open connection to spacenavd"; + return; + } + m_connected = true; + + for (;;) { + { + std::scoped_lock lock(m_params_ui_mutex); + if (m_stop) + break; + if (m_params_ui_changed) { + m_params = m_params_ui; + m_params_ui_changed = false; + } + } + this->collect_input(); + } + + m_connected = false; + // Finalize the spnav library + spnav_close(); +#else // Initialize the hidapi library int res = hid_init(); if (res != 0) { @@ -817,6 +844,7 @@ void Mouse3DController::run() // Finalize the hidapi library hid_exit(); +#endif } bool Mouse3DController::connect_device() @@ -1106,8 +1134,51 @@ void Mouse3DController::disconnect_device() } } +#ifdef HAVE_SPNAV +// Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. +static double convert_spnav_input(int value) +{ + return (double)value/100; +} +#endif + void Mouse3DController::collect_input() { +#ifdef HAVE_SPNAV + // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. + int fd = spnav_fd(); + + if (fd != -1) { + fd_set fds; + struct timeval tv = {.tv_sec = 0, .tv_usec = 100000}; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + if (select(fd + 1, &fds, NULL, NULL, &tv) == 1) { + spnav_event ev = {}; + switch (spnav_poll_event(&ev)) { + case SPNAV_EVENT_MOTION: { + Vec3d translation(-convert_spnav_input(ev.motion.x), convert_spnav_input(ev.motion.y), -convert_spnav_input(ev.motion.z)); + if (!translation.isApprox(Vec3d::Zero())) { + m_state.append_translation(translation, m_params.input_queue_max_size); + } + Vec3f rotation(convert_spnav_input(ev.motion.rx), convert_spnav_input(ev.motion.ry), -convert_spnav_input(ev.motion.rz)); + if (!rotation.isApprox(Vec3f::Zero())) { + m_state.append_rotation(rotation, m_params.input_queue_max_size); + } + break; + } + case SPNAV_EVENT_BUTTON: + if (ev.button.press) + m_state.append_button((unsigned int)ev.button.bnum, m_params.input_queue_max_size); + break; + } + wxGetApp().plater()->set_current_canvas_as_dirty(); + // ask for an idle event to update 3D scene + wxWakeUpIdle(); + } + } +#else DataPacketRaw packet = { 0 }; // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100); @@ -1116,6 +1187,7 @@ void Mouse3DController::collect_input() this->disconnect_device(); } else this->handle_input(packet, res, m_params, m_state); +#endif } #ifdef _WIN32