mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			188 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef slic3r_Mouse3DController_hpp_
 | |
| #define slic3r_Mouse3DController_hpp_
 | |
| 
 | |
| // Enabled debug output to console and extended imgui dialog
 | |
| #define ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT 0
 | |
| 
 | |
| #include "libslic3r/Point.hpp"
 | |
| 
 | |
| #include "hidapi.h"
 | |
| 
 | |
| #include <queue>
 | |
| #include <thread>
 | |
| #include <mutex>
 | |
| #include <vector>
 | |
| #include <chrono>
 | |
| 
 | |
| namespace Slic3r {
 | |
| namespace GUI {
 | |
| 
 | |
| struct Camera;
 | |
| #if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
| class GLCanvas3D;
 | |
| #endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
| 
 | |
| class Mouse3DController
 | |
| {
 | |
|     class State
 | |
|     {
 | |
|     public:
 | |
|         static const double DefaultTranslationScale;
 | |
|         static const double MaxTranslationDeadzone;
 | |
|         static const double DefaultTranslationDeadzone;
 | |
|         static const float DefaultRotationScale;
 | |
|         static const float MaxRotationDeadzone;
 | |
|         static const float DefaultRotationDeadzone;
 | |
| 
 | |
|     private:
 | |
|         template <typename Number>
 | |
|         struct CustomParameters
 | |
|         {
 | |
|             Number scale;
 | |
|             Number deadzone;
 | |
| 
 | |
|             CustomParameters(Number scale, Number deadzone) : scale(scale), deadzone(deadzone) {}
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct InputQueue
 | |
|         {
 | |
|             size_t max_size;
 | |
|             std::queue<T> queue;
 | |
| 
 | |
|             // The default value of 5 for max_size seems to work fine on all platforms
 | |
|             // The effects of changing this value can be tested by setting ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT to 1
 | |
|             // and playing with the imgui dialog which shows by pressing CTRL+M
 | |
|             InputQueue() : max_size(5) {}
 | |
|         };
 | |
| 
 | |
|         InputQueue<Vec3d> m_translation;
 | |
|         InputQueue<Vec3f> m_rotation;
 | |
|         std::queue<unsigned int> m_buttons;
 | |
| 
 | |
|         bool m_buttons_enabled;
 | |
| 
 | |
|         CustomParameters<double> m_translation_params;
 | |
|         CustomParameters<float> m_rotation_params;
 | |
| 
 | |
|         // When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected.
 | |
|         // We want to filter these out because we are getting the data directly from the device, bypassing the driver, and those mouse wheel events interfere
 | |
|         // by triggering unwanted zoom in/out of the scene
 | |
|         // The following variable is used to count the potential mouse wheel events triggered and is updated by: 
 | |
|         // Mouse3DController::collect_input() through the call to the append_rotation() method
 | |
|         // GLCanvas3D::on_mouse_wheel() through the call to the process_mouse_wheel() method
 | |
|         // GLCanvas3D::on_idle() through the call to the apply() method
 | |
|         unsigned int m_mouse_wheel_counter;
 | |
| 
 | |
| #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
 | |
|         size_t m_translation_queue_max_size;
 | |
|         size_t m_rotation_queue_max_size;
 | |
|         size_t m_buttons_queue_max_size;
 | |
| #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
 | |
| 
 | |
|     public:
 | |
|         State();
 | |
| 
 | |
|         void append_translation(const Vec3d& translation);
 | |
|         void append_rotation(const Vec3f& rotation);
 | |
|         void append_button(unsigned int id);
 | |
| 
 | |
|         bool has_translation() const { return !m_translation.queue.empty(); }
 | |
|         bool has_rotation() const { return !m_rotation.queue.empty(); }
 | |
|         bool has_button() const { return !m_buttons.empty(); }
 | |
| 
 | |
|         bool process_mouse_wheel();
 | |
| 
 | |
|         double get_translation_scale() const { return m_translation_params.scale; }
 | |
|         void set_translation_scale(double scale) { m_translation_params.scale = scale; }
 | |
| 
 | |
|         float get_rotation_scale() const { return m_rotation_params.scale; }
 | |
|         void set_rotation_scale(float scale) { m_rotation_params.scale = scale; }
 | |
| 
 | |
|         double get_translation_deadzone() const { return m_translation_params.deadzone; }
 | |
|         void set_translation_deadzone(double deadzone) { m_translation_params.deadzone = deadzone; }
 | |
| 
 | |
|         float get_rotation_deadzone() const { return m_rotation_params.deadzone; }
 | |
|         void set_rotation_deadzone(float deadzone) { m_rotation_params.deadzone = deadzone; }
 | |
| 
 | |
| #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
 | |
|         Vec3d get_translation() const { return has_translation() ? m_translation.queue.front() : Vec3d::Zero(); }
 | |
|         Vec3f get_rotation() const { return has_rotation() ? m_rotation.queue.front() : Vec3f::Zero(); }
 | |
|         unsigned int get_button() const { return has_button() ? m_buttons.front() : 0; }
 | |
| 
 | |
|         unsigned int get_translation_queue_size() const { return (unsigned int)m_translation.queue.size(); }
 | |
|         unsigned int get_rotation_queue_size() const { return (unsigned int)m_rotation.queue.size(); }
 | |
|         unsigned int get_buttons_queue_size() const { return (unsigned int)m_buttons.size(); }
 | |
| 
 | |
|         size_t get_translation_queue_max_size() const { return m_translation_queue_max_size; }
 | |
|         size_t get_rotation_queue_max_size() const { return m_rotation_queue_max_size; }
 | |
|         size_t get_buttons_queue_max_size() const { return m_buttons_queue_max_size; }
 | |
| #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
 | |
| 
 | |
|         size_t get_queues_max_size() const { return m_translation.max_size; }
 | |
|         void set_queues_max_size(size_t size);
 | |
| 
 | |
|         // return true if any change to the camera took place
 | |
|         bool apply(Camera& camera);
 | |
|     };
 | |
| 
 | |
|     bool m_initialized;
 | |
|     mutable State m_state;
 | |
|     std::mutex m_mutex;
 | |
|     std::thread m_thread;
 | |
|     hid_device* m_device;
 | |
|     std::string m_device_str;
 | |
|     bool m_running;
 | |
| #if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
|     mutable bool m_show_settings_dialog;
 | |
|     // set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
 | |
|     mutable bool m_settings_dialog_closed_by_user;
 | |
| #else
 | |
|     bool m_show_settings_dialog;
 | |
| #endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
|     std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
 | |
| 
 | |
| public:
 | |
|     Mouse3DController();
 | |
| 
 | |
|     void init();
 | |
|     void shutdown();
 | |
| 
 | |
|     bool is_device_connected() const { return m_device != nullptr; }
 | |
|     bool is_running() const { return m_running; }
 | |
| 
 | |
|     bool process_mouse_wheel() { std::lock_guard<std::mutex> lock(m_mutex); return m_state.process_mouse_wheel(); }
 | |
| 
 | |
|     bool apply(Camera& camera);
 | |
| 
 | |
|     bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
 | |
|     void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
 | |
| #if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
|     void render_settings_dialog(GLCanvas3D& canvas) const;
 | |
| #else
 | |
|     void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
 | |
| #endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
 | |
| 
 | |
| private:
 | |
|     bool connect_device();
 | |
|     void disconnect_device();
 | |
|     void start();
 | |
|     void stop() { m_running = false; }
 | |
| 
 | |
|     // secondary thread methods
 | |
|     void run();
 | |
|     void collect_input();
 | |
| 
 | |
|     typedef std::array<unsigned char, 13> DataPacket;
 | |
|     bool handle_packet(const DataPacket& packet);
 | |
|     bool handle_wireless_packet(const DataPacket& packet);
 | |
|     bool handle_packet_translation(const DataPacket& packet);
 | |
|     bool handle_packet_rotation(const DataPacket& packet, unsigned int first_byte);
 | |
|     bool handle_packet_button(const DataPacket& packet, unsigned int packet_size);
 | |
| };
 | |
| 
 | |
| } // namespace GUI
 | |
| } // namespace Slic3r
 | |
| 
 | |
| #endif // slic3r_Mouse3DController_hpp_
 | |
| 
 | 
