From 88cc93cdc94ffd95c76d14ddfae2e0b11eb1f320 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 1 Apr 2019 14:12:05 +0200 Subject: [PATCH 01/17] imgui: Refactor font size, font initialization --- src/slic3r/GUI/GLCanvas3D.cpp | 8 +++-- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/ImGuiWrapper.cpp | 59 ++++++++++++++++++--------------- src/slic3r/GUI/ImGuiWrapper.hpp | 19 ++++++----- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4178dcb43..31c3717ff 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4403,11 +4403,13 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) if ((m_canvas == nullptr) && (m_context == nullptr)) return; - wxGetApp().imgui()->set_display_size((float)w, (float)h); + auto *imgui = wxGetApp().imgui(); + imgui->set_display_size((float)w, (float)h); + imgui->set_font_size(m_canvas->GetFont().GetPixelSize().y); #if ENABLE_RETINA_GL - wxGetApp().imgui()->set_style_scaling(m_retina_helper->get_scale_factor()); + imgui->set_style_scaling(m_retina_helper->get_scale_factor()); #else - wxGetApp().imgui()->set_style_scaling(m_canvas->GetContentScaleFactor()); + imgui->set_style_scaling(m_canvas->GetContentScaleFactor()); #endif // ensures that this canvas is current diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fdb8968d3..f1a7d9263 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -81,7 +81,7 @@ IMPLEMENT_APP(GUI_App) GUI_App::GUI_App() : wxApp() , m_em_unit(10) - , m_imgui(nullptr) + , m_imgui(new ImGuiWrapper()) {} bool GUI_App::OnInit() @@ -138,7 +138,6 @@ bool GUI_App::OnInit() // initialize label colors and fonts init_label_colours(); init_fonts(); - m_imgui.reset(new ImGuiWrapper(m_normal_font.GetPixelSize().y)); load_language(); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f626fa7f5..001e0b33f 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -25,9 +25,9 @@ namespace Slic3r { namespace GUI { -ImGuiWrapper::ImGuiWrapper(float font_size) +ImGuiWrapper::ImGuiWrapper() : m_glyph_ranges(nullptr) - , m_font_size(font_size) + , m_font_size(18.0) , m_font_texture(0) , m_style_scaling(1.0) , m_mouse_buttons(0) @@ -36,7 +36,6 @@ ImGuiWrapper::ImGuiWrapper(float font_size) { ImGui::CreateContext(); - init_default_font(); init_input(); init_style(); @@ -45,7 +44,7 @@ ImGuiWrapper::ImGuiWrapper(float font_size) ImGuiWrapper::~ImGuiWrapper() { - destroy_device_objects(); + destroy_font(); ImGui::DestroyContext(); } @@ -82,7 +81,7 @@ void ImGuiWrapper::set_language(const std::string &language) if (ranges != m_glyph_ranges) { m_glyph_ranges = ranges; - init_default_font(); + destroy_font(); } } @@ -93,12 +92,20 @@ void ImGuiWrapper::set_display_size(float w, float h) io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); } +void ImGuiWrapper::set_font_size(float font_size) +{ + if (m_font_size != font_size) { + m_font_size = font_size; + destroy_font(); + } +} + void ImGuiWrapper::set_style_scaling(float scaling) { if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) { ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); m_style_scaling = scaling; - init_default_font(); + destroy_font(); } } @@ -156,12 +163,15 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) void ImGuiWrapper::new_frame() { + printf("ImGuiWrapper: new_frame()\n"); + if (m_new_frame_open) { return; } - if (m_font_texture == 0) - create_device_objects(); + if (m_font_texture == 0) { + init_font(); + } ImGui::NewFrame(); m_new_frame_open = true; @@ -254,7 +264,8 @@ void ImGuiWrapper::text(const std::string &label) void ImGuiWrapper::text(const wxString &label) { - this->text(into_u8(label).c_str()); + auto label_utf8 = into_u8(label); + this->text(label_utf8.c_str()); } bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection) @@ -282,6 +293,12 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector& return res; } +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) +{ + auto text_utf8 = into_u8(text); + return ImGui::CalcTextSize(text_utf8.c_str()); +} + void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -323,11 +340,13 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } -void ImGuiWrapper::init_default_font() +void ImGuiWrapper::init_font() { + printf("ImGuiWrapper: init_font()\n"); + const float font_size = m_font_size * m_style_scaling; - destroy_fonts_texture(); + destroy_font(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); @@ -338,17 +357,8 @@ void ImGuiWrapper::init_default_font() throw std::runtime_error("ImGui: Could not load deafult font"); } } -} -void ImGuiWrapper::create_device_objects() -{ - create_fonts_texture(); -} - -void ImGuiWrapper::create_fonts_texture() -{ // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. @@ -554,14 +564,9 @@ bool ImGuiWrapper::display_initialized() const return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f; } -void ImGuiWrapper::destroy_device_objects() +void ImGuiWrapper::destroy_font() { - destroy_fonts_texture(); -} - -void ImGuiWrapper::destroy_fonts_texture() -{ - if (m_font_texture) { + if (m_font_texture != 0) { ImGuiIO& io = ImGui::GetIO(); io.Fonts->TexID = 0; glDeleteTextures(1, &m_font_texture); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 7e022532a..476379da2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -18,9 +18,6 @@ namespace GUI { class ImGuiWrapper { - typedef std::map FontsMap; - - FontsMap m_fonts; const ImWchar *m_glyph_ranges; float m_font_size; unsigned m_font_texture; @@ -31,22 +28,27 @@ class ImGuiWrapper std::string m_clipboard_text; public: - ImGuiWrapper(float font_size); + ImGuiWrapper(); ~ImGuiWrapper(); void read_glsl_version(); void set_language(const std::string &language); void set_display_size(float w, float h); + void set_font_size(float font_size); void set_style_scaling(float scaling); bool update_mouse_data(wxMouseEvent &evt); bool update_key_data(wxKeyEvent &evt); + float get_font_size() const { return m_font_size; } float get_style_scaling() const { return m_style_scaling; } void new_frame(); void render(); + float scaled(float x) const { return x * m_font_size * m_style_scaling; } + ImVec2 scaled_vec(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + void set_next_window_pos(float x, float y, int flag); void set_next_window_bg_alpha(float alpha); @@ -64,6 +66,8 @@ public: void text(const wxString &label); bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected + ImVec2 calc_text_size(const wxString &text); + void disabled_begin(bool disabled); void disabled_end(); @@ -73,15 +77,12 @@ public: bool want_any_input() const; private: - void init_default_font(); - void create_device_objects(); - void create_fonts_texture(); + void init_font(); void init_input(); void init_style(); void render_draw_data(ImDrawData *draw_data); bool display_initialized() const; - void destroy_device_objects(); - void destroy_fonts_texture(); + void destroy_font(); static const char* clipboard_get(void* user_data); static void clipboard_set(void* user_data, const char* text); From fbce7b001b8449d2a5bcee3a6fc4185e6626462c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 14:50:40 +0200 Subject: [PATCH 02/17] Some optimizations of "Fix crash on splitting some models #2042" replaced std::vector with std::vector as std::vector is a specialized version optimized for memory, not speed (8 bools are packed into a single boolean). The triangle neighbor traversal was optimized to not push visited or non-neighbors into the queue. --- src/libslic3r/TriangleMesh.cpp | 43 +++++++++++++++++----------------- src/libslic3r/TriangleMesh.hpp | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 759568860..c145380c9 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -343,7 +343,7 @@ void TriangleMesh::rotate(double angle, Point* center) */ bool TriangleMesh::is_splittable() const { - std::vector visited; + std::vector visited; find_unvisited_neighbors(visited); // Try finding an unvisited facet. If there are none, the mesh is not splittable. @@ -359,36 +359,37 @@ bool TriangleMesh::is_splittable() const * facet with the same index has been visited. * @return A deque with all newly visited facets. */ -std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const +std::deque TriangleMesh::find_unvisited_neighbors(std::vector &facet_visited) const { // Make sure we're not operating on a broken mesh. if (!this->repaired) - throw std::runtime_error("split() requires repair()"); + throw std::runtime_error("find_unvisited_neighbors() requires repair()"); // If the visited list is empty, populate it with false for every facet. - if (facet_visited.empty()) { - facet_visited = std::vector(this->stl.stats.number_of_facets, false); - } + if (facet_visited.empty()) + facet_visited = std::vector(this->stl.stats.number_of_facets, false); // Find the first unvisited facet. - std::queue facet_queue; + std::queue facet_queue; + std::deque facets; auto facet = std::find(facet_visited.begin(), facet_visited.end(), false); - if (facet != facet_visited.end()) - facet_queue.push(facet - facet_visited.begin()); + if (facet != facet_visited.end()) { + uint32_t idx = uint32_t(facet - facet_visited.begin()); + facet_queue.push(idx); + facet_visited[idx] = true; + facets.emplace_back(idx); + } // Traverse all reachable neighbors and mark them as visited. - std::deque facets; - while (!facet_queue.empty()) { - int facet_idx = facet_queue.front(); + while (! facet_queue.empty()) { + uint32_t facet_idx = facet_queue.front(); facet_queue.pop(); - - if (facet_idx != -1 && !facet_visited[facet_idx]) { - facet_visited[facet_idx] = true; - - facets.emplace_back(facet_idx); - for (int facet : this->stl.neighbors_start[facet_idx].neighbor) - facet_queue.push(facet); - } + for (int neighbor_idx : this->stl.neighbors_start[facet_idx].neighbor) + if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) { + facet_queue.push(uint32_t(neighbor_idx)); + facet_visited[neighbor_idx] = true; + facets.emplace_back(uint32_t(neighbor_idx)); + } } return facets; @@ -402,7 +403,7 @@ std::deque TriangleMesh::find_unvisited_neighbors(std::vector &f TriangleMeshPtrs TriangleMesh::split() const { // Loop while we have remaining facets. - std::vector facet_visited; + std::vector facet_visited; TriangleMeshPtrs meshes; for (;;) { std::deque facets = find_unvisited_neighbors(facet_visited); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b204a9a3e..a65a4be75 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -69,13 +69,13 @@ public: bool empty() const { return this->facets_count() == 0; } bool is_splittable() const; - std::deque find_unvisited_neighbors(std::vector &facet_visited) const; stl_file stl; bool repaired; private: void require_shared_vertices(); + std::deque find_unvisited_neighbors(std::vector &facet_visited) const; friend class TriangleMeshSlicer; }; From 5f66a2d181aa1f249f7b9ba9b048182c59318f38 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 1 Apr 2019 10:45:51 +0200 Subject: [PATCH 03/17] SLA gizmo dialog now respects system font settings --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d83ef9ed8..d094225ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -565,8 +565,7 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const float scaling = m_imgui->get_style_scaling(); - const ImVec2 window_size(285.f * scaling, 300.f * scaling); + const ImVec2 window_size(m_imgui->scaled_vec(15.f, 16.5f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); From b8289c32b0a099abdc8d73f3b9043bf0470d5449 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 1 Apr 2019 16:10:15 +0200 Subject: [PATCH 04/17] Fix for broken SLA status indication. --- src/libslic3r/SLAPrint.cpp | 40 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 424881491..c7bacaa31 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -46,13 +46,13 @@ const std::array OBJ_STEP_LEVELS = 30, // slaposSupportPoints, 25, // slaposSupportTree, 25, // slaposBasePool, - 10, // slaposSliceSupports, + 10, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = { L("Slicing model"), // slaposObjectSlice, - L("Generating support points"), // slaposSupportPoints, + L("Generating support points"), // slaposSupportPoints, L("Generating support tree"), // slaposSupportTree, L("Generating pad"), // slaposBasePool, L("Slicing supports"), // slaposSliceSupports, @@ -61,7 +61,7 @@ const std::array OBJ_STEP_LABELS = // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { - 5, // slapsStats + 5, // slapsMergeSlicesAndEval 95, // slapsRasterize }; @@ -645,7 +645,7 @@ void SLAPrint::process() const size_t objcount = m_objects.size(); const unsigned min_objstatus = 0; // where the per object operations start - const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsMergeSlicesAndEval]; // where the per object operations end + const unsigned max_objstatus = 50; // where the per object operations end // the coefficient that multiplies the per object status values which // are set up for <0, 100>. They need to be scaled into the whole process @@ -802,13 +802,13 @@ void SLAPrint::process() init = int(init * ostepd); // scale the init portion // scaling for the sub operations - double d = *stthis / (objcount * 100.0); + double d = *stthis / 100.0; - ctl.statuscb = [this, init, d](unsigned st, const std::string& msg) + ctl.statuscb = [this, init, d, ostepd](unsigned st, const std::string& /*msg*/) { //FIXME this status line scaling does not seem to be correct. // How does it account for an increasing object index? - report_status(*this, int(init + st*d), msg); + report_status(*this, int(init + st*d*ostepd), OBJ_STEP_LABELS[slaposSupportTree]); }; ctl.stopcondition = [this](){ return canceled(); }; @@ -1252,18 +1252,29 @@ void SLAPrint::process() auto lvlcnt = unsigned(m_printer_input.size()); printer.layers(lvlcnt); - // slot is the portion of 100% that is realted to rasterization - unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; - // ist: initial state; pst: previous state - unsigned ist = max_objstatus, pst = ist; // coefficient to map the rasterization state (0-99) to the allocated // portion (slot) of the process state - double sd = (100 - ist) / 100.0; + double sd = (100 - max_objstatus) / 100.0; + + // slot is the portion of 100% that is realted to rasterization + unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; + + // ist: initial state; pst: previous state + unsigned ist = std::accumulate(PRINT_STEP_LEVELS.begin(), + PRINT_STEP_LEVELS.begin()+slapsRasterize, + 0u); + + ist = max_objstatus + unsigned(ist * sd); + unsigned pst = ist; + + double increment = (slot * sd) / m_printer_input.size(); + double dstatus = double(ist); + SpinMutex slck; // procedure to process one height level. This will run in parallel auto lvlfn = - [this, &slck, &printer, slot, sd, ist, &pst] + [this, &slck, &printer, increment, &dstatus, &pst] (unsigned level_id) { if(canceled()) return; @@ -1280,9 +1291,10 @@ void SLAPrint::process() printer.finish_layer(level_id); // Status indication guarded with the spinlock - auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size()); { std::lock_guard lck(slck); + dstatus += increment; + auto st = unsigned(dstatus); if( st > pst) { report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]); From c1b7d987a0540e8d686f9b78b0fe9c0e6963bc52 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 1 Apr 2019 17:12:39 +0200 Subject: [PATCH 05/17] Improvement in handling of the custom bridging angle value. In case the bridge is only supported at one side, it is technically not considered to be a support, therefore the default infill angle is used. With this change, the bridging areas use the custom angle value even if not supported on both sides. --- src/libslic3r/LayerRegion.cpp | 9 +++++++-- src/libslic3r/Rasterizer/Rasterizer.hpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 913ba76a6..19fbb3bb6 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -258,13 +258,18 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) #ifdef SLIC3R_DEBUG printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); #endif - if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) { + double custom_angle = Geometry::deg2rad(this->region()->config().bridge_angle.value); + if (bd.detect_angle(custom_angle)) { bridges[idx_last].bridge_angle = bd.angle; if (this->layer()->object()->config().support_material) { polygons_append(this->bridged, bd.coverage()); this->unsupported_bridge_edges.append(bd.unsupported_edges()); } - } + } else if (custom_angle > 0) { + // Bridge was not detected (likely it is only supported at one side). Still it is a surface filled in + // using a bridging flow, therefore it makes sense to respect the custom bridging direction. + bridges[idx_last].bridge_angle = custom_angle; + } // without safety offset, artifacts are generated (GH #2494) surfaces_append(bottom, union_ex(grown, true), bridges[idx_last]); } diff --git a/src/libslic3r/Rasterizer/Rasterizer.hpp b/src/libslic3r/Rasterizer/Rasterizer.hpp index a8c8e1866..671dcbb3d 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.hpp +++ b/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -6,7 +6,7 @@ #include #include -namespace ClipperLib { class Polygon; } +namespace ClipperLib { struct Polygon; } namespace Slic3r { From e20ffbfd858b36ae090ac3946bedeadec7cf5255 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 2 Apr 2019 09:36:16 +0200 Subject: [PATCH 06/17] SLA gizmo uses CallAfter to trigger SLA supports calculation to prevent recursive rendering calls --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index d094225ac..c5d0f28ed 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -816,7 +816,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() // Recalculate support structures once the editing mode is left. // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); } m_editing_mode = false; m_unsaved_changes = false; @@ -869,7 +869,7 @@ void GLGizmoSlaSupports::auto_generate() m_model_object->sla_support_points.clear(); m_model_object->sla_points_status = sla::PointsStatus::Generating; m_editing_mode_cache.clear(); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); + wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); }); } } From 75990923f7b74ddb97bf0d12f977a18c8c46fad2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 27 Mar 2019 16:49:44 +0100 Subject: [PATCH 07/17] Firmware updater: Support for CW1 --- src/slic3r/GUI/FirmwareDialog.cpp | 109 ++++++++++++++++++++---------- src/slic3r/Utils/HexFile.cpp | 1 + src/slic3r/Utils/HexFile.hpp | 1 + 3 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 1a294d210..5da818395 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -59,6 +59,8 @@ enum { USB_PID_MK3 = 2, USB_PID_MMU_BOOT = 3, USB_PID_MMU_APP = 4, + USB_PID_CW1_BOOT = 7, + USB_PID_CW1_APP = 8, }; // This enum discriminates the kind of information in EVT_AVRDUDE, @@ -77,6 +79,13 @@ wxDEFINE_EVENT(EVT_AVRDUDE, wxCommandEvent); wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); +struct Avr109Pid +{ + unsigned boot; + unsigned app; + + Avr109Pid(unsigned boot, unsigned app) : boot(boot), app(app) {} +}; // Private @@ -151,19 +160,21 @@ struct FirmwareDialog::priv bool ask_model_id_mismatch(const std::string &printer_model); bool check_model_id(); - void wait_for_mmu_bootloader(unsigned retries); - void mmu_reboot(const SerialPortInfo &port); - void lookup_port_mmu(); + void avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries); + void avr109_reboot(const SerialPortInfo &port); + void avr109_lookup_port(Avr109Pid usb_pid); void prepare_common(); void prepare_mk2(); void prepare_mk3(); - void prepare_mm_control(); + void prepare_avr109(Avr109Pid usb_pid); void perform_upload(); void user_cancel(); void on_avrdude(const wxCommandEvent &evt); void on_async_dialog(const wxCommandEvent &evt); void ensure_joined(); + + static const char* avr109_dev_name(Avr109Pid usb_pid); }; void FirmwareDialog::priv::find_serial_ports() @@ -259,7 +270,8 @@ void FirmwareDialog::priv::enable_port_picker(bool enable) void FirmwareDialog::priv::load_hex_file(const wxString &path) { hex_file = HexFile(path.wx_str()); - enable_port_picker(hex_file.device != HexFile::DEV_MM_CONTROL); + const bool auto_lookup = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1; + enable_port_picker(! auto_lookup); } void FirmwareDialog::priv::queue_status(wxString message) @@ -356,7 +368,7 @@ bool FirmwareDialog::priv::check_model_id() // return false; } -void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) +void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries) { enum { SLEEP_MS = 500, @@ -367,61 +379,67 @@ void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { - return port.id_vendor != USB_VID_PRUSA || port.id_product != USB_PID_MMU_BOOT; + return port.id_vendor != USB_VID_PRUSA || port.id_product != usb_pid.boot; }), ports.end()); if (ports.size() == 1) { port = ports[0]; return; } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; - queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); + BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; + queue_error(wxString::Format( + _(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid))); return; } } } -void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port) +void FirmwareDialog::priv::avr109_reboot(const SerialPortInfo &port) { asio::io_service io; Serial serial(io, port.port, 1200); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } -void FirmwareDialog::priv::lookup_port_mmu() +void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) { - static const auto msg_not_found = - "The Multi Material Control device was not found.\n" - "If the device is connected, please press the Reset button next to the USB connector ..."; + const char *dev_name = avr109_dev_name(usb_pid); + const wxString msg_not_found = wxString::Format( + _(L("The %s device was not found.\n" + "If the device is connected, please press the Reset button next to the USB connector ...")), + dev_name); - BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ..."; + BOOST_LOG_TRIVIAL(info) << boost::format("Flashing %1%, looking for VID/PID 0x2c99/%2% or 0x2c99/%3% ...") + % dev_name + % usb_pid.boot + % usb_pid.app; auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { return port.id_vendor != USB_VID_PRUSA || - port.id_product != USB_PID_MMU_BOOT && - port.id_product != USB_PID_MMU_APP; + port.id_product != usb_pid.boot && + port.id_product != usb_pid.app; }), ports.end()); if (ports.size() == 0) { - BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ..."; - queue_status(_(L(msg_not_found))); - wait_for_mmu_bootloader(30); + BOOST_LOG_TRIVIAL(info) << "Device not found, asking the user to press Reset and waiting for the device to show up ..."; + queue_status(msg_not_found); + avr109_wait_for_bootloader(usb_pid, 30); } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; - queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); + BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; + queue_error(wxString::Format(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name)); } else { - if (ports[0].id_product == USB_PID_MMU_APP) { + if (ports[0].id_product == usb_pid.app) { // The device needs to be rebooted into the bootloader mode - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port; - mmu_reboot(ports[0]); - wait_for_mmu_bootloader(10); + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, rebooting the device ...") % usb_pid.app % ports[0].port; + avr109_reboot(ports[0]); + avr109_wait_for_bootloader(usb_pid, 10); if (! port) { // The device in bootloader mode was not found, inform the user and wait some more... - BOOST_LOG_TRIVIAL(info) << "MMU 2.0 bootloader device not found after reboot, asking the user to press Reset and waiting for the device to show up ..."; - queue_status(_(L(msg_not_found))); - wait_for_mmu_bootloader(30); + BOOST_LOG_TRIVIAL(info) << boost::format("%1% device not found after reboot, asking the user to press Reset and waiting for the device to show up ...") % dev_name; + queue_status(msg_not_found); + avr109_wait_for_bootloader(usb_pid, 30); } } else { port = ports[0]; @@ -498,16 +516,16 @@ void FirmwareDialog::priv::prepare_mk3() avrdude->push_args(std::move(args)); } -void FirmwareDialog::priv::prepare_mm_control() +void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid) { port = boost::none; - lookup_port_mmu(); + avr109_lookup_port(usb_pid); if (! port) { - queue_error(_(L("The device could not have been found"))); + queue_error(wxString::Format(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid))); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port->port; + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, flashing ...") % usb_pid.boot % port->port; queue_status(label_status_flashing); std::vector args {{ @@ -568,7 +586,11 @@ void FirmwareDialog::priv::perform_upload() break; case HexFile::DEV_MM_CONTROL: - this->prepare_mm_control(); + this->prepare_avr109(Avr109Pid(USB_PID_MMU_BOOT, USB_PID_MMU_APP)); + break; + + case HexFile::DEV_CW1: + this->prepare_avr109(Avr109Pid(USB_PID_CW1_BOOT, USB_PID_CW1_APP)); break; default: @@ -576,7 +598,11 @@ void FirmwareDialog::priv::perform_upload() break; } } catch (const std::exception &ex) { - queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + if (port) { + queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + } else { + queue_error(wxString::Format(_(L("Error: %s")), ex.what())); + } } }) .on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) { @@ -688,6 +714,19 @@ void FirmwareDialog::priv::ensure_joined() avrdude.reset(); } +const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) { + switch (usb_pid.boot) { + case USB_PID_MMU_BOOT: + return "Prusa MMU 2.0 Control"; + break; + case USB_PID_CW1_BOOT: + return "Prusa CurWa"; + break; + + default: throw std::runtime_error((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str()); + } +} + // Public diff --git a/src/slic3r/Utils/HexFile.cpp b/src/slic3r/Utils/HexFile.cpp index 9e0803325..26596f629 100644 --- a/src/slic3r/Utils/HexFile.cpp +++ b/src/slic3r/Utils/HexFile.cpp @@ -18,6 +18,7 @@ static HexFile::DeviceKind parse_device_kind(const std::string &str) if (str == "mk2") { return HexFile::DEV_MK2; } else if (str == "mk3") { return HexFile::DEV_MK3; } else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; } + else if (str == "cw1") { return HexFile::DEV_CW1; } else { return HexFile::DEV_GENERIC; } } diff --git a/src/slic3r/Utils/HexFile.hpp b/src/slic3r/Utils/HexFile.hpp index 1201d23a4..742ae00e6 100644 --- a/src/slic3r/Utils/HexFile.hpp +++ b/src/slic3r/Utils/HexFile.hpp @@ -16,6 +16,7 @@ struct HexFile DEV_MK2, DEV_MK3, DEV_MM_CONTROL, + DEV_CW1, }; boost::filesystem::path path; From 145b8fd0dfa013d7965fba1ac8fb51694a2310d4 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 29 Mar 2019 16:01:47 +0100 Subject: [PATCH 08/17] Firmware updater: Improve logging --- src/slic3r/GUI/FirmwareDialog.cpp | 61 ++++++++++++++++--------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 5da818395..8095a3237 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -155,8 +155,7 @@ struct FirmwareDialog::priv void flashing_done(AvrDudeComplete complete); void enable_port_picker(bool enable); void load_hex_file(const wxString &path); - void queue_status(wxString message); - void queue_error(const wxString &message); + void queue_event(AvrdudeEvent aevt, wxString message); bool ask_model_id_mismatch(const std::string &printer_model); bool check_model_id(); @@ -174,6 +173,21 @@ struct FirmwareDialog::priv void on_async_dialog(const wxCommandEvent &evt); void ensure_joined(); + void queue_status(wxString message) { queue_event(AE_STATUS, std::move(message)); } + + template void queue_message(const wxString &format, Args... args) { + auto message = wxString::Format(format, args...); + BOOST_LOG_TRIVIAL(info) << message; + message.Append('\n'); + queue_event(AE_MESSAGE, std::move(message)); + } + + template void queue_error(const wxString &format, Args... args) { + queue_message(format, args...); + queue_event(AE_STATUS, _(L("Flashing failed: ")) + wxString::Format(format, args...)); + avrdude->cancel(); + } + static const char* avr109_dev_name(Avr109Pid usb_pid); }; @@ -274,23 +288,14 @@ void FirmwareDialog::priv::load_hex_file(const wxString &path) enable_port_picker(! auto_lookup); } -void FirmwareDialog::priv::queue_status(wxString message) +void FirmwareDialog::priv::queue_event(AvrdudeEvent aevt, wxString message) { auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); - evt->SetExtraLong(AE_STATUS); + evt->SetExtraLong(aevt); evt->SetString(std::move(message)); wxQueueEvent(this->q, evt); } -void FirmwareDialog::priv::queue_error(const wxString &message) -{ - auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); - evt->SetExtraLong(AE_STATUS); - evt->SetString(wxString::Format(_(L("Flashing failed: %s")), message)); - - wxQueueEvent(this->q, evt); avrdude->cancel(); -} - bool FirmwareDialog::priv::ask_model_id_mismatch(const std::string &printer_model) { // model_id in the hex file doesn't match what the printer repoted. @@ -386,9 +391,8 @@ void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigne port = ports[0]; return; } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; - queue_error(wxString::Format( - _(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid))); + queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot); + queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid)); return; } } @@ -409,10 +413,7 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) "If the device is connected, please press the Reset button next to the USB connector ...")), dev_name); - BOOST_LOG_TRIVIAL(info) << boost::format("Flashing %1%, looking for VID/PID 0x2c99/%2% or 0x2c99/%3% ...") - % dev_name - % usb_pid.boot - % usb_pid.app; + queue_message("Flashing %s, looking for VID/PID 0x2c99/%u or 0x2c99/%u ...", dev_name, usb_pid.boot, usb_pid.app); auto ports = Utils::scan_serial_ports_extended(); ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { @@ -422,22 +423,22 @@ void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid) }), ports.end()); if (ports.size() == 0) { - BOOST_LOG_TRIVIAL(info) << "Device not found, asking the user to press Reset and waiting for the device to show up ..."; + queue_message("The %s device was not found.", dev_name); queue_status(msg_not_found); avr109_wait_for_bootloader(usb_pid, 30); } else if (ports.size() > 1) { - BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot; - queue_error(wxString::Format(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name)); + queue_message("Several VID/PID 0x2c99/%u devices found", usb_pid.boot); + queue_error(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name); } else { if (ports[0].id_product == usb_pid.app) { // The device needs to be rebooted into the bootloader mode - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, rebooting the device ...") % usb_pid.app % ports[0].port; + queue_message("Found VID/PID 0x2c99/%u at `%s`, rebooting the device ...", usb_pid.app, ports[0].port); avr109_reboot(ports[0]); avr109_wait_for_bootloader(usb_pid, 10); if (! port) { // The device in bootloader mode was not found, inform the user and wait some more... - BOOST_LOG_TRIVIAL(info) << boost::format("%1% device not found after reboot, asking the user to press Reset and waiting for the device to show up ...") % dev_name; + queue_message("%s device not found after reboot", dev_name); queue_status(msg_not_found); avr109_wait_for_bootloader(usb_pid, 30); } @@ -521,11 +522,11 @@ void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid) port = boost::none; avr109_lookup_port(usb_pid); if (! port) { - queue_error(wxString::Format(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid))); + queue_error(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid)); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, flashing ...") % usb_pid.boot % port->port; + queue_message("Found VID/PID 0x2c99/%u at `%s`, flashing ...", usb_pid.boot, port->port); queue_status(label_status_flashing); std::vector args {{ @@ -599,9 +600,9 @@ void FirmwareDialog::priv::perform_upload() } } catch (const std::exception &ex) { if (port) { - queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); + queue_error(_(L("Error accessing port at %s: %s")), port->port, ex.what()); } else { - queue_error(wxString::Format(_(L("Error: %s")), ex.what())); + queue_error(_(L("Error: %s")), ex.what()); } } }) @@ -796,7 +797,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : vsizer->Add(grid, 0, wxEXPAND | wxTOP | wxBOTTOM, SPACING); - p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: avrdude output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE); + p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: Output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE); auto *spoiler_pane = p->spoiler->GetPane(); auto *spoiler_sizer = new wxBoxSizer(wxVERTICAL); p->txt_stdout = new wxTextCtrl(spoiler_pane, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); From c542413962eb4f49c28d19a36b4b9546a064968e Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 1 Apr 2019 15:36:48 +0200 Subject: [PATCH 09/17] imgui: More refactoring, cut gizmo window positioning --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++--- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 3 +++ src/slic3r/GUI/ImGuiWrapper.cpp | 37 +++++++++++----------------- src/slic3r/GUI/ImGuiWrapper.hpp | 8 +++--- 4 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 31c3717ff..e6365e32a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4405,12 +4405,12 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) auto *imgui = wxGetApp().imgui(); imgui->set_display_size((float)w, (float)h); - imgui->set_font_size(m_canvas->GetFont().GetPixelSize().y); #if ENABLE_RETINA_GL - imgui->set_style_scaling(m_retina_helper->get_scale_factor()); + const float scaling = m_retina_helper->get_scale_factor(); #else - imgui->set_style_scaling(m_canvas->GetContentScaleFactor()); + const float scaling = m_canvas->GetContentScaleFactor(); #endif + imgui->set_scaling(m_canvas->GetFont().GetPixelSize().y, scaling); // ensures that this canvas is current _set_current(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 566090504..02d663e93 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -185,7 +185,10 @@ void GLGizmoCut::on_render_for_picking(const Selection& selection) const void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) { + const float approx_height = m_imgui->scaled(11.0f); + y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); + m_imgui->set_next_window_bg_alpha(0.5f); m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 001e0b33f..b008c17a7 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -92,21 +92,18 @@ void ImGuiWrapper::set_display_size(float w, float h) io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); } -void ImGuiWrapper::set_font_size(float font_size) +void ImGuiWrapper::set_scaling(float font_size, float scaling) { - if (m_font_size != font_size) { - m_font_size = font_size; - destroy_font(); + if (m_font_size == font_size && m_style_scaling == scaling) { + return; } -} -void ImGuiWrapper::set_style_scaling(float scaling) -{ - if (!std::isnan(scaling) && !std::isinf(scaling) && scaling != m_style_scaling) { - ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); - m_style_scaling = scaling; - destroy_font(); - } + m_font_size = font_size; + + ImGui::GetStyle().ScaleAllSizes(scaling / m_style_scaling); + m_style_scaling = scaling; + + destroy_font(); } bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) @@ -163,8 +160,6 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) void ImGuiWrapper::new_frame() { - printf("ImGuiWrapper: new_frame()\n"); - if (m_new_frame_open) { return; } @@ -184,6 +179,12 @@ void ImGuiWrapper::render() m_new_frame_open = false; } +ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) +{ + auto text_utf8 = into_u8(text); + return ImGui::CalcTextSize(text_utf8.c_str()); +} + void ImGuiWrapper::set_next_window_pos(float x, float y, int flag) { ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag); @@ -293,12 +294,6 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector& return res; } -ImVec2 ImGuiWrapper::calc_text_size(const wxString &text) -{ - auto text_utf8 = into_u8(text); - return ImGui::CalcTextSize(text_utf8.c_str()); -} - void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -342,8 +337,6 @@ bool ImGuiWrapper::want_any_input() const void ImGuiWrapper::init_font() { - printf("ImGuiWrapper: init_font()\n"); - const float font_size = m_font_size * m_style_scaling; destroy_font(); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 476379da2..84a60e3d1 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -35,8 +35,7 @@ public: void set_language(const std::string &language); void set_display_size(float w, float h); - void set_font_size(float font_size); - void set_style_scaling(float scaling); + void set_scaling(float font_size, float scaling); bool update_mouse_data(wxMouseEvent &evt); bool update_key_data(wxKeyEvent &evt); @@ -47,7 +46,8 @@ public: void render(); float scaled(float x) const { return x * m_font_size * m_style_scaling; } - ImVec2 scaled_vec(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + ImVec2 calc_text_size(const wxString &text); void set_next_window_pos(float x, float y, int flag); void set_next_window_bg_alpha(float alpha); @@ -66,8 +66,6 @@ public: void text(const wxString &label); bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected - ImVec2 calc_text_size(const wxString &text); - void disabled_begin(bool disabled); void disabled_end(); From a3dcb6863e1887319fb74a655aab08e13bccc4f0 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 2 Apr 2019 10:54:14 +0200 Subject: [PATCH 10/17] Rethought sla status indication. --- src/libslic3r/SLA/SLAAutoSupports.cpp | 10 ++- src/libslic3r/SLA/SLAAutoSupports.hpp | 7 +- src/libslic3r/SLAPrint.cpp | 109 ++++++++++++++------------ src/libslic3r/SLAPrint.hpp | 9 +++ 4 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/libslic3r/SLA/SLAAutoSupports.cpp b/src/libslic3r/SLA/SLAAutoSupports.cpp index 9e9f07b6c..0a2537b91 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.cpp +++ b/src/libslic3r/SLA/SLAAutoSupports.cpp @@ -49,8 +49,8 @@ float SLAAutoSupports::distance_limit(float angle) const }*/ SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights, - const Config& config, std::function throw_on_cancel) -: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel) + const Config& config, std::function throw_on_cancel, std::function statusfn) +: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel), m_statusfn(statusfn) { process(slices, heights); project_onto_mesh(m_output); @@ -197,6 +197,9 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: PointGrid3D point_grid; point_grid.cell_size = Vec3f(10.f, 10.f, 10.f); + double increment = 100.0 / layers.size(); + double status = 0; + for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) { SLAAutoSupports::MyLayer *layer_top = &layers[layer_id]; SLAAutoSupports::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr; @@ -252,6 +255,9 @@ void SLAAutoSupports::process(const std::vector& slices, const std:: m_throw_on_cancel(); + status += increment; + m_statusfn(int(std::round(status))); + #ifdef SLA_AUTOSUPPORTS_DEBUG /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i); output_expolygons(expolys_top, "top" + layer_num_str + ".svg"); diff --git a/src/libslic3r/SLA/SLAAutoSupports.hpp b/src/libslic3r/SLA/SLAAutoSupports.hpp index 038b505da..d32d182bc 100644 --- a/src/libslic3r/SLA/SLAAutoSupports.hpp +++ b/src/libslic3r/SLA/SLAAutoSupports.hpp @@ -24,7 +24,7 @@ public: }; SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, - const std::vector& heights, const Config& config, std::function throw_on_cancel); + const std::vector& heights, const Config& config, std::function throw_on_cancel, std::function statusfn); const std::vector& output() { return m_output; } struct MyLayer; @@ -196,12 +196,13 @@ private: static void output_structures(const std::vector &structures); #endif // SLA_AUTOSUPPORTS_DEBUG - std::function m_throw_on_cancel; const sla::EigenMesh3D& m_emesh; + std::function m_throw_on_cancel; + std::function m_statusfn; }; } // namespace Slic3r -#endif // SLAAUTOSUPPORTS_HPP_ \ No newline at end of file +#endif // SLAAUTOSUPPORTS_HPP_ diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index c7bacaa31..454fbe78b 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -619,14 +619,6 @@ bool SLAPrint::invalidate_step(SLAPrintStep step) return invalidated; } -template -void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) -{ - BOOST_LOG_TRIVIAL(info) << st << "% " << msg; - p.set_status(st, msg, std::forward(args)...); -} - - void SLAPrint::process() { using namespace sla; @@ -720,7 +712,7 @@ void SLAPrint::process() // In this step we check the slices, identify island and cover them with // support points. Then we sprinkle the rest of the mesh. - auto support_points = [this](SLAPrintObject& po) { + auto support_points = [this, ostepd](SLAPrintObject& po) { const ModelObject& mo = *po.m_model_object; po.m_supportdata.reset( new SLAPrintObject::SupportData(po.transformed_mesh()) ); @@ -754,6 +746,19 @@ void SLAPrint::process() config.minimal_distance = float(cfg.support_points_minimal_distance); config.head_diameter = float(cfg.support_head_front_diameter); + // scaling for the sub operations + double d = ostepd * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0; + double init = m_report_status.status(); + + auto statuscb = [this, d, init](unsigned st) + { + double current = init + st * d; + if(std::round(m_report_status.status()) < std::round(current)) + m_report_status(*this, current, + OBJ_STEP_LABELS[slaposSupportPoints]); + + }; + // Construction of this object does the calculation. this->throw_if_canceled(); SLAAutoSupports auto_supports(po.transformed_mesh(), @@ -761,7 +766,8 @@ void SLAPrint::process() po.get_model_slices(), heights, config, - [this]() { throw_if_canceled(); }); + [this]() { throw_if_canceled(); }, + statuscb); // Now let's extract the result. const std::vector& points = auto_supports.output(); @@ -772,7 +778,7 @@ void SLAPrint::process() << po.m_supportdata->support_points.size(); // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports - report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); + m_report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. @@ -781,7 +787,8 @@ void SLAPrint::process() }; // In this step we create the supports - auto support_tree = [this, objcount, ostepd](SLAPrintObject& po) { + auto support_tree = [this, ostepd](SLAPrintObject& po) + { if(!po.m_supportdata) return; if(!po.m_config.supports_enable.getBool()) { @@ -793,22 +800,17 @@ void SLAPrint::process() sla::SupportConfig scfg = make_support_cfg(po.m_config); sla::Controller ctl; - // some magic to scale the status values coming from the support - // tree creation into the whole print process - auto stfirst = OBJ_STEP_LEVELS.begin(); - auto stthis = stfirst + slaposSupportTree; - // we need to add up the status portions until this operation - int init = std::accumulate(stfirst, stthis, 0); - init = int(init * ostepd); // scale the init portion - // scaling for the sub operations - double d = *stthis / 100.0; + double d = ostepd * OBJ_STEP_LEVELS[slaposSupportTree] / 100.0; + double init = m_report_status.status(); - ctl.statuscb = [this, init, d, ostepd](unsigned st, const std::string& /*msg*/) + ctl.statuscb = [this, d, init](unsigned st, const std::string&) { - //FIXME this status line scaling does not seem to be correct. - // How does it account for an increasing object index? - report_status(*this, int(init + st*d*ostepd), OBJ_STEP_LABELS[slaposSupportTree]); + double current = init + st * d; + if(std::round(m_report_status.status()) < std::round(current)) + m_report_status(*this, current, + OBJ_STEP_LABELS[slaposSupportTree]); + }; ctl.stopcondition = [this](){ return canceled(); }; @@ -824,7 +826,7 @@ void SLAPrint::process() auto rc = SlicingStatus::RELOAD_SCENE; // This is to prevent "Done." being displayed during merged_mesh() - report_status(*this, -1, L("Visualizing supports")); + m_report_status(*this, -1, L("Visualizing supports")); po.m_supportdata->support_tree_ptr->merged_mesh(); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " @@ -834,8 +836,7 @@ void SLAPrint::process() if(po.support_mesh().empty()) BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; - report_status(*this, -1, L("Visualizing supports"), rc); - + m_report_status(*this, -1, L("Visualizing supports"), rc); }; // This step generates the sla base pad @@ -883,7 +884,7 @@ void SLAPrint::process() po.throw_if_canceled(); auto rc = SlicingStatus::RELOAD_SCENE; - report_status(*this, -1, L("Visualizing supports"), rc); + m_report_status(*this, -1, L("Visualizing supports"), rc); }; // Slicing the support geometries similarly to the model slicing procedure. @@ -914,7 +915,7 @@ void SLAPrint::process() } // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices. - report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); + m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; // Merging the slices from all the print objects into one slice grid and @@ -1213,7 +1214,7 @@ void SLAPrint::process() m_print_statistics.fast_layers_count = fast_layers; m_print_statistics.slow_layers_count = slow_layers; - report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); + m_report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); }; // Rasterizing the model objects, and their supports @@ -1259,16 +1260,11 @@ void SLAPrint::process() // slot is the portion of 100% that is realted to rasterization unsigned slot = PRINT_STEP_LEVELS[slapsRasterize]; - // ist: initial state; pst: previous state - unsigned ist = std::accumulate(PRINT_STEP_LEVELS.begin(), - PRINT_STEP_LEVELS.begin()+slapsRasterize, - 0u); - - ist = max_objstatus + unsigned(ist * sd); - unsigned pst = ist; + // pst: previous state + double pst = m_report_status.status(); double increment = (slot * sd) / m_printer_input.size(); - double dstatus = double(ist); + double dstatus = m_report_status.status(); SpinMutex slck; @@ -1294,10 +1290,10 @@ void SLAPrint::process() { std::lock_guard lck(slck); dstatus += increment; - auto st = unsigned(dstatus); - if( st > pst) { - report_status(*this, int(st), - PRINT_STEP_LABELS[slapsRasterize]); + double st = std::round(dstatus); + if(st > pst) { + m_report_status(*this, st, + PRINT_STEP_LABELS[slapsRasterize]); pst = st; } } @@ -1338,7 +1334,7 @@ void SLAPrint::process() rasterize }; - unsigned st = min_objstatus; + double st = min_objstatus; unsigned incr = 0; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; @@ -1352,18 +1348,18 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name; - for (int s = (int)step_ranges[idx_range]; s < (int)step_ranges[idx_range + 1]; ++s) { - auto currentstep = (SLAPrintObjectStep)s; + for (int s = int(step_ranges[idx_range]); s < int(step_ranges[idx_range + 1]); ++s) { + auto currentstep = static_cast(s); // Cancellation checking. Each step will check for cancellation // on its own and return earlier gracefully. Just after it returns // execution gets to this point and throws the canceled signal. throw_if_canceled(); - st += unsigned(incr * ostepd); + st += incr * ostepd; if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { - report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); + m_report_status(*this, st, OBJ_STEP_LABELS[currentstep]); pobj_program[currentstep](*po); throw_if_canceled(); po->set_done(currentstep); @@ -1390,17 +1386,17 @@ void SLAPrint::process() if(m_stepmask[currentstep] && set_started(currentstep)) { - report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]); + m_report_status(*this, st, PRINT_STEP_LABELS[currentstep]); print_program[currentstep](); throw_if_canceled(); set_done(currentstep); } - st += unsigned(PRINT_STEP_LEVELS[currentstep] * pstd); + st += PRINT_STEP_LEVELS[currentstep] * pstd; } // If everything vent well - report_status(*this, 100, L("Slicing done")); + m_report_status(*this, 100, L("Slicing done")); } bool SLAPrint::invalidate_state_by_config_options(const std::vector &opt_keys) @@ -1724,7 +1720,8 @@ DynamicConfig SLAPrintStatistics::placeholders() "print_time", "total_cost", "total_weight", "objects_used_material", "support_used_material" }) config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}")); - return config; + + return config; } std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const @@ -1744,4 +1741,12 @@ std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) return final_path; } +void SLAPrint::StatusReporter::operator()( + SLAPrint &p, double st, const std::string &msg, unsigned flags) +{ + m_st = st; + BOOST_LOG_TRIVIAL(info) << st << "% " << msg; + p.set_status(int(std::round(st)), msg, flags); +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9cf826097..54128e3bf 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -471,6 +471,15 @@ private: // Estimated print time, material consumed. SLAPrintStatistics m_print_statistics; + class StatusReporter { + double m_st = 0; + public: + void operator() (SLAPrint& p, double st, const std::string& msg, + unsigned flags = SlicingStatus::DEFAULT); + double status() const { return m_st; } + } m_report_status; + + friend SLAPrintObject; }; From adf9c4bd40afa3e1cfd50e5988aa7ae46987cc20 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 10:55:36 +0200 Subject: [PATCH 11/17] Follow-up of d4b22cfb87f8b6bc9c8c7ec34158be2e852450e8 -> Fixed dragging of sla instances after slicing --- src/slic3r/GUI/Selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 34b5f4067..7103ca12d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1703,7 +1703,7 @@ bool Selection::_is_from_fully_selected_instance(unsigned int volume_idx) const GLVolumePtrs& volumes; SameInstance(int obj_idx, int inst_idx, GLVolumePtrs& volumes) : obj_idx(obj_idx), inst_idx(inst_idx), volumes(volumes) {} - bool operator () (unsigned int i) { return (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); } + bool operator () (unsigned int i) { return (volumes[i]->volume_idx() >= 0) && (volumes[i]->object_idx() == obj_idx) && (volumes[i]->instance_idx() == inst_idx); } }; if ((unsigned int)m_volumes->size() <= volume_idx) From 9d5eb2cd48b84a079f6f5adcb48ae63aed5af09e Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 2 Apr 2019 10:56:08 +0200 Subject: [PATCH 12/17] Fix build --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index c5d0f28ed..75f13cdcf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -565,7 +565,7 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const ImVec2 window_size(m_imgui->scaled_vec(15.f, 16.5f)); + const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); From 6a745649001133420fadd4e7c31b48c8860558f5 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 2 Apr 2019 11:19:52 +0200 Subject: [PATCH 13/17] More accurate status proportions for SLA steps. --- src/libslic3r/SLAPrint.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 454fbe78b..0304363f6 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -42,11 +42,11 @@ namespace { // should add up to 100 (%) const std::array OBJ_STEP_LEVELS = { - 10, // slaposObjectSlice, - 30, // slaposSupportPoints, - 25, // slaposSupportTree, - 25, // slaposBasePool, - 10, // slaposSliceSupports, + 30, // slaposObjectSlice, + 20, // slaposSupportPoints, + 10, // slaposSupportTree, + 10, // slaposBasePool, + 30, // slaposSliceSupports, }; const std::array OBJ_STEP_LABELS = @@ -61,8 +61,8 @@ const std::array OBJ_STEP_LABELS = // Should also add up to 100 (%) const std::array PRINT_STEP_LEVELS = { - 5, // slapsMergeSlicesAndEval - 95, // slapsRasterize + 10, // slapsMergeSlicesAndEval + 90, // slapsRasterize }; const std::array PRINT_STEP_LABELS = From 086f11df98c20d133baac7367ffda2988eb0cd7d Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 2 Apr 2019 13:47:49 +0200 Subject: [PATCH 14/17] Handling of left hand oriented coordinate systems: is_left_handed() method on transformations and volumes rendering of GLVolumes in left handed coordinate systems by glFrontFace(GL_CW); SLA slicing on left hand oriented instances by flipping the mesh for SLAPrintObject in X. rendering of the SLA cutting plane in left handed systems resetting the SLA clipping planes on 3D preview invalidation --- src/libslic3r/Geometry.hpp | 1 + src/libslic3r/Model.hpp | 1 + src/libslic3r/SLAPrint.cpp | 7 ++- src/libslic3r/SLAPrint.hpp | 7 ++- src/slic3r/GUI/3DScene.cpp | 23 ++++++++++ src/slic3r/GUI/3DScene.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 81 +++++++++++++--------------------- src/slic3r/GUI/GLCanvas3D.hpp | 1 + src/slic3r/GUI/GUI_Preview.cpp | 13 ++++-- src/slic3r/GUI/GUI_Preview.hpp | 5 ++- src/slic3r/GUI/Plater.cpp | 2 +- 11 files changed, 80 insertions(+), 62 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 380245b5f..d556f664c 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -246,6 +246,7 @@ public: const Vec3d& get_mirror() const { return m_mirror; } double get_mirror(Axis axis) const { return m_mirror(axis); } + bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; } void set_mirror(const Vec3d& mirror); void set_mirror(Axis axis, double mirror); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 8a48f8ee9..3d476cbb0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -394,6 +394,7 @@ public: const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } + bool is_left_handed() const { return m_transformation.is_left_handed(); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index c7bacaa31..04778f584 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -93,7 +93,10 @@ static Transform3d sla_trafo(const ModelObject &model_object) offset(0) = 0.; offset(1) = 0.; rotation(2) = 0.; - return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); + Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); + if (model_instance.is_left_handed()) + trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo; + return trafo; } // List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance. @@ -399,7 +402,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf // FIXME: this invalidates the transformed mesh in SLAPrintObject // which is expensive to calculate (especially the raw_mesh() call) - print_object->set_trafo(sla_trafo(model_object)); + print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed()); print_object->set_instances(new_instances); print_object->config_apply(config, true); diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 9cf826097..272252a2a 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -51,6 +51,7 @@ public: const SLAPrintObjectConfig& config() const { return m_config; } const Transform3d& trafo() const { return m_trafo; } + bool is_left_handed() const { return m_left_handed; } struct Instance { Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {} @@ -241,8 +242,8 @@ protected: void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } - void set_trafo(const Transform3d& trafo) { - m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; }); + void set_trafo(const Transform3d& trafo, bool left_handed) { + m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; }); } void set_instances(const std::vector &instances) { m_instances = instances; } @@ -262,6 +263,8 @@ private: // Translation in Z + Rotation by Y and Z + Scaling / Mirroring. Transform3d m_trafo = Transform3d::Identity(); + // m_trafo is left handed -> 3x3 affine transformation has negative determinant. + bool m_left_handed = false; std::vector m_instances; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 58011730b..7ba61bdb6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -333,6 +333,13 @@ Transform3d GLVolume::world_matrix() const return m; } +bool GLVolume::is_left_handed() const +{ + const Vec3d &m1 = m_instance_transformation.get_mirror(); + const Vec3d &m2 = m_volume_transformation.get_mirror(); + return m1.x() * m1.y() * m1.z() * m2.x() * m2.y() * m2.z() < 0.; +} + const BoundingBoxf3& GLVolume::transformed_bounding_box() const { assert(bounding_box.defined || bounding_box.min(0) >= bounding_box.max(0) || bounding_box.min(1) >= bounding_box.max(1) || bounding_box.min(2) >= bounding_box.max(2)); @@ -401,6 +408,8 @@ void GLVolume::render() const if (!is_active) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); glsafe(::glCullFace(GL_BACK)); glsafe(::glPushMatrix()); @@ -410,6 +419,8 @@ void GLVolume::render() const else this->indexed_vertex_array.render(); glsafe(::glPopMatrix()); + if (this->is_left_handed()) + glFrontFace(GL_CCW); } void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const @@ -420,6 +431,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); + GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first)); GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first)); if (n_triangles + n_quads == 0) @@ -481,6 +495,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c } glsafe(::glPopMatrix()); + + if (this->is_left_handed()) + glFrontFace(GL_CCW); } void GLVolume::render_legacy() const @@ -489,6 +506,9 @@ void GLVolume::render_legacy() const if (!is_active) return; + if (this->is_left_handed()) + glFrontFace(GL_CW); + GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first)); GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first)); if (n_triangles + n_quads == 0) @@ -520,6 +540,9 @@ void GLVolume::render_legacy() const glsafe(::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first)); glsafe(::glPopMatrix()); + + if (this->is_left_handed()) + glFrontFace(GL_CCW); } std::vector GLVolumeCollection::load_object( diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e421997e5..5cc301a39 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -388,6 +388,7 @@ public: int instance_idx() const { return this->composite_id.instance_id; } Transform3d world_matrix() const; + bool is_left_handed() const; const BoundingBoxf3& transformed_bounding_box() const; const BoundingBoxf3& transformed_convex_hull_bounding_box() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 31c3717ff..862ce74b7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5010,24 +5010,12 @@ void GLCanvas3D::_render_sla_slices() const Pointf3s &top_obj_triangles = it_caps_top->second.object; Pointf3s &top_sup_triangles = it_caps_top->second.supports; - const std::vector& instances = obj->instances(); - struct InstanceTransform - { - Vec3d offset; - float rotation; - }; - - std::vector instance_transforms; - for (const SLAPrintObject::Instance& inst : instances) - { - instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) }); - } - if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) { double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value; + bool left_handed = obj->is_left_handed(); coord_t key_zero = obj->get_slice_index().front().print_level(); // Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane. @@ -5046,10 +5034,10 @@ void GLCanvas3D::_render_sla_slices() const const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); // calculate model bottom cap if (bottom_obj_triangles.empty() && !obj_bottom.empty()) - bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, true); + bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed); // calculate support bottom cap if (bottom_sup_triangles.empty() && !sup_bottom.empty()) - bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, true); + bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed); } if (slice_high.is_valid()) { @@ -5057,49 +5045,35 @@ void GLCanvas3D::_render_sla_slices() const const ExPolygons& sup_top = slice_high.get_slice(soSupport); // calculate model top cap if (top_obj_triangles.empty() && !obj_top.empty()) - top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, false); + top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed); // calculate support top cap if (top_sup_triangles.empty() && !sup_top.empty()) - top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, false); + top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed); } } if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty()) { - for (const InstanceTransform& inst : instance_transforms) + for (const SLAPrintObject::Instance& inst : obj->instances()) { ::glPushMatrix(); - ::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2)); - ::glRotatef(inst.rotation, 0.0, 0.0, 1.0); - - ::glBegin(GL_TRIANGLES); - + ::glTranslated(unscale(inst.shift.x()), unscale(inst.shift.y()), 0); + ::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0); + if (obj->is_left_handed()) + // The polygons are mirrored by X. + ::glScalef(-1.0, 1.0, 1.0); ::glColor3f(1.0f, 0.37f, 0.0f); - - for (const Vec3d& v : bottom_obj_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - for (const Vec3d& v : top_obj_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - ::glColor3f(1.0f, 0.0f, 0.37f); - - for (const Vec3d& v : bottom_sup_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - for (const Vec3d& v : top_sup_triangles) - { - ::glVertex3dv((GLdouble*)v.data()); - } - - ::glEnd(); - + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size()); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size()); + ::glColor3f(1.0f, 0.0f, 0.37f); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size()); + ::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data()); + ::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size()); + ::glDisableClientState(GL_VERTEX_ARRAY); ::glPopMatrix(); } } @@ -6217,6 +6191,8 @@ void GLCanvas3D::_load_shells_fff() void GLCanvas3D::_load_shells_sla() { + //FIXME use reload_scene +#if 1 const SLAPrint* print = this->sla_print(); if (print->objects().empty()) // nothing to render, return @@ -6240,9 +6216,7 @@ void GLCanvas3D::_load_shells_sla() m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized); - const std::vector& instances = obj->instances(); - - for (const SLAPrintObject::Instance& instance : instances) + for (const SLAPrintObject::Instance& instance : obj->instances()) { Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0); Vec3d rotation(0.0, 0.0, (double)instance.rotation); @@ -6265,6 +6239,7 @@ void GLCanvas3D::_load_shells_sla() v.composite_id.volume_id = -1; v.set_instance_offset(offset); v.set_instance_rotation(rotation); + v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); } // add pad @@ -6283,6 +6258,7 @@ void GLCanvas3D::_load_shells_sla() v.composite_id.volume_id = -1; v.set_instance_offset(offset); v.set_instance_rotation(rotation); + v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); } // finalize volumes and sends geometry to gpu @@ -6305,6 +6281,9 @@ void GLCanvas3D::_load_shells_sla() } update_volumes_colors_by_extruder(); +#else + this->reload_scene(true, true); +#endif } void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2b1061c95..7e414d52a 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -634,6 +634,7 @@ public: m_sla_caps[id].reset(); } } + void reset_clipping_planes_cache() { m_sla_caps[0].triangles.clear(); m_sla_caps[1].triangles.clear(); } void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; } void set_color_by(const std::string& value); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 14d19e251..438e9d236 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -27,7 +27,7 @@ namespace Slic3r { namespace GUI { - View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) +View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) : m_canvas_widget(nullptr) , m_canvas(nullptr) { @@ -155,7 +155,9 @@ void View3D::render() m_canvas->set_as_dirty(); } -Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process_func) +Preview::Preview( + wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process_func) : m_canvas_widget(nullptr) , m_canvas(nullptr) , m_double_slider_sizer(nullptr) @@ -179,14 +181,14 @@ Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_t , m_volumes_cleanup_required(false) #endif // __linux__ { - if (init(parent, bed, camera, view_toolbar)) + if (init(parent, bed, camera, view_toolbar, model)) { show_hide_ui_elements("none"); load_print(); } } -bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) +bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model) { if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; @@ -196,6 +198,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view m_canvas = _3DScene::get_canvas(this->m_canvas_widget); m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); m_canvas->set_config(m_config); + m_canvas->set_model(model); m_canvas->set_process(m_process); m_canvas->enable_legend_texture(true); m_canvas->enable_dynamic_background(true); @@ -781,6 +784,8 @@ void Preview::load_print_as_sla() } sort_remove_duplicates(zs); + m_canvas->reset_clipping_planes_cache(); + n_layers = (unsigned int)zs.size(); if (n_layers == 0) { diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 96c49e54f..a2929f2e6 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -102,7 +102,8 @@ class Preview : public wxPanel PrusaDoubleSlider* m_slider {nullptr}; public: - Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process = [](){}); + Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function schedule_background_process = [](){}); virtual ~Preview(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } @@ -120,7 +121,7 @@ public: void refresh_print(); private: - bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); + bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model); void bind_event_handlers(); void unbind_event_handlers(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c92c22c50..435d9548f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1350,7 +1350,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this); view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process); - preview = new Preview(q, bed, camera, view_toolbar, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); + preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); panels.push_back(view3D); panels.push_back(preview); From e1177b1810bffcbf6c19e7a142e260deeec3f18e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 2 Apr 2019 13:54:23 +0200 Subject: [PATCH 15/17] Fix of the previous commmit. --- src/libslic3r/Model.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 3d476cbb0..5cf7f49ca 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -499,6 +499,7 @@ public: const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } + bool is_left_handed() const { return m_transformation.is_left_handed(); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } From f147da1e5d9d341ca83a67dee3029c9e82f27598 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 10:25:47 +0200 Subject: [PATCH 16/17] Fixed conflicts after cherry-picking 5c89135 --- src/slic3r/GUI/GLCanvas3D.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index eb934ba7d..1ae4d642f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6207,16 +6207,25 @@ void GLCanvas3D::_load_shells_sla() unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); + // selects only instances which were sliced const ModelObject* model_obj = obj->model_object(); - std::vector instance_idxs(model_obj->instances.size()); - for (int i = 0; i < (int)model_obj->instances.size(); ++i) + const std::vector& sla_instances = obj->instances(); + std::vector instances_model_idxs(sla_instances.size()); + for (int i = 0; i < (int)sla_instances.size(); ++i) { - instance_idxs[i] = i; + instances_model_idxs[i] = (int)sla_instances[i].instance_id.id; } - m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized); + std::vector sliced_instance_idxs; + for (int i = 0; i < (int)model_obj->instances.size(); ++i) + { + if (std::find(instances_model_idxs.begin(), instances_model_idxs.end(), (int)model_obj->instances[i]->id().id) != instances_model_idxs.end()) + sliced_instance_idxs.push_back(i); + } - for (const SLAPrintObject::Instance& instance : obj->instances()) + m_volumes.load_object(model_obj, obj_idx, sliced_instance_idxs, "object", m_use_VBOs && m_initialized); + + for (const SLAPrintObject::Instance& instance : sla_instances) { Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0); Vec3d rotation(0.0, 0.0, (double)instance.rotation); From ba4f0445c361c24bde074e1ab321debef5614a18 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 12:13:45 +0200 Subject: [PATCH 17/17] Fixed rendering of sla cap slices after deleting object --- src/slic3r/GUI/GLCanvas3D.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1ae4d642f..ca3f6261b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4987,6 +4987,9 @@ void GLCanvas3D::_render_sla_slices() const { const SLAPrintObject* obj = print_objects[i]; + if (!obj->is_step_done(slaposSliceSupports)) + continue; + SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i); { @@ -5011,7 +5014,7 @@ void GLCanvas3D::_render_sla_slices() const Pointf3s &top_sup_triangles = it_caps_top->second.supports; if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && - obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty()) + !obj->get_slice_index().empty()) { double layer_height = print->default_object_config().layer_height.value; double initial_layer_height = print->material_config().initial_layer_height.value;