diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index fa0b94200e..23ab4ef13e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -18,17 +18,17 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent, const std::string &icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, -1) - , state(State::settings) - , is_valid_result(false) - , progress(0) - , volume(nullptr) - , obj_index(0) - , need_reload(false) + , m_state(State::settings) + , m_is_valid_result(false) + , m_progress(0) + , m_volume(nullptr) + , m_obj_index(0) + , m_need_reload(false) {} GLGizmoSimplify::~GLGizmoSimplify() { - state = State::canceling; - if (worker.joinable()) worker.join(); + m_state = State::canceling; + if (m_worker.joinable()) m_worker.join(); } bool GLGizmoSimplify::on_init() @@ -60,34 +60,34 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi // Check selection of new volume // Do not reselect object when processing - if (act_volume != volume && state == State::settings) { - bool change_window_position = (volume == nullptr); + if (act_volume != m_volume && m_state == State::settings) { + bool change_window_position = (m_volume == nullptr); // select different model - if (volume != nullptr && original_its.has_value()) { - set_its(*original_its); + if (m_volume != nullptr && m_original_its.has_value()) { + set_its(*m_original_its); } - obj_index = object_idx; // to remember correct object - volume = act_volume; - original_its = {}; - const TriangleMesh &tm = volume->mesh(); - c.wanted_percent = 50.; // default value - c.update_percent(tm.its.indices.size()); - is_valid_result = false; + m_obj_index = object_idx; // to remember correct object + m_volume = act_volume; + m_original_its = {}; + const TriangleMesh &tm = m_volume->mesh(); + m_configuration.wanted_percent = 50.; // default value + m_configuration.update_percent(tm.its.indices.size()); + m_is_valid_result = false; if (change_window_position) { ImVec2 pos = ImGui::GetMousePos(); - pos.x -= gui_cfg->window_offset; - pos.y -= gui_cfg->window_offset; + pos.x -= m_gui_cfg->window_offset; + pos.y -= m_gui_cfg->window_offset; // minimal top left value - ImVec2 tl(gui_cfg->window_padding, gui_cfg->window_padding); + ImVec2 tl(m_gui_cfg->window_padding, m_gui_cfg->window_padding); if (pos.x < tl.x) pos.x = tl.x; if (pos.y < tl.y) pos.y = tl.y; // maximal bottom right value auto parent_size = m_parent.get_canvas_size(); ImVec2 br( - parent_size.get_width() - (2 * gui_cfg->window_offset + gui_cfg->window_padding), - parent_size.get_height() - (2 * gui_cfg->window_offset + gui_cfg->window_padding)); + parent_size.get_width() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding), + parent_size.get_height() - (2 * m_gui_cfg->window_offset + m_gui_cfg->window_padding)); if (pos.x > br.x) pos.x = br.x; if (pos.y > br.y) pos.y = br.y; ImGui::SetNextWindowPos(pos, ImGuiCond_Always); @@ -98,98 +98,100 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_NoCollapse; m_imgui->begin(on_get_name(), flag); - size_t triangle_count = volume->mesh().its.indices.size(); + size_t triangle_count = m_volume->mesh().its.indices.size(); // already reduced mesh - if (original_its.has_value()) - triangle_count = original_its->indices.size(); + if (m_original_its.has_value()) + triangle_count = m_original_its->indices.size(); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Mesh name") + ":"); - ImGui::SameLine(gui_cfg->top_left_width); - std::string name = volume->name; + ImGui::SameLine(m_gui_cfg->top_left_width); + std::string name = m_volume->name; if (name.length() > max_char_in_name) name = name.substr(0, max_char_in_name-3) + "..."; m_imgui->text(name); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Triangles") + ":"); - ImGui::SameLine(gui_cfg->top_left_width); + ImGui::SameLine(m_gui_cfg->top_left_width); m_imgui->text(std::to_string(triangle_count)); ImGui::Separator(); ImGui::Text(_L("Limit by triangles").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); // First initialization + fix triangle count - if (m_imgui->checkbox("##UseCount", c.use_count)) { - if (!c.use_count) c.use_error = true; - is_valid_result = false; + if (m_imgui->checkbox("##UseCount", m_configuration.use_count)) { + if (!m_configuration.use_count) m_configuration.use_error = true; + m_is_valid_result = false; } - m_imgui->disabled_begin(!c.use_count); + m_imgui->disabled_begin(!m_configuration.use_count); ImGui::Text(_L("Triangle count").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - int wanted_count = c.wanted_count; - ImGui::SetNextItemWidth(gui_cfg->input_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); + int wanted_count = m_configuration.wanted_count; + ImGui::SetNextItemWidth(m_gui_cfg->input_width); if (ImGui::SliderInt("##triangle_count", &wanted_count, min_triangle_count, triangle_count, "%d")) { - c.wanted_count = static_cast(wanted_count); - if (c.wanted_count < min_triangle_count) - c.wanted_count = min_triangle_count; - if (c.wanted_count > triangle_count) - c.wanted_count = triangle_count; - c.update_count(triangle_count); - is_valid_result = false; + m_configuration.wanted_count = static_cast(wanted_count); + if (m_configuration.wanted_count < min_triangle_count) + m_configuration.wanted_count = min_triangle_count; + if (m_configuration.wanted_count > triangle_count) + m_configuration.wanted_count = triangle_count; + m_configuration.update_count(triangle_count); + m_is_valid_result = false; } ImGui::Text(_L("Ratio").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - ImGui::SetNextItemWidth(gui_cfg->input_small_width); - const char * precision = (c.wanted_percent > 10)? "%.0f": ((c.wanted_percent > 1)? "%.1f":"%.2f"); - float step = (c.wanted_percent > 10)? 1.f: ((c.wanted_percent > 1)? 0.1f : 0.01f); - if (ImGui::InputFloat("%", &c.wanted_percent, step, 10*step, precision)) { - if (c.wanted_percent > 100.f) c.wanted_percent = 100.f; - c.update_percent(triangle_count); - if (c.wanted_count < min_triangle_count) { - c.wanted_count = min_triangle_count; - c.update_count(triangle_count); + ImGui::SameLine(m_gui_cfg->bottom_left_width); + ImGui::SetNextItemWidth(m_gui_cfg->input_small_width); + const char * precision = (m_configuration.wanted_percent > 10)? "%.0f": + ((m_configuration.wanted_percent > 1)? "%.1f":"%.2f"); + float step = (m_configuration.wanted_percent > 10)? 1.f: + ((m_configuration.wanted_percent > 1)? 0.1f : 0.01f); + if (ImGui::InputFloat("%", &m_configuration.wanted_percent, step, 10*step, precision)) { + if (m_configuration.wanted_percent > 100.f) m_configuration.wanted_percent = 100.f; + m_configuration.update_percent(triangle_count); + if (m_configuration.wanted_count < min_triangle_count) { + m_configuration.wanted_count = min_triangle_count; + m_configuration.update_count(triangle_count); } - is_valid_result = false; + m_is_valid_result = false; } m_imgui->disabled_end(); // use_count ImGui::NewLine(); ImGui::Text(_L("Limit by error").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - if (m_imgui->checkbox("##UseError", c.use_error)) { - if (!c.use_error) c.use_count = true; - is_valid_result = false; + ImGui::SameLine(m_gui_cfg->bottom_left_width); + if (m_imgui->checkbox("##UseError", m_configuration.use_error)) { + if (!m_configuration.use_error) m_configuration.use_count = true; + m_is_valid_result = false; } - m_imgui->disabled_begin(!c.use_error); + m_imgui->disabled_begin(!m_configuration.use_error); ImGui::Text(_L("Max. error").c_str()); - ImGui::SameLine(gui_cfg->bottom_left_width); - ImGui::SetNextItemWidth(gui_cfg->input_small_width); - if (ImGui::InputFloat("##maxError", &c.max_error, 0.01f, .1f, "%.2f")) { - if (c.max_error < 0.f) c.max_error = 0.f; - is_valid_result = false; + ImGui::SameLine(m_gui_cfg->bottom_left_width); + ImGui::SetNextItemWidth(m_gui_cfg->input_small_width); + if (ImGui::InputFloat("##maxError", &m_configuration.max_error, 0.01f, .1f, "%.2f")) { + if (m_configuration.max_error < 0.f) m_configuration.max_error = 0.f; + m_is_valid_result = false; } m_imgui->disabled_end(); // use_error - if (state == State::settings) { + if (m_state == State::settings) { if (m_imgui->button(_L("Cancel"))) { - if (original_its.has_value()) { - set_its(*original_its); - state = State::close_on_end; + if (m_original_its.has_value()) { + set_its(*m_original_its); + m_state = State::close_on_end; } else { close(); } } - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); if (m_imgui->button(_L("Preview"))) { - state = State::simplifying; + m_state = State::simplifying; // simplify but not aply on mesh process(); } ImGui::SameLine(); if (m_imgui->button(_L("Apply"))) { - if (!is_valid_result) { - state = State::close_on_end; + if (!m_is_valid_result) { + m_state = State::close_on_end; process(); } else { // use preview and close @@ -197,35 +199,35 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi } } } else { - m_imgui->disabled_begin(state == State::canceling); - if (m_imgui->button(_L("Cancel"))) state = State::canceling; + m_imgui->disabled_begin(m_state == State::canceling); + if (m_imgui->button(_L("Cancel"))) m_state = State::canceling; m_imgui->disabled_end(); - ImGui::SameLine(gui_cfg->bottom_left_width); + ImGui::SameLine(m_gui_cfg->bottom_left_width); // draw progress bar char buf[32]; - sprintf(buf, L("Process %d / 100"), progress); - ImGui::ProgressBar(progress / 100., ImVec2(gui_cfg->input_width, 0.f), buf); + sprintf(buf, L("Process %d / 100"), m_progress); + ImGui::ProgressBar(m_progress / 100., ImVec2(m_gui_cfg->input_width, 0.f), buf); } m_imgui->end(); - if (need_reload) { - need_reload = false; + if (m_need_reload) { + m_need_reload = false; // Reload visualization of mesh - change VBO, FBO on GPU m_parent.reload_scene(true); - if (state == State::close_on_end) { + if (m_state == State::close_on_end) { // fix hollowing, sla support points, modifiers, ... auto plater = wxGetApp().plater(); - plater->changed_mesh(obj_index); + plater->changed_mesh(m_obj_index); close(); } // change from simplifying | apply - state = State::settings; + m_state = State::settings; // Fix warning icon in object list - wxGetApp().obj_list()->update_item_error_icon(obj_index, -1); + wxGetApp().obj_list()->update_item_error_icon(m_obj_index, -1); } } @@ -243,51 +245,53 @@ void GLGizmoSimplify::process() const char* what() const throw() { return L("Model simplification has been canceled"); } }; - if (!original_its.has_value()) - original_its = volume->mesh().its; // copy + if (!m_original_its.has_value()) + m_original_its = m_volume->mesh().its; // copy auto plater = wxGetApp().plater(); - plater->take_snapshot(_L("Simplify ") + volume->name); - plater->clear_before_change_mesh(obj_index); - progress = 0; - if (worker.joinable()) worker.join(); - worker = std::thread([&]() { + 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([&]() { // store original triangles - uint32_t triangle_count = (c.use_count) ? c.wanted_count : 0; - float max_error = (c.use_error) ? c.max_error : std::numeric_limits::max(); + uint32_t triangle_count = (m_configuration.use_count) ? m_configuration.wanted_count : 0; + float max_error = (m_configuration.use_error) ? + m_configuration.max_error : std::numeric_limits::max(); std::function throw_on_cancel = [&]() { - if (state == State::canceling) { + if (m_state == State::canceling) { throw SimplifyCanceledException(); } }; std::function statusfn = [&](int percent) { - progress = percent; + m_progress = percent; m_parent.schedule_extra_frame(0); }; indexed_triangle_set collapsed; - if (last_error.has_value()) { + if (m_last_error.has_value()) { // is chance to continue with last reduction - const indexed_triangle_set &its = volume->mesh().its; + const indexed_triangle_set &its = m_volume->mesh().its; uint32_t last_triangle_count = static_cast(its.indices.size()); - if ((!c.use_count || triangle_count <= last_triangle_count) && - (!c.use_error || c.max_error <= *last_error)) { + if ((!m_configuration.use_count || triangle_count <= last_triangle_count) && + (!m_configuration.use_error || m_configuration.max_error <= *m_last_error)) { collapsed = its; // small copy } else { - collapsed = *original_its; // copy + collapsed = *m_original_its; // copy } } else { - collapsed = *original_its; // copy + collapsed = *m_original_its; // copy } try { its_quadric_edge_collapse(collapsed, triangle_count, &max_error, throw_on_cancel, statusfn); set_its(collapsed); - is_valid_result = true; - last_error = max_error; + m_is_valid_result = true; + m_last_error = max_error; } catch (SimplifyCanceledException &) { - state = State::settings; + // set state out of main thread + m_state = State::settings; } // need to render last status fn // without sleep it freezes until mouse move @@ -299,10 +303,10 @@ void GLGizmoSimplify::process() void GLGizmoSimplify::set_its(indexed_triangle_set &its) { auto tm = std::make_unique(its); tm->repair(); - volume->set_mesh(std::move(tm)); - volume->set_new_unique_id(); - volume->get_object()->invalidate_bounding_box(); - need_reload = true; + m_volume->set_mesh(std::move(tm)); + m_volume->set_new_unique_id(); + m_volume->get_object()->invalidate_bounding_box(); + m_need_reload = true; } bool GLGizmoSimplify::on_is_activable() const @@ -313,13 +317,13 @@ bool GLGizmoSimplify::on_is_activable() const void GLGizmoSimplify::on_set_state() { // Closing gizmo. e.g. selecting another one - if (m_state == GLGizmoBase::Off) { - volume = nullptr; + if (GLGizmoBase::m_state == GLGizmoBase::Off) { + m_volume = nullptr; } } void GLGizmoSimplify::create_gui_cfg() { - if (gui_cfg.has_value()) return; + if (m_gui_cfg.has_value()) return; int space_size = m_imgui->calc_text_size(":MM").x; GuiCfg cfg; @@ -337,7 +341,7 @@ void GLGizmoSimplify::create_gui_cfg() { cfg.input_width = cfg.bottom_left_width; cfg.input_small_width = cfg.input_width * 0.8; cfg.window_offset = cfg.input_width; - gui_cfg = cfg; + m_gui_cfg = cfg; } } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index cefd1abf05..57174b7c12 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -10,26 +10,7 @@ namespace Slic3r { namespace GUI { class GLGizmoSimplify : public GLGizmoBase -{ - enum class State { - settings, - simplifying, // start processing - canceling, // canceled - successfull, // successful simplified - close_on_end - } state; - - bool is_valid_result; // differ what to do in apply - int progress; - - ModelVolume *volume; - size_t obj_index; - std::optional original_its; - - std::optional last_error; // for use previous reduction - - bool need_reload; // after simplify, glReload must be on main thread - std::thread worker; +{ public: GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); virtual ~GLGizmoSimplify(); @@ -47,6 +28,28 @@ private: void close(); void process(); void set_its(indexed_triangle_set &its); + void create_gui_cfg(); + + bool m_is_valid_result; // differ what to do in apply + volatile int m_progress; // percent of done work + ModelVolume *m_volume; // + size_t m_obj_index; + + std::optional m_original_its; + std::optional m_last_error; // for use previous reduction + + volatile bool m_need_reload; // after simplify, glReload must be on main thread + std::thread m_worker; + + enum class State { + settings, + simplifying, // start processing + canceling, // canceled + successfull, // successful simplified + close_on_end + }; + volatile State m_state; + struct Configuration { bool use_count = true; @@ -67,7 +70,7 @@ private: wanted_count = static_cast( std::round(triangle_count * wanted_percent / 100.f)); } - } c; + } m_configuration; // This configs holds GUI layout size given by translated texts. // etc. When language changes, GUI is recreated and this class constructed again, @@ -81,8 +84,7 @@ private: int window_offset = 100; int window_padding = 0; }; - std::optional gui_cfg; - void create_gui_cfg(); + std::optional m_gui_cfg; }; } // namespace GUI