mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 02:31:10 -06:00
ENABLE_3DCONNEXION_DEVICES - 1st installment of support for 3Dconnexion devices
Implemented using hidapi library (https://github.com/libusb/hidapi) and https://github.com/koenieee/CrossplatformSpacemouseDriver/tree/master/SpaceMouseDriver as reference Unsolved issues: - When manipulating the SpaceNavigator wxWidgets generates a mouse wheel event that needs to be filtered out - wxWidgets does not detect devices being connected/disconnected to the pc - Current state forces a continuous rendering - Current state misses dependence on camera zoom - Non intuitive movement limits - Translation and rotation speed factors are hardcoded - Number of device buttons hardcoded
This commit is contained in:
parent
c1e3be9b27
commit
f958cfd2ff
14 changed files with 3805 additions and 1 deletions
|
|
@ -22,6 +22,9 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
#include "Mouse3DController.hpp"
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
#include "I18N.hpp"
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
|
|
@ -2305,14 +2308,28 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
|||
m_dirty |= m_main_toolbar.update_items_state();
|
||||
m_dirty |= m_undoredo_toolbar.update_items_state();
|
||||
m_dirty |= m_view_toolbar.update_items_state();
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply();
|
||||
m_dirty |= mouse3d_controller_applied;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
if (!m_dirty)
|
||||
return;
|
||||
|
||||
_refresh_if_shown_on_screen();
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
if (m_keep_dirty || wxGetApp().plater()->get_mouse3d_controller().is_device_connected())
|
||||
{
|
||||
m_dirty = true;
|
||||
evt.RequestMore();
|
||||
}
|
||||
else
|
||||
m_dirty = false;
|
||||
#else
|
||||
if (m_keep_dirty)
|
||||
m_dirty = true;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
}
|
||||
|
||||
void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||
|
|
@ -2531,6 +2548,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
|
||||
void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
|
||||
{
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
// try to filter out events coming from mouse 3d controller
|
||||
const Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller();
|
||||
if (controller.has_rotation() || controller.has_translation())
|
||||
return;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
|
|
@ -3815,7 +3839,9 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
|
|||
// updates camera
|
||||
m_camera.apply_viewport(0, 0, w, h);
|
||||
|
||||
#if !ENABLE_3DCONNEXION_DEVICES
|
||||
m_dirty = false;
|
||||
#endif // !ENABLE_3DCONNEXION_DEVICES
|
||||
}
|
||||
|
||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const
|
||||
|
|
|
|||
|
|
@ -486,6 +486,9 @@ public:
|
|||
void set_color_by(const std::string& value);
|
||||
|
||||
const Camera& get_camera() const { return m_camera; }
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
Camera& get_camera() { return m_camera; }
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
BoundingBoxf3 volumes_bounding_box() const;
|
||||
BoundingBoxf3 scene_bounding_box() const;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
#include "PrintHostDialogs.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
#include "Mouse3DController.hpp"
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
|
@ -108,6 +111,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
}
|
||||
|
||||
if(m_plater) m_plater->stop_jobs();
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
if (m_plater != nullptr)
|
||||
m_plater->get_mouse3d_controller().set_canvas(nullptr);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
// Weird things happen as the Paint messages are floating around the windows being destructed.
|
||||
// Avoid the Paint messages by hiding the main window.
|
||||
|
|
|
|||
332
src/slic3r/GUI/Mouse3DController.cpp
Normal file
332
src/slic3r/GUI/Mouse3DController.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "Mouse3DController.hpp"
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
static const std::vector<int> _3DCONNEXION_VENDORS =
|
||||
{
|
||||
0x046d, // LOGITECH = 1133 // Logitech (3Dconnexion is made by Logitech)
|
||||
0x256F // 3DCONNECTION = 9583 // 3Dconnexion
|
||||
};
|
||||
|
||||
static const std::vector<int> _3DCONNEXION_DEVICES =
|
||||
{
|
||||
0xC623, // TRAVELER = 50723
|
||||
0xC626, // NAVIGATOR = 50726
|
||||
0xc628, // NAVIGATOR_FOR_NOTEBOOKS = 50728
|
||||
0xc627, // SPACEEXPLORER = 50727
|
||||
0xC603, // SPACEMOUSE = 50691
|
||||
0xC62B, // SPACEMOUSEPRO = 50731
|
||||
0xc621, // SPACEBALL5000 = 50721
|
||||
0xc625, // SPACEPILOT = 50725
|
||||
0xc629 // SPACEPILOTPRO = 50729
|
||||
};
|
||||
|
||||
static const unsigned int _3DCONNEXION_BUTTONS_COUNT = 2;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const double Mouse3DController::State::DefaultTranslationScale = 2.5;
|
||||
const float Mouse3DController::State::DefaultRotationScale = 1.0;
|
||||
|
||||
Mouse3DController::State::State()
|
||||
: m_translation(Vec3d::Zero())
|
||||
, m_rotation(Vec3f::Zero())
|
||||
, m_buttons(_3DCONNEXION_BUTTONS_COUNT, false)
|
||||
, m_translation_scale(DefaultTranslationScale)
|
||||
, m_rotation_scale(DefaultRotationScale)
|
||||
{
|
||||
}
|
||||
|
||||
void Mouse3DController::State::set_translation(const Vec3d& translation)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_translation = translation;
|
||||
}
|
||||
|
||||
void Mouse3DController::State::set_rotation(const Vec3f& rotation)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_rotation = rotation;
|
||||
}
|
||||
|
||||
void Mouse3DController::State::set_button(unsigned int id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (id < _3DCONNEXION_BUTTONS_COUNT)
|
||||
m_buttons[id] = true;
|
||||
}
|
||||
|
||||
bool Mouse3DController::State::has_translation() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return !m_translation.isApprox(Vec3d::Zero());
|
||||
}
|
||||
bool Mouse3DController::State::has_rotation() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return !m_rotation.isApprox(Vec3f::Zero());
|
||||
}
|
||||
|
||||
bool Mouse3DController::State::has_any_button() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (int i = 0; i < _3DCONNEXION_BUTTONS_COUNT; ++i)
|
||||
{
|
||||
if (m_buttons[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mouse3DController::State::apply(GLCanvas3D& canvas)
|
||||
{
|
||||
if (!wxGetApp().IsActive())
|
||||
return false;
|
||||
|
||||
bool ret = false;
|
||||
Camera& camera = canvas.get_camera();
|
||||
|
||||
if (has_translation())
|
||||
{
|
||||
camera.set_target(camera.get_target() + m_translation_scale * (m_translation(0) * camera.get_dir_right() + m_translation(1) * camera.get_dir_forward() + m_translation(2) * camera.get_dir_up()));
|
||||
m_translation = Vec3d::Zero();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (has_rotation())
|
||||
{
|
||||
float theta = m_rotation_scale * m_rotation(0);
|
||||
float phi = m_rotation_scale * m_rotation(2);
|
||||
float sign = camera.inverted_phi ? -1.0f : 1.0f;
|
||||
camera.phi += sign * phi;
|
||||
camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
|
||||
m_rotation = Vec3f::Zero();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (has_any_button())
|
||||
{
|
||||
if (m_buttons[0])
|
||||
canvas.set_camera_zoom(1.0);
|
||||
else if (m_buttons[1])
|
||||
canvas.set_camera_zoom(-1.0);
|
||||
|
||||
m_buttons = std::vector<bool>(_3DCONNEXION_BUTTONS_COUNT, false);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Mouse3DController::Mouse3DController()
|
||||
: m_initialized(false)
|
||||
, m_canvas(nullptr)
|
||||
, m_device(nullptr)
|
||||
, m_running(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Mouse3DController::init()
|
||||
{
|
||||
if (m_initialized)
|
||||
return;
|
||||
|
||||
// Initialize the hidapi library
|
||||
int res = hid_init();
|
||||
if (res != 0)
|
||||
return;
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
connect_device();
|
||||
start();
|
||||
}
|
||||
|
||||
void Mouse3DController::shutdown()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
stop();
|
||||
|
||||
if (m_thread.joinable())
|
||||
m_thread.join();
|
||||
|
||||
disconnect_device();
|
||||
|
||||
// Finalize the hidapi library
|
||||
hid_exit();
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void Mouse3DController::connect_device()
|
||||
{
|
||||
if (m_device != nullptr)
|
||||
return;
|
||||
|
||||
// Enumerates devices
|
||||
hid_device_info* devices = hid_enumerate(0, 0);
|
||||
if (devices == nullptr)
|
||||
return;
|
||||
|
||||
// Searches for 1st connected 3Dconnexion device
|
||||
unsigned short vendor_id = 0;
|
||||
unsigned short product_id = 0;
|
||||
|
||||
hid_device_info* current = devices;
|
||||
while (current != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i)
|
||||
{
|
||||
if (_3DCONNEXION_VENDORS[i] == current->vendor_id)
|
||||
{
|
||||
vendor_id = current->vendor_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vendor_id != 0)
|
||||
{
|
||||
for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i)
|
||||
{
|
||||
if (_3DCONNEXION_DEVICES[i] == current->product_id)
|
||||
{
|
||||
product_id = current->product_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (product_id == 0)
|
||||
vendor_id = 0;
|
||||
}
|
||||
|
||||
if (vendor_id != 0)
|
||||
break;
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
// Free enumerated devices
|
||||
hid_free_enumeration(devices);
|
||||
|
||||
if (vendor_id == 0)
|
||||
return;
|
||||
|
||||
// Open the 3Dconnexion device using the VID, PID
|
||||
m_device = hid_open(vendor_id, product_id, nullptr);
|
||||
}
|
||||
|
||||
void Mouse3DController::disconnect_device()
|
||||
{
|
||||
if (m_device == nullptr)
|
||||
return;
|
||||
|
||||
// Close the 3Dconnexion device
|
||||
hid_close(m_device);
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
void Mouse3DController::start()
|
||||
{
|
||||
if ((m_device == nullptr) || m_running)
|
||||
return;
|
||||
|
||||
m_thread = std::thread(&Mouse3DController::run, this);
|
||||
}
|
||||
|
||||
void Mouse3DController::run()
|
||||
{
|
||||
m_running = true;
|
||||
while (m_running)
|
||||
{
|
||||
collect_input();
|
||||
}
|
||||
}
|
||||
|
||||
double convert_input(int first, unsigned char val)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case 0: { ret = first; break; }
|
||||
case 1: { ret = first + 255; break; }
|
||||
case 254: { ret = -511 + first; break; }
|
||||
case 255: { ret = -255 + first; break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
return (double)ret / 349.0;
|
||||
}
|
||||
|
||||
void Mouse3DController::collect_input()
|
||||
{
|
||||
// Read data from device
|
||||
enum EDataType
|
||||
{
|
||||
Translation = 1,
|
||||
Rotation,
|
||||
Button
|
||||
};
|
||||
|
||||
unsigned char retrieved_data[8] = { 0 };
|
||||
int res = hid_read_timeout(m_device, retrieved_data, sizeof(retrieved_data), 100);
|
||||
if (res < 0)
|
||||
{
|
||||
// An error occourred (device detached from pc ?)
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
switch (retrieved_data[0])
|
||||
{
|
||||
case Translation:
|
||||
{
|
||||
Vec3d translation(-convert_input((int)retrieved_data[1], retrieved_data[2]),
|
||||
convert_input((int)retrieved_data[3], retrieved_data[4]),
|
||||
convert_input((int)retrieved_data[5], retrieved_data[6]));
|
||||
if (!translation.isApprox(Vec3d::Zero()))
|
||||
m_state.set_translation(translation);
|
||||
|
||||
break;
|
||||
}
|
||||
case Rotation:
|
||||
{
|
||||
Vec3f rotation(-(float)convert_input((int)retrieved_data[1], retrieved_data[2]),
|
||||
(float)convert_input((int)retrieved_data[3], retrieved_data[4]),
|
||||
-(float)convert_input((int)retrieved_data[5], retrieved_data[6]));
|
||||
if (!rotation.isApprox(Vec3f::Zero()))
|
||||
m_state.set_rotation(rotation);
|
||||
|
||||
break;
|
||||
}
|
||||
case Button:
|
||||
{
|
||||
for (unsigned int i = 0; i < _3DCONNEXION_BUTTONS_COUNT; ++i)
|
||||
{
|
||||
if (retrieved_data[1] & (0x1 << i))
|
||||
m_state.set_button(i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
96
src/slic3r/GUI/Mouse3DController.hpp
Normal file
96
src/slic3r/GUI/Mouse3DController.hpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef slic3r_Mouse3DController_hpp_
|
||||
#define slic3r_Mouse3DController_hpp_
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
#include "hidapi/hidapi.h"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class GLCanvas3D;
|
||||
|
||||
class Mouse3DController
|
||||
{
|
||||
class State
|
||||
{
|
||||
static const double DefaultTranslationScale;
|
||||
static const float DefaultRotationScale;
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
Vec3d m_translation;
|
||||
Vec3f m_rotation;
|
||||
std::vector<bool> m_buttons;
|
||||
|
||||
double m_translation_scale;
|
||||
float m_rotation_scale;
|
||||
|
||||
public:
|
||||
State();
|
||||
|
||||
void set_translation(const Vec3d& translation);
|
||||
void set_rotation(const Vec3f& rotation);
|
||||
void set_button(unsigned int id);
|
||||
|
||||
bool has_translation() const;
|
||||
bool has_rotation() const;
|
||||
bool has_any_button() const;
|
||||
|
||||
// return true if any change to the camera took place
|
||||
bool apply(GLCanvas3D& canvas);
|
||||
};
|
||||
|
||||
bool m_initialized;
|
||||
State m_state;
|
||||
std::thread m_thread;
|
||||
GLCanvas3D* m_canvas;
|
||||
std::mutex m_mutex;
|
||||
hid_device* m_device;
|
||||
bool m_running;
|
||||
|
||||
public:
|
||||
Mouse3DController();
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
bool is_device_connected() const { return m_device != nullptr; }
|
||||
bool is_running() const { return m_running; }
|
||||
|
||||
void set_canvas(GLCanvas3D* canvas)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_canvas = canvas;
|
||||
}
|
||||
|
||||
bool has_translation() const { return m_state.has_translation(); }
|
||||
bool has_rotation() const { return m_state.has_rotation(); }
|
||||
bool has_any_button() const { return m_state.has_any_button(); }
|
||||
|
||||
bool apply()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return (m_canvas != nullptr) ? m_state.apply(*m_canvas) : false;
|
||||
}
|
||||
|
||||
private:
|
||||
void connect_device();
|
||||
void disconnect_device();
|
||||
void start();
|
||||
void stop() { m_running = false; }
|
||||
|
||||
void run();
|
||||
void collect_input();
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
#endif // slic3r_Mouse3DController_hpp_
|
||||
|
||||
|
|
@ -61,6 +61,9 @@
|
|||
#include "GUI_Preview.hpp"
|
||||
#include "3DBed.hpp"
|
||||
#include "Camera.hpp"
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
#include "Mouse3DController.hpp"
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
#include "Tab.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "BackgroundSlicingProcess.hpp"
|
||||
|
|
@ -1367,6 +1370,9 @@ struct Plater::priv
|
|||
Sidebar *sidebar;
|
||||
Bed3D bed;
|
||||
Camera camera;
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
Mouse3DController mouse3d_controller;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
View3D* view3D;
|
||||
GLToolbar view_toolbar;
|
||||
Preview *preview;
|
||||
|
|
@ -2094,12 +2100,20 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
// updates camera type from .ini file
|
||||
camera.set_type(get_config("use_perspective_camera"));
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
mouse3d_controller.init();
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
// Initialize the Undo / Redo stack with a first snapshot.
|
||||
this->take_snapshot(_(L("New Project")));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
{
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
mouse3d_controller.shutdown();
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
if (config != nullptr)
|
||||
delete config;
|
||||
}
|
||||
|
|
@ -3248,6 +3262,11 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||
} else
|
||||
view3D->reload_scene(true);
|
||||
}
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
mouse3d_controller.set_canvas(view3D->get_canvas3d());
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
// sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
|
||||
view3D->set_as_dirty();
|
||||
view_toolbar.select_item("3D");
|
||||
|
|
@ -3262,6 +3281,11 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||
this->q->reslice();
|
||||
// keeps current gcode preview, if any
|
||||
preview->reload_print(true);
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
mouse3d_controller.set_canvas(preview->get_canvas3d());
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
preview->set_canvas_as_dirty();
|
||||
view_toolbar.select_item("Preview");
|
||||
}
|
||||
|
|
@ -5020,6 +5044,18 @@ const Camera& Plater::get_camera() const
|
|||
return p->camera;
|
||||
}
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
const Mouse3DController& Plater::get_mouse3d_controller() const
|
||||
{
|
||||
return p->mouse3d_controller;
|
||||
}
|
||||
|
||||
Mouse3DController& Plater::get_mouse3d_controller()
|
||||
{
|
||||
return p->mouse3d_controller;
|
||||
}
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
bool Plater::can_delete() const { return p->can_delete(); }
|
||||
bool Plater::can_delete_all() const { return p->can_delete_all(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class ObjectSettings;
|
|||
class ObjectLayers;
|
||||
class ObjectList;
|
||||
class GLCanvas3D;
|
||||
class Mouse3DController;
|
||||
|
||||
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
|
||||
|
||||
|
|
@ -251,6 +252,10 @@ public:
|
|||
void msw_rescale();
|
||||
|
||||
const Camera& get_camera() const;
|
||||
#if ENABLE_3DCONNEXION_DEVICES
|
||||
const Mouse3DController& get_mouse3d_controller() const;
|
||||
Mouse3DController& get_mouse3d_controller();
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES
|
||||
|
||||
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
|
||||
class SuppressSnapshots
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue