diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 1d8a1e26e..f54189762 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -47,6 +47,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoFlatten.hpp GUI/Gizmos/GLGizmoCut.cpp GUI/Gizmos/GLGizmoCut.hpp + GUI/GLSelectionRectangle.cpp + GUI/GLSelectionRectangle.hpp GUI/GLTexture.hpp GUI/GLTexture.cpp GUI/GLToolbar.hpp diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp new file mode 100644 index 000000000..a908d13ec --- /dev/null +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -0,0 +1,116 @@ +#include "GLSelectionRectangle.hpp" +#include "Camera.hpp" +#include "3DScene.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, float width, float height, EState status) +{ + if (is_active() || status==Off) + return; + + m_width = width; + m_height = height; + m_status = status; + m_start_corner = mouse_position; + m_end_corner = mouse_position; +} + + + +void GLSelectionRectangle::dragging(const Vec2d& mouse_position) +{ + if (is_active()) + m_end_corner = mouse_position; +} + + + +std::vector GLSelectionRectangle::end_dragging(const Camera& camera, const std::vector& points) +{ + if (!is_active()) + return std::vector(); + + m_status = Off; + std::vector out; + + const std::array& viewport = camera.get_viewport(); + const Transform3d& modelview_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + + // bounding box created from the rectangle corners - will take care of order of the corners + BoundingBox rectangle(Points{Point(m_start_corner.cast()), Point(m_end_corner.cast())}); + + // Iterate over all points and determine whether they're in the rectangle. + for (unsigned int i=0; i end_dragging(const Camera& camera, const std::vector& points); + + void render() const; + + bool is_active() const { return m_status != Off; } + EState get_status() const { return m_status; } + + + +private: + EState m_status = Off; + Vec2d m_start_corner; + Vec2d m_end_corner; + float m_width; + float m_height; +}; + + +} // namespace GUI +} // namespace Slic3r + + +#endif // slic3r_GLGizmoSlaSupports_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index e8fe32688..b31eb272b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -100,7 +100,7 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const if (m_quadric != nullptr && selection.is_from_single_instance()) render_points(selection, false); - render_selection_rectangle(); + m_selection_rectangle.render(); render_clipping_plane(selection); glsafe(::glDisable(GL_BLEND)); @@ -240,52 +240,6 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const } - -void GLGizmoSlaSupports::render_selection_rectangle() const -{ - if (m_selection_rectangle_status == srOff) - return; - - glsafe(::glLineWidth(1.5f)); - float render_color[3] = {0.f, 1.f, 0.f}; - if (m_selection_rectangle_status == srDeselect) { - render_color[0] = 1.f; - render_color[1] = 0.3f; - render_color[2] = 0.3f; - } - glsafe(::glColor3fv(render_color)); - - glsafe(::glPushAttrib(GL_TRANSFORM_BIT)); // remember current MatrixMode - - glsafe(::glMatrixMode(GL_MODELVIEW)); // cache modelview matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - - glsafe(::glMatrixMode(GL_PROJECTION)); // cache projection matrix and set to identity - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - - glsafe(::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): - glsafe(::glPushAttrib(GL_ENABLE_BIT)); - glsafe(::glLineStipple(4, 0xAAAA)); - glsafe(::glEnable(GL_LINE_STIPPLE)); - - ::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); - glsafe(::glEnd()); - glsafe(::glPopAttrib()); - - glsafe(::glPopMatrix()); // restore former projection matrix - glsafe(::glMatrixMode(GL_MODELVIEW)); - glsafe(::glPopMatrix()); // restore former modelview matrix - glsafe(::glPopAttrib()); // restore former MatrixMode -} - void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const { glsafe(::glEnable(GL_DEPTH_TEST)); @@ -513,11 +467,9 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { if (m_hover_id == -1) { if (shift_down || alt_down) { - m_selection_rectangle_status = shift_down ? srSelect : srDeselect; - 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(); + Size size = m_parent.get_canvas_size(); + m_selection_rectangle.start_dragging(mouse_position, size.get_width(), size.get_height(), + shift_down ? GLSelectionRectangle::SlaSelect : GLSelectionRectangle::SlaDeselect); } } else { @@ -533,7 +485,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left down without selection rectangle - place point on the mesh: - if (action == SLAGizmoEventType::LeftDown && m_selection_rectangle_status == srOff && !shift_down) { + if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_active() && !shift_down) { // If any point is in hover state, this should initiate its move - return control back to GLCanvas: if (m_hover_id != -1) return false; @@ -558,38 +510,36 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } // left up with selection rectangle - select points inside the rectangle: - if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle_status != srOff) { - const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); - const Camera& camera = m_parent.get_camera(); - const std::array& viewport = camera.get_viewport(); - const Transform3d& modelview_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); + if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_active()) { + // Is this a selection or deselection rectangle? + GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_status(); + // First collect positions of all the points in world coordinates. + const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + std::vector points; + for (unsigned int i=0; i()); + points.back()(2) += m_z_shift; + } + // Now ask the rectangle which of the points are inside. + const Camera& camera = m_parent.get_camera(); + std::vector selected_idxs = m_selection_rectangle.end_dragging(camera, points); + + // we'll recover current look direction (in world coords) and transform it to model coords. const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - - // 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())}); - const Transform3d& instance_matrix_no_translation_no_scaling = volume->get_instance_transformation().get_matrix(true,false,true); - - // we'll recover current look direction from the modelview matrix (in world coords)... Vec3f direction_to_camera = camera.get_dir_forward().cast(); - // ...and transform it to model coords. Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast() * direction_to_camera).normalized().eval(); Vec3f scaling = volume->get_instance_scaling_factor().cast(); direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - // Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh: - for (unsigned int i=0; i() * support_point.pos; - pos(2) += m_z_shift; - GLdouble out_x, out_y, out_z; - ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z); - out_y = m_canvas_height - out_y; - - if (rectangle.contains(Point(out_x, out_y)) && !is_point_clipped(support_point.pos.cast())) { + if (!is_point_clipped(support_point.pos.cast())) { bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector hits; @@ -627,14 +577,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } if (!is_obscured) { - if (m_selection_rectangle_status == srDeselect) + if (rectangle_status == GLSelectionRectangle::SlaDeselect) unselect_point(i); else select_point(i); } } } - m_selection_rectangle_status = srOff; return true; } @@ -652,9 +601,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous return true; // point has been placed and the button not released yet // this prevents GLCanvas from starting scene rotation - if (m_selection_rectangle_status != srOff) { - m_selection_rectangle_end_corner = mouse_position; - m_selection_rectangle_status = shift_down ? srSelect : srDeselect; + if (m_selection_rectangle.is_active()) { + m_selection_rectangle.dragging(mouse_position); return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index eaf0932c4..92d80b6eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -3,6 +3,7 @@ #include "GLGizmoBase.hpp" #include "GLGizmos.hpp" +#include "slic3r/GUI/GLSelectionRectangle.hpp" // There is an L function in igl that would be overridden by our localization macro - let's undefine it... #undef L @@ -73,7 +74,7 @@ private: virtual void on_render(const Selection& selection) const; virtual void on_render_for_picking(const Selection& selection) const; - void render_selection_rectangle() const; + //void render_selection_rectangle() const; void render_points(const Selection& selection, bool picking = false) const; void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; @@ -91,20 +92,11 @@ private: mutable Vec3d m_old_clipping_plane_normal; mutable Vec3d m_clipping_plane_normal = Vec3d::Zero(); - enum SelectionRectangleStatus { - srOff = 0, - srSelect = 1, - srDeselect = 2 - }m_selection_rectangle_status = srOff; - - Vec2d m_selection_rectangle_start_corner; - Vec2d m_selection_rectangle_end_corner; + GLSelectionRectangle m_selection_rectangle; bool m_wait_for_up_event = false; bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? 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) - int m_canvas_width; - int m_canvas_height; mutable std::unique_ptr m_tms; mutable std::unique_ptr m_supports_tms;