mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge branch 'et_selection_rectangle' of https://github.com/prusa3d/Slic3r
This commit is contained in:
		
						commit
						d971c821b7
					
				
					 11 changed files with 632 additions and 151 deletions
				
			
		| 
						 | 
				
			
			@ -11,6 +11,8 @@
 | 
			
		|||
#define ENABLE_SELECTION_DEBUG_OUTPUT 0
 | 
			
		||||
// Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active
 | 
			
		||||
#define ENABLE_RENDER_SELECTION_CENTER 0
 | 
			
		||||
// Shows an imgui dialog with render related data
 | 
			
		||||
#define ENABLE_RENDER_STATISTICS 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//====================
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -223,7 +223,8 @@ void GLIndexedVertexArray::render(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
 | 
			
		||||
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
 | 
			
		||||
const float GLVolume::HOVER_SELECT_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
 | 
			
		||||
const float GLVolume::HOVER_DESELECT_COLOR[4] = { 1.0f, 0.75f, 0.75f, 1.0f };
 | 
			
		||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
 | 
			
		||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
 | 
			
		||||
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +252,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
 | 
			
		|||
    , zoom_to_volumes(true)
 | 
			
		||||
    , shader_outside_printer_detection_enabled(false)
 | 
			
		||||
    , is_outside(false)
 | 
			
		||||
    , hover(false)
 | 
			
		||||
    , hover(HS_None)
 | 
			
		||||
    , is_modifier(false)
 | 
			
		||||
    , is_wipe_tower(false)
 | 
			
		||||
    , is_extrusion_path(false)
 | 
			
		||||
| 
						 | 
				
			
			@ -291,10 +292,12 @@ void GLVolume::set_render_color()
 | 
			
		|||
    if (force_native_color)
 | 
			
		||||
        set_render_color(color, 4);
 | 
			
		||||
    else {
 | 
			
		||||
        if (selected)
 | 
			
		||||
        if (hover == HS_Select)
 | 
			
		||||
            set_render_color(HOVER_SELECT_COLOR, 4);
 | 
			
		||||
        else if (hover == HS_Deselect)
 | 
			
		||||
            set_render_color(HOVER_DESELECT_COLOR, 4);
 | 
			
		||||
        else if (selected)
 | 
			
		||||
            set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
 | 
			
		||||
        else if (hover)
 | 
			
		||||
            set_render_color(HOVER_COLOR, 4);
 | 
			
		||||
        else if (disabled)
 | 
			
		||||
            set_render_color(DISABLED_COLOR, 4);
 | 
			
		||||
        else if (is_outside && shader_outside_printer_detection_enabled)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -225,7 +225,8 @@ private:
 | 
			
		|||
class GLVolume {
 | 
			
		||||
public:
 | 
			
		||||
    static const float SELECTED_COLOR[4];
 | 
			
		||||
    static const float HOVER_COLOR[4];
 | 
			
		||||
    static const float HOVER_SELECT_COLOR[4];
 | 
			
		||||
    static const float HOVER_DESELECT_COLOR[4];
 | 
			
		||||
    static const float OUTSIDE_COLOR[4];
 | 
			
		||||
    static const float SELECTED_OUTSIDE_COLOR[4];
 | 
			
		||||
    static const float DISABLED_COLOR[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +234,13 @@ public:
 | 
			
		|||
    static const float SLA_SUPPORT_COLOR[4];
 | 
			
		||||
    static const float SLA_PAD_COLOR[4];
 | 
			
		||||
 | 
			
		||||
    enum EHoverState : unsigned char
 | 
			
		||||
    {
 | 
			
		||||
        HS_None,
 | 
			
		||||
        HS_Select,
 | 
			
		||||
        HS_Deselect
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
 | 
			
		||||
    GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
 | 
			
		||||
    ~GLVolume();
 | 
			
		||||
| 
						 | 
				
			
			@ -296,8 +304,8 @@ public:
 | 
			
		|||
    bool                shader_outside_printer_detection_enabled;
 | 
			
		||||
    // Wheter or not this volume is outside print volume.
 | 
			
		||||
    bool                is_outside;
 | 
			
		||||
    // Boolean: Is mouse over this object?
 | 
			
		||||
    bool                hover;
 | 
			
		||||
    // Is mouse or rectangle selection over this object to select/deselect it ?
 | 
			
		||||
    EHoverState         hover;
 | 
			
		||||
    // Wheter or not this volume has been generated from a modifier
 | 
			
		||||
    bool                is_modifier;
 | 
			
		||||
    // Wheter or not this volume has been generated from the wipe tower
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,9 @@
 | 
			
		|||
#include <float.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
 | 
			
		||||
static const float TRACKBALLSIZE = 0.8f;
 | 
			
		||||
static const float GROUND_Z = -0.02f;
 | 
			
		||||
| 
						 | 
				
			
			@ -672,6 +675,7 @@ GLCanvas3D::Mouse::Mouse()
 | 
			
		|||
    : dragging(false)
 | 
			
		||||
    , position(DBL_MAX, DBL_MAX)
 | 
			
		||||
    , scene_position(DBL_MAX, DBL_MAX, DBL_MAX)
 | 
			
		||||
    , ignore_left_up(false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1228,7 +1232,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 | 
			
		|||
    , m_initialized(false)
 | 
			
		||||
    , m_use_VBOs(false)
 | 
			
		||||
    , m_apply_zoom_to_volumes_filter(false)
 | 
			
		||||
    , m_hover_volume_id(-1)
 | 
			
		||||
    , m_legend_texture_enabled(false)
 | 
			
		||||
    , m_picking_enabled(false)
 | 
			
		||||
    , m_moving_enabled(false)
 | 
			
		||||
| 
						 | 
				
			
			@ -1237,6 +1240,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
 | 
			
		|||
    , m_regenerate_volumes(true)
 | 
			
		||||
    , m_moving(false)
 | 
			
		||||
    , m_tab_down(false)
 | 
			
		||||
    , m_cursor_type(Standard)
 | 
			
		||||
    , m_color_by("volume")
 | 
			
		||||
    , m_reload_delayed(false)
 | 
			
		||||
    , m_render_sla_auxiliaries(true)
 | 
			
		||||
| 
						 | 
				
			
			@ -1588,6 +1592,10 @@ void GLCanvas3D::render()
 | 
			
		|||
    if (!_set_current() || !_3DScene::init(m_canvas))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
    auto start_time = std::chrono::high_resolution_clock::now();
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
 | 
			
		||||
    if (m_bed.get_shape().empty())
 | 
			
		||||
    {
 | 
			
		||||
        // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
 | 
			
		||||
| 
						 | 
				
			
			@ -1617,8 +1625,15 @@ void GLCanvas3D::render()
 | 
			
		|||
 | 
			
		||||
    wxGetApp().imgui()->new_frame();
 | 
			
		||||
 | 
			
		||||
    // picking pass
 | 
			
		||||
    _picking_pass();
 | 
			
		||||
    if (m_picking_enabled)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_rectangle_selection.is_dragging())
 | 
			
		||||
            // picking pass using rectangle selection
 | 
			
		||||
            _rectangular_selection_picking_pass();
 | 
			
		||||
        else
 | 
			
		||||
            // regular picking pass
 | 
			
		||||
            _picking_pass();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // draw scene
 | 
			
		||||
    glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
 | 
			
		||||
| 
						 | 
				
			
			@ -1654,6 +1669,9 @@ void GLCanvas3D::render()
 | 
			
		|||
    _render_camera_target();
 | 
			
		||||
#endif // ENABLE_SHOW_CAMERA_TARGET
 | 
			
		||||
 | 
			
		||||
    if (m_picking_enabled && m_rectangle_selection.is_dragging())
 | 
			
		||||
        m_rectangle_selection.render(*this);
 | 
			
		||||
 | 
			
		||||
    // draw overlays
 | 
			
		||||
    _render_gizmos_overlay();
 | 
			
		||||
    _render_warning_texture();
 | 
			
		||||
| 
						 | 
				
			
			@ -1666,9 +1684,26 @@ void GLCanvas3D::render()
 | 
			
		|||
    if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f))
 | 
			
		||||
        m_layers_editing.render_overlay(*this);
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
    ImGuiWrapper& imgui = *wxGetApp().imgui();
 | 
			
		||||
    imgui.set_next_window_bg_alpha(0.5f);
 | 
			
		||||
    imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
 | 
			
		||||
    imgui.text("Last frame: ");
 | 
			
		||||
    ImGui::SameLine();
 | 
			
		||||
    imgui.text(std::to_string(m_render_stats.last_frame));
 | 
			
		||||
    ImGui::SameLine();
 | 
			
		||||
    imgui.text(" ms");
 | 
			
		||||
    imgui.end();
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
 | 
			
		||||
    wxGetApp().imgui()->render();
 | 
			
		||||
 | 
			
		||||
    m_canvas->SwapBuffers();
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
    auto end_time = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    m_render_stats.last_frame = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::select_all()
 | 
			
		||||
| 
						 | 
				
			
			@ -2347,9 +2382,51 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
 | 
			
		|||
                    // m_canvas->HandleAsNavigationKey(evt);   // XXX: Doesn't work in some cases / on Linux
 | 
			
		||||
                    post_event(SimpleEvent(EVT_GLCANVAS_TAB));
 | 
			
		||||
                }
 | 
			
		||||
                else if (keyCode == WXK_SHIFT)
 | 
			
		||||
                {
 | 
			
		||||
                    if (m_picking_enabled && m_rectangle_selection.is_dragging())
 | 
			
		||||
                    {
 | 
			
		||||
                        _update_selection_from_hover();
 | 
			
		||||
                        m_rectangle_selection.stop_dragging();
 | 
			
		||||
                        m_mouse.ignore_left_up = true;
 | 
			
		||||
                        m_dirty = true;
 | 
			
		||||
                    }
 | 
			
		||||
//                    set_cursor(Standard);
 | 
			
		||||
                }
 | 
			
		||||
                else if (keyCode == WXK_ALT)
 | 
			
		||||
                {
 | 
			
		||||
                    if (m_picking_enabled && m_rectangle_selection.is_dragging())
 | 
			
		||||
                    {
 | 
			
		||||
                        _update_selection_from_hover();
 | 
			
		||||
                        m_rectangle_selection.stop_dragging();
 | 
			
		||||
                        m_mouse.ignore_left_up = true;
 | 
			
		||||
                        m_dirty = true;
 | 
			
		||||
                    }
 | 
			
		||||
//                    set_cursor(Standard);
 | 
			
		||||
                }
 | 
			
		||||
                else if (keyCode == WXK_CONTROL)
 | 
			
		||||
                    m_dirty = true;
 | 
			
		||||
            }
 | 
			
		||||
            else if (evt.GetEventType() == wxEVT_KEY_DOWN) {
 | 
			
		||||
                m_tab_down = keyCode == WXK_TAB && !evt.HasAnyModifiers();
 | 
			
		||||
                if (keyCode == WXK_SHIFT)
 | 
			
		||||
                {
 | 
			
		||||
                    if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports))
 | 
			
		||||
                    {
 | 
			
		||||
                        m_mouse.ignore_left_up = false;
 | 
			
		||||
//                        set_cursor(Cross);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (keyCode == WXK_ALT)
 | 
			
		||||
                {
 | 
			
		||||
                    if (m_picking_enabled && (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports))
 | 
			
		||||
                    {
 | 
			
		||||
                        m_mouse.ignore_left_up = false;
 | 
			
		||||
//                        set_cursor(Cross);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (keyCode == WXK_CONTROL)
 | 
			
		||||
                    m_dirty = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2468,6 +2545,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
        m_mouse.set_start_position_3D_as_invalid();
 | 
			
		||||
        m_mouse.set_start_position_2D_as_invalid();
 | 
			
		||||
        m_mouse.dragging = false;
 | 
			
		||||
        m_mouse.ignore_left_up = false;
 | 
			
		||||
        m_dirty = true;
 | 
			
		||||
 | 
			
		||||
        if (m_canvas->HasCapture())
 | 
			
		||||
| 
						 | 
				
			
			@ -2566,7 +2644,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
            if (top_level_wnd && top_level_wnd->IsActive())
 | 
			
		||||
                m_canvas->SetFocus();
 | 
			
		||||
            m_mouse.position = pos.cast<double>();
 | 
			
		||||
            // 1) forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while
 | 
			
		||||
            // 1) forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
 | 
			
		||||
            // the context menu is shown, ensuring it to disappear if the mouse is outside any volume and to
 | 
			
		||||
            // change the volume hover state if any is under the mouse 
 | 
			
		||||
            // 2) when switching between 3d view and preview the size of the canvas changes if the side panels are visible,
 | 
			
		||||
| 
						 | 
				
			
			@ -2606,26 +2684,35 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
                m_dirty = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
 | 
			
		||||
        {
 | 
			
		||||
            if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)
 | 
			
		||||
            {
 | 
			
		||||
                m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
 | 
			
		||||
                m_dirty = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Select volume in this 3D canvas.
 | 
			
		||||
            // Don't deselect a volume if layer editing is enabled. We want the object to stay selected
 | 
			
		||||
            // during the scene manipulation.
 | 
			
		||||
 | 
			
		||||
            if (m_picking_enabled && ((m_hover_volume_id != -1) || !is_layers_editing_enabled()))
 | 
			
		||||
            if (m_picking_enabled && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled()))
 | 
			
		||||
            {
 | 
			
		||||
                if (evt.LeftDown() && (m_hover_volume_id != -1))
 | 
			
		||||
                if (evt.LeftDown() && !m_hover_volume_idxs.empty())
 | 
			
		||||
                {
 | 
			
		||||
                    bool already_selected = m_selection.contains_volume(m_hover_volume_id);
 | 
			
		||||
                    int volume_idx = get_first_hover_volume_idx();
 | 
			
		||||
                    bool already_selected = m_selection.contains_volume(volume_idx);
 | 
			
		||||
                    bool ctrl_down = evt.CmdDown();
 | 
			
		||||
 | 
			
		||||
                    Selection::IndicesList curr_idxs = m_selection.get_volume_idxs();
 | 
			
		||||
 | 
			
		||||
                    if (already_selected && ctrl_down)
 | 
			
		||||
                        m_selection.remove(m_hover_volume_id);
 | 
			
		||||
                        m_selection.remove(volume_idx);
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        m_selection.add(m_hover_volume_id, !ctrl_down, true);
 | 
			
		||||
                        m_selection.add(volume_idx, !ctrl_down, true);
 | 
			
		||||
                        m_mouse.drag.move_requires_threshold = !already_selected;
 | 
			
		||||
                        if (already_selected)
 | 
			
		||||
                            m_mouse.set_move_start_threshold_position_2D_as_invalid();
 | 
			
		||||
| 
						 | 
				
			
			@ -2633,6 +2720,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
                            m_mouse.drag.move_start_threshold_position_2D = pos;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // propagate event through callback
 | 
			
		||||
                    if (curr_idxs != m_selection.get_volume_idxs())
 | 
			
		||||
                    {
 | 
			
		||||
                        m_gizmos.refresh_on_off_state(m_selection);
 | 
			
		||||
| 
						 | 
				
			
			@ -2643,18 +2731,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // propagate event through callback
 | 
			
		||||
            if (m_hover_volume_id != -1)
 | 
			
		||||
            if (!m_hover_volume_idxs.empty())
 | 
			
		||||
            {
 | 
			
		||||
                if (evt.LeftDown() && m_moving_enabled && (m_mouse.drag.move_volume_idx == -1))
 | 
			
		||||
                {
 | 
			
		||||
                    // Only accept the initial position, if it is inside the volume bounding box.
 | 
			
		||||
                    BoundingBoxf3 volume_bbox = m_volumes.volumes[m_hover_volume_id]->transformed_bounding_box();
 | 
			
		||||
                    int volume_idx = get_first_hover_volume_idx();
 | 
			
		||||
                    BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box();
 | 
			
		||||
                    volume_bbox.offset(1.0);
 | 
			
		||||
                    if (volume_bbox.contains(m_mouse.scene_position))
 | 
			
		||||
                    {
 | 
			
		||||
                        // The dragging operation is initiated.
 | 
			
		||||
                        m_mouse.drag.move_volume_idx = m_hover_volume_id;
 | 
			
		||||
                        m_mouse.drag.move_volume_idx = volume_idx;
 | 
			
		||||
                        m_selection.start_dragging();
 | 
			
		||||
                        m_mouse.drag.start_position_3D = m_mouse.scene_position;
 | 
			
		||||
                        m_moving = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -2671,7 +2759,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
 | 
			
		||||
            Vec3d cur_pos = m_mouse.drag.start_position_3D;
 | 
			
		||||
            // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
 | 
			
		||||
            if (m_selection.contains_volume(m_hover_volume_id))
 | 
			
		||||
            if (m_selection.contains_volume(get_first_hover_volume_idx()))
 | 
			
		||||
            {
 | 
			
		||||
                if (m_camera.get_theta() == 90.0f)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -2709,10 +2797,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
            m_regenerate_volumes = false;
 | 
			
		||||
            m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
 | 
			
		||||
            wxGetApp().obj_manipul()->update_settings_value(m_selection);
 | 
			
		||||
 | 
			
		||||
            m_dirty = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging())
 | 
			
		||||
    {
 | 
			
		||||
        m_rectangle_selection.dragging(pos.cast<double>());
 | 
			
		||||
        m_dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (evt.Dragging())
 | 
			
		||||
    {
 | 
			
		||||
        m_mouse.dragging = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -2726,7 +2818,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
        else if (evt.LeftIsDown())
 | 
			
		||||
        {
 | 
			
		||||
            // if dragging over blank area with left button, rotate
 | 
			
		||||
            if ((m_hover_volume_id == -1) && m_mouse.is_start_position_3D_defined())
 | 
			
		||||
            if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
 | 
			
		||||
            {
 | 
			
		||||
                const Vec3d& orig = m_mouse.drag.start_position_3D;
 | 
			
		||||
                float sign = m_camera.inverted_phi ? -1.0f : 1.0f;
 | 
			
		||||
| 
						 | 
				
			
			@ -2769,7 +2861,14 @@ 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_mouse.dragging && (m_hover_volume_id == -1) && !is_layers_editing_enabled())
 | 
			
		||||
        else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging())
 | 
			
		||||
        {
 | 
			
		||||
            if (evt.ShiftDown() || evt.AltDown())
 | 
			
		||||
                _update_selection_from_hover();
 | 
			
		||||
 | 
			
		||||
            m_rectangle_selection.stop_dragging();
 | 
			
		||||
        }
 | 
			
		||||
        else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled())
 | 
			
		||||
        {
 | 
			
		||||
            // deselect and propagate event through callback
 | 
			
		||||
            if (!evt.ShiftDown() && m_picking_enabled)
 | 
			
		||||
| 
						 | 
				
			
			@ -2788,18 +2887,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
        else if (evt.RightUp())
 | 
			
		||||
        {
 | 
			
		||||
            m_mouse.position = pos.cast<double>();
 | 
			
		||||
            // forces a frame render to ensure that m_hover_volume_id is updated even when the user right clicks while
 | 
			
		||||
            // forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
 | 
			
		||||
            // the context menu is already shown
 | 
			
		||||
            render();
 | 
			
		||||
            if (m_hover_volume_id != -1)
 | 
			
		||||
            if (!m_hover_volume_idxs.empty())
 | 
			
		||||
            {
 | 
			
		||||
                // if right clicking on volume, propagate event through callback (shows context menu)
 | 
			
		||||
                if (m_volumes.volumes[m_hover_volume_id]->hover
 | 
			
		||||
                    && !m_volumes.volumes[m_hover_volume_id]->is_wipe_tower // no context menu for the wipe tower
 | 
			
		||||
                int volume_idx = get_first_hover_volume_idx();
 | 
			
		||||
                if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower
 | 
			
		||||
                    && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)  // disable context menu when the gizmo is open
 | 
			
		||||
                {
 | 
			
		||||
                    // forces the selection of the volume
 | 
			
		||||
                    m_selection.add(m_hover_volume_id);
 | 
			
		||||
                    m_selection.add(volume_idx);
 | 
			
		||||
                    m_gizmos.refresh_on_off_state(m_selection);
 | 
			
		||||
                    post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
 | 
			
		||||
                    m_gizmos.update_data(*this);
 | 
			
		||||
| 
						 | 
				
			
			@ -3199,6 +3298,20 @@ double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const
 | 
			
		|||
    return factor * m_bed.get_bounding_box().max_size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::set_cursor(ECursorType type)
 | 
			
		||||
{
 | 
			
		||||
    if ((m_canvas != nullptr) && (m_cursor_type != type))
 | 
			
		||||
    {
 | 
			
		||||
        switch (type)
 | 
			
		||||
        {
 | 
			
		||||
        case Standard: { m_canvas->SetCursor(*wxSTANDARD_CURSOR); break; }
 | 
			
		||||
        case Cross: { m_canvas->SetCursor(*wxCROSS_CURSOR); break; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_cursor_type = type;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::msw_rescale()
 | 
			
		||||
{
 | 
			
		||||
    m_warning_texture.msw_rescale(*this);
 | 
			
		||||
| 
						 | 
				
			
			@ -3569,10 +3682,10 @@ void GLCanvas3D::_refresh_if_shown_on_screen()
 | 
			
		|||
 | 
			
		||||
void GLCanvas3D::_picking_pass() const
 | 
			
		||||
{
 | 
			
		||||
    const Vec2d& pos = m_mouse.position;
 | 
			
		||||
 | 
			
		||||
    if (m_picking_enabled && !m_mouse.dragging && (pos != Vec2d(DBL_MAX, DBL_MAX)))
 | 
			
		||||
    if (m_picking_enabled && !m_mouse.dragging && (m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)))
 | 
			
		||||
    {
 | 
			
		||||
        m_hover_volume_idxs.clear();
 | 
			
		||||
 | 
			
		||||
        // Render the object for picking.
 | 
			
		||||
        // FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing.
 | 
			
		||||
        // Better to use software ray - casting on a bounding - box hierarchy.
 | 
			
		||||
| 
						 | 
				
			
			@ -3603,27 +3716,98 @@ void GLCanvas3D::_picking_pass() const
 | 
			
		|||
 | 
			
		||||
        GLubyte color[4] = { 0, 0, 0, 0 };
 | 
			
		||||
        const Size& cnv_size = get_canvas_size();
 | 
			
		||||
        bool inside = (0 <= pos(0)) && (pos(0) < cnv_size.get_width()) && (0 <= pos(1)) && (pos(1) < cnv_size.get_height());
 | 
			
		||||
        bool inside = (0 <= m_mouse.position(0)) && (m_mouse.position(0) < cnv_size.get_width()) && (0 <= m_mouse.position(1)) && (m_mouse.position(1) < cnv_size.get_height());
 | 
			
		||||
        if (inside)
 | 
			
		||||
        {
 | 
			
		||||
            glsafe(::glReadPixels(pos(0), cnv_size.get_height() - pos(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
 | 
			
		||||
            volume_id = color[0] + color[1] * 256 + color[2] * 256 * 256;
 | 
			
		||||
            glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
 | 
			
		||||
            volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
 | 
			
		||||
        }
 | 
			
		||||
        if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
 | 
			
		||||
        {
 | 
			
		||||
            m_hover_volume_id = volume_id;
 | 
			
		||||
            m_hover_volume_idxs.push_back(volume_id);
 | 
			
		||||
            m_gizmos.set_hover_id(-1);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            m_hover_volume_id = -1;
 | 
			
		||||
            m_gizmos.set_hover_id(inside && volume_id <= GLGizmoBase::BASE_ID ? (GLGizmoBase::BASE_ID - volume_id) : -1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _update_volumes_hover_state();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_rectangular_selection_picking_pass() const
 | 
			
		||||
{
 | 
			
		||||
    m_gizmos.set_hover_id(-1);
 | 
			
		||||
 | 
			
		||||
    std::set<int> idxs;
 | 
			
		||||
 | 
			
		||||
    if (m_picking_enabled)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_multisample_allowed)
 | 
			
		||||
            glsafe(::glDisable(GL_MULTISAMPLE));
 | 
			
		||||
 | 
			
		||||
        glsafe(::glDisable(GL_BLEND));
 | 
			
		||||
        glsafe(::glEnable(GL_DEPTH_TEST));
 | 
			
		||||
 | 
			
		||||
        glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
 | 
			
		||||
 | 
			
		||||
        _render_volumes_for_picking();
 | 
			
		||||
 | 
			
		||||
        if (m_multisample_allowed)
 | 
			
		||||
            glsafe(::glEnable(GL_MULTISAMPLE));
 | 
			
		||||
 | 
			
		||||
        int width = std::max((int)m_rectangle_selection.get_width(), 1);
 | 
			
		||||
        int height = std::max((int)m_rectangle_selection.get_height(), 1);
 | 
			
		||||
        int px_count = width * height;
 | 
			
		||||
 | 
			
		||||
        int left = (int)m_rectangle_selection.get_left();
 | 
			
		||||
        int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top();
 | 
			
		||||
        if ((left >= 0) && (top >= 0))
 | 
			
		||||
        {
 | 
			
		||||
#define USE_PARALLEL 1
 | 
			
		||||
#if USE_PARALLEL
 | 
			
		||||
            struct Pixel
 | 
			
		||||
            {
 | 
			
		||||
                std::array<GLubyte, 4> data;
 | 
			
		||||
                int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            std::vector<Pixel> frame(px_count);
 | 
			
		||||
            glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
 | 
			
		||||
 | 
			
		||||
            tbb::spin_mutex mutex;
 | 
			
		||||
            tbb::parallel_for(tbb::blocked_range<size_t>(0, frame.size(), (size_t)width),
 | 
			
		||||
                [this, &frame, &idxs, &mutex](const tbb::blocked_range<size_t>& range) {
 | 
			
		||||
                for (size_t i = range.begin(); i < range.end(); ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    int volume_id = frame[i].id();
 | 
			
		||||
                    if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
 | 
			
		||||
                    {
 | 
			
		||||
                        mutex.lock();
 | 
			
		||||
                        idxs.insert(volume_id);
 | 
			
		||||
                        mutex.unlock();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            );
 | 
			
		||||
#else
 | 
			
		||||
            std::vector<GLubyte> frame(4 * px_count);
 | 
			
		||||
            glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < px_count; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                int px_id = 4 * i;
 | 
			
		||||
                int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16);
 | 
			
		||||
                if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
 | 
			
		||||
                    idxs.insert(volume_id);
 | 
			
		||||
            }
 | 
			
		||||
#endif // USE_PARALLEL
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_hover_volume_idxs.assign(idxs.begin(), idxs.end());
 | 
			
		||||
    _update_volumes_hover_state();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_render_background() const
 | 
			
		||||
{
 | 
			
		||||
    glsafe(::glPushMatrix());
 | 
			
		||||
| 
						 | 
				
			
			@ -4109,24 +4293,93 @@ void GLCanvas3D::_update_volumes_hover_state() const
 | 
			
		|||
{
 | 
			
		||||
    for (GLVolume* v : m_volumes.volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->hover = false;
 | 
			
		||||
        v->hover = GLVolume::HS_None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_hover_volume_id == -1)
 | 
			
		||||
    if (m_hover_volume_idxs.empty())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    GLVolume* volume = m_volumes.volumes[m_hover_volume_id];
 | 
			
		||||
    if (volume->is_modifier)
 | 
			
		||||
        volume->hover = true;
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        int object_idx = volume->object_idx();
 | 
			
		||||
        int instance_idx = volume->instance_idx();
 | 
			
		||||
    bool ctrl_pressed = wxGetKeyState(WXK_CONTROL); // additive select/deselect
 | 
			
		||||
    bool shift_pressed = wxGetKeyState(WXK_SHIFT);  // select by rectangle
 | 
			
		||||
    bool alt_pressed = wxGetKeyState(WXK_ALT);      // deselect by rectangle
 | 
			
		||||
 | 
			
		||||
        for (GLVolume* v : m_volumes.volumes)
 | 
			
		||||
    if (alt_pressed && (shift_pressed || ctrl_pressed))
 | 
			
		||||
    {
 | 
			
		||||
        // illegal combinations of keys
 | 
			
		||||
        m_hover_volume_idxs.clear();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool selection_modifiers_only = m_selection.is_empty() || m_selection.is_any_modifier();
 | 
			
		||||
 | 
			
		||||
    bool hover_modifiers_only = true;
 | 
			
		||||
    for (int i : m_hover_volume_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        if (!m_volumes.volumes[i]->is_modifier)
 | 
			
		||||
        {
 | 
			
		||||
            if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
 | 
			
		||||
                v->hover = true;
 | 
			
		||||
            hover_modifiers_only = false;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::set<std::pair<int, int>> hover_instances;
 | 
			
		||||
    for (int i : m_hover_volume_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        const GLVolume& v = *m_volumes.volumes[i];
 | 
			
		||||
        hover_instances.insert(std::make_pair(v.object_idx(), v.instance_idx()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool hover_from_single_instance = hover_instances.size() == 1;
 | 
			
		||||
 | 
			
		||||
    if (hover_modifiers_only && !hover_from_single_instance)
 | 
			
		||||
    {
 | 
			
		||||
        // do not allow to select volumes from different instances
 | 
			
		||||
        m_hover_volume_idxs.clear();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i : m_hover_volume_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        GLVolume& volume = *m_volumes.volumes[i];
 | 
			
		||||
        if (volume.hover != GLVolume::HS_None)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        bool deselect = volume.selected && ((ctrl_pressed && !shift_pressed) || alt_pressed);
 | 
			
		||||
        // (volume->is_modifier && !selection_modifiers_only && !is_ctrl_pressed) -> allows hovering on selected modifiers belonging to selection of type Instance
 | 
			
		||||
        bool select = (!volume.selected || (volume.is_modifier && !selection_modifiers_only && !ctrl_pressed)) && !alt_pressed;
 | 
			
		||||
 | 
			
		||||
        if (select || deselect)
 | 
			
		||||
        {
 | 
			
		||||
            bool as_volume =
 | 
			
		||||
                volume.is_modifier && hover_from_single_instance && !ctrl_pressed &&
 | 
			
		||||
                (
 | 
			
		||||
                (!deselect) ||
 | 
			
		||||
                (deselect && !m_selection.is_single_full_instance() && (volume.object_idx() == m_selection.get_object_idx()) && (volume.instance_idx() == m_selection.get_instance_idx()))
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            if (as_volume)
 | 
			
		||||
            {
 | 
			
		||||
                if (deselect)
 | 
			
		||||
                    volume.hover = GLVolume::HS_Deselect;
 | 
			
		||||
                else
 | 
			
		||||
                    volume.hover = GLVolume::HS_Select;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                int object_idx = volume.object_idx();
 | 
			
		||||
                int instance_idx = volume.instance_idx();
 | 
			
		||||
 | 
			
		||||
                for (GLVolume* v : m_volumes.volumes)
 | 
			
		||||
                {
 | 
			
		||||
                    if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (deselect)
 | 
			
		||||
                            v->hover = GLVolume::HS_Deselect;
 | 
			
		||||
                        else
 | 
			
		||||
                            v->hover = GLVolume::HS_Select;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5405,6 +5658,55 @@ void GLCanvas3D::_resize_toolbars() const
 | 
			
		|||
}
 | 
			
		||||
#endif // !ENABLE_SVG_ICONS
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_update_selection_from_hover()
 | 
			
		||||
{
 | 
			
		||||
    bool ctrl_pressed = wxGetKeyState(WXK_CONTROL);
 | 
			
		||||
 | 
			
		||||
    if (m_hover_volume_idxs.empty())
 | 
			
		||||
    {
 | 
			
		||||
        if (!ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))
 | 
			
		||||
            m_selection.clear();
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLSelectionRectangle::EState state = m_rectangle_selection.get_state();
 | 
			
		||||
 | 
			
		||||
    bool hover_modifiers_only = true;
 | 
			
		||||
    for (int i : m_hover_volume_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        if (!m_volumes.volumes[i]->is_modifier)
 | 
			
		||||
        {
 | 
			
		||||
            hover_modifiers_only = false;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((state == GLSelectionRectangle::Select) && !ctrl_pressed)
 | 
			
		||||
        m_selection.clear();
 | 
			
		||||
 | 
			
		||||
    for (int i : m_hover_volume_idxs)
 | 
			
		||||
    {
 | 
			
		||||
        if (state == GLSelectionRectangle::Select)
 | 
			
		||||
        {
 | 
			
		||||
            if (hover_modifiers_only)
 | 
			
		||||
            {
 | 
			
		||||
                const GLVolume& v = *m_volumes.volumes[i];
 | 
			
		||||
                m_selection.add_volume(v.object_idx(), v.volume_idx(), v.instance_idx(), false);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                m_selection.add(i, false);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            m_selection.remove(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_gizmos.refresh_on_off_state(m_selection);
 | 
			
		||||
    m_gizmos.update_data(*this);
 | 
			
		||||
    post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
 | 
			
		||||
    m_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Print* GLCanvas3D::fff_print() const
 | 
			
		||||
{
 | 
			
		||||
    return (m_process == nullptr) ? nullptr : m_process->fff_print();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -303,6 +303,7 @@ class GLCanvas3D
 | 
			
		|||
        Vec2d position;
 | 
			
		||||
        Vec3d scene_position;
 | 
			
		||||
        Drag drag;
 | 
			
		||||
        bool ignore_left_up;
 | 
			
		||||
 | 
			
		||||
        Mouse();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +320,6 @@ class GLCanvas3D
 | 
			
		|||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct SlaCap
 | 
			
		||||
    {
 | 
			
		||||
        struct Triangles
 | 
			
		||||
| 
						 | 
				
			
			@ -399,6 +399,23 @@ private:
 | 
			
		|||
        void render(const GLCanvas3D& canvas) const;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
    struct RenderStats
 | 
			
		||||
    {
 | 
			
		||||
        long long last_frame;
 | 
			
		||||
 | 
			
		||||
        RenderStats() : last_frame(0) {}
 | 
			
		||||
    };
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    enum ECursorType : unsigned char
 | 
			
		||||
    {
 | 
			
		||||
        Standard,
 | 
			
		||||
        Cross
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    wxGLCanvas* m_canvas;
 | 
			
		||||
    wxGLContext* m_context;
 | 
			
		||||
#if ENABLE_RETINA_GL
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +450,7 @@ private:
 | 
			
		|||
    bool m_initialized;
 | 
			
		||||
    bool m_use_VBOs;
 | 
			
		||||
    bool m_apply_zoom_to_volumes_filter;
 | 
			
		||||
    mutable int m_hover_volume_id;
 | 
			
		||||
    mutable std::vector<int> m_hover_volume_idxs;
 | 
			
		||||
    bool m_warning_texture_enabled;
 | 
			
		||||
    bool m_legend_texture_enabled;
 | 
			
		||||
    bool m_picking_enabled;
 | 
			
		||||
| 
						 | 
				
			
			@ -443,6 +460,8 @@ private:
 | 
			
		|||
    bool m_regenerate_volumes;
 | 
			
		||||
    bool m_moving;
 | 
			
		||||
    bool m_tab_down;
 | 
			
		||||
    ECursorType m_cursor_type;
 | 
			
		||||
    GLSelectionRectangle m_rectangle_selection;
 | 
			
		||||
 | 
			
		||||
    // Following variable is obsolete and it should be safe to remove it.
 | 
			
		||||
    // I just don't want to do it now before a release (Lukas Matena 24.3.2019)
 | 
			
		||||
| 
						 | 
				
			
			@ -454,6 +473,10 @@ private:
 | 
			
		|||
 | 
			
		||||
    GCodePreviewVolumeIndex m_gcode_preview_volume_index;
 | 
			
		||||
 | 
			
		||||
#if ENABLE_RENDER_STATISTICS
 | 
			
		||||
    RenderStats m_render_stats;
 | 
			
		||||
#endif // ENABLE_RENDER_STATISTICS
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
 | 
			
		||||
    ~GLCanvas3D();
 | 
			
		||||
| 
						 | 
				
			
			@ -582,7 +605,7 @@ public:
 | 
			
		|||
    float get_view_toolbar_height() const { return m_view_toolbar.get_height(); }
 | 
			
		||||
 | 
			
		||||
    int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
 | 
			
		||||
    int get_hover_volume_id() const { return m_hover_volume_id; }
 | 
			
		||||
    int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
 | 
			
		||||
 | 
			
		||||
    // Returns the view ray line, in world coordinate, at the given mouse position.
 | 
			
		||||
    Linef3 mouse_ray(const Point& mouse_pos);
 | 
			
		||||
| 
						 | 
				
			
			@ -594,6 +617,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    double get_size_proportional_to_max_bed_size(double factor) const;
 | 
			
		||||
 | 
			
		||||
    void set_cursor(ECursorType type);
 | 
			
		||||
    void msw_rescale();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -612,6 +636,7 @@ private:
 | 
			
		|||
    void _refresh_if_shown_on_screen();
 | 
			
		||||
 | 
			
		||||
    void _picking_pass() const;
 | 
			
		||||
    void _rectangular_selection_picking_pass() const;
 | 
			
		||||
    void _render_background() const;
 | 
			
		||||
    void _render_bed(float theta) const;
 | 
			
		||||
    void _render_axes() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -690,6 +715,9 @@ private:
 | 
			
		|||
    void _resize_toolbars() const;
 | 
			
		||||
#endif // !ENABLE_SVG_ICONS
 | 
			
		||||
 | 
			
		||||
    // updates the selection from the content of m_hover_volume_idxs
 | 
			
		||||
    void _update_selection_from_hover();
 | 
			
		||||
 | 
			
		||||
    static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										117
									
								
								src/slic3r/GUI/GLSelectionRectangle.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/slic3r/GUI/GLSelectionRectangle.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,117 @@
 | 
			
		|||
#include "GLSelectionRectangle.hpp"
 | 
			
		||||
#include "Camera.hpp"
 | 
			
		||||
#include "3DScene.hpp"
 | 
			
		||||
#include "GLCanvas3D.hpp"
 | 
			
		||||
 | 
			
		||||
#include <GL/glew.h>
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
    void GLSelectionRectangle::start_dragging(const Vec2d& mouse_position, EState state)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_dragging() || (state == Off))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        m_state = state;
 | 
			
		||||
        m_start_corner = mouse_position;
 | 
			
		||||
        m_end_corner = mouse_position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GLSelectionRectangle::dragging(const Vec2d& mouse_position)
 | 
			
		||||
    {
 | 
			
		||||
        if (!is_dragging())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        m_end_corner = mouse_position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<unsigned int> GLSelectionRectangle::stop_dragging(const GLCanvas3D& canvas, const std::vector<Vec3d>& points)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<unsigned int> out;
 | 
			
		||||
 | 
			
		||||
        if (!is_dragging())
 | 
			
		||||
            return out;
 | 
			
		||||
 | 
			
		||||
        m_state = Off;
 | 
			
		||||
 | 
			
		||||
        const Camera& camera = canvas.get_camera();
 | 
			
		||||
        const std::array<int, 4>& 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<int>()), Point(m_end_corner.cast<int>()) });
 | 
			
		||||
 | 
			
		||||
        // Iterate over all points and determine whether they're in the rectangle.
 | 
			
		||||
        for (unsigned int i = 0; i<points.size(); ++i) {
 | 
			
		||||
            const Vec3d& point = points[i];
 | 
			
		||||
            GLdouble out_x, out_y, out_z;
 | 
			
		||||
            ::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);
 | 
			
		||||
            out_y = canvas.get_canvas_size().get_height() - out_y;
 | 
			
		||||
 | 
			
		||||
            if (rectangle.contains(Point(out_x, out_y)))
 | 
			
		||||
                out.push_back(i);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GLSelectionRectangle::stop_dragging()
 | 
			
		||||
    {
 | 
			
		||||
        if (is_dragging())
 | 
			
		||||
            m_state = Off;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GLSelectionRectangle::render(const GLCanvas3D& canvas) const
 | 
			
		||||
    {
 | 
			
		||||
        if (!is_dragging())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        float zoom = canvas.get_camera().zoom;
 | 
			
		||||
        float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
 | 
			
		||||
 | 
			
		||||
        Size cnv_size = canvas.get_canvas_size();
 | 
			
		||||
        float cnv_half_width = 0.5f * (float)cnv_size.get_width();
 | 
			
		||||
        float cnv_half_height = 0.5f * (float)cnv_size.get_height();
 | 
			
		||||
        if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Vec2d start(m_start_corner(0) - cnv_half_width, cnv_half_height - m_start_corner(1));
 | 
			
		||||
        Vec2d end(m_end_corner(0) - cnv_half_width, cnv_half_height - m_end_corner(1));
 | 
			
		||||
 | 
			
		||||
        float left = (float)std::min(start(0), end(0)) * inv_zoom;
 | 
			
		||||
        float top = (float)std::max(start(1), end(1)) * inv_zoom;
 | 
			
		||||
        float right = (float)std::max(start(0), end(0)) * inv_zoom;
 | 
			
		||||
        float bottom = (float)std::min(start(1), end(1)) * inv_zoom;
 | 
			
		||||
 | 
			
		||||
        glsafe(::glLineWidth(1.5f));
 | 
			
		||||
        float color[3];
 | 
			
		||||
        color[0] = (m_state == Select) ? 0.3f : 1.0f;
 | 
			
		||||
        color[1] = (m_state == Select) ? 1.0f : 0.3f;
 | 
			
		||||
        color[2] = 0.3f;
 | 
			
		||||
        glsafe(::glColor3fv(color));
 | 
			
		||||
 | 
			
		||||
        glsafe(::glDisable(GL_DEPTH_TEST));
 | 
			
		||||
 | 
			
		||||
        glsafe(::glPushMatrix());
 | 
			
		||||
        glsafe(::glLoadIdentity());
 | 
			
		||||
 | 
			
		||||
        glsafe(::glPushAttrib(GL_ENABLE_BIT));
 | 
			
		||||
        glsafe(::glLineStipple(4, 0xAAAA));
 | 
			
		||||
        glsafe(::glEnable(GL_LINE_STIPPLE));
 | 
			
		||||
 | 
			
		||||
        ::glBegin(GL_LINE_LOOP);
 | 
			
		||||
        ::glVertex2f((GLfloat)left, (GLfloat)bottom);
 | 
			
		||||
        ::glVertex2f((GLfloat)right, (GLfloat)bottom);
 | 
			
		||||
        ::glVertex2f((GLfloat)right, (GLfloat)top);
 | 
			
		||||
        ::glVertex2f((GLfloat)left, (GLfloat)top);
 | 
			
		||||
        glsafe(::glEnd());
 | 
			
		||||
 | 
			
		||||
        glsafe(::glPopAttrib());
 | 
			
		||||
 | 
			
		||||
        glsafe(::glPopMatrix());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
							
								
								
									
										56
									
								
								src/slic3r/GUI/GLSelectionRectangle.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/slic3r/GUI/GLSelectionRectangle.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
#ifndef slic3r_GLSelectionRectangle_hpp_
 | 
			
		||||
#define slic3r_GLSelectionRectangle_hpp_
 | 
			
		||||
 | 
			
		||||
#include "libslic3r/Point.hpp"
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
    
 | 
			
		||||
struct Camera;
 | 
			
		||||
class GLCanvas3D;
 | 
			
		||||
 | 
			
		||||
class GLSelectionRectangle {
 | 
			
		||||
public:
 | 
			
		||||
    enum EState {
 | 
			
		||||
            Off,
 | 
			
		||||
            Select,
 | 
			
		||||
            Deselect
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Initiates the rectangle. 
 | 
			
		||||
    void start_dragging(const Vec2d& mouse_position, EState state);
 | 
			
		||||
 | 
			
		||||
    // To be called on mouse move.
 | 
			
		||||
    void dragging(const Vec2d& mouse_position);
 | 
			
		||||
 | 
			
		||||
    // Given a vector of points in world coordinates, the function returns indices of those
 | 
			
		||||
    // that are in the rectangle. It then disables the rectangle.
 | 
			
		||||
    std::vector<unsigned int> stop_dragging(const GLCanvas3D& canvas, const std::vector<Vec3d>& points);
 | 
			
		||||
 | 
			
		||||
    // Disables the rectangle.
 | 
			
		||||
    void stop_dragging();
 | 
			
		||||
 | 
			
		||||
    void render(const GLCanvas3D& canvas) const;
 | 
			
		||||
 | 
			
		||||
    bool is_dragging() const { return m_state != Off; }
 | 
			
		||||
    EState get_state() const { return m_state; }
 | 
			
		||||
 | 
			
		||||
    float get_width() const { return std::abs(m_start_corner(0) - m_end_corner(0)); }
 | 
			
		||||
    float get_height() const { return std::abs(m_start_corner(1) - m_end_corner(1)); }
 | 
			
		||||
    float get_left() const { return std::min(m_start_corner(0), m_end_corner(0)); }
 | 
			
		||||
    float get_right() const { return std::max(m_start_corner(0), m_end_corner(0)); }
 | 
			
		||||
    float get_top() const { return std::max(m_start_corner(1), m_end_corner(1)); }
 | 
			
		||||
    float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    EState m_state = Off;
 | 
			
		||||
    Vec2d m_start_corner;
 | 
			
		||||
    Vec2d m_end_corner;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
} // namespace GUI
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // slic3r_GLGizmoSlaSupports_hpp_
 | 
			
		||||
| 
						 | 
				
			
			@ -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(m_parent);
 | 
			
		||||
    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,7 @@ 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();
 | 
			
		||||
                    m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
| 
						 | 
				
			
			@ -533,7 +483,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_dragging() && !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 +508,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<int, 4>& 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_dragging()) {
 | 
			
		||||
            // Is this a selection or deselection rectangle?
 | 
			
		||||
            GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state();
 | 
			
		||||
 | 
			
		||||
            // 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<Vec3d> points;
 | 
			
		||||
            for (unsigned int i=0; i<m_editing_mode_cache.size(); ++i) {
 | 
			
		||||
                const sla::SupportPoint &support_point = m_editing_mode_cache[i].support_point;
 | 
			
		||||
                points.push_back(instance_matrix * support_point.pos.cast<double>());
 | 
			
		||||
                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<unsigned int> selected_idxs = m_selection_rectangle.stop_dragging(m_parent, 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<int>()), Point(m_selection_rectangle_end_corner.cast<int>())});
 | 
			
		||||
 | 
			
		||||
            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<float>();
 | 
			
		||||
            // ...and transform it to model coords.
 | 
			
		||||
            Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
 | 
			
		||||
            Vec3f scaling = volume->get_instance_scaling_factor().cast<float>();
 | 
			
		||||
            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<m_editing_mode_cache.size(); ++i) {
 | 
			
		||||
            // Iterate over all points in the rectangle and check that they are neither clipped by the
 | 
			
		||||
            // clipping plane nor obscured by the mesh.
 | 
			
		||||
            for (const unsigned int i : selected_idxs) {
 | 
			
		||||
                const sla::SupportPoint &support_point = m_editing_mode_cache[i].support_point;
 | 
			
		||||
                Vec3f pos = instance_matrix.cast<float>() * 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<double>())) {
 | 
			
		||||
                if (!is_point_clipped(support_point.pos.cast<double>())) {
 | 
			
		||||
                    bool is_obscured = false;
 | 
			
		||||
                    // Cast a ray in the direction of the camera and look for intersection with the mesh:
 | 
			
		||||
                    std::vector<igl::Hit> hits;
 | 
			
		||||
| 
						 | 
				
			
			@ -627,14 +575,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
 | 
			
		|||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!is_obscured) {
 | 
			
		||||
                        if (m_selection_rectangle_status == srDeselect)
 | 
			
		||||
                        if (rectangle_status == GLSelectionRectangle::Deselect)
 | 
			
		||||
                            unselect_point(i);
 | 
			
		||||
                        else
 | 
			
		||||
                            select_point(i);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            m_selection_rectangle_status = srOff;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -652,9 +599,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_dragging())  {
 | 
			
		||||
                m_selection_rectangle.dragging(mouse_position);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -67,13 +68,16 @@ public:
 | 
			
		|||
    void delete_selected_points(bool force = false);
 | 
			
		||||
    ClippingPlane get_sla_clipping_plane() const;
 | 
			
		||||
 | 
			
		||||
    bool is_in_editing_mode() const { return m_editing_mode; }
 | 
			
		||||
    bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool on_init();
 | 
			
		||||
    void on_update(const UpdateData& data, const Selection& selection);
 | 
			
		||||
    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 +95,12 @@ 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;
 | 
			
		||||
    GLSelectionRectangle m_selection_rectangle;
 | 
			
		||||
 | 
			
		||||
    Vec2d m_selection_rectangle_start_corner;
 | 
			
		||||
    Vec2d m_selection_rectangle_end_corner;
 | 
			
		||||
    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<TriangleMeshSlicer> m_tms;
 | 
			
		||||
    mutable std::unique_ptr<TriangleMeshSlicer> m_supports_tms;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -693,7 +693,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
 | 
			
		|||
            gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
 | 
			
		||||
            processed = true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_hover_volume_id() != -1) || grabber_contains_mouse()))
 | 
			
		||||
        else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_first_hover_volume_idx() != -1) || grabber_contains_mouse()))
 | 
			
		||||
        {
 | 
			
		||||
            // to avoid to loose the selection when user clicks an object while the Flatten gizmo is active
 | 
			
		||||
            processed = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -843,13 +843,34 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
 | 
			
		|||
 | 
			
		||||
    if (evt.GetEventType() == wxEVT_KEY_UP)
 | 
			
		||||
    {
 | 
			
		||||
        if ((m_current == SlaSupports) && (keyCode == WXK_SHIFT) && gizmo_event(SLAGizmoEventType::ShiftUp))
 | 
			
		||||
            // shift has been just released - SLA gizmo might want to close rectangular selection.
 | 
			
		||||
            processed = true;
 | 
			
		||||
        if (m_current == SlaSupports)
 | 
			
		||||
        {
 | 
			
		||||
            GLGizmoSlaSupports* gizmo = reinterpret_cast<GLGizmoSlaSupports*>(get_current());
 | 
			
		||||
 | 
			
		||||
        if ((m_current == SlaSupports) && (keyCode == WXK_ALT) && gizmo_event(SLAGizmoEventType::AltUp))
 | 
			
		||||
            // alt has been just released - SLA gizmo might want to close rectangular selection.
 | 
			
		||||
            if (keyCode == WXK_SHIFT)
 | 
			
		||||
            {
 | 
			
		||||
                // shift has been just released - SLA gizmo might want to close rectangular selection.
 | 
			
		||||
                if (gizmo_event(SLAGizmoEventType::ShiftUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging()))
 | 
			
		||||
                    processed = true;
 | 
			
		||||
            }
 | 
			
		||||
            else if (keyCode == WXK_ALT)
 | 
			
		||||
            {
 | 
			
		||||
                // alt has been just released - SLA gizmo might want to close rectangular selection.
 | 
			
		||||
                if (gizmo_event(SLAGizmoEventType::AltUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging()))
 | 
			
		||||
                    processed = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
//        if (processed)
 | 
			
		||||
//            canvas.set_cursor(GLCanvas3D::Standard);
 | 
			
		||||
    }
 | 
			
		||||
    else if (evt.GetEventType() == wxEVT_KEY_DOWN)
 | 
			
		||||
    {
 | 
			
		||||
        if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
 | 
			
		||||
        {
 | 
			
		||||
//            canvas.set_cursor(GLCanvas3D::Cross);
 | 
			
		||||
            processed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (processed)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue