diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 76c0337d17..7a0ca3e8ff 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3430,14 +3430,14 @@ void GLCanvas3D::Gizmos::set_sla_support_data(ModelObject* model_object, const G reinterpret_cast(it->second)->set_sla_support_data(model_object, selection); } -void GLCanvas3D::Gizmos::clicked_on_object(const Vec2d& mouse_position) +void GLCanvas3D::Gizmos::mouse_event(int action, const Vec2d& mouse_position, bool shift_down) { if (!m_enabled) return; GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); if (it != m_gizmos.end()) - reinterpret_cast(it->second)->clicked_on_object(mouse_position); + reinterpret_cast(it->second)->mouse_event(action, mouse_position, shift_down); } void GLCanvas3D::Gizmos::delete_current_grabber(bool delete_all) @@ -5396,6 +5396,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) _update_gizmos_data(); m_dirty = true; } + else if (evt.LeftDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown()) // inform the gizmo about the event (rectangular selection init) + { + m_gizmos.mouse_event(1, Vec2d(pos(0), pos(1)), evt.ShiftDown()); + } else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) { _update_gizmos_data(); @@ -5579,6 +5583,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } + else if (evt.Dragging() && m_gizmos.get_current_type() == Gizmos::SlaSupports && evt.ShiftDown()) + { + m_gizmos.mouse_event(3, Vec2d(pos(0), pos(1)), evt.ShiftDown()); + } else if (evt.Dragging() && !gizmos_overlay_contains_mouse) { m_mouse.dragging = true; @@ -5643,12 +5651,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); } - else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_hover_volume_id != -1) + else if (evt.LeftUp() && m_gizmos.get_current_type() == Gizmos::SlaSupports/* && m_hover_volume_id != -1*/) { int id = m_selection.get_object_idx(); if ((id != -1) && (m_model != nullptr)) { - m_gizmos.clicked_on_object(Vec2d(pos(0), pos(1))); + m_gizmos.mouse_event(2, Vec2d(pos(0), pos(1)), evt.ShiftDown()); } } else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9f341083be..6fd4584a6f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -789,7 +789,7 @@ private: void set_flattening_data(const ModelObject* model_object); void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); - void clicked_on_object(const Vec2d& mouse_position); + void mouse_event(int action, const Vec2d& mouse_position, bool shift_down); void delete_current_grabber(bool delete_all = false); void render_current_gizmo(const Selection& selection) const; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index f9191b69b6..f752e7d943 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1816,13 +1816,49 @@ void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const ::glEnable(GL_DEPTH_TEST); render_points(selection, false); + render_selection_rectangle(); #if !ENABLE_IMGUI render_tooltip_texture(); #endif // not ENABLE_IMGUI + ::glDisable(GL_BLEND); } +void GLGizmoSlaSupports::render_selection_rectangle() const +{ + if (!m_selection_rectangle_active) + return; + + ::glLineWidth(1.5f); + float render_color[3] = {1.f, 0.f, 0.f}; + ::glColor3fv(render_color); + + ::glPushAttrib(GL_TRANSFORM_BIT); // remember current MatrixMode + + ::glMatrixMode(GL_MODELVIEW); // cache modelview matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::glMatrixMode(GL_PROJECTION); // cache projection matrix and set to identity + ::glPushMatrix(); + ::glLoadIdentity(); + + ::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f); // set projection matrix so that world coords = window coords + + // render the selection rectangle (window coordinates): + ::glBegin(GL_LINE_LOOP); + ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); + ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); + ::glEnd(); + + ::glPopMatrix(); // restore former projection matrix + ::glMatrixMode(GL_MODELVIEW); + ::glPopMatrix(); // restore former modelview matrix + ::glPopAttrib(); // restore former MatrixMode +} void GLGizmoSlaSupports::on_render_for_picking(const GLCanvas3D::Selection& selection) const { @@ -1984,34 +2020,82 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) return bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)); } -void GLGizmoSlaSupports::clicked_on_object(const Vec2d& mouse_position) +void GLGizmoSlaSupports::mouse_event(int action, const Vec2d& mouse_position, bool shift_down) { if (!m_editing_mode) return; - int instance_id = m_parent.get_selection().get_instance_idx(); - if (m_old_instance_id != instance_id) - { - bool something_selected = (m_old_instance_id != -1); - m_old_instance_id = instance_id; - if (something_selected) + // left down - show the selection rectangle: + if (action == 1 && shift_down) { + m_selection_rectangle_active = true; + m_selection_rectangle_start_corner = mouse_position; + m_selection_rectangle_end_corner = mouse_position; + m_canvas_width = m_parent.get_canvas_size().get_width(); + m_canvas_height = m_parent.get_canvas_size().get_height(); + } + + // dragging the selection rectangle: + if (action == 3 && m_selection_rectangle_active) { + m_selection_rectangle_end_corner = mouse_position; + m_parent.render(); + } + + // mouse up without selection rectangle - place point on the mesh: + if (action == 2 && !m_selection_rectangle_active) { + int instance_id = m_parent.get_selection().get_instance_idx(); + if (m_old_instance_id != instance_id) + { + bool something_selected = (m_old_instance_id != -1); + m_old_instance_id = instance_id; + if (something_selected) + return; + } + if (instance_id == -1) return; + + Vec3f new_pos; + try { + new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case + } + catch (...) { return; } + + m_editing_mode_cache.emplace_back(new_pos, m_new_point_head_diameter, false); } - if (instance_id == -1) - return; - Vec3f new_pos; - try { - new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case + // left up with selection rectangle - select points inside the rectangle: + if (action == 2 && m_selection_rectangle_active) { + const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + GLint viewport[4]; + ::glGetIntegerv(GL_VIEWPORT, viewport); + GLdouble modelview_matrix[16]; + ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); + GLdouble projection_matrix[16]; + ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); + + const GLCanvas3D::Selection& selection = m_parent.get_selection(); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + double z_offset = volume->get_sla_shift_z(); + + // bounding box created from the rectangle corners - will take care of order of the corners + BoundingBox rectangle(Points{Point(m_selection_rectangle_start_corner.cast()), Point(m_selection_rectangle_end_corner.cast())}); + + for (sla::SupportPoint& support_point : m_editing_mode_cache) { + Vec3f pos = instance_matrix.cast() * support_point.pos; + pos(2) += z_offset; + GLdouble out_x, out_y, out_z; + ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z); + out_y = m_canvas_height - out_y; + + /*GLfloat depth_comp; + ::glReadPixels( out_x, out_y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth_comp); + if (depth_comp > out_z + EPSILON) // the point is obscured by something else + continue;*/ + + if (rectangle.contains(Point(out_x, out_y))) + support_point.head_front_radius = 1.f; + } + m_selection_rectangle_active = false; } - catch (...) { return; } - - m_editing_mode_cache.emplace_back(new_pos, m_new_point_head_diameter, false); - - // This should trigger the support generation - // wxGetApp().plater()->reslice(); - - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } void GLGizmoSlaSupports::delete_current_point(bool delete_all) diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index f5ddbd76fb..96dafafdfd 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -464,7 +464,7 @@ public: explicit GLGizmoSlaSupports(GLCanvas3D& parent); virtual ~GLGizmoSlaSupports(); void set_sla_support_data(ModelObject* model_object, const GLCanvas3D::Selection& selection); - void clicked_on_object(const Vec2d& mouse_position); + void mouse_event(int action, const Vec2d& mouse_position, bool shift_down); void delete_current_point(bool delete_all); private: @@ -473,6 +473,7 @@ private: virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; + void render_selection_rectangle() const; void render_points(const GLCanvas3D::Selection& selection, bool picking = false) const; bool is_mesh_update_necessary() const; void update_mesh(); @@ -488,6 +489,12 @@ private: float m_new_point_head_diameter = 0.4f; std::vector m_editing_mode_cache; + bool m_selection_rectangle_active = false; + Vec2d m_selection_rectangle_start_corner; + Vec2d m_selection_rectangle_end_corner; + int m_canvas_width; + int m_canvas_height; + protected: void on_set_state() override;