From 57cf3d17e2dc25c1500f403e584684430f9580a0 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 17 Dec 2019 15:57:24 +0100
Subject: [PATCH] First steps on SLA and Hollowing gizmo data sharing

---
 src/slic3r/GUI/Gizmos/GLGizmoBase.cpp        |   3 +-
 src/slic3r/GUI/Gizmos/GLGizmoBase.hpp        |  36 ++-
 src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp      | 262 +++++++++----------
 src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp      |  34 ++-
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 194 +++++++-------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  27 +-
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp    |   6 +-
 src/slic3r/GUI/Gizmos/GLGizmosManager.hpp    |   1 +
 8 files changed, 296 insertions(+), 267 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
index cb18bdb16..7dce249f2 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
@@ -135,7 +135,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
 }
 
 
-GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
+GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* common_data_ptr)
     : m_parent(parent)
     , m_group_id(-1)
     , m_state(Off)
@@ -146,6 +146,7 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
     , m_dragging(false)
     , m_imgui(wxGetApp().imgui())
     , m_first_input_window_render(true)
+    , m_c(common_data_ptr)
 {
     ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
     ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
index da3042779..9479174fb 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
@@ -30,7 +30,7 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
 
 
 class ImGuiWrapper;
-
+class CommonGizmosData;
 
 class GLGizmoBase
 {
@@ -99,9 +99,13 @@ protected:
     mutable std::vector<Grabber> m_grabbers;
     ImGuiWrapper* m_imgui;
     bool m_first_input_window_render;
+    CommonGizmosData* m_c = nullptr;
 
 public:
-    GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
+    GLGizmoBase(GLCanvas3D& parent,
+                const std::string& icon_filename,
+                unsigned int sprite_id,
+                CommonGizmosData* common_data = nullptr);
     virtual ~GLGizmoBase() {}
 
     bool init() { return on_init(); }
@@ -179,6 +183,34 @@ protected:
 // were not interpolated by alpha blending or multi sampling.
 extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
 
+class MeshRaycaster;
+class MeshClipper;
+
+class CommonGizmosData {
+public:
+    const TriangleMesh* mesh() const {
+        return (! m_mesh ? nullptr : (m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
+    }
+
+
+
+    ModelObject* m_model_object = nullptr;
+    const TriangleMesh* m_mesh;
+    std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
+    std::unique_ptr<MeshClipper> m_object_clipper;
+    std::unique_ptr<MeshClipper> m_supports_clipper;
+
+    std::unique_ptr<TriangleMesh> m_cavity_mesh;
+    std::unique_ptr<GLVolume> m_volume_with_cavity;
+
+    int m_active_instance = -1;
+    float m_active_instance_bb_radius = 0;
+    ObjectID m_model_object_id = 0;
+    int m_print_object_idx = -1;
+    int m_print_objects_count = -1;
+    int m_old_timestamp = -1;
+};
+
 } // namespace GUI
 } // namespace Slic3r
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
index cad0243f0..f8f2e125f 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
@@ -18,8 +18,8 @@
 namespace Slic3r {
 namespace GUI {
 
-GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
-    : GLGizmoBase(parent, icon_filename, sprite_id)
+GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
+    : GLGizmoBase(parent, icon_filename, sprite_id, cd)
     , m_quadric(nullptr)
 {
     m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
@@ -58,23 +58,23 @@ bool GLGizmoHollow::on_init()
 void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Selection& selection)
 {
     if (! model_object || selection.is_empty()) {
-        m_model_object = nullptr;
+        m_c->m_model_object = nullptr;
         return;
     }
 
-    if (m_model_object != model_object || m_model_object_id != model_object->id()) {
-        m_model_object = model_object;
-        m_print_object_idx = -1;
+    if (m_c->m_model_object != model_object || m_c->m_model_object_id != model_object->id()) {
+        m_c->m_model_object = model_object;
+        m_c->m_print_object_idx = -1;
     }
 
-    m_active_instance = selection.get_instance_idx();
+    m_c->m_active_instance = selection.get_instance_idx();
 
     if (model_object && selection.is_from_single_instance())
     {
         // Cache the bb - it's needed for dealing with the clipping plane quite often
         // It could be done inside update_mesh but one has to account for scaling of the instance.
         //FIXME calling ModelObject::instance_bounding_box() is expensive!
-        m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
+        m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius();
 
         if (is_mesh_update_necessary()) {
             update_mesh();
@@ -83,7 +83,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Select
 
         if (m_state == On) {
             m_parent.toggle_model_objects_visibility(false);
-            m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
+            m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
         }
         else
             m_parent.toggle_model_objects_visibility(true, nullptr, -1);
@@ -96,24 +96,24 @@ void GLGizmoHollow::on_render() const
 {
     const Selection& selection = m_parent.get_selection();
 
-    // If current m_model_object does not match selection, ask GLCanvas3D to turn us off
+    // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off
     if (m_state == On
-     && (m_model_object != selection.get_model()->objects[selection.get_object_idx()]
-      || m_active_instance != selection.get_instance_idx()
-      || m_model_object_id != m_model_object->id())) {
+     && (m_c->m_model_object != selection.get_model()->objects[selection.get_object_idx()]
+      || m_c->m_active_instance != selection.get_instance_idx()
+      || m_c->m_model_object_id != m_c->m_model_object->id())) {
         m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS));
         return;
     }
 
-    if (! m_mesh)
+    if (! m_c->m_mesh)
         const_cast<GLGizmoHollow*>(this)->update_mesh();
 
     glsafe(::glEnable(GL_BLEND));
     glsafe(::glEnable(GL_DEPTH_TEST));
 
-    if (m_volume_with_cavity) {
+    if (m_c->m_volume_with_cavity) {
         m_parent.get_shader().start_using();
-        m_volume_with_cavity->render();
+        m_c->m_volume_with_cavity->render();
         m_parent.get_shader().stop_using();
     }
 
@@ -132,7 +132,7 @@ void GLGizmoHollow::on_render() const
 
 void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
 {
-    if (m_clipping_plane_distance == 0.f || mesh()->empty())
+    if (m_clipping_plane_distance == 0.f || m_c->mesh()->empty())
         return;
 
     // Get transformation of the instance
@@ -150,65 +150,65 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
                                     1.));
 
     // Now initialize the TMS for the object, perform the cut and save the result.
-    if (! m_object_clipper) {
-        m_object_clipper.reset(new MeshClipper);
-        m_object_clipper->set_mesh(*mesh());
+    if (! m_c->m_object_clipper) {
+        m_c->m_object_clipper.reset(new MeshClipper);
+        m_c->m_object_clipper->set_mesh(*m_c->mesh());
     }
-    m_object_clipper->set_plane(*m_clipping_plane);
-    m_object_clipper->set_transformation(trafo);
+    m_c->m_object_clipper->set_plane(*m_clipping_plane);
+    m_c->m_object_clipper->set_transformation(trafo);
 
 
     // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
     // First we need a pointer to the respective SLAPrintObject. The index into objects vector is
     // cached so we don't have todo it on each render. We only search for the po if needed:
-    if (m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) {
-        m_print_objects_count = m_parent.sla_print()->objects().size();
-        m_print_object_idx = -1;
+    if (m_c->m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_c->m_print_objects_count) {
+        m_c->m_print_objects_count = m_parent.sla_print()->objects().size();
+        m_c->m_print_object_idx = -1;
         for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
-            ++m_print_object_idx;
-            if (po->model_object()->id() == m_model_object->id())
+            ++m_c->m_print_object_idx;
+            if (po->model_object()->id() == m_c->m_model_object->id())
                 break;
         }
     }
-    if (m_print_object_idx >= 0) {
-        const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx];
+    if (m_c->m_print_object_idx >= 0) {
+        const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx];
 
         if (print_object->is_step_done(slaposSupportTree) && !print_object->get_mesh(slaposSupportTree).empty()) {
             // If the supports are already calculated, save the timestamp of the respective step
             // so we can later tell they were recalculated.
             size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
 
-            if (! m_supports_clipper || (int)timestamp != m_old_timestamp) {
+            if (! m_c->m_supports_clipper || (int)timestamp != m_c->m_old_timestamp) {
                 // The timestamp has changed.
-                m_supports_clipper.reset(new MeshClipper);
+                m_c->m_supports_clipper.reset(new MeshClipper);
                 // The mesh should already have the shared vertices calculated.
-                m_supports_clipper->set_mesh(print_object->support_mesh());
-                m_old_timestamp = timestamp;
+                m_c->m_supports_clipper->set_mesh(print_object->support_mesh());
+                m_c->m_old_timestamp = timestamp;
             }
-            m_supports_clipper->set_plane(*m_clipping_plane);
-            m_supports_clipper->set_transformation(supports_trafo);
+            m_c->m_supports_clipper->set_plane(*m_clipping_plane);
+            m_c->m_supports_clipper->set_transformation(supports_trafo);
         }
         else
             // The supports are not valid. We better dump the cached data.
-            m_supports_clipper.reset();
+            m_c->m_supports_clipper.reset();
     }
 
     // At this point we have the triangulated cuts for both the object and supports - let's render.
-    if (! m_object_clipper->get_triangles().empty()) {
+    if (! m_c->m_object_clipper->get_triangles().empty()) {
         ::glPushMatrix();
         ::glColor3f(1.0f, 0.37f, 0.0f);
         ::glBegin(GL_TRIANGLES);
-        for (const Vec3f& point : m_object_clipper->get_triangles())
+        for (const Vec3f& point : m_c->m_object_clipper->get_triangles())
             ::glVertex3f(point(0), point(1), point(2));
         ::glEnd();
         ::glPopMatrix();
     }
 
-    if (m_show_supports && m_supports_clipper && ! m_supports_clipper->get_triangles().empty()) {
+    if (m_show_supports && m_c->m_supports_clipper && ! m_c->m_supports_clipper->get_triangles().empty()) {
         ::glPushMatrix();
         ::glColor3f(1.0f, 0.f, 0.37f);
         ::glBegin(GL_TRIANGLES);
-        for (const Vec3f& point : m_supports_clipper->get_triangles())
+        for (const Vec3f& point : m_c->m_supports_clipper->get_triangles())
             ::glVertex3f(point(0), point(1), point(2));
         ::glEnd();
         ::glPopMatrix();
@@ -241,10 +241,10 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
     glsafe(::glMultMatrixd(instance_matrix.data()));
 
     float render_color[4];
-    size_t cache_size = m_model_object->sla_drain_holes.size();
+    size_t cache_size = m_c->m_model_object->sla_drain_holes.size();
     for (size_t i = 0; i < cache_size; ++i)
     {
-        const sla::DrainHole& drain_hole = m_model_object->sla_drain_holes[i];
+        const sla::DrainHole& drain_hole = m_c->m_model_object->sla_drain_holes[i];
         const bool& point_selected = m_selected[i];
 
         if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast<double>()))
@@ -324,7 +324,7 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const
     if (m_clipping_plane_distance == 0.f)
         return false;
 
-    Vec3d transformed_point = m_model_object->instances[m_active_instance]->get_transformation().get_matrix() * point;
+    Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point;
     transformed_point(2) += m_z_shift;
     return m_clipping_plane->is_point_clipped(transformed_point);
 }
@@ -333,34 +333,34 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const
 
 bool GLGizmoHollow::is_mesh_update_necessary() const
 {
-    return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty())
-        && ((m_model_object->id() != m_model_object_id) || ! m_mesh);
+    return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty())
+        && ((m_c->m_model_object->id() != m_c->m_model_object_id) || ! m_c->m_mesh);
 }
 
 
 
 void GLGizmoHollow::update_mesh()
 {
-    if (! m_model_object)
+    if (! m_c->m_model_object)
         return;
 
     wxBusyCursor wait;
     // this way we can use that mesh directly.
     // This mesh does not account for the possible Z up SLA offset.
-    m_mesh = &m_model_object->volumes.front()->mesh();
+    m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh();
 
     // If this is different mesh than last time
-    if (m_model_object_id != m_model_object->id()) {
-        m_cavity_mesh.reset(); // dump the cavity
-        m_volume_with_cavity.reset();
-        m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
-        m_mesh_raycaster.reset();
+    if (m_c->m_model_object_id != m_c->m_model_object->id()) {
+        m_c->m_cavity_mesh.reset(); // dump the cavity
+        m_c->m_volume_with_cavity.reset();
+        m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
+        m_c->m_mesh_raycaster.reset();
     }
 
-    if (! m_mesh_raycaster)
-        m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
+    if (! m_c->m_mesh_raycaster)
+        m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
 
-    m_model_object_id = m_model_object->id();
+    m_c->m_model_object_id = m_c->m_model_object->id();
 }
 
 
@@ -370,7 +370,7 @@ void GLGizmoHollow::update_mesh()
 bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
 {
     // if the gizmo doesn't have the V, F structures for igl, calculate them first:
-    if (! m_mesh_raycaster)
+    if (! m_c->m_mesh_raycaster)
         update_mesh();
 
     const Camera& camera = m_parent.get_camera();
@@ -382,7 +382,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
     // The raycaster query
     Vec3f hit;
     Vec3f normal;
-    if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) {
+    if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) {
         // Return both the point and the facet normal.
         pos_and_normal = std::make_pair(hit, normal);
         return true;
@@ -427,10 +427,10 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
             std::pair<Vec3f, Vec3f> pos_and_normal;
             if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection
                 Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add drainage hole")));
-                m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second,
+                m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second,
                                                              -pos_and_normal.second, m_new_hole_radius, m_new_hole_height+HoleStickOutLength);
                 m_selected.push_back(false);
-                assert(m_selected.size() == m_model_object->sla_drain_holes.size());
+                assert(m_selected.size() == m_c->m_model_object->sla_drain_holes.size());
                 m_parent.set_as_dirty();
                 m_wait_for_up_event = true;
             }
@@ -449,11 +449,11 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
         GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state();
 
         // First collect positions of all the points in world coordinates.
-        Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation();
+        Geometry::Transformation trafo = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation();
         trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
         std::vector<Vec3d> points;
-        for (unsigned int i=0; i<m_model_object->sla_drain_holes.size(); ++i)
-            points.push_back(trafo.get_matrix() * m_model_object->sla_drain_holes[i].pos.cast<double>());
+        for (unsigned int i=0; i<m_c->m_model_object->sla_drain_holes.size(); ++i)
+            points.push_back(trafo.get_matrix() * m_c->m_model_object->sla_drain_holes[i].pos.cast<double>());
 
         // Now ask the rectangle which of the points are inside.
         std::vector<Vec3f> points_inside;
@@ -462,7 +462,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
             points_inside.push_back(points[idx].cast<float>());
 
         // Only select/deselect points that are actually visible
-        for (size_t idx :  m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
+        for (size_t idx :  m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
         {
             if (rectangle_status == GLSelectionRectangle::Deselect)
                 unselect_point(points_idxs[idx]);
@@ -539,10 +539,10 @@ void GLGizmoHollow::delete_selected_points()
 {
     Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete drainage hole")));
 
-    for (unsigned int idx=0; idx<m_model_object->sla_drain_holes.size(); ++idx) {
+    for (unsigned int idx=0; idx<m_c->m_model_object->sla_drain_holes.size(); ++idx) {
         if (m_selected[idx]) {
             m_selected.erase(m_selected.begin()+idx);
-            m_model_object->sla_drain_holes.erase(m_model_object->sla_drain_holes.begin() + (idx--));
+            m_c->m_model_object->sla_drain_holes.erase(m_c->m_model_object->sla_drain_holes.begin() + (idx--));
         }
     }
 
@@ -555,8 +555,8 @@ void GLGizmoHollow::on_update(const UpdateData& data)
         std::pair<Vec3f, Vec3f> pos_and_normal;
         if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
             return;
-        m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second;
-        m_model_object->sla_drain_holes[m_hover_id].normal = -pos_and_normal.second;
+        m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second;
+        m_c->m_model_object->sla_drain_holes[m_hover_id].normal = -pos_and_normal.second;
     }
 }
 
@@ -568,14 +568,14 @@ std::pair<const TriangleMesh *, sla::HollowingConfig> GLGizmoHollow::get_hollowi
     double offset = static_cast<const ConfigOptionFloat*>(opts[0])->value;
     double quality = static_cast<const ConfigOptionFloat*>(opts[1])->value;
     double closing_d = static_cast<const ConfigOptionFloat*>(opts[2])->value;
-    return std::make_pair(m_mesh, sla::HollowingConfig{offset, quality, closing_d});
+    return std::make_pair(m_c->m_mesh, sla::HollowingConfig{offset, quality, closing_d});
 }
 
 void GLGizmoHollow::update_mesh_raycaster(std::unique_ptr<MeshRaycaster> &&rc)
 {
-    m_mesh_raycaster = std::move(rc);
-    m_object_clipper.reset();
-    m_volume_with_cavity.reset();
+    m_c->m_mesh_raycaster = std::move(rc);
+    m_c->m_object_clipper.reset();
+    m_c->m_volume_with_cavity.reset();
 }
 
 void GLGizmoHollow::hollow_mesh()
@@ -588,13 +588,13 @@ void GLGizmoHollow::hollow_mesh()
 void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
 {
     // Called from Plater when the UI job finishes
-    m_cavity_mesh = std::move(mesh);
+    m_c->m_cavity_mesh = std::move(mesh);
     
-    if(m_cavity_mesh) {
+    if(m_c->m_cavity_mesh) {
         // First subtract the holes:
-        if (! m_model_object->sla_drain_holes.empty()) {
+        if (! m_c->m_model_object->sla_drain_holes.empty()) {
             TriangleMesh holes_mesh;
-            for (const sla::DrainHole& hole : m_model_object->sla_drain_holes) {
+            for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) {
                 TriangleMesh hole_mesh = make_cylinder(hole.radius, hole.height, 2*M_PI/8);
                 Eigen::Quaternionf q;
                 Transform3f m = Transform3f::Identity();
@@ -602,22 +602,22 @@ void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
                 hole_mesh.transform(m.cast<double>());
                 hole_mesh.translate(hole.pos);
                 holes_mesh.merge(hole_mesh);
-                //MeshBoolean::minus(*m_cavity_mesh.get(), hole_mesh);
+                //MeshBoolean::minus(*m_c->m_cavity_mesh.get(), hole_mesh);
             }
-            MeshBoolean::minus(*m_cavity_mesh.get(), holes_mesh);
+            MeshBoolean::minus(*m_c->m_cavity_mesh.get(), holes_mesh);
         }
 
 
         // create a new GLVolume that only has the cavity inside
-        Geometry::Transformation volume_trafo = m_model_object->volumes.front()->get_transformation();
+        Geometry::Transformation volume_trafo = m_c->m_model_object->volumes.front()->get_transformation();
         volume_trafo.set_offset(volume_trafo.get_offset() + Vec3d(0., 0., m_z_shift));
-        m_volume_with_cavity.reset(new GLVolume(1.f, 0.f, 0.f, 0.5f));
-        m_volume_with_cavity->indexed_vertex_array.load_mesh(*m_cavity_mesh.get());
-        m_volume_with_cavity->finalize_geometry(true);
-        m_volume_with_cavity->set_volume_transformation(volume_trafo);
-        m_volume_with_cavity->set_instance_transformation(m_model_object->instances[size_t(m_active_instance)]->get_transformation());
+        m_c->m_volume_with_cavity.reset(new GLVolume(1.f, 0.f, 0.f, 0.5f));
+        m_c->m_volume_with_cavity->indexed_vertex_array.load_mesh(*m_c->m_cavity_mesh.get());
+        m_c->m_volume_with_cavity->finalize_geometry(true);
+        m_c->m_volume_with_cavity->set_volume_transformation(volume_trafo);
+        m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation());
     }
-    m_parent.toggle_model_objects_visibility(! m_cavity_mesh, m_model_object, m_active_instance);
+    m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance);
     if (m_clipping_plane_distance == 0.f) {
         m_clipping_plane_distance = 0.5f;
         update_clipping_plane();
@@ -628,10 +628,10 @@ std::vector<const ConfigOption*> GLGizmoHollow::get_config_options(const std::ve
 {
     std::vector<const ConfigOption*> out;
 
-    if (!m_model_object)
+    if (!m_c->m_model_object)
         return out;
 
-    const DynamicPrintConfig& object_cfg = m_model_object->config;
+    const DynamicPrintConfig& object_cfg = m_c->m_model_object->config;
     const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
     std::unique_ptr<DynamicPrintConfig> default_cfg = nullptr;
 
@@ -654,7 +654,7 @@ std::vector<const ConfigOption*> GLGizmoHollow::get_config_options(const std::ve
 
 ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const
 {
-    if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
+    if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
         return ClippingPlane::ClipsNothing();
     else
         return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]);
@@ -663,7 +663,7 @@ ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const
 
 void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit)
 {
-    if (! m_model_object)
+    if (! m_c->m_model_object)
         return;
 
     bool first_run = true; // This is a hack to redraw the button when all points are removed,
@@ -694,7 +694,7 @@ RENDER_AGAIN:
         std::vector<const ConfigOption*> opts = get_config_options({"hollowing_enable"});
         m_enable_hollowing = static_cast<const ConfigOptionBool*>(opts[0])->value;
         if (m_imgui->checkbox(m_desc["enable"], m_enable_hollowing)) {
-            m_model_object->config.opt<ConfigOptionBool>("hollowing_enable", true)->value = m_enable_hollowing;
+            m_c->m_model_object->config.opt<ConfigOptionBool>("hollowing_enable", true)->value = m_enable_hollowing;
             wxGetApp().obj_list()->update_and_show_object_settings_item();
         }
     }
@@ -738,14 +738,14 @@ RENDER_AGAIN:
     }
     if (slider_edited || slider_released) {
         if (slider_released) {
-            m_model_object->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = m_offset_stash;
-            m_model_object->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = m_quality_stash;
-            m_model_object->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = m_closing_d_stash;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = m_offset_stash;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = m_quality_stash;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = m_closing_d_stash;
             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Hollowing parameter change")));
         }
-        m_model_object->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = offset;
-        m_model_object->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = quality;
-        m_model_object->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = closing_d;
+        m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_min_thickness", true)->value = offset;
+        m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_quality", true)->value = quality;
+        m_c->m_model_object->config.opt<ConfigOptionFloat>("hollowing_closing_distance", true)->value = closing_d;
         if (slider_released)
             wxGetApp().obj_list()->update_and_show_object_settings_item();
     }
@@ -786,19 +786,19 @@ RENDER_AGAIN:
     //  - take correct undo/redo snapshot after the user is done with moving the slider
     if (! m_selection_empty) {
         if (clicked) {
-            m_holes_stash = m_model_object->sla_drain_holes;
+            m_holes_stash = m_c->m_model_object->sla_drain_holes;
         }
         if (edited) {
             for (size_t idx=0; idx<m_selected.size(); ++idx)
                 if (m_selected[idx]) {
-                    m_model_object->sla_drain_holes[idx].radius = m_new_hole_radius;
-                    m_model_object->sla_drain_holes[idx].height = m_new_hole_height;
+                    m_c->m_model_object->sla_drain_holes[idx].radius = m_new_hole_radius;
+                    m_c->m_model_object->sla_drain_holes[idx].height = m_new_hole_height;
                 }
         }
         if (deactivated) {
             // momentarily restore the old value to take snapshot
-            sla::DrainHoles new_holes = m_model_object->sla_drain_holes;
-            m_model_object->sla_drain_holes = m_holes_stash;
+            sla::DrainHoles new_holes = m_c->m_model_object->sla_drain_holes;
+            m_c->m_model_object->sla_drain_holes = m_holes_stash;
             float backup_rad = m_new_hole_radius;
             float backup_hei = m_new_hole_height;
             for (size_t i=0; i<m_holes_stash.size(); ++i) {
@@ -811,7 +811,7 @@ RENDER_AGAIN:
             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Change drainage hole diameter")));
             m_new_hole_radius = backup_rad;
             m_new_hole_height = backup_hei;
-            m_model_object->sla_drain_holes = new_holes;
+            m_c->m_model_object->sla_drain_holes = new_holes;
         }
     }
 
@@ -819,7 +819,7 @@ RENDER_AGAIN:
     remove_selected = m_imgui->button(m_desc.at("remove_selected"));
     m_imgui->disabled_end();
 
-    m_imgui->disabled_begin(m_model_object->sla_drain_holes.empty());
+    m_imgui->disabled_begin(m_c->m_model_object->sla_drain_holes.empty());
     remove_all = m_imgui->button(m_desc.at("remove_all"));
     m_imgui->disabled_end();
 
@@ -842,7 +842,7 @@ RENDER_AGAIN:
 
     // make sure supports are shown/hidden as appropriate
     m_imgui->checkbox(m_desc["show_supports"], m_show_supports);
-    force_refresh = m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_model_object, m_active_instance);
+    force_refresh = m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
 
     m_imgui->end();
 
@@ -896,19 +896,19 @@ std::string GLGizmoHollow::on_get_name() const
 }
 
 
-const TriangleMesh* GLGizmoHollow::mesh() const {
-    return (! m_mesh ? nullptr : (m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
-}
+//const TriangleMesh* GLGizmoHollow::mesh() const {
+//    return (! m_c->m_mesh ? nullptr : (m_c->m_cavity_mesh ? m_c->m_cavity_mesh.get() : m_c->m_mesh));
+//}
 
 
 void GLGizmoHollow::on_set_state()
 {
-    // m_model_object pointer can be invalid (for instance because of undo/redo action),
+    // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action),
     // we should recover it from the object id
-    m_model_object = nullptr;
+    m_c->m_model_object = nullptr;
     for (const auto mo : wxGetApp().model().objects) {
-        if (mo->id() == m_model_object_id) {
-            m_model_object = mo;
+        if (mo->id() == m_c->m_model_object_id) {
+            m_c->m_model_object = mo;
             break;
         }
     }
@@ -922,12 +922,12 @@ void GLGizmoHollow::on_set_state()
             update_mesh();
 
         // we'll now reload support points:
-        if (m_model_object)
+        if (m_c->m_model_object)
             reload_cache();
 
         m_parent.toggle_model_objects_visibility(false);
-        if (m_model_object)
-            m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
+        if (m_c->m_model_object)
+            m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
 
         // Set default head diameter from config.
         const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
@@ -938,11 +938,11 @@ void GLGizmoHollow::on_set_state()
         m_parent.toggle_model_objects_visibility(true);
         m_clipping_plane_distance = 0.f;
         // Release clippers and the AABB raycaster.
-        m_object_clipper.reset();
-        m_supports_clipper.reset();
-        m_mesh_raycaster.reset();
-        m_cavity_mesh.reset();
-        m_volume_with_cavity.reset();
+        m_c->m_object_clipper.reset();
+        m_c->m_supports_clipper.reset();
+        m_c->m_mesh_raycaster.reset();
+        m_c->m_cavity_mesh.reset();
+        m_c->m_volume_with_cavity.reset();
     }
     m_old_state = m_state;
 }
@@ -954,7 +954,7 @@ void GLGizmoHollow::on_start_dragging()
     if (m_hover_id != -1) {
         select_point(NoPoints);
         select_point(m_hover_id);
-        m_hole_before_drag = m_model_object->sla_drain_holes[m_hover_id].pos;
+        m_hole_before_drag = m_c->m_model_object->sla_drain_holes[m_hover_id].pos;
     }
     else
         m_hole_before_drag = Vec3f::Zero();
@@ -964,14 +964,14 @@ void GLGizmoHollow::on_start_dragging()
 void GLGizmoHollow::on_stop_dragging()
 {
     if (m_hover_id != -1) {
-        Vec3f backup = m_model_object->sla_drain_holes[m_hover_id].pos;
+        Vec3f backup = m_c->m_model_object->sla_drain_holes[m_hover_id].pos;
 
         if (m_hole_before_drag != Vec3f::Zero() // some point was touched
          && backup != m_hole_before_drag) // and it was moved, not just selected
         {
-            m_model_object->sla_drain_holes[m_hover_id].pos = m_hole_before_drag;
+            m_c->m_model_object->sla_drain_holes[m_hover_id].pos = m_hole_before_drag;
             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Move drainage hole")));
-            m_model_object->sla_drain_holes[m_hover_id].pos = backup;
+            m_c->m_model_object->sla_drain_holes[m_hover_id].pos = backup;
         }
     }
     m_hole_before_drag = Vec3f::Zero();
@@ -983,7 +983,7 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
 {
     ar(m_clipping_plane_distance,
        *m_clipping_plane,
-       m_model_object_id,
+       m_c->m_model_object_id,
        m_new_hole_radius,
        m_new_hole_height,
        m_selected,
@@ -997,7 +997,7 @@ void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const
 {
     ar(m_clipping_plane_distance,
        *m_clipping_plane,
-       m_model_object_id,
+       m_c->m_model_object_id,
        m_new_hole_radius,
        m_new_hole_height,
        m_selected,
@@ -1014,8 +1014,8 @@ void GLGizmoHollow::select_point(int i)
         m_selection_empty = (i == NoPoints);
 
         if (i == AllPoints) {
-            m_new_hole_radius = m_model_object->sla_drain_holes[0].radius;
-            m_new_hole_height = m_model_object->sla_drain_holes[0].height;
+            m_new_hole_radius = m_c->m_model_object->sla_drain_holes[0].radius;
+            m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height;
         }
     }
     else {
@@ -1023,8 +1023,8 @@ void GLGizmoHollow::select_point(int i)
             m_selected.push_back(false);
         m_selected[i] = true;
         m_selection_empty = false;
-        m_new_hole_radius = m_model_object->sla_drain_holes[i].radius;
-        m_new_hole_height = m_model_object->sla_drain_holes[i].height;
+        m_new_hole_radius = m_c->m_model_object->sla_drain_holes[i].radius;
+        m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height;
     }
 }
 
@@ -1044,7 +1044,7 @@ void GLGizmoHollow::unselect_point(int i)
 void GLGizmoHollow::reload_cache()
 {
     m_selected.clear();
-    m_selected.assign(m_model_object->sla_drain_holes.size(), false);
+    m_selected.assign(m_c->m_model_object->sla_drain_holes.size(), false);
 }
 
 void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
@@ -1052,9 +1052,9 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
     Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
                         m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
 
-    const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
+    const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
     float dist = normal.dot(center);
-    *m_clipping_plane = ClippingPlane(normal, (dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius));
+    *m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius));
     m_parent.set_as_dirty();
 }
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp
index 8e022eb1e..bea396097 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp
@@ -21,10 +21,10 @@ enum class SLAGizmoEventType : unsigned char;
 class GLGizmoHollow : public GLGizmoBase
 {
 private:
-    ModelObject* m_model_object = nullptr;
-    ObjectID m_model_object_id = 0;
-    int m_active_instance = -1;
-    float m_active_instance_bb_radius; // to cache the bb
+    //ModelObject* m_model_object = nullptr;
+    //ObjectID m_model_object_id = 0;
+    //int m_active_instance = -1;
+    //float m_active_instance_bb_radius; // to cache the bb
     mutable double m_z_shift = 0.;
     bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
 
@@ -32,19 +32,16 @@ private:
 
     GLUquadricObj* m_quadric;
 
-    std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
-    std::unique_ptr<TriangleMesh> m_cavity_mesh;
-    std::unique_ptr<GLVolume> m_volume_with_cavity;
-    const TriangleMesh* m_mesh;
-    mutable const TriangleMesh* m_supports_mesh;
-    mutable std::vector<Vec2f> m_triangles;
-    mutable std::vector<Vec2f> m_supports_triangles;
-    mutable int m_old_timestamp = -1;
-    mutable int m_print_object_idx = -1;
-    mutable int m_print_objects_count = -1;
+    //std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
+    //std::unique_ptr<TriangleMesh> m_cavity_mesh;
+    //std::unique_ptr<GLVolume> m_volume_with_cavity;
+    //const TriangleMesh* m_mesh;
+    //mutable int m_old_timestamp = -1;
+    //mutable int m_print_object_idx = -1;
+    //mutable int m_print_objects_count = -1;
 
 public:
-    GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
+    GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
     ~GLGizmoHollow() override;
     void set_sla_support_data(ModelObject* model_object, const Selection& selection);
     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@@ -70,7 +67,6 @@ private:
     void update_mesh();
     void hollow_mesh();
     bool unsaved_changes() const;
-    const TriangleMesh* mesh() const;
 
     bool  m_show_supports = true;
     float m_new_hole_radius;        // Size of a new hole.
@@ -104,8 +100,8 @@ private:
     bool m_selection_empty = true;
     EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
 
-    mutable std::unique_ptr<MeshClipper> m_object_clipper;
-    mutable std::unique_ptr<MeshClipper> m_supports_clipper;
+    //mutable std::unique_ptr<MeshClipper> m_object_clipper;
+    //mutable std::unique_ptr<MeshClipper> m_supports_clipper;
 
     std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
     bool is_mesh_point_clipped(const Vec3d& point) const;
@@ -126,7 +122,7 @@ protected:
     void on_set_hover_id() override
 
     {
-        if (int(m_model_object->sla_drain_holes.size()) <= m_hover_id)
+        if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
             m_hover_id = -1;
     }
     void on_start_dragging() override;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index b10f57108..85d57a211 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -22,8 +22,8 @@
 namespace Slic3r {
 namespace GUI {
 
-GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
-    : GLGizmoBase(parent, icon_filename, sprite_id)
+GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
+    : GLGizmoBase(parent, icon_filename, sprite_id, cd)
     , m_quadric(nullptr)
     , m_its(nullptr)
 {
@@ -64,23 +64,23 @@ bool GLGizmoSlaSupports::on_init()
 void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
 {
     if (! model_object || selection.is_empty()) {
-        m_model_object = nullptr;
+        m_c->m_model_object = nullptr;
         return;
     }
 
-    if (m_model_object != model_object || m_model_object_id != model_object->id()) {
-        m_model_object = model_object;
-        m_print_object_idx = -1;
+    if (m_c->m_model_object != model_object || m_c->m_model_object_id != model_object->id()) {
+        m_c->m_model_object = model_object;
+        m_c->m_print_object_idx = -1;
     }
 
-    m_active_instance = selection.get_instance_idx();
+    m_c->m_active_instance = selection.get_instance_idx();
 
     if (model_object && selection.is_from_single_instance())
     {
         // Cache the bb - it's needed for dealing with the clipping plane quite often
         // It could be done inside update_mesh but one has to account for scaling of the instance.
         //FIXME calling ModelObject::instance_bounding_box() is expensive!
-        m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
+        m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius();
 
         if (is_mesh_update_necessary()) {
             update_mesh();
@@ -88,12 +88,12 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
         }
 
         // If we triggered autogeneration before, check backend and fetch results if they are there
-        if (m_model_object->sla_points_status == sla::PointsStatus::Generating)
+        if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)
             get_data_from_backend();
 
         if (m_state == On) {
             m_parent.toggle_model_objects_visibility(false);
-            m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
+            m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
         }
         else
             m_parent.toggle_model_objects_visibility(true, nullptr, -1);
@@ -106,16 +106,16 @@ void GLGizmoSlaSupports::on_render() const
 {
     const Selection& selection = m_parent.get_selection();
 
-    // If current m_model_object does not match selection, ask GLCanvas3D to turn us off
+    // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off
     if (m_state == On
-     && (m_model_object != selection.get_model()->objects[selection.get_object_idx()]
-      || m_active_instance != selection.get_instance_idx()
-      || m_model_object_id != m_model_object->id())) {
+     && (m_c->m_model_object != selection.get_model()->objects[selection.get_object_idx()]
+      || m_c->m_active_instance != selection.get_instance_idx()
+      || m_c->m_model_object_id != m_c->m_model_object->id())) {
         m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS));
         return;
     }
 
-    if (! m_its || ! m_mesh)
+    if (! m_its || ! m_c->m_mesh)
         const_cast<GLGizmoSlaSupports*>(this)->update_mesh();
 
     glsafe(::glEnable(GL_BLEND));
@@ -136,7 +136,7 @@ void GLGizmoSlaSupports::on_render() const
 
 void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
 {
-    if (m_clipping_plane_distance == 0.f || m_mesh->empty())
+    if (m_clipping_plane_distance == 0.f || m_c->m_mesh->empty())
         return;
 
     // Get transformation of the instance
@@ -154,66 +154,66 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
                                     1.));
 
     // Now initialize the TMS for the object, perform the cut and save the result.
-    if (! m_object_clipper) {
-        m_object_clipper.reset(new MeshClipper);
-        m_object_clipper->set_mesh(*m_mesh);
+    if (! m_c->m_object_clipper) {
+        m_c->m_object_clipper.reset(new MeshClipper);
+        m_c->m_object_clipper->set_mesh(*m_c->mesh());
     }
-    m_object_clipper->set_plane(*m_clipping_plane);
-    m_object_clipper->set_transformation(trafo);
+    m_c->m_object_clipper->set_plane(*m_clipping_plane);
+    m_c->m_object_clipper->set_transformation(trafo);
 
 
     // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
     // First we need a pointer to the respective SLAPrintObject. The index into objects vector is
     // cached so we don't have todo it on each render. We only search for the po if needed:
-    if (m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) {
-        m_print_objects_count = m_parent.sla_print()->objects().size();
-        m_print_object_idx = -1;
+    if (m_c->m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_c->m_print_objects_count) {
+        m_c->m_print_objects_count = m_parent.sla_print()->objects().size();
+        m_c->m_print_object_idx = -1;
         for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
-            ++m_print_object_idx;
-            if (po->model_object()->id() == m_model_object->id())
+            ++m_c->m_print_object_idx;
+            if (po->model_object()->id() == m_c->m_model_object->id())
                 break;
         }
     }
-    if (m_print_object_idx >= 0) {
-        const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx];
+    if (m_c->m_print_object_idx >= 0) {
+        const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx];
 
         if (print_object->is_step_done(slaposSupportTree) && !print_object->get_mesh(slaposSupportTree).empty()) {
             // If the supports are already calculated, save the timestamp of the respective step
             // so we can later tell they were recalculated.
             size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
 
-            if (! m_supports_clipper || (int)timestamp != m_old_timestamp) {
+            if (! m_c->m_supports_clipper || (int)timestamp != m_c->m_old_timestamp) {
                 // The timestamp has changed.
-                m_supports_clipper.reset(new MeshClipper);
+                m_c->m_supports_clipper.reset(new MeshClipper);
                 // The mesh should already have the shared vertices calculated.
-                m_supports_clipper->set_mesh(print_object->support_mesh());
-                m_old_timestamp = timestamp;
+                m_c->m_supports_clipper->set_mesh(print_object->support_mesh());
+                m_c->m_old_timestamp = timestamp;
             }
-            m_supports_clipper->set_plane(*m_clipping_plane);
-            m_supports_clipper->set_transformation(supports_trafo);
+            m_c->m_supports_clipper->set_plane(*m_clipping_plane);
+            m_c->m_supports_clipper->set_transformation(supports_trafo);
         }
         else
             // The supports are not valid. We better dump the cached data.
-            m_supports_clipper.reset();
+            m_c->m_supports_clipper.reset();
     }
 
     // At this point we have the triangulated cuts for both the object and supports - let's render.
-    if (! m_object_clipper->get_triangles().empty()) {
+    if (! m_c->m_object_clipper->get_triangles().empty()) {
 		::glPushMatrix();
         ::glColor3f(1.0f, 0.37f, 0.0f);
         ::glBegin(GL_TRIANGLES);
-        for (const Vec3f& point : m_object_clipper->get_triangles())
+        for (const Vec3f& point : m_c->m_object_clipper->get_triangles())
             ::glVertex3f(point(0), point(1), point(2));
         ::glEnd();
 		::glPopMatrix();
 	}
 
-    if (m_supports_clipper && ! m_supports_clipper->get_triangles().empty() && !m_editing_mode) {
+    if (m_c->m_supports_clipper && ! m_c->m_supports_clipper->get_triangles().empty() && !m_editing_mode) {
         // The supports are hidden in the editing mode, so it makes no sense to render the cuts.
         ::glPushMatrix();
         ::glColor3f(1.0f, 0.f, 0.37f);
         ::glBegin(GL_TRIANGLES);
-        for (const Vec3f& point : m_supports_clipper->get_triangles())
+        for (const Vec3f& point : m_c->m_supports_clipper->get_triangles())
             ::glVertex3f(point(0), point(1), point(2));
         ::glEnd();
 		::glPopMatrix();
@@ -298,7 +298,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
         if (m_editing_mode) {
             // in case the normal is not yet cached, find and cache it
             if (m_editing_cache[i].normal == Vec3f::Zero())
-                m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
+                m_c->m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
 
             Eigen::Quaterniond q;
             q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
@@ -333,7 +333,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
     render_color[2] = 0.7f;
     render_color[3] = 0.7f;
     glsafe(::glColor4fv(render_color));
-    for (const sla::DrainHole& drain_hole : m_model_object->sla_drain_holes) {
+    for (const sla::DrainHole& drain_hole : m_c->m_model_object->sla_drain_holes) {
         // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
         glsafe(::glPushMatrix());
         glsafe(::glTranslatef(drain_hole.pos(0), drain_hole.pos(1), drain_hole.pos(2)));
@@ -377,7 +377,7 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
     if (m_clipping_plane_distance == 0.f)
         return false;
 
-    Vec3d transformed_point = m_model_object->instances[m_active_instance]->get_transformation().get_matrix() * point;
+    Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point;
     transformed_point(2) += m_z_shift;
     return m_clipping_plane->is_point_clipped(transformed_point);
 }
@@ -386,28 +386,28 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
 
 bool GLGizmoSlaSupports::is_mesh_update_necessary() const
 {
-    return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty())
-        && ((m_model_object->id() != m_model_object_id) || m_its == nullptr);
+    return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty())
+        && ((m_c->m_model_object->id() != m_c->m_model_object_id) || m_its == nullptr);
 }
 
 
 
 void GLGizmoSlaSupports::update_mesh()
 {
-    if (! m_model_object)
+    if (! m_c->m_model_object)
         return;
 
     wxBusyCursor wait;
     // this way we can use that mesh directly.
     // This mesh does not account for the possible Z up SLA offset.
-    m_mesh = &m_model_object->volumes.front()->mesh();
-    m_its = &m_mesh->its;
+    m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh();
+    m_its = &m_c->m_mesh->its;
 
     // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
-    if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster)
-        m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
+    if (m_c->m_model_object_id != m_c->m_model_object->id() || ! m_c->m_mesh_raycaster)
+        m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
 
-    m_model_object_id = m_model_object->id();
+    m_c->m_model_object_id = m_c->m_model_object->id();
     disable_editing_mode();
 }
 
@@ -417,7 +417,7 @@ void GLGizmoSlaSupports::update_mesh()
 bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
 {
     // if the gizmo doesn't have the V, F structures for igl, calculate them first:
-    if (! m_mesh_raycaster)
+    if (! m_c->m_mesh_raycaster)
         update_mesh();
 
     const Camera& camera = m_parent.get_camera();
@@ -429,10 +429,10 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
     // The raycaster query
     Vec3f hit;
     Vec3f normal;
-    if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) {
+    if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) {
         // Check whether the hit is in a hole
         bool in_hole = false;
-        for (const sla::DrainHole& hole : m_model_object->sla_drain_holes) {
+        for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) {
             if (hole.is_inside(hit)) {
                 in_hole = true;
                 break;
@@ -505,7 +505,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
             GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state();
 
             // First collect positions of all the points in world coordinates.
-            Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation();
+            Geometry::Transformation trafo = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation();
             trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
             std::vector<Vec3d> points;
             for (unsigned int i=0; i<m_editing_cache.size(); ++i)
@@ -518,7 +518,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
                 points_inside.push_back(points[idx].cast<float>());
 
             // Only select/deselect points that are actually visible
-            for (size_t idx :  m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
+            for (size_t idx :  m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
             {
                 if (rectangle_status == GLSelectionRectangle::Deselect)
                     unselect_point(points_idxs[idx]);
@@ -656,10 +656,10 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
 {
     std::vector<const ConfigOption*> out;
 
-    if (!m_model_object)
+    if (!m_c->m_model_object)
         return out;
 
-    const DynamicPrintConfig& object_cfg = m_model_object->config;
+    const DynamicPrintConfig& object_cfg = m_c->m_model_object->config;
     const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
     std::unique_ptr<DynamicPrintConfig> default_cfg = nullptr;
 
@@ -682,7 +682,7 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
 
 ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const
 {
-    if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
+    if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f)
         return ClippingPlane::ClipsNothing();
     else
         return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]);
@@ -711,7 +711,7 @@ void GLGizmoSlaSupports::find_intersecting_facets(const igl::AABB<Eigen::MatrixX
 
 void GLGizmoSlaSupports::make_line_segments() const
 {
-    TriangleMeshSlicer tms(&m_model_object->volumes.front()->mesh);
+    TriangleMeshSlicer tms(&m_c->m_model_object->volumes.front()->mesh);
     Vec3f normal(0.f, 1.f, 1.f);
     double d = 0.;
 
@@ -732,7 +732,7 @@ void GLGizmoSlaSupports::make_line_segments() const
 
 void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit)
 {
-    if (!m_model_object)
+    if (!m_c->m_model_object)
         return;
 
     bool first_run = true; // This is a hack to redraw the button when all points are removed,
@@ -853,15 +853,15 @@ RENDER_AGAIN:
             m_density_stash = density;
         }
         if (slider_edited) {
-            m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
-            m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
+            m_c->m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
         }
         if (slider_released) {
-            m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash;
-            m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)m_density_stash;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash;
+            m_c->m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)m_density_stash;
             Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support parameter change")));
-            m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
-            m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
+            m_c->m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
+            m_c->m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
             wxGetApp().obj_list()->update_and_show_object_settings_item();
         }
 
@@ -879,10 +879,10 @@ RENDER_AGAIN:
         m_imgui->disabled_end();
 
         // m_imgui->text("");
-        // m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::NoPoints ? _(L("No points  (will be autogenerated)")) :
-        //              (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? _(L("Autogenerated points (no modifications)")) :
-        //              (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? _(L("User-modified points")) :
-        //              (m_model_object->sla_points_status == sla::PointsStatus::Generating ? _(L("Generation in progress...")) : "UNKNOWN STATUS"))));
+        // m_imgui->text(m_c->m_model_object->sla_points_status == sla::PointsStatus::NoPoints ? _(L("No points  (will be autogenerated)")) :
+        //              (m_c->m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? _(L("Autogenerated points (no modifications)")) :
+        //              (m_c->m_model_object->sla_points_status == sla::PointsStatus::UserModified ? _(L("User-modified points")) :
+        //              (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating ? _(L("Generation in progress...")) : "UNKNOWN STATUS"))));
     }
 
 
@@ -920,7 +920,7 @@ RENDER_AGAIN:
     // is done on each refresh because the user can switch the editing mode
     // before background process finishes.
     force_refresh = m_parent.toggle_sla_auxiliaries_visibility(
-                ! m_editing_mode, m_model_object, m_active_instance);
+                ! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
 
     if (remove_selected || remove_all) {
         force_refresh = false;
@@ -978,12 +978,12 @@ std::string GLGizmoSlaSupports::on_get_name() const
 
 void GLGizmoSlaSupports::on_set_state()
 {
-    // m_model_object pointer can be invalid (for instance because of undo/redo action),
+    // m_c->m_model_object pointer can be invalid (for instance because of undo/redo action),
     // we should recover it from the object id
-    m_model_object = nullptr;
+    m_c->m_model_object = nullptr;
     for (const auto mo : wxGetApp().model().objects) {
-        if (mo->id() == m_model_object_id) {
-            m_model_object = mo;
+        if (mo->id() == m_c->m_model_object_id) {
+            m_c->m_model_object = mo;
             break;
         }
     }
@@ -997,19 +997,19 @@ void GLGizmoSlaSupports::on_set_state()
             update_mesh();
 
         // we'll now reload support points:
-        if (m_model_object)
+        if (m_c->m_model_object)
             reload_cache();
 
         m_parent.toggle_model_objects_visibility(false);
-        if (m_model_object)
-            m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
+        if (m_c->m_model_object)
+            m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
 
         // Set default head diameter from config.
         const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
         m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
     }
     if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
-        bool will_ask = m_model_object && m_editing_mode && unsaved_changes();
+        bool will_ask = m_c->m_model_object && m_editing_mode && unsaved_changes();
         if (will_ask) {
             wxGetApp().CallAfter([this]() {
                 // Following is called through CallAfter, because otherwise there was a problem
@@ -1033,9 +1033,9 @@ void GLGizmoSlaSupports::on_set_state()
             m_clipping_plane_distance = 0.f;
             // Release clippers and the AABB raycaster.
             m_its = nullptr;
-            m_object_clipper.reset();
-            m_supports_clipper.reset();
-            m_mesh_raycaster.reset();
+            m_c->m_object_clipper.reset();
+            m_c->m_supports_clipper.reset();
+            m_c->m_mesh_raycaster.reset();
         }
     }
     m_old_state = m_state;
@@ -1077,7 +1077,7 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
 {
     ar(m_clipping_plane_distance,
        *m_clipping_plane,
-       m_model_object_id,
+       m_c->m_model_object_id,
        m_new_point_head_diameter,
        m_normal_cache,
        m_editing_cache,
@@ -1091,7 +1091,7 @@ void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
 {
     ar(m_clipping_plane_distance,
        *m_clipping_plane,
-       m_model_object_id,
+       m_c->m_model_object_id,
        m_new_point_head_diameter,
        m_normal_cache,
        m_editing_cache,
@@ -1169,9 +1169,9 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
         for (const CacheEntry& ce : m_editing_cache)
             m_normal_cache.push_back(ce.support_point);
 
-        m_model_object->sla_points_status = sla::PointsStatus::UserModified;
-        m_model_object->sla_support_points.clear();
-        m_model_object->sla_support_points = m_normal_cache;
+        m_c->m_model_object->sla_points_status = sla::PointsStatus::UserModified;
+        m_c->m_model_object->sla_support_points.clear();
+        m_c->m_model_object->sla_support_points = m_normal_cache;
 
         reslice_SLA_supports();
     }
@@ -1182,10 +1182,10 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
 void GLGizmoSlaSupports::reload_cache()
 {
     m_normal_cache.clear();
-    if (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated || m_model_object->sla_points_status == sla::PointsStatus::Generating)
+    if (m_c->m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated || m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)
         get_data_from_backend();
     else
-        for (const sla::SupportPoint& point : m_model_object->sla_support_points)
+        for (const sla::SupportPoint& point : m_c->m_model_object->sla_support_points)
             m_normal_cache.emplace_back(point);
 }
 
@@ -1194,7 +1194,7 @@ bool GLGizmoSlaSupports::has_backend_supports() const
 {
     // find SlaPrintObject with this ID
     for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
-        if (po->model_object()->id() == m_model_object->id())
+        if (po->model_object()->id() == m_c->m_model_object->id())
         	return po->is_step_done(slaposSupportPoints);
     }
     return false;
@@ -1202,7 +1202,7 @@ bool GLGizmoSlaSupports::has_backend_supports() const
 
 void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const
 {
-    wxGetApp().CallAfter([this, postpone_error_messages]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object, postpone_error_messages); });
+    wxGetApp().CallAfter([this, postpone_error_messages]() { wxGetApp().plater()->reslice_SLA_supports(*m_c->m_model_object, postpone_error_messages); });
 }
 
 void GLGizmoSlaSupports::get_data_from_backend()
@@ -1212,14 +1212,14 @@ void GLGizmoSlaSupports::get_data_from_backend()
 
     // find the respective SLAPrintObject, we need a pointer to it
     for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
-        if (po->model_object()->id() == m_model_object->id()) {
+        if (po->model_object()->id() == m_c->m_model_object->id()) {
             m_normal_cache.clear();
             const std::vector<sla::SupportPoint>& points = po->get_support_points();
             auto mat = po->trafo().inverse().cast<float>();
             for (unsigned int i=0; i<points.size();++i)
                 m_normal_cache.emplace_back(sla::SupportPoint(mat * points[i].pos, points[i].head_front_radius, points[i].is_new_island));
 
-            m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated;
+            m_c->m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated;
             break;
         }
     }
@@ -1236,10 +1236,10 @@ void GLGizmoSlaSupports::auto_generate()
                         _(L("Are you sure you want to do it?")) + "\n",
                         _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
 
-    if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) {
+    if (m_c->m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) {
         Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Autogenerate support points")));
         wxGetApp().CallAfter([this]() { reslice_SLA_supports(); });
-        m_model_object->sla_points_status = sla::PointsStatus::Generating;
+        m_c->m_model_object->sla_points_status = sla::PointsStatus::Generating;
     }
 }
 
@@ -1284,9 +1284,9 @@ void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const
     Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
                         m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
 
-    const Vec3d& center = m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
+    const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
     float dist = normal.dot(center);
-    *m_clipping_plane = ClippingPlane(normal, (dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius));
+    *m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius));
     m_parent.set_as_dirty();
 }
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index 1de241a53..7700ad3a6 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -21,10 +21,10 @@ enum class SLAGizmoEventType : unsigned char;
 class GLGizmoSlaSupports : public GLGizmoBase
 {
 private:
-    ModelObject* m_model_object = nullptr;
-    ObjectID m_model_object_id = 0;
-    int m_active_instance = -1;
-    float m_active_instance_bb_radius; // to cache the bb
+    //ModelObject* m_model_object = nullptr;
+    //ObjectID m_model_object_id = 0;
+    //int m_active_instance = -1;
+    //float m_active_instance_bb_radius; // to cache the bb
     mutable double m_z_shift = 0.f;
     bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
 
@@ -34,15 +34,12 @@ private:
     typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
     typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
 
-    std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
-    const TriangleMesh* m_mesh;
+    //std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
+    //const TriangleMesh* m_mesh;
     const indexed_triangle_set* m_its;
-    mutable const TriangleMesh* m_supports_mesh;
-    mutable std::vector<Vec2f> m_triangles;
-    mutable std::vector<Vec2f> m_supports_triangles;
-    mutable int m_old_timestamp = -1;
-    mutable int m_print_object_idx = -1;
-    mutable int m_print_objects_count = -1;
+    //mutable int m_old_timestamp = -1;
+    //mutable int m_print_object_idx = -1;
+    //mutable int m_print_objects_count = -1;
 
     class CacheEntry {
     public:
@@ -72,7 +69,7 @@ private:
     };
 
 public:
-    GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
+    GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
     ~GLGizmoSlaSupports() override;
     void set_sla_support_data(ModelObject* model_object, const Selection& selection);
     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@@ -120,8 +117,8 @@ private:
     bool m_selection_empty = true;
     EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
 
-    mutable std::unique_ptr<MeshClipper> m_object_clipper;
-    mutable std::unique_ptr<MeshClipper> m_supports_clipper;
+    //mutable std::unique_ptr<MeshClipper> m_object_clipper;
+    //mutable std::unique_ptr<MeshClipper> m_supports_clipper;
 
     std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
     bool is_mesh_point_clipped(const Vec3d& point) const;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 89a313445..e089de3fc 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -88,13 +88,15 @@ bool GLGizmosManager::init()
             return false;
     }
 
+    m_common_gizmos_data.reset(new CommonGizmosData());
+
     m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
     m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
     m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
     m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
     m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
-    m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5));
-    m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 6));
+    m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5, m_common_gizmos_data.get()));
+    m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 6, m_common_gizmos_data.get()));
 
     for (auto& gizmo : m_gizmos) {
         if (! gizmo->init()) {
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index 2c4d71316..f816056a0 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -101,6 +101,7 @@ private:
     MouseCapture m_mouse_capture;
     std::string m_tooltip;
     bool m_serializing;
+    std::unique_ptr<CommonGizmosData> m_common_gizmos_data;
 
 public:
     explicit GLGizmosManager(GLCanvas3D& parent);