From e1be0f041c688e891ac30e5754e04729352a30ee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 6 Nov 2024 09:06:38 +0100 Subject: [PATCH] Autoslice (part 1) --- src/libslic3r/MultipleBeds.cpp | 38 ++++++++ src/libslic3r/MultipleBeds.hpp | 8 ++ src/slic3r/GUI/GLCanvas3D.cpp | 161 ++++++++++++++++++++++----------- src/slic3r/GUI/GLCanvas3D.hpp | 6 +- src/slic3r/GUI/Plater.cpp | 12 ++- src/slic3r/GUI/Plater.hpp | 1 + 6 files changed, 166 insertions(+), 60 deletions(-) diff --git a/src/libslic3r/MultipleBeds.cpp b/src/libslic3r/MultipleBeds.cpp index c84087ef16..389bbea131 100644 --- a/src/libslic3r/MultipleBeds.cpp +++ b/src/libslic3r/MultipleBeds.cpp @@ -318,6 +318,44 @@ void MultipleBeds::ensure_wipe_towers_on_beds(Model& model, const std::vector select_bed_fn) +{ + if (is_autoslicing()) + return; + m_select_bed_fn = select_bed_fn; + + m_autoslicing_original_bed = get_active_bed(); + + m_autoslicing = true; +} + + + +void MultipleBeds::stop_autoslice(bool restore_original) +{ + if (! is_autoslicing()) + return; + m_autoslicing = false; + + if (restore_original) + m_select_bed_fn(m_autoslicing_original_bed, false); +} + + + +void MultipleBeds::autoslice_next_bed() +{ + if (! is_autoslicing()) + return; + int next_bed = s_multiple_beds.get_active_bed() + 1; + if (next_bed >= s_multiple_beds.get_number_of_beds()) + next_bed = 0; + m_select_bed_fn(next_bed, false); +} +#endif // SLIC3R_GUI + } diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 9c6cdd6120..ccc5fbcc66 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -64,6 +64,11 @@ public: Vec2crd get_bed_gap() const; void ensure_wipe_towers_on_beds(Model& model, const std::vector>& prints); + void start_autoslice(std::function); + void stop_autoslice(bool restore_original); + bool is_autoslicing() const { return m_autoslicing; } + void autoslice_next_bed(); + private: bool is_instance_on_active_bed(ObjectID id) const; @@ -78,6 +83,9 @@ private: bool m_legacy_layout = false; bool m_loading_project = false; + bool m_autoslicing = false; + int m_autoslicing_original_bed = 0; + std::function m_select_bed_fn; }; extern MultipleBeds s_multiple_beds; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 78dec96942..51fb51e1ec 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -102,10 +102,10 @@ static bool show_imgui_demo_window = false; namespace Slic3r { namespace GUI { -void GLCanvas3D::select_bed(int i) +void GLCanvas3D::select_bed(int i, bool triggered_by_user) { int old_bed = s_multiple_beds.get_active_bed(); - if (i == old_bed || i == -1) + if ((i == old_bed && !s_multiple_beds.is_autoslicing()) || i == -1) return; wxGetApp().plater()->canvas3D()->m_process->stop(); m_sequential_print_clearance.m_evaluating = true; @@ -115,7 +115,7 @@ void GLCanvas3D::select_bed(int i) // Among else, on_process_completed would be called, which would stop slicing of // the new bed. We need to stop the process, pump all the events out of the queue // and then switch the beds. - wxGetApp().CallAfter([i, old_bed]() { + wxGetApp().CallAfter([i, old_bed, triggered_by_user]() { wxYield(); s_multiple_beds.set_active_bed(i); s_beds_just_switched = true; @@ -125,6 +125,8 @@ void GLCanvas3D::select_bed(int i) wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); } wxGetApp().plater()->schedule_background_process(); + if (s_multiple_beds.is_autoslicing() && triggered_by_user) + s_multiple_beds.stop_autoslice(false); }); } @@ -1899,21 +1901,7 @@ void GLCanvas3D::render() #endif // SHOW_IMGUI_DEMO_WINDOW - { - if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) { - ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize); - for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) { - bool inactive = i != s_multiple_beds.get_active_bed(); - if (inactive) - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5)); - if (ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0))) - select_bed(i); - if (inactive) - ImGui::PopStyleColor(); - } - ImGui::End(); - } - } + const bool is_looking_downward = camera.is_looking_downward(); @@ -1922,40 +1910,41 @@ void GLCanvas3D::render() glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); _render_background(); - _render_objects(GLVolumeCollection::ERenderType::Opaque); - _render_sla_slices(); - _render_selection(); - _render_bed_axes(); - if (is_looking_downward) - _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false); - if (!m_main_toolbar.is_enabled() && current_printer_technology() != ptSLA) - _render_gcode(); - _render_objects(GLVolumeCollection::ERenderType::Transparent); + if (! s_multiple_beds.is_autoslicing()) { + _render_objects(GLVolumeCollection::ERenderType::Opaque); + _render_sla_slices(); + _render_selection(); + _render_bed_axes(); + if (is_looking_downward) + _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false); + if (!m_main_toolbar.is_enabled() && current_printer_technology() != ptSLA) + _render_gcode(); + _render_objects(GLVolumeCollection::ERenderType::Transparent); - _render_sequential_clearance(); -#if ENABLE_RENDER_SELECTION_CENTER - _render_selection_center(); -#endif // ENABLE_RENDER_SELECTION_CENTER - if (!m_main_toolbar.is_enabled()) - _render_gcode_cog(); + _render_sequential_clearance(); + #if ENABLE_RENDER_SELECTION_CENTER + _render_selection_center(); + #endif // ENABLE_RENDER_SELECTION_CENTER + if (!m_main_toolbar.is_enabled()) + _render_gcode_cog(); - // we need to set the mouse's scene position here because the depth buffer - // could be invalidated by the following gizmo render methods - // this position is used later into on_mouse() to drag the objects - if (m_picking_enabled) - m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast()); + // we need to set the mouse's scene position here because the depth buffer + // could be invalidated by the following gizmo render methods + // this position is used later into on_mouse() to drag the objects + if (m_picking_enabled) + m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast()); - // sidebar hints need to be rendered before the gizmos because the depth buffer - // could be invalidated by the following gizmo render methods - _render_selection_sidebar_hints(); - _render_current_gizmo(); - if (!is_looking_downward) - _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true); + // sidebar hints need to be rendered before the gizmos because the depth buffer + // could be invalidated by the following gizmo render methods + _render_selection_sidebar_hints(); + _render_current_gizmo(); + if (!is_looking_downward) + _render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true); -#if ENABLE_RAYCAST_PICKING_DEBUG - if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging()) - m_scene_raycaster.render_hit(camera); -#endif // ENABLE_RAYCAST_PICKING_DEBUG + #if ENABLE_RAYCAST_PICKING_DEBUG + if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging()) + m_scene_raycaster.render_hit(camera); + #endif // ENABLE_RAYCAST_PICKING_DEBUG #if ENABLE_SHOW_CAMERA_TARGET _render_camera_target(); @@ -1963,11 +1952,74 @@ void GLCanvas3D::render() _render_camera_target_validation_box(); #endif // ENABLE_SHOW_CAMERA_TARGET - if (m_picking_enabled && m_rectangle_selection.is_dragging()) - m_rectangle_selection.render(*this); + if (m_picking_enabled && m_rectangle_selection.is_dragging()) + m_rectangle_selection.render(*this); + } else { + // Autoslicing. + // Render the combined statistics if all is ready. + bool valid = true; + double total_g = 0; + for (size_t i=0; iget_fff_prints()[i].get(); + if (!print->finished()) { + // TODO: Only active bed invalidation can be detected here. + valid = false; + break; + } + total_g += print->print_statistics().total_used_filament; + } + ImGui::Begin("Total stats"); + if (valid) + ImGui::Text("%s", std::to_string(total_g).c_str()); + else + ImGui::Text("Wait until all beds are sliced..."); + ImGui::End(); + + if (!valid) { + if (fff_print()->finished()) + s_multiple_beds.autoslice_next_bed(); + else + wxGetApp().plater()->schedule_background_process(); + } + } + // draw overlays + _render_overlays(); + + { + if (s_multiple_beds.get_number_of_beds() != 1 && wxGetApp().plater()->is_preview_shown()) { + ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_NoResize); + for (int i = 0; i < s_multiple_beds.get_number_of_beds(); ++i) { + bool inactive = i != s_multiple_beds.get_active_bed() || s_multiple_beds.is_autoslicing(); + if (inactive) + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5)); + if (bool clicked = (i >= int(s_th_tex_id.size())) + ? ImGui::Button(std::to_string(i).c_str(), ImVec2(100,100)) + : ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)); + clicked) + select_bed(i, true); + if (inactive) + ImGui::PopStyleColor(); + + std::string status_text; + if (wxGetApp().plater()->get_fff_prints()[i]->finished()) + status_text = "finished"; + else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running()) + status_text = "running"; + else + status_text = "idle"; + ImGui::SameLine(); + ImGui::Text("%s", status_text.c_str()); + + + } + if (ImGui::Button("ALL", ImVec2(105, 105))) { + if (! s_multiple_beds.is_autoslicing()) + s_multiple_beds.start_autoslice([this](int i, bool user) { this->select_bed(i, user); }); + } + ImGui::End(); + } + } - // draw overlays - _render_overlays(); if (wxGetApp().plater()->is_render_statistic_dialog_visible()) { ImGuiPureWrap::begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); @@ -2046,7 +2098,8 @@ void GLCanvas3D::render() wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); - wxGetApp().plater()->render_sliders(*this); + if (! s_multiple_beds.is_autoslicing()) + wxGetApp().plater()->render_sliders(*this); wxGetApp().imgui()->render(); @@ -3696,7 +3749,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_dirty = true; } } else if (evt.LeftDown()) { - select_bed(s_multiple_beds.get_last_hovered_bed()); + select_bed(s_multiple_beds.get_last_hovered_bed(), true); } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 23760bd1ea..0203fd70e4 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -526,9 +526,13 @@ private: Selection m_selection; const DynamicPrintConfig* m_config; Model* m_model; +public: BackgroundSlicingProcess *m_process; +private: bool m_requires_check_outside_state{ false }; + void select_bed(int i, bool triggered_by_user); + std::array m_old_size{ 0, 0 }; // Screen is only refreshed from the OnIdle handler if it is dirty. @@ -742,8 +746,6 @@ private: // returns the containment state in the given out_state, if non-null bool check_volumes_outside_state(GLVolumeCollection& volumes, ModelInstanceEPrintVolumeState* out_state, bool selection_only = true) const; - void select_bed(int i); - public: void init_gcode_viewer() { m_gcode_viewer.init(); } void reset_gcode_toolpaths() { m_gcode_viewer.reset(); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8669484e61..7a4b24cd0d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2228,10 +2228,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool glsafe(glPixelStorei(GL_UNPACK_ALIGNMENT, curr_unpack_alignment)); } - - - - // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. if (view3D->is_layers_editing_enabled()) view3D->get_wxglcanvas()->Refresh(); @@ -2945,6 +2941,9 @@ void Plater::priv::set_current_panel(wxPanel* panel) panel_sizer->Layout(); if (current_panel == view3D) { + + s_multiple_beds.stop_autoslice(true); + if (old_panel == preview) preview->get_canvas3d()->unbind_event_handlers(); @@ -7314,6 +7313,11 @@ std::vector>& Plater::get_fff_prints() return p->fff_prints; } +const std::vector& Plater::get_gcode_results() const +{ + return p->gcode_results; +} + wxMenu* Plater::object_menu() { return p->menus.object_menu(); } wxMenu* Plater::part_menu() { return p->menus.part_menu(); } wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index cdd5a6bc78..8816196558 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -102,6 +102,7 @@ public: SLAPrint& active_sla_print(); std::vector>& get_fff_prints(); + const std::vector& get_gcode_results() const; void new_project(); void load_project();