1 #include "GLSelectionRectangle.hpp"
2 #include "Camera.hpp"
3 #include "3DScene.hpp"
4 #include "GLCanvas3D.hpp"
5 #include "GUI_App.hpp"
6 #include "Plater.hpp"
7 
8 #include <GL/glew.h>
9 
10 namespace Slic3r {
11 namespace GUI {
12 
start_dragging(const Vec2d & mouse_position,EState state)13     void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, EState state)
14     {
15         if (is_dragging() || (state == Off))
16             return;
17 
18         m_state = state;
19         m_start_corner = mouse_position;
20         m_end_corner = mouse_position;
21     }
22 
dragging(const Vec2d & mouse_position)23     void GLSelectionRectangle::dragging(const Vec2d& mouse_position)
24     {
25         if (!is_dragging())
26             return;
27 
28         m_end_corner = mouse_position;
29     }
30 
stop_dragging(const GLCanvas3D & canvas,const std::vector<Vec3d> & points)31     std::vector<unsigned int> GLSelectionRectangle::stop_dragging(const GLCanvas3D& canvas, const std::vector<Vec3d>& points)
32     {
33         std::vector<unsigned int> out;
34 
35         if (!is_dragging())
36             return out;
37 
38         m_state = Off;
39 
40         const Camera& camera = wxGetApp().plater()->get_camera();
41         const std::array<int, 4>& viewport = camera.get_viewport();
42         const Transform3d& modelview_matrix = camera.get_view_matrix();
43         const Transform3d& projection_matrix = camera.get_projection_matrix();
44 
45         // bounding box created from the rectangle corners - will take care of order of the corners
46         BoundingBox rectangle(Points{ Point(m_start_corner.cast<coord_t>()), Point(m_end_corner.cast<coord_t>()) });
47 
48         // Iterate over all points and determine whether they're in the rectangle.
49         for (unsigned int i = 0; i<points.size(); ++i) {
50             const Vec3d& point = points[i];
51             GLdouble out_x, out_y, out_z;
52             ::gluProject((GLdouble)point(0), (GLdouble)point(1), (GLdouble)point(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z);
53             out_y = canvas.get_canvas_size().get_height() - out_y;
54 
55             if (rectangle.contains(Point(out_x, out_y)))
56                 out.push_back(i);
57         }
58 
59         return out;
60     }
61 
stop_dragging()62     void GLSelectionRectangle::stop_dragging()
63     {
64         if (is_dragging())
65             m_state = Off;
66     }
67 
render(const GLCanvas3D & canvas) const68     void GLSelectionRectangle::render(const GLCanvas3D& canvas) const
69     {
70         if (!is_dragging())
71             return;
72 
73         const Camera& camera = wxGetApp().plater()->get_camera();
74         float inv_zoom = (float)camera.get_inv_zoom();
75 
76         Size cnv_size = canvas.get_canvas_size();
77         float cnv_half_width = 0.5f * (float)cnv_size.get_width();
78         float cnv_half_height = 0.5f * (float)cnv_size.get_height();
79         if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f))
80             return;
81 
82         Vec2d start(m_start_corner(0) - cnv_half_width, cnv_half_height - m_start_corner(1));
83         Vec2d end(m_end_corner(0) - cnv_half_width, cnv_half_height - m_end_corner(1));
84 
85         float left = (float)std::min(start(0), end(0)) * inv_zoom;
86         float top = (float)std::max(start(1), end(1)) * inv_zoom;
87         float right = (float)std::max(start(0), end(0)) * inv_zoom;
88         float bottom = (float)std::min(start(1), end(1)) * inv_zoom;
89 
90         glsafe(::glLineWidth(1.5f));
91         float color[3];
92         color[0] = (m_state == Select) ? 0.3f : 1.0f;
93         color[1] = (m_state == Select) ? 1.0f : 0.3f;
94         color[2] = 0.3f;
95         glsafe(::glColor3fv(color));
96 
97         glsafe(::glDisable(GL_DEPTH_TEST));
98 
99         glsafe(::glPushMatrix());
100         glsafe(::glLoadIdentity());
101         // ensure that the rectangle is renderered inside the frustrum
102         glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
103         // ensure that the overlay fits the frustrum near z plane
104         double gui_scale = camera.get_gui_scale();
105         glsafe(::glScaled(gui_scale, gui_scale, 1.0));
106 
107         glsafe(::glPushAttrib(GL_ENABLE_BIT));
108         glsafe(::glLineStipple(4, 0xAAAA));
109         glsafe(::glEnable(GL_LINE_STIPPLE));
110 
111         ::glBegin(GL_LINE_LOOP);
112         ::glVertex2f((GLfloat)left, (GLfloat)bottom);
113         ::glVertex2f((GLfloat)right, (GLfloat)bottom);
114         ::glVertex2f((GLfloat)right, (GLfloat)top);
115         ::glVertex2f((GLfloat)left, (GLfloat)top);
116         glsafe(::glEnd());
117 
118         glsafe(::glPopAttrib());
119 
120         glsafe(::glPopMatrix());
121     }
122 
123 } // namespace GUI
124 } // namespace Slic3r
125