From aa47729c470dbe399bd320dadf3b90f8f5defb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 19 Oct 2021 11:53:21 +0200 Subject: [PATCH 01/11] Added a missing include (GCC 11.1). --- src/slic3r/GUI/Plater.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 1f5c2b6e7c..97e4af218c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -48,6 +48,7 @@ #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/PresetBundle.hpp" +#include "libslic3r/ClipperUtils.hpp" #include "GUI.hpp" #include "GUI_App.hpp" From 5a1809579ec60397a7ff60d64ea393f40b9bb4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 19 Oct 2021 12:54:27 +0200 Subject: [PATCH 02/11] Fixed unintended space after ImGui::SliderFloat in the hollow and sla supports gizmos. --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 49 +++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 8 ++-- src/slic3r/GUI/ImGuiWrapper.cpp | 18 ++++++- src/slic3r/GUI/ImGuiWrapper.hpp | 6 ++- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index f7feed44ae..d45a2e6137 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -508,20 +508,23 @@ RENDER_AGAIN: m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: - const float settings_sliders_left = - std::max({m_imgui->calc_text_size(m_desc.at("offset")).x, - m_imgui->calc_text_size(m_desc.at("quality")).x, - m_imgui->calc_text_size(m_desc.at("closing_distance")).x, - m_imgui->calc_text_size(m_desc.at("hole_diameter")).x, - m_imgui->calc_text_size(m_desc.at("hole_depth")).x}) - + m_imgui->scaled(1.f); + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, + m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(0.5f); + + const float settings_sliders_left = + std::max(std::max({m_imgui->calc_text_size(m_desc.at("offset")).x, + m_imgui->calc_text_size(m_desc.at("quality")).x, + m_imgui->calc_text_size(m_desc.at("closing_distance")).x, + m_imgui->calc_text_size(m_desc.at("hole_diameter")).x, + m_imgui->calc_text_size(m_desc.at("hole_depth")).x}) + m_imgui->scaled(0.5f), clipping_slider_left); - const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); + const float button_preview_width = m_imgui->calc_button_size(m_desc.at("preview")).x; + float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left}); - window_width = std::max(window_width, m_imgui->calc_text_size(m_desc.at("preview")).x); + window_width = std::max(window_width, button_preview_width); if (m_imgui->button(m_desc["preview"])) hollow_mesh(); @@ -544,9 +547,9 @@ RENDER_AGAIN: float max_tooltip_width = ImGui::GetFontSize() * 20.0f; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("offset")); - ImGui::SameLine(settings_sliders_left); + ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); ImGui::PushItemWidth(window_width - settings_sliders_left); - m_imgui->slider_float(" ", &offset, offset_min, offset_max, "%.1f mm"); + m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm"); if (ImGui::IsItemHovered()) m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width); @@ -557,8 +560,8 @@ RENDER_AGAIN: if (current_mode >= quality_mode) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("quality")); - ImGui::SameLine(settings_sliders_left); - m_imgui->slider_float(" ", &quality, quality_min, quality_max, "%.1f"); + ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); + m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f"); if (ImGui::IsItemHovered()) m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width); @@ -570,8 +573,8 @@ RENDER_AGAIN: if (current_mode >= closing_d_mode) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("closing_distance")); - ImGui::SameLine(settings_sliders_left); - m_imgui->slider_float(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); + ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); + m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); if (ImGui::IsItemHovered()) m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width); @@ -614,11 +617,11 @@ RENDER_AGAIN: m_new_hole_radius = diameter_upper_cap / 2.f; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("hole_diameter")); - ImGui::SameLine(diameter_slider_left); + ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x); ImGui::PushItemWidth(window_width - diameter_slider_left); float diam = 2.f * m_new_hole_radius; - m_imgui->slider_float("", &diam, 1.f, 15.f, "%.1f mm", 1.f, false); + m_imgui->slider_float("##hole_diameter", &diam, 1.f, 15.f, "%.1f mm", 1.f, false); // Let's clamp the value (which could have been entered by keyboard) to a larger range // than the slider. This allows entering off-scale values and still protects against //complete non-sense. @@ -630,8 +633,8 @@ RENDER_AGAIN: ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["hole_depth"]); - ImGui::SameLine(diameter_slider_left); - m_imgui->slider_float(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false); + ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x); + m_imgui->slider_float("##hole_depth", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false); // Same as above: m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f); @@ -697,10 +700,10 @@ RENDER_AGAIN: } } - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); + ImGui::PushItemWidth(window_width - settings_sliders_left); float clp_dist = m_c->object_clipper()->get_position(); - if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); // make sure supports are shown/hidden as appropriate @@ -732,7 +735,7 @@ RENDER_AGAIN: if (force_refresh) m_parent.set_as_dirty(); - + if (config_changed) m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index b7a6d89fa3..ccc67b6305 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -673,7 +673,7 @@ RENDER_AGAIN: // - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene // - take correct undo/redo snapshot after the user is done with moving the slider float initial_value = m_new_point_head_diameter; - m_imgui->slider_float("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); + m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); if (ImGui::IsItemClicked()) { if (m_old_point_head_diameter == 0.f) m_old_point_head_diameter = initial_value; @@ -733,7 +733,7 @@ RENDER_AGAIN: float density = static_cast(opts[0])->value; float minimal_point_distance = static_cast(opts[1])->value; - m_imgui->slider_float("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); + m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm"); bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider @@ -742,7 +742,7 @@ RENDER_AGAIN: m_imgui->text(m_desc.at("points_density")); ImGui::SameLine(settings_sliders_left); - m_imgui->slider_float(" ", &density, 0.f, 200.f, "%.f %%"); + m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%"); slider_clicked |= ImGui::IsItemClicked(); slider_edited |= ImGui::IsItemEdited(); slider_released |= ImGui::IsItemDeactivatedAfterEdit(); @@ -802,7 +802,7 @@ RENDER_AGAIN: ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); float clp_dist = m_c->object_clipper()->get_position(); - if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index fe6c18db9b..22dccc695a 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -280,7 +280,7 @@ void ImGuiWrapper::render() m_new_frame_open = false; } -ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width) +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width) const { auto text_utf8 = into_u8(text); ImVec2 size = ImGui::CalcTextSize(text_utf8.c_str(), NULL, false, wrap_width); @@ -293,6 +293,22 @@ ImVec2 ImGuiWrapper::calc_text_size(const wxString &text, float wrap_width) return size; } +ImVec2 ImGuiWrapper::calc_button_size(const wxString &text, const ImVec2 &button_size) const +{ + const ImVec2 text_size = this->calc_text_size(text); + const ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; + + return ImGui::CalcItemSize(button_size, text_size.x + style.FramePadding.x * 2.0f, text_size.y + style.FramePadding.y * 2.0f); +} + +ImVec2 ImGuiWrapper::get_item_spacing() const +{ + const ImGuiContext &g = *GImGui; + const ImGuiStyle &style = g.Style; + return g.Style.ItemSpacing; +} + float ImGuiWrapper::get_slider_float_height() const { const ImGuiContext& g = *GImGui; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 3712ff6a87..27cd098ff1 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -53,9 +53,11 @@ public: float scaled(float x) const { return x * m_font_size; } ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); } - ImVec2 calc_text_size(const wxString &text, float wrap_width = -1.0f); + ImVec2 calc_text_size(const wxString &text, float wrap_width = -1.0f) const; + ImVec2 calc_button_size(const wxString &text, const ImVec2 &button_size = ImVec2(0, 0)) const; - float get_slider_float_height() const; + ImVec2 get_item_spacing() const; + float get_slider_float_height() const; void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); void set_next_window_bg_alpha(float alpha); From 79dd007ec7c403e5f781ffc9e0d078d2fd535c57 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 19 Oct 2021 16:15:27 +0200 Subject: [PATCH 03/11] Fix bloating of history with live preview --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 38 +++++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 34 ++++++++++++++++++-- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index c43f215d94..d61033ec49 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -294,6 +294,7 @@ void GLGizmoSimplify::live_preview() { // wait until cancel if (m_worker.joinable()) { m_state = State::canceling; + m_dealy_process_cv.notify_one(); m_worker.join(); } } @@ -304,20 +305,38 @@ void GLGizmoSimplify::live_preview() { void GLGizmoSimplify::process() { - class SimplifyCanceledException : public std::exception { - public: - const char* what() const throw() { return L("Model simplification has been canceled"); } - }; + if (m_volume == nullptr) return; + if (m_volume->mesh().its.indices.empty()) return; + size_t count_triangles = m_volume->mesh().its.indices.size(); + if (m_configuration.use_count && + m_configuration.wanted_count >= count_triangles) + return; - if (!m_original_its.has_value()) + // when not store original volume store it for cancelation + if (!m_original_its.has_value()) { m_original_its = m_volume->mesh().its; // copy - auto plater = wxGetApp().plater(); - plater->take_snapshot(_L("Simplify ") + m_volume->name); - plater->clear_before_change_mesh(m_obj_index); + // store previous state + auto plater = wxGetApp().plater(); + plater->take_snapshot(_L("Simplify ") + m_volume->name); + plater->clear_before_change_mesh(m_obj_index); + } + m_progress = 0; if (m_worker.joinable()) m_worker.join(); - m_worker = std::thread([this]() { + + m_worker = std::thread([this]() { + {// delay before process + std::unique_lock lk(m_state_mutex); + auto is_modify = [this]() { return m_state == State::canceling; }; + if (m_dealy_process_cv.wait_for(lk, m_gui_cfg->prcess_delay, is_modify)) { + // exist modification + m_state = State::settings; + request_rerender(); + return; + } + } + // store original triangles uint32_t triangle_count = (m_configuration.use_count) ? m_configuration.wanted_count : 0; float max_error = (!m_configuration.use_count) ? m_configuration.max_error : std::numeric_limits::max(); @@ -357,6 +376,7 @@ void GLGizmoSimplify::process() } void GLGizmoSimplify::set_its(indexed_triangle_set &its) { + if (m_volume == nullptr) return; // could appear after process m_volume->set_mesh(its); m_volume->calculate_convex_hull(); m_volume->set_new_unique_id(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index b609c5cdd0..7935123446 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -7,6 +7,9 @@ #include "GLGizmoPainterBase.hpp" // for render wireframe #include "admesh/stl.h" // indexed_triangle_set #include +#include +#include +#include #include #include @@ -47,6 +50,7 @@ private: void set_its(indexed_triangle_set &its); void create_gui_cfg(); void request_rerender(); + // move to global functions static ModelVolume *get_volume(const Selection &selection, Model &model); static const ModelVolume *get_volume(const GLVolume::CompositeID &cid, const Model &model); @@ -62,10 +66,14 @@ private: size_t m_obj_index; std::optional m_original_its; - bool m_show_wireframe; + bool m_show_wireframe; volatile bool m_need_reload; // after simplify, glReload must be on main thread + std::thread m_worker; + // wait before process + std::mutex m_state_mutex; + std::condition_variable m_dealy_process_cv; enum class State { settings, @@ -87,8 +95,14 @@ private: void fix_count_by_ratio(size_t triangle_count) { - wanted_count = static_cast( - std::round(triangle_count * (100.f-decimate_ratio) / 100.f)); + if (decimate_ratio <= 0.f) { + wanted_count = static_cast(triangle_count); + return; + } else if (decimate_ratio >= 1.f) { + wanted_count = 0; + return; + } + wanted_count = static_cast(std::round(triangle_count * (100.f-decimate_ratio) / 100.f)); } } m_configuration; @@ -106,6 +120,10 @@ private: // trunc model name when longer size_t max_char_in_name = 30; + + // to prevent freezing when move in gui + // delay before process in [ms] + std::chrono::duration prcess_delay = std::chrono::milliseconds(250); }; std::optional m_gui_cfg; @@ -122,6 +140,16 @@ private: void free_gpu(); GLuint m_wireframe_VBO_id, m_wireframe_IBO_id; size_t m_wireframe_IBO_size; + + // cancel exception + class SimplifyCanceledException: public std::exception + { + public: + const char *what() const throw() + { + return L("Model simplification has been canceled"); + } + }; }; } // namespace GUI From ee7d5db31ca5575b974048ddb2a0774c85b1fdee Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 19 Oct 2021 16:51:03 +0200 Subject: [PATCH 04/11] Add live preview on open gizmo Add delay 250ms before process for live move with slider Add short cut for unmodified mesh in processing --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 20 +++++++++++++++++--- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 11 +++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index d61033ec49..1d44aaa25c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -91,7 +91,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_is_valid_result = false; m_exist_preview = false; init_wireframe(); - + live_preview(); if (change_window_position) { ImVec2 pos = ImGui::GetMousePos(); pos.x -= m_gui_cfg->window_offset_x; @@ -308,9 +308,23 @@ void GLGizmoSimplify::process() if (m_volume == nullptr) return; if (m_volume->mesh().its.indices.empty()) return; size_t count_triangles = m_volume->mesh().its.indices.size(); - if (m_configuration.use_count && - m_configuration.wanted_count >= count_triangles) + // Is neccessary simplification + if ((m_configuration.use_count && m_configuration.wanted_count >= count_triangles) || + (!m_configuration.use_count && m_configuration.max_error <= 0.f)) { + + // Exist different original volume? + if (m_original_its.has_value() && + m_original_its->indices.size() != count_triangles) { + indexed_triangle_set its = *m_original_its; // copy + set_its(its); + } + m_is_valid_result = true; + + // re-render bargraph + set_dirty(); + m_parent.schedule_extra_frame(0); return; + } // when not store original volume store it for cancelation if (!m_original_its.has_value()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 7935123446..21d0933efe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -95,14 +95,13 @@ private: void fix_count_by_ratio(size_t triangle_count) { - if (decimate_ratio <= 0.f) { + if (decimate_ratio <= 0.f) wanted_count = static_cast(triangle_count); - return; - } else if (decimate_ratio >= 1.f) { + else if (decimate_ratio >= 100.f) wanted_count = 0; - return; - } - wanted_count = static_cast(std::round(triangle_count * (100.f-decimate_ratio) / 100.f)); + else + wanted_count = static_cast(std::round( + triangle_count * (100.f - decimate_ratio) / 100.f)); } } m_configuration; From 76c0c76f5feda10528f06063b9c99a6685a858c0 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 19 Oct 2021 18:53:42 +0200 Subject: [PATCH 05/11] open simplification on center when open from notification --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 70 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 13 ++++- src/slic3r/GUI/Plater.cpp | 54 ++--------------- 3 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 1d44aaa25c..f823afb6ff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -24,6 +24,7 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, , m_obj_index(0) , m_need_reload(false) , m_show_wireframe(false) + , m_move_to_center(false) // translation for GUI size , tr_mesh_name(_u8L("Mesh name")) , tr_triangles(_u8L("Triangles")) @@ -50,6 +51,61 @@ bool GLGizmoSimplify::on_esc_key_down() { return true; } +// while opening needs GLGizmoSimplify to set window position +void GLGizmoSimplify::add_simplify_suggestion_notification( + const std::vector &object_ids, + const ModelObjectPtrs & objects, + NotificationManager & manager) +{ + std::vector big_ids; + big_ids.reserve(object_ids.size()); + auto is_big_object = [&objects](size_t object_id) { + const uint32_t triangles_to_suggest_simplify = 1000000; + if (object_id >= objects.size()) return false; // out of object index + ModelVolumePtrs &volumes = objects[object_id]->volumes; + if (volumes.size() != 1) return false; // not only one volume + size_t triangle_count = volumes.front()->mesh().its.indices.size(); + if (triangle_count < triangles_to_suggest_simplify) + return false; // small volume + return true; + }; + std::copy_if(object_ids.begin(), object_ids.end(), + std::back_inserter(big_ids), is_big_object); + if (big_ids.empty()) return; + + for (size_t object_id : big_ids) { + std::string t = _u8L( + "Processing model '@object_name' with more than 1M triangles " + "could be slow. It is highly recommend to reduce " + "amount of triangles."); + t.replace(t.find("@object_name"), sizeof("@object_name") - 1, + objects[object_id]->name); + // std::stringstream text; + // text << t << "\n"; + std::string hypertext = _u8L("Simplify model"); + + std::function open_simplify = + [object_id](wxEvtHandler *) { + auto plater = wxGetApp().plater(); + if (object_id >= plater->model().objects.size()) return true; + + Selection &selection = plater->canvas3D()->get_selection(); + selection.clear(); + selection.add_object((unsigned int) object_id); + + auto &manager = plater->canvas3D()->get_gizmos_manager(); + bool close_notification = true; + if(!manager.open_gizmo(GLGizmosManager::Simplify)) + return close_notification; + GLGizmoSimplify* simplify = dynamic_cast(manager.get_current()); + if (simplify == nullptr) return close_notification; + simplify->set_center_position(); + }; + manager.push_simplify_suggestion_notification( + t, objects[object_id]->id(), hypertext, open_simplify); + } +} + std::string GLGizmoSimplify::on_get_name() const { return _u8L("Simplify"); @@ -92,7 +148,15 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_exist_preview = false; init_wireframe(); live_preview(); - if (change_window_position) { + + // set window position + if (m_move_to_center && change_window_position) { + m_move_to_center = false; + auto parent_size = m_parent.get_canvas_size(); + ImVec2 pos(parent_size.get_width() / 2 - m_gui_cfg->window_offset_x, + parent_size.get_height() / 2 - m_gui_cfg->window_offset_y); + ImGui::SetNextWindowPos(pos, ImGuiCond_Always); + }else if (change_window_position) { ImVec2 pos = ImGui::GetMousePos(); pos.x -= m_gui_cfg->window_offset_x; pos.y -= m_gui_cfg->window_offset_y; @@ -474,6 +538,10 @@ void GLGizmoSimplify::request_rerender() { }); } +void GLGizmoSimplify::set_center_position() { + m_move_to_center = true; +} + bool GLGizmoSimplify::exist_volume(ModelVolume *volume) { auto objs = wxGetApp().plater()->model().objects; for (const auto &obj : objs) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index 21d0933efe..b978e9356d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -15,12 +15,14 @@ #include // GLUint -namespace Slic3r { +// for simplify suggestion +class ModelObjectPtrs; // std::vector +namespace Slic3r { class ModelVolume; namespace GUI { - +class NotificationManager; // for simplify suggestion class GLGizmoSimplify: public GLGizmoBase, public GLGizmoTransparentRender // GLGizmoBase { @@ -28,6 +30,10 @@ public: GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); virtual ~GLGizmoSimplify(); bool on_esc_key_down(); + static void add_simplify_suggestion_notification( + const std::vector &object_ids, + const ModelObjectPtrs & objects, + NotificationManager & manager); protected: virtual std::string on_get_name() const override; virtual void on_render_input_window(float x, float y, float bottom_limit) override; @@ -51,6 +57,7 @@ private: void create_gui_cfg(); void request_rerender(); + void set_center_position(); // move to global functions static ModelVolume *get_volume(const Selection &selection, Model &model); static const ModelVolume *get_volume(const GLVolume::CompositeID &cid, const Model &model); @@ -61,6 +68,8 @@ private: std::atomic_bool m_is_valid_result; // differ what to do in apply std::atomic_bool m_exist_preview; // set when process end + bool m_move_to_center; // opening gizmo + volatile int m_progress; // percent of done work ModelVolume *m_volume; // keep pointer to actual working volume size_t m_obj_index; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 97e4af218c..9a24d91cc8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -89,6 +89,7 @@ #include "PresetComboBoxes.hpp" #include "MsgDialog.hpp" #include "ProjectDirtyStateManager.hpp" +#include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification #ifdef __APPLE__ #include "Gizmos/GLGizmosManager.hpp" @@ -1779,7 +1780,6 @@ struct Plater::priv #endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE void replace_with_stl(); void reload_all_from_disk(); - void create_simplify_notification(const std::vector& obj_ids); void set_current_panel(wxPanel* panel); void on_select_preset(wxCommandEvent&); @@ -2564,8 +2564,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ // this is required because the selected object changed and the flatten on face an sla support gizmos need to be updated accordingly view3D->get_canvas3d()->update_gizmos_on_off_state(); } - - create_simplify_notification(obj_idxs); + + GLGizmoSimplify::add_simplify_suggestion_notification( + obj_idxs, model.objects, *notification_manager); return obj_idxs; } @@ -3755,53 +3756,6 @@ void Plater::priv::reload_all_from_disk() } } -void Plater::priv::create_simplify_notification(const std::vector& obj_ids) { - const uint32_t triangles_to_suggest_simplify = 1000000; - - std::vector big_ids; - big_ids.reserve(obj_ids.size()); - std::copy_if(obj_ids.begin(), obj_ids.end(), std::back_inserter(big_ids), - [this, triangles_to_suggest_simplify](size_t object_id) { - if (object_id >= model.objects.size()) return false; // out of object index - ModelVolumePtrs& volumes = model.objects[object_id]->volumes; - if (volumes.size() != 1) return false; // not only one volume - size_t triangle_count = volumes.front()->mesh().its.indices.size(); - if (triangle_count < triangles_to_suggest_simplify) return false; // small volume - return true; - }); - - if (big_ids.empty()) return; - - for (size_t object_id : big_ids) { - std::string t = _u8L( - "Processing model '@object_name' with more than 1M triangles " - "could be slow. It is highly recommend to reduce " - "amount of triangles."); - t.replace(t.find("@object_name"), sizeof("@object_name") - 1, - model.objects[object_id]->name); - //std::stringstream text; - //text << t << "\n"; - std::string hypertext = _u8L("Simplify model"); - - std::function open_simplify = [object_id](wxEvtHandler *) { - auto plater = wxGetApp().plater(); - if (object_id >= plater->model().objects.size()) return true; - - Selection &selection = plater->canvas3D()->get_selection(); - selection.clear(); - selection.add_object((unsigned int) object_id); - - auto &manager = plater->canvas3D()->get_gizmos_manager(); - manager.open_gizmo(GLGizmosManager::EType::Simplify); - return true; - }; - notification_manager->push_simplify_suggestion_notification(t, - model.objects[object_id]->id(), - hypertext, - open_simplify); - } -} - void Plater::priv::set_current_panel(wxPanel* panel) { if (std::find(panels.begin(), panels.end(), panel) == panels.end()) From 51056adee8df6aae09912b9da42126c437cff3b1 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Fri, 13 Aug 2021 11:04:02 -0700 Subject: [PATCH 06/11] build_win: Don't delete preferences on clean build --- build_win.bat | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build_win.bat b/build_win.bat index 600d6d6e6f..e00f8dbd4d 100644 --- a/build_win.bat +++ b/build_win.bat @@ -159,7 +159,7 @@ REM Build deps :BUILD_DEPS SET EXIT_STATUS=3 SET PS_CURRENT_STEP=deps -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" .vs cd deps\build || GOTO :END cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" @@ -171,7 +171,7 @@ REM Build app :BUILD_APP SET EXIT_STATUS=4 SET PS_CURRENT_STEP=app -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" .vs cd build || GOTO :END REM Make sure we have a custom batch file skeleton for the run stage set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE% @@ -262,8 +262,11 @@ REM Functions and stubs start here. :RESOLVE_DESTDIR_CACHE @REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT -@REM Note: This just sets global variableq, so it doesn't use setlocal. -SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME% +@REM Note: This just sets global variables, so it doesn't use setlocal. +SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME% +mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul +REM Copy a legacy file if we don't have one in the proper location. +echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%" CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" ( FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO ( From 70faa27247346a757f410ee550dedd74d13862ac Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Fri, 13 Aug 2021 11:05:32 -0700 Subject: [PATCH 07/11] build_win: Reduce msbuild verbosity --- build_win.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_win.bat b/build_win.bat index e00f8dbd4d..893d8c3448 100644 --- a/build_win.bat +++ b/build_win.bat @@ -163,7 +163,7 @@ IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_ cd deps\build || GOTO :END cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" -msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END cd ..\.. IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP @@ -183,7 +183,7 @@ FOR /F "tokens=2 delims=," %%I in ( ) do SET PS_PROJECT_IS_OPEN=%%~I cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% || GOTO :END REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv -IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%" REM Run app From d4be22df8a42d98d754c129b787573aec7d247cd Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Fri, 13 Aug 2021 11:22:35 -0700 Subject: [PATCH 08/11] build_win: Retry on cmake cache failure --- build_win.bat | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build_win.bat b/build_win.bat index 893d8c3448..34fea8d617 100644 --- a/build_win.bat +++ b/build_win.bat @@ -161,7 +161,10 @@ SET EXIT_STATUS=3 SET PS_CURRENT_STEP=deps IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" .vs cd deps\build || GOTO :END -cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END +cmake.exe .. -DDESTDIR="%PS_DESTDIR%" +IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" ( + (del CMakeCache.txt && cmake.exe .. -DDESTDIR="%PS_DESTDIR%") || GOTO :END +) ELSE GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END cd ..\.. @@ -181,7 +184,10 @@ SET PS_PROJECT_IS_OPEN= FOR /F "tokens=2 delims=," %%I in ( 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"' ) do SET PS_PROJECT_IS_OPEN=%%~I -cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% || GOTO :END +cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% +IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" ( + (del CMakeCache.txt && cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%) || GOTO :END +) ELSE GOTO :END REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%" From 26cfc9ebb35894b69a664982e51c1daf07425044 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Wed, 1 Sep 2021 14:55:44 -0700 Subject: [PATCH 09/11] build_win: Don't report an error on help switch --- build_win.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/build_win.bat b/build_win.bat index 34fea8d617..c03ebf0399 100644 --- a/build_win.bat +++ b/build_win.bat @@ -65,6 +65,7 @@ SET PS_DESTDIR= CALL :RESOLVE_DESTDIR_CACHE REM Set up parameters used by help menu +SET EXIT_STATUS=0 SET PS_CONFIG_DEFAULT=%PS_CONFIG% SET PS_ARCH_HOST=%PS_ARCH% (echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP From 2f5f35bbefdf958a0cb7576b084027a6010d5af3 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Fri, 13 Aug 2021 13:46:28 -0700 Subject: [PATCH 10/11] Update Windows build docs for build_win.bat --- doc/How to build - Windows.md | 38 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md index 42d559c5a7..d0da05d7b5 100644 --- a/doc/How to build - Windows.md +++ b/doc/How to build - Windows.md @@ -3,7 +3,7 @@ ### Install the tools Install Visual Studio Community 2019 from [visualstudio.microsoft.com/vs/](https://visualstudio.microsoft.com/vs/). Older versions are not supported as PrusaSlicer requires support for C++17. -Select all workload options for C++ +Select all workload options for C++ and make sure to launch Visual Studio after install (to ensure that the full setup completes). Install git for Windows from [gitforwindows.org](https://gitforwindows.org/) Download and run the exe accepting all defaults @@ -17,6 +17,42 @@ c:> cd src c:\src> git clone https://github.com/prusa3d/PrusaSlicer.git ``` +### Run the automatic build script + +The script `build_win.bat` will automatically find the default Visual Studio installation, set up the build environment, and then run both CMake and MSBuild to generate the dependencies and application as needed. If you'd rather do these steps manually, you can skip to the [Manual Build Instructions](#manual-build-instructions) in the next section. Otherwise, just run the following command to get everything going with the default configs: + +``` +c:\src>cd c:\src\PrusaSlicer +c:\src\PrusaSlicer>build_win.bat -d=..\PrusaSlicer-deps -r=console +``` + +The build script will run for a while (over an hour, depending on your machine) and automatically perform the following steps: +1. Configure and build [deps](#compile-the-dependencies) as RelWithDebInfo with `c:\src\PrusaSlicer-deps` as the destination directory +2. Configure and build all [application targets](#compile-prusaslicer) as RelWithDebInfo +3. Launch the resulting `prusa-slicer-console.exe` binary + +You can change the above command line options to do things like: +* Change the destination for the dependencies by pointing `-d` to a different directory such as: `build_win.bat -d=s:\PrusaSlicerDeps` +* Open the solution in Visual Studio after the build completes by changing the `-r` switch to `-r=ide` +* Generate a release build without debug info by adding `-c=Release` or a full debug build with `-c=Debug` +* Perform an incremental application build (the default) with: `build_win.bat -s=app-dirty` +* Clean and rebuild the application: `build_win.bat -s=app` +* Clean and rebuild the dependencies: `build_win.bat -s=deps` +* Clean and rebuild everything (app and deps): `build_win.bat -s=all` +* _The full list of build script options can be listed by running:_ `build_win.bat -?` + +### Troubleshooting + +You're best off initiating builds from within Visual Studio for day-to-day development. However, the `build_win.bat` script can be very helpful if you run into build failures after updating your source tree. Here are some tips to keep in mind: +* The last several lines of output from `build_win.bat` will usually have the most helpful error messages. +* If CMake complains about missing binaries or paths (e.g. after updating Visual Studio), building with `build_win.bat` will force CMake to regenerate its cache on an error. +* After a deps change, you may just need to rebuild everything with the `-s=all` switch. +* Reading through the instructions in the next section may help diagnose more complex issues. + +# Manual Build Instructions + +_Follow the steps below if you want to understand how to perform a manual build, or if you're troubleshooting issues with the automatic build script._ + ### Compile the dependencies. Dependencies are updated seldomly, thus they are compiled out of the PrusaSlicer source tree. Go to the Windows Start Menu and Click on "Visual Studio 2019" folder, then select the ->"x64 Native Tools Command Prompt" to open a command window and run the following: From fa7b2f351f1293940e37f1e5659d709c6dbc0d01 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 20 Oct 2021 11:19:15 +0200 Subject: [PATCH 11/11] Fix for: ../src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:102:46: error: control reaches end of non-void function [-Werror=return-type] src\slic3r\GUI\Gizmos\GLGizmoSimplify.cpp(103) : warning C4715: '::operator()': not all control paths return a value --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index f823afb6ff..2c094bf784 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -100,6 +100,7 @@ void GLGizmoSimplify::add_simplify_suggestion_notification( GLGizmoSimplify* simplify = dynamic_cast(manager.get_current()); if (simplify == nullptr) return close_notification; simplify->set_center_position(); + return close_notification; }; manager.push_simplify_suggestion_notification( t, objects[object_id]->id(), hypertext, open_simplify);