From d4adcd4077d2514059da880cb11a6f1a1760d0c7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 24 Jul 2018 13:39:17 +0200 Subject: [PATCH 1/9] Out of print volume detection for toolpaths --- lib/Slic3r/GUI/Plater/3DPreview.pm | 11 +- xs/src/slic3r/GUI/3DScene.cpp | 22 +- xs/src/slic3r/GUI/3DScene.hpp | 4 +- xs/src/slic3r/GUI/GLCanvas3D.cpp | 801 +++++++++++++----------- xs/src/slic3r/GUI/GLCanvas3D.hpp | 22 +- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 31 +- xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 4 +- xs/xsp/GUI_3DScene.xsp | 30 +- 8 files changed, 473 insertions(+), 452 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 9ed2374ec4..09c2f0b8cf 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -25,6 +25,7 @@ sub new { # init GUI elements my $canvas = Slic3r::GUI::3DScene->new($self); Slic3r::GUI::_3DScene::enable_shader($canvas, 1); + Slic3r::GUI::_3DScene::set_config($canvas, $config); $self->canvas($canvas); my $slider_low = Wx::Slider->new( $self, -1, @@ -365,16 +366,8 @@ sub load_print { if ($self->gcode_preview_data->empty) { # load skirt and brim Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print); - Slic3r::GUI::_3DScene::load_print_toolpaths($self->canvas); - Slic3r::GUI::_3DScene::load_wipe_tower_toolpaths($self->canvas, \@colors); - foreach my $object (@{$self->print->objects}) { - Slic3r::GUI::_3DScene::load_print_object_toolpaths($self->canvas, $object, \@colors); - # Show the objects in very transparent color. - #my @volume_ids = $self->canvas->load_object($object->model_object); - #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids; - } + Slic3r::GUI::_3DScene::load_preview($self->canvas, \@colors); $self->show_hide_ui_elements('simple'); - Slic3r::GUI::_3DScene::reset_legend_texture(); } else { $self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0); Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print); diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 62659033ad..e23641cb18 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -250,7 +250,7 @@ void GLVolume::set_render_color() set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); else if (hover) set_render_color(HOVER_COLOR, 4); - else if (is_outside) + else if (is_outside && outside_printer_detection_enabled) set_render_color(OUTSIDE_COLOR, 4); else set_render_color(color, 4); @@ -1968,26 +1968,16 @@ void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) s_canvas_mgr.reload_scene(canvas, force); } -void _3DScene::load_print_toolpaths(wxGLCanvas* canvas) -{ - s_canvas_mgr.load_print_toolpaths(canvas); -} - -void _3DScene::load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector& str_tool_colors) -{ - s_canvas_mgr.load_print_object_toolpaths(canvas, print_object, str_tool_colors); -} - -void _3DScene::load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors) -{ - s_canvas_mgr.load_wipe_tower_toolpaths(canvas, str_tool_colors); -} - void _3DScene::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors) { s_canvas_mgr.load_gcode_preview(canvas, preview_data, str_tool_colors); } +void _3DScene::load_preview(wxGLCanvas* canvas, const std::vector& str_tool_colors) +{ + s_canvas_mgr.load_preview(canvas, str_tool_colors); +} + void _3DScene::reset_legend_texture() { s_canvas_mgr.reset_legend_texture(); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 5409b95883..0cd2d81f0e 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -536,10 +536,8 @@ public: static void reload_scene(wxGLCanvas* canvas, bool force); - static void load_print_toolpaths(wxGLCanvas* canvas); - static void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector& str_tool_colors); - static void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors); static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); + static void load_preview(wxGLCanvas* canvas, const std::vector& str_tool_colors); static void reset_legend_texture(); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 722f1c1124..819f26609d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2326,372 +2326,6 @@ void GLCanvas3D::reload_scene(bool force) } } -void GLCanvas3D::load_print_toolpaths() -{ - // ensures this canvas is current - if (!set_current()) - return; - - if (m_print == nullptr) - return; - - if (!m_print->state.is_done(psSkirt) || !m_print->state.is_done(psBrim)) - return; - - if (!m_print->has_skirt() && (m_print->config.brim_width.value == 0)) - return; - - const float color[] = { 0.5f, 1.0f, 0.5f, 1.0f }; // greenish - - // number of skirt layers - size_t total_layer_count = 0; - for (const PrintObject* print_object : m_print->objects) - { - total_layer_count = std::max(total_layer_count, print_object->total_layer_count()); - } - size_t skirt_height = m_print->has_infinite_skirt() ? total_layer_count : std::min(m_print->config.skirt_height.value, total_layer_count); - if ((skirt_height == 0) && (m_print->config.brim_width.value > 0)) - skirt_height = 1; - - // get first skirt_height layers (maybe this should be moved to a PrintObject method?) - const PrintObject* object0 = m_print->objects.front(); - std::vector print_zs; - print_zs.reserve(skirt_height * 2); - for (size_t i = 0; i < std::min(skirt_height, object0->layers.size()); ++i) - { - print_zs.push_back(float(object0->layers[i]->print_z)); - } - //FIXME why there are support layers? - for (size_t i = 0; i < std::min(skirt_height, object0->support_layers.size()); ++i) - { - print_zs.push_back(float(object0->support_layers[i]->print_z)); - } - sort_remove_duplicates(print_zs); - if (print_zs.size() > skirt_height) - print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); - - m_volumes.volumes.emplace_back(new GLVolume(color)); - GLVolume& volume = *m_volumes.volumes.back(); - for (size_t i = 0; i < skirt_height; ++i) { - volume.print_zs.push_back(print_zs[i]); - volume.offsets.push_back(volume.indexed_vertex_array.quad_indices.size()); - volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size()); - if (i == 0) - _3DScene::extrusionentity_to_verts(m_print->brim, print_zs[i], Point(0, 0), volume); - - _3DScene::extrusionentity_to_verts(m_print->skirt, print_zs[i], Point(0, 0), volume); - } - volume.bounding_box = volume.indexed_vertex_array.bounding_box(); - volume.indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); -} - -void GLCanvas3D::load_print_object_toolpaths(const PrintObject& print_object, const std::vector& str_tool_colors) -{ - std::vector tool_colors = _parse_colors(str_tool_colors); - - struct Ctxt - { - const Points *shifted_copies; - std::vector layers; - bool has_perimeters; - bool has_infill; - bool has_support; - const std::vector* tool_colors; - - // Number of vertices (each vertex is 6x4=24 bytes long) - static const size_t alloc_size_max() { return 131072; } // 3.15MB - // static const size_t alloc_size_max () { return 65536; } // 1.57MB - // static const size_t alloc_size_max () { return 32768; } // 786kB - static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } - - static const float* color_perimeters() { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow - static const float* color_infill() { static float color[4] = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish - static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish - - // For cloring by a tool, return a parsed color. - bool color_by_tool() const { return tool_colors != nullptr; } - size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } - const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } - int volume_idx(int extruder, int feature) const - { - return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(extruder - 1, 0)) : feature; - } - } ctxt; - - ctxt.shifted_copies = &print_object._shifted_copies; - - // order layers by print_z - ctxt.layers.reserve(print_object.layers.size() + print_object.support_layers.size()); - for (const Layer *layer : print_object.layers) - ctxt.layers.push_back(layer); - for (const Layer *layer : print_object.support_layers) - ctxt.layers.push_back(layer); - std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; }); - - // Maximum size of an allocation block: 32MB / sizeof(float) - ctxt.has_perimeters = print_object.state.is_done(posPerimeters); - ctxt.has_infill = print_object.state.is_done(posInfill); - ctxt.has_support = print_object.state.is_done(posSupportMaterial); - ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; - - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; - - //FIXME Improve the heuristics for a grain size. - size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); - tbb::spin_mutex new_volume_mutex; - auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { - auto *volume = new GLVolume(color); - new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; - m_volumes.volumes.emplace_back(volume); - new_volume_mutex.unlock(); - return volume; - }; - const size_t volumes_cnt_initial = m_volumes.volumes.size(); - std::vector volumes_per_thread(ctxt.layers.size()); - tbb::parallel_for( - tbb::blocked_range(0, ctxt.layers.size(), grain_size), - [&ctxt, &new_volume](const tbb::blocked_range& range) { - std::vector vols; - if (ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) - vols.emplace_back(new_volume(ctxt.color_tool(i))); - } - else - vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; - for (GLVolume *vol : vols) - vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { - const Layer *layer = ctxt.layers[idx_layer]; - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.print_zs.empty() || vol.print_zs.back() != layer->print_z) { - vol.print_zs.push_back(layer->print_z); - vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); - vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); - } - } - for (const Point © : *ctxt.shifted_copies) { - for (const LayerRegion *layerm : layer->regions) { - if (ctxt.has_perimeters) - _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, - *vols[ctxt.volume_idx(layerm->region()->config.perimeter_extruder.value, 0)]); - if (ctxt.has_infill) { - for (const ExtrusionEntity *ee : layerm->fills.entities) { - // fill represents infill extrusions of a single island. - const auto *fill = dynamic_cast(ee); - if (!fill->entities.empty()) - _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, - *vols[ctxt.volume_idx( - is_solid_infill(fill->entities.front()->role()) ? - layerm->region()->config.solid_infill_extruder : - layerm->region()->config.infill_extruder, - 1)]); - } - } - } - if (ctxt.has_support) { - const SupportLayer *support_layer = dynamic_cast(layer); - if (support_layer) { - for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) - _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, - *vols[ctxt.volume_idx( - (extrusion_entity->role() == erSupportMaterial) ? - support_layer->object()->config.support_material_extruder : - support_layer->object()->config.support_material_interface_extruder, - 2)]); - } - } - } - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Store the vertex arrays and restart their containers, - vols[i] = new_volume(vol.color); - GLVolume &vol_new = *vols[i]; - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol.indexed_vertex_array = vol_new.indexed_vertex_array; - // Finalize a bounding box of the old GLVolume. - vol.bounding_box = vol.indexed_vertex_array.bounding_box(); - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - } - } - } - for (GLVolume *vol : vols) { - vol->bounding_box = vol->indexed_vertex_array.bounding_box(); - vol->indexed_vertex_array.shrink_to_fit(); - } - }); - - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results"; - // Remove empty volumes from the newly added volumes. - m_volumes.volumes.erase( - std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - m_volumes.volumes.end()); - for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) - m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); - - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; -} - -void GLCanvas3D::load_wipe_tower_toolpaths(const std::vector& str_tool_colors) -{ - if ((m_print == nullptr) || m_print->m_wipe_tower_tool_changes.empty()) - return; - - if (!m_print->state.is_done(psWipeTower)) - return; - - std::vector tool_colors = _parse_colors(str_tool_colors); - - struct Ctxt - { - const Print *print; - const std::vector *tool_colors; - - // Number of vertices (each vertex is 6x4=24 bytes long) - static const size_t alloc_size_max() { return 131072; } // 3.15MB - static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } - - static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish - - // For cloring by a tool, return a parsed color. - bool color_by_tool() const { return tool_colors != nullptr; } - size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } - const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } - int volume_idx(int tool, int feature) const - { - return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(tool, 0)) : feature; - } - - const std::vector& tool_change(size_t idx) { - return priming.empty() ? - ((idx == print->m_wipe_tower_tool_changes.size()) ? final : print->m_wipe_tower_tool_changes[idx]) : - ((idx == 0) ? priming : (idx == print->m_wipe_tower_tool_changes.size() + 1) ? final : print->m_wipe_tower_tool_changes[idx - 1]); - } - std::vector priming; - std::vector final; - } ctxt; - - ctxt.print = m_print; - ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; - if (m_print->m_wipe_tower_priming) - ctxt.priming.emplace_back(*m_print->m_wipe_tower_priming.get()); - if (m_print->m_wipe_tower_final_purge) - ctxt.final.emplace_back(*m_print->m_wipe_tower_final_purge.get()); - - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; - - //FIXME Improve the heuristics for a grain size. - size_t n_items = m_print->m_wipe_tower_tool_changes.size() + (ctxt.priming.empty() ? 0 : 1); - size_t grain_size = std::max(n_items / 128, size_t(1)); - tbb::spin_mutex new_volume_mutex; - auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { - auto *volume = new GLVolume(color); - new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; - m_volumes.volumes.emplace_back(volume); - new_volume_mutex.unlock(); - return volume; - }; - const size_t volumes_cnt_initial = m_volumes.volumes.size(); - std::vector volumes_per_thread(n_items); - tbb::parallel_for( - tbb::blocked_range(0, n_items, grain_size), - [&ctxt, &new_volume](const tbb::blocked_range& range) { - // Bounding box of this slab of a wipe tower. - std::vector vols; - if (ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) - vols.emplace_back(new_volume(ctxt.color_tool(i))); - } - else - vols = { new_volume(ctxt.color_support()) }; - for (GLVolume *volume : vols) - volume->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { - const std::vector &layer = ctxt.tool_change(idx_layer); - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { - vol.print_zs.push_back(layer.front().print_z); - vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); - vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); - } - } - for (const WipeTower::ToolChangeResult &extrusions : layer) { - for (size_t i = 1; i < extrusions.extrusions.size();) { - const WipeTower::Extrusion &e = extrusions.extrusions[i]; - if (e.width == 0.) { - ++i; - continue; - } - size_t j = i + 1; - if (ctxt.color_by_tool()) - for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].tool == e.tool && extrusions.extrusions[j].width > 0.f; ++j); - else - for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].width > 0.f; ++j); - size_t n_lines = j - i; - Lines lines; - std::vector widths; - std::vector heights; - lines.reserve(n_lines); - widths.reserve(n_lines); - heights.assign(n_lines, extrusions.layer_height); - for (; i < j; ++i) { - const WipeTower::Extrusion &e = extrusions.extrusions[i]; - assert(e.width > 0.f); - const WipeTower::Extrusion &e_prev = *(&e - 1); - lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y)); - widths.emplace_back(e.width); - } - _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, - *vols[ctxt.volume_idx(e.tool, 0)]); - } - } - } - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Store the vertex arrays and restart their containers, - vols[i] = new_volume(vol.color); - GLVolume &vol_new = *vols[i]; - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol.indexed_vertex_array = vol_new.indexed_vertex_array; - // Finalize a bounding box of the old GLVolume. - vol.bounding_box = vol.indexed_vertex_array.bounding_box(); - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - } - } - for (GLVolume *vol : vols) { - vol->bounding_box = vol->indexed_vertex_array.bounding_box(); - vol->indexed_vertex_array.shrink_to_fit(); - } - }); - - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results"; - // Remove empty volumes from the newly added volumes. - m_volumes.volumes.erase( - std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - m_volumes.volumes.end()); - for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) - m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); - - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; -} - void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const std::vector& str_tool_colors) { if ((m_canvas != nullptr) && (m_print != nullptr)) @@ -2723,12 +2357,31 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const _load_shells(); } + _update_toolpath_volumes_outside_state(); } _update_gcode_volumes_visibility(preview_data); + _show_warning_texture_if_needed(); } } +void GLCanvas3D::load_preview(const std::vector& str_tool_colors) +{ + if (m_print == nullptr) + return; + + _load_print_toolpaths(); + _load_wipe_tower_toolpaths(str_tool_colors); + for (const PrintObject* object : m_print->objects) + { + if (object != nullptr) + _load_print_object_toolpaths(*object, str_tool_colors); + } + _update_toolpath_volumes_outside_state(); + _show_warning_texture_if_needed(); + reset_legend_texture(); +} + void GLCanvas3D::register_on_viewport_changed_callback(void* callback) { if (callback != nullptr) @@ -4112,6 +3765,372 @@ int GLCanvas3D::_get_first_selected_volume_id() const return -1; } +void GLCanvas3D::_load_print_toolpaths() +{ + // ensures this canvas is current + if (!set_current()) + return; + + if (m_print == nullptr) + return; + + if (!m_print->state.is_done(psSkirt) || !m_print->state.is_done(psBrim)) + return; + + if (!m_print->has_skirt() && (m_print->config.brim_width.value == 0)) + return; + + const float color[] = { 0.5f, 1.0f, 0.5f, 1.0f }; // greenish + + // number of skirt layers + size_t total_layer_count = 0; + for (const PrintObject* print_object : m_print->objects) + { + total_layer_count = std::max(total_layer_count, print_object->total_layer_count()); + } + size_t skirt_height = m_print->has_infinite_skirt() ? total_layer_count : std::min(m_print->config.skirt_height.value, total_layer_count); + if ((skirt_height == 0) && (m_print->config.brim_width.value > 0)) + skirt_height = 1; + + // get first skirt_height layers (maybe this should be moved to a PrintObject method?) + const PrintObject* object0 = m_print->objects.front(); + std::vector print_zs; + print_zs.reserve(skirt_height * 2); + for (size_t i = 0; i < std::min(skirt_height, object0->layers.size()); ++i) + { + print_zs.push_back(float(object0->layers[i]->print_z)); + } + //FIXME why there are support layers? + for (size_t i = 0; i < std::min(skirt_height, object0->support_layers.size()); ++i) + { + print_zs.push_back(float(object0->support_layers[i]->print_z)); + } + sort_remove_duplicates(print_zs); + if (print_zs.size() > skirt_height) + print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); + + m_volumes.volumes.emplace_back(new GLVolume(color)); + GLVolume& volume = *m_volumes.volumes.back(); + for (size_t i = 0; i < skirt_height; ++i) { + volume.print_zs.push_back(print_zs[i]); + volume.offsets.push_back(volume.indexed_vertex_array.quad_indices.size()); + volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size()); + if (i == 0) + _3DScene::extrusionentity_to_verts(m_print->brim, print_zs[i], Point(0, 0), volume); + + _3DScene::extrusionentity_to_verts(m_print->skirt, print_zs[i], Point(0, 0), volume); + } + volume.bounding_box = volume.indexed_vertex_array.bounding_box(); + volume.indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); +} + +void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector& str_tool_colors) +{ + std::vector tool_colors = _parse_colors(str_tool_colors); + + struct Ctxt + { + const Points *shifted_copies; + std::vector layers; + bool has_perimeters; + bool has_infill; + bool has_support; + const std::vector* tool_colors; + + // Number of vertices (each vertex is 6x4=24 bytes long) + static const size_t alloc_size_max() { return 131072; } // 3.15MB + // static const size_t alloc_size_max () { return 65536; } // 1.57MB + // static const size_t alloc_size_max () { return 32768; } // 786kB + static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } + + static const float* color_perimeters() { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow + static const float* color_infill() { static float color[4] = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish + static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish + + // For cloring by a tool, return a parsed color. + bool color_by_tool() const { return tool_colors != nullptr; } + size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } + const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } + int volume_idx(int extruder, int feature) const + { + return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(extruder - 1, 0)) : feature; + } + } ctxt; + + ctxt.shifted_copies = &print_object._shifted_copies; + + // order layers by print_z + ctxt.layers.reserve(print_object.layers.size() + print_object.support_layers.size()); + for (const Layer *layer : print_object.layers) + ctxt.layers.push_back(layer); + for (const Layer *layer : print_object.support_layers) + ctxt.layers.push_back(layer); + std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; }); + + // Maximum size of an allocation block: 32MB / sizeof(float) + ctxt.has_perimeters = print_object.state.is_done(posPerimeters); + ctxt.has_infill = print_object.state.is_done(posInfill); + ctxt.has_support = print_object.state.is_done(posSupportMaterial); + ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; + + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; + + //FIXME Improve the heuristics for a grain size. + size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); + tbb::spin_mutex new_volume_mutex; + auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { + auto *volume = new GLVolume(color); + new_volume_mutex.lock(); + volume->outside_printer_detection_enabled = false; + m_volumes.volumes.emplace_back(volume); + new_volume_mutex.unlock(); + return volume; + }; + const size_t volumes_cnt_initial = m_volumes.volumes.size(); + std::vector volumes_per_thread(ctxt.layers.size()); + tbb::parallel_for( + tbb::blocked_range(0, ctxt.layers.size(), grain_size), + [&ctxt, &new_volume](const tbb::blocked_range& range) { + std::vector vols; + if (ctxt.color_by_tool()) { + for (size_t i = 0; i < ctxt.number_tools(); ++i) + vols.emplace_back(new_volume(ctxt.color_tool(i))); + } + else + vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; + for (GLVolume *vol : vols) + vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { + const Layer *layer = ctxt.layers[idx_layer]; + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume &vol = *vols[i]; + if (vol.print_zs.empty() || vol.print_zs.back() != layer->print_z) { + vol.print_zs.push_back(layer->print_z); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); + } + } + for (const Point © : *ctxt.shifted_copies) { + for (const LayerRegion *layerm : layer->regions) { + if (ctxt.has_perimeters) + _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, + *vols[ctxt.volume_idx(layerm->region()->config.perimeter_extruder.value, 0)]); + if (ctxt.has_infill) { + for (const ExtrusionEntity *ee : layerm->fills.entities) { + // fill represents infill extrusions of a single island. + const auto *fill = dynamic_cast(ee); + if (!fill->entities.empty()) + _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, + *vols[ctxt.volume_idx( + is_solid_infill(fill->entities.front()->role()) ? + layerm->region()->config.solid_infill_extruder : + layerm->region()->config.infill_extruder, + 1)]); + } + } + } + if (ctxt.has_support) { + const SupportLayer *support_layer = dynamic_cast(layer); + if (support_layer) { + for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) + _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, + *vols[ctxt.volume_idx( + (extrusion_entity->role() == erSupportMaterial) ? + support_layer->object()->config.support_material_extruder : + support_layer->object()->config.support_material_interface_extruder, + 2)]); + } + } + } + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume &vol = *vols[i]; + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { + // Store the vertex arrays and restart their containers, + vols[i] = new_volume(vol.color); + GLVolume &vol_new = *vols[i]; + // Assign the large pre-allocated buffers to the new GLVolume. + vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); + // Copy the content back to the old GLVolume. + vol.indexed_vertex_array = vol_new.indexed_vertex_array; + // Finalize a bounding box of the old GLVolume. + vol.bounding_box = vol.indexed_vertex_array.bounding_box(); + // Clear the buffers, but keep them pre-allocated. + vol_new.indexed_vertex_array.clear(); + // Just make sure that clear did not clear the reserved memory. + vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + } + } + } + for (GLVolume *vol : vols) { + vol->bounding_box = vol->indexed_vertex_array.bounding_box(); + vol->indexed_vertex_array.shrink_to_fit(); + } + }); + + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results"; + // Remove empty volumes from the newly added volumes. + m_volumes.volumes.erase( + std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), + [](const GLVolume *volume) { return volume->empty(); }), + m_volumes.volumes.end()); + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) + m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); + + BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; +} + +void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_tool_colors) +{ + if ((m_print == nullptr) || m_print->m_wipe_tower_tool_changes.empty()) + return; + + if (!m_print->state.is_done(psWipeTower)) + return; + + std::vector tool_colors = _parse_colors(str_tool_colors); + + struct Ctxt + { + const Print *print; + const std::vector *tool_colors; + + // Number of vertices (each vertex is 6x4=24 bytes long) + static const size_t alloc_size_max() { return 131072; } // 3.15MB + static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } + + static const float* color_support() { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish + + // For cloring by a tool, return a parsed color. + bool color_by_tool() const { return tool_colors != nullptr; } + size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } + const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } + int volume_idx(int tool, int feature) const + { + return this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(tool, 0)) : feature; + } + + const std::vector& tool_change(size_t idx) { + return priming.empty() ? + ((idx == print->m_wipe_tower_tool_changes.size()) ? final : print->m_wipe_tower_tool_changes[idx]) : + ((idx == 0) ? priming : (idx == print->m_wipe_tower_tool_changes.size() + 1) ? final : print->m_wipe_tower_tool_changes[idx - 1]); + } + std::vector priming; + std::vector final; + } ctxt; + + ctxt.print = m_print; + ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; + if (m_print->m_wipe_tower_priming) + ctxt.priming.emplace_back(*m_print->m_wipe_tower_priming.get()); + if (m_print->m_wipe_tower_final_purge) + ctxt.final.emplace_back(*m_print->m_wipe_tower_final_purge.get()); + + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; + + //FIXME Improve the heuristics for a grain size. + size_t n_items = m_print->m_wipe_tower_tool_changes.size() + (ctxt.priming.empty() ? 0 : 1); + size_t grain_size = std::max(n_items / 128, size_t(1)); + tbb::spin_mutex new_volume_mutex; + auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { + auto *volume = new GLVolume(color); + new_volume_mutex.lock(); + volume->outside_printer_detection_enabled = false; + m_volumes.volumes.emplace_back(volume); + new_volume_mutex.unlock(); + return volume; + }; + const size_t volumes_cnt_initial = m_volumes.volumes.size(); + std::vector volumes_per_thread(n_items); + tbb::parallel_for( + tbb::blocked_range(0, n_items, grain_size), + [&ctxt, &new_volume](const tbb::blocked_range& range) { + // Bounding box of this slab of a wipe tower. + std::vector vols; + if (ctxt.color_by_tool()) { + for (size_t i = 0; i < ctxt.number_tools(); ++i) + vols.emplace_back(new_volume(ctxt.color_tool(i))); + } + else + vols = { new_volume(ctxt.color_support()) }; + for (GLVolume *volume : vols) + volume->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { + const std::vector &layer = ctxt.tool_change(idx_layer); + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume &vol = *vols[i]; + if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { + vol.print_zs.push_back(layer.front().print_z); + vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); + vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); + } + } + for (const WipeTower::ToolChangeResult &extrusions : layer) { + for (size_t i = 1; i < extrusions.extrusions.size();) { + const WipeTower::Extrusion &e = extrusions.extrusions[i]; + if (e.width == 0.) { + ++i; + continue; + } + size_t j = i + 1; + if (ctxt.color_by_tool()) + for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].tool == e.tool && extrusions.extrusions[j].width > 0.f; ++j); + else + for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].width > 0.f; ++j); + size_t n_lines = j - i; + Lines lines; + std::vector widths; + std::vector heights; + lines.reserve(n_lines); + widths.reserve(n_lines); + heights.assign(n_lines, extrusions.layer_height); + for (; i < j; ++i) { + const WipeTower::Extrusion &e = extrusions.extrusions[i]; + assert(e.width > 0.f); + const WipeTower::Extrusion &e_prev = *(&e - 1); + lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y)); + widths.emplace_back(e.width); + } + _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, + *vols[ctxt.volume_idx(e.tool, 0)]); + } + } + } + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume &vol = *vols[i]; + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { + // Store the vertex arrays and restart their containers, + vols[i] = new_volume(vol.color); + GLVolume &vol_new = *vols[i]; + // Assign the large pre-allocated buffers to the new GLVolume. + vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); + // Copy the content back to the old GLVolume. + vol.indexed_vertex_array = vol_new.indexed_vertex_array; + // Finalize a bounding box of the old GLVolume. + vol.bounding_box = vol.indexed_vertex_array.bounding_box(); + // Clear the buffers, but keep them pre-allocated. + vol_new.indexed_vertex_array.clear(); + // Just make sure that clear did not clear the reserved memory. + vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + } + } + for (GLVolume *vol : vols) { + vol->bounding_box = vol->indexed_vertex_array.bounding_box(); + vol->indexed_vertex_array.shrink_to_fit(); + } + }); + + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results"; + // Remove empty volumes from the newly added volumes. + m_volumes.volumes.erase( + std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), + [](const GLVolume *volume) { return volume->empty(); }), + m_volumes.volumes.end()); + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) + m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_use_VBOs && m_initialized); + + BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; +} + static inline int hex_digit_to_int(const char c) { return @@ -4643,6 +4662,7 @@ void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& previe for (std::vector::iterator it = begin; it != end; ++it) { GLVolume* volume = *it; + // to avoid the shader to change the color of this volume if outside the print volume volume->outside_printer_detection_enabled = false; switch (m_gcode_preview_volume_index.first_volumes[i].type) @@ -4691,6 +4711,55 @@ void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& previe } } +void GLCanvas3D::_update_toolpath_volumes_outside_state() +{ + // tolerance to avoid false detection at bed edges + static const coordf_t tolerance_x = 0.05; + static const coordf_t tolerance_y = 0.05; + + BoundingBoxf3 print_volume; + if (m_config != nullptr) + { + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + if (opt != nullptr) + { + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + print_volume = BoundingBoxf3(Pointf3(unscale(bed_box_2D.min.x) - tolerance_x, unscale(bed_box_2D.min.y) - tolerance_y, 0.0), Pointf3(unscale(bed_box_2D.max.x) + tolerance_x, unscale(bed_box_2D.max.y) + tolerance_y, m_config->opt_float("max_print_height"))); + // Allow the objects to protrude below the print bed + print_volume.min.z = -1e10; + } + } + + for (GLVolume* volume : m_volumes.volumes) + { + volume->is_outside = (print_volume.radius() > 0.0) ? !print_volume.contains(volume->transformed_bounding_box()) : false; + } +} + +void GLCanvas3D::_show_warning_texture_if_needed() +{ + bool detected_outside = false; + for (const GLVolume* volume : m_volumes.volumes) + { + if ((volume != nullptr) && volume->is_outside) + { + detected_outside = true; + break; + } + } + + if (detected_outside) + { + enable_warning_texture(true); + _generate_warning_texture(L("Detected toolpath outside print volume")); + } + else + { + enable_warning_texture(false); + _reset_warning_texture(); + } +} + void GLCanvas3D::_on_move(const std::vector& volume_idxs) { if (m_model == nullptr) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index a9a6117ecc..d52d69eebf 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -559,16 +559,8 @@ public: void reload_scene(bool force); - // Create 3D thick extrusion lines for a skirt and brim. - // Adds a new Slic3r::GUI::3DScene::Volume to volumes. - void load_print_toolpaths(); - // Create 3D thick extrusion lines for object forming extrusions. - // Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes, - // one for perimeters, one for infill and one for supports. - void load_print_object_toolpaths(const PrintObject& print_object, const std::vector& str_tool_colors); - // Create 3D thick extrusion lines for wipe tower extrusions - void load_wipe_tower_toolpaths(const std::vector& str_tool_colors); void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector& str_tool_colors); + void load_preview(const std::vector& str_tool_colors); void register_on_viewport_changed_callback(void* callback); void register_on_double_click_callback(void* callback); @@ -652,6 +644,16 @@ private: int _get_first_selected_object_id() const; int _get_first_selected_volume_id() const; + // Create 3D thick extrusion lines for a skirt and brim. + // Adds a new Slic3r::GUI::3DScene::Volume to volumes. + void _load_print_toolpaths(); + // Create 3D thick extrusion lines for object forming extrusions. + // Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes, + // one for perimeters, one for infill and one for supports. + void _load_print_object_toolpaths(const PrintObject& print_object, const std::vector& str_tool_colors); + // Create 3D thick extrusion lines for wipe tower extrusions + void _load_wipe_tower_toolpaths(const std::vector& str_tool_colors); + // generates gcode extrusion paths geometry void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector& tool_colors); // generates gcode travel paths geometry @@ -667,6 +669,8 @@ private: void _load_shells(); // sets gcode geometry visibility according to user selection void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data); + void _update_toolpath_volumes_outside_state(); + void _show_warning_texture_if_needed(); void _on_move(const std::vector& volume_idxs); void _on_select(int volume_idx); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 5e9048d541..25733c7a26 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -516,30 +516,6 @@ void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) it->second->reload_scene(force); } -void GLCanvas3DManager::load_print_toolpaths(wxGLCanvas* canvas) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->load_print_toolpaths(); -} - -void GLCanvas3DManager::load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector& tool_colors) -{ - if (print_object == nullptr) - return; - - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->load_print_object_toolpaths(*print_object, tool_colors); -} - -void GLCanvas3DManager::load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->load_wipe_tower_toolpaths(str_tool_colors); -} - void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors) { if (preview_data == nullptr) @@ -550,6 +526,13 @@ void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePrevie it->second->load_gcode_preview(*preview_data, str_tool_colors); } +void GLCanvas3DManager::load_preview(wxGLCanvas* canvas, const std::vector& str_tool_colors) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->load_preview(str_tool_colors); +} + void GLCanvas3DManager::reset_legend_texture() { for (CanvasesMap::value_type& canvas : m_canvases) diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 32aa712d35..f27293273e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -132,10 +132,8 @@ public: void reload_scene(wxGLCanvas* canvas, bool force); - void load_print_toolpaths(wxGLCanvas* canvas); - void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector& tool_colors); - void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors); void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); + void load_preview(wxGLCanvas* canvas, const std::vector& str_tool_colors); void reset_legend_texture(); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 5c2f7df854..e094941462 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -657,27 +657,6 @@ reload_scene(canvas, force) CODE: _3DScene::reload_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), force); -void -load_print_toolpaths(canvas) - SV *canvas; - CODE: - _3DScene::load_print_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); - -void -load_print_object_toolpaths(canvas, print_object, tool_colors) - SV *canvas; - PrintObject *print_object; - std::vector tool_colors; - CODE: - _3DScene::load_print_object_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print_object, tool_colors); - -void -load_wipe_tower_toolpaths(canvas, tool_colors) - SV *canvas; - std::vector tool_colors; - CODE: - _3DScene::load_wipe_tower_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), tool_colors); - void load_gcode_preview(canvas, preview_data, str_tool_colors) SV *canvas; @@ -685,5 +664,12 @@ load_gcode_preview(canvas, preview_data, str_tool_colors) std::vector str_tool_colors; CODE: _3DScene::load_gcode_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), preview_data, str_tool_colors); - + +void +load_preview(canvas, str_tool_colors) + SV *canvas; + std::vector str_tool_colors; + CODE: + _3DScene::load_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), str_tool_colors); + %} From d8f5daf345d09e61a6e6fd48ad1d09d6d1b073fb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 24 Jul 2018 15:32:44 +0200 Subject: [PATCH 2/9] Fixed selection of object modified by gizmo --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 33 +++++++++----------------------- xs/src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 819f26609d..193ccd0687 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2715,7 +2715,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { update_gizmos_data(); m_gizmos.start_dragging(); - m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(); + m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); m_dirty = true; } else @@ -3736,32 +3736,17 @@ int GLCanvas3D::_get_first_selected_object_id() const return -1; } -int GLCanvas3D::_get_first_selected_volume_id() const +int GLCanvas3D::_get_first_selected_volume_id(int object_id) const { - if (m_print != nullptr) - { - int objects_count = (int)m_print->objects.size(); + int volume_id = -1; - for (const GLVolume* vol : m_volumes.volumes) - { - if ((vol != nullptr) && vol->selected) - { - int object_id = vol->select_group_id / 1000000; - // Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy. - if ((object_id < 10000) && (object_id < objects_count)) - { - int volume_id = 0; - for (int i = 0; i < object_id; ++i) - { - const PrintObject* obj = m_print->objects[i]; - const ModelObject* model = obj->model_object(); - volume_id += model->instances.size(); - } - return volume_id; - } - } - } + for (const GLVolume* vol : m_volumes.volumes) + { + ++volume_id; + if ((vol != nullptr) && vol->selected && (object_id == vol->select_group_id / 1000000)) + return volume_id; } + return -1; } diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index d52d69eebf..0d8cf8855e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -642,7 +642,7 @@ private: void _stop_timer(); int _get_first_selected_object_id() const; - int _get_first_selected_volume_id() const; + int _get_first_selected_volume_id(int object_id) const; // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. From 2107ea7702d56810c584f3fcafff5555458a86f9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 25 Jul 2018 08:40:34 +0200 Subject: [PATCH 3/9] Fixed selection of multimaterial objects --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 193ccd0687..3ee1fdb02c 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2816,7 +2816,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { if (v != nullptr) { - if ((m_mouse.drag.move_with_shift && (v->select_group_id == group_id)) || (v->drag_group_id == group_id)) + if ((m_mouse.drag.move_with_shift && (v->select_group_id == group_id)) || (!m_mouse.drag.move_with_shift && (v->drag_group_id == group_id))) volumes.push_back(v); } } From 4243c7d84aff757108d365c147955210c7058b86 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 25 Jul 2018 09:42:03 +0200 Subject: [PATCH 4/9] Removed 2D panel --- lib/Slic3r/GUI/Plater.pm | 157 ++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index c0718c77be..0433deac66 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -128,8 +128,8 @@ sub new { } $_->set_scaling_factor($scale) for @{ $model_object->instances }; - $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%"); - $object->transform_thumbnail($self->{model}, $obj_idx); + $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%"); +# $object->transform_thumbnail($self->{model}, $obj_idx); #update print and start background processing $self->{print}->add_model_object($model_object, $obj_idx); @@ -203,13 +203,13 @@ sub new { Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); }); } - # Initialize 2D preview canvas - $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config}); - $self->{preview_notebook}->AddPage($self->{canvas}, L('2D')); - $self->{canvas}->on_select_object($on_select_object); - $self->{canvas}->on_double_click($on_double_click); - $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); }); - $self->{canvas}->on_instances_moved($on_instances_moved); +# # Initialize 2D preview canvas +# $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config}); +# $self->{preview_notebook}->AddPage($self->{canvas}, L('2D')); +# $self->{canvas}->on_select_object($on_select_object); +# $self->{canvas}->on_double_click($on_double_click); +# $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); }); +# $self->{canvas}->on_instances_moved($on_instances_moved); # Initialize 3D toolpaths preview if ($Slic3r::GUI::have_OpenGL) { @@ -401,7 +401,8 @@ sub new { $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self)) for grep defined($_), - $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list}; + $self, $self->{canvas3D}, $self->{preview3D}, $self->{list}; +# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list}; EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub { my ($self, $event) = @_; @@ -432,7 +433,7 @@ sub new { }); } - $self->{canvas}->update_bed_size; +# $self->{canvas}->update_bed_size; if ($self->{canvas3D}) { Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape); Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D}); @@ -847,8 +848,8 @@ sub load_model_objects { $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count); $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%"); - - $self->reset_thumbnail($obj_idx); + +# $self->reset_thumbnail($obj_idx); } $self->arrange if $need_arrange; $self->update; @@ -1057,7 +1058,7 @@ sub rotate { $inst->set_rotation($rotation); Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); } - $object->transform_thumbnail($self->{model}, $obj_idx); +# $object->transform_thumbnail($self->{model}, $obj_idx); } else { # rotation around X and Y needs to be performed on mesh # so we first apply any Z rotation @@ -1067,9 +1068,9 @@ sub rotate { } $model_object->rotate(deg2rad($angle), $axis); - # realign object to Z = 0 - $model_object->center_around_origin; - $self->reset_thumbnail($obj_idx); +# # realign object to Z = 0 +# $model_object->center_around_origin; +# $self->reset_thumbnail($obj_idx); } # update print and start background processing @@ -1097,9 +1098,9 @@ sub mirror { $model_object->mirror($axis); - # realign object to Z = 0 - $model_object->center_around_origin; - $self->reset_thumbnail($obj_idx); +# # realign object to Z = 0 +# $model_object->center_around_origin; +# $self->reset_thumbnail($obj_idx); # update print and start background processing $self->stop_background_process; @@ -1149,7 +1150,7 @@ sub changescale { #FIXME Scale the layer height profile when $axis == Z? #FIXME Scale the layer height ranges $axis == Z? # object was already aligned to Z = 0, so no need to realign it - $self->reset_thumbnail($obj_idx); +# $self->reset_thumbnail($obj_idx); } else { my $scale; if ($tosize) { @@ -1173,7 +1174,7 @@ sub changescale { $range->[1] *= $variation; } $_->set_scaling_factor($scale) for @{ $model_object->instances }; - $object->transform_thumbnail($self->{model}, $obj_idx); +# $object->transform_thumbnail($self->{model}, $obj_idx); } # update print and start background processing @@ -1804,10 +1805,10 @@ sub _get_export_file { return $output_file; } -sub reset_thumbnail { - my ($self, $obj_idx) = @_; - $self->{objects}[$obj_idx]->thumbnail(undef); -} +#sub reset_thumbnail { +# my ($self, $obj_idx) = @_; +# $self->{objects}[$obj_idx]->thumbnail(undef); +#} # this method gets called whenever print center is changed or the objects' bounding box changes # (i.e. when an object is added/removed/moved/rotated/scaled) @@ -1831,7 +1832,7 @@ sub update { $self->resume_background_process; } - $self->{canvas}->reload_scene if $self->{canvas}; +# $self->{canvas}->reload_scene if $self->{canvas}; my $selections = $self->collect_selections; Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0); @@ -1888,7 +1889,7 @@ sub on_config_change { foreach my $opt_key (@{$self->{config}->diff($config)}) { $self->{config}->set($opt_key, $config->get($opt_key)); if ($opt_key eq 'bed_shape') { - $self->{canvas}->update_bed_size; +# $self->{canvas}->update_bed_size; Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D}; Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D}; $update_scheduled = 1; @@ -1948,7 +1949,7 @@ sub list_item_deselected { $self->{_lecursor} = Wx::BusyCursor->new(); if ($self->{list}->GetFirstSelected == -1) { $self->select_object(undef); - $self->{canvas}->Refresh; +# $self->{canvas}->Refresh; Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D}; Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D}; } @@ -1961,7 +1962,7 @@ sub list_item_selected { $self->{_lecursor} = Wx::BusyCursor->new(); my $obj_idx = $event->GetIndex; $self->select_object($obj_idx); - $self->{canvas}->Refresh; +# $self->{canvas}->Refresh; if ($self->{canvas3D}) { my $selections = $self->collect_selections; Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections); @@ -2058,19 +2059,19 @@ sub object_settings_dialog { $self->pause_background_process; $dlg->ShowModal; - # update thumbnail since parts may have changed - if ($dlg->PartsChanged) { - # recenter and re-align to Z = 0 - $model_object->center_around_origin; - $self->reset_thumbnail($obj_idx); - } +# # update thumbnail since parts may have changed +# if ($dlg->PartsChanged) { +# # recenter and re-align to Z = 0 +# $model_object->center_around_origin; +# $self->reset_thumbnail($obj_idx); +# } # update print if ($dlg->PartsChanged || $dlg->PartSettingsChanged) { $self->stop_background_process; $self->{print}->reload_object($obj_idx); $self->schedule_background_process; - $self->{canvas}->reload_scene if $self->{canvas}; +# $self->{canvas}->reload_scene if $self->{canvas}; my $selections = $self->collect_selections; Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0); @@ -2356,48 +2357,48 @@ package Slic3r::GUI::Plater::Object; use Moo; has 'name' => (is => 'rw', required => 1); -has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms -has 'transformed_thumbnail' => (is => 'rw'); -has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units +#has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms +#has 'transformed_thumbnail' => (is => 'rw'); +#has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units has 'selected' => (is => 'rw', default => sub { 0 }); -sub make_thumbnail { - my ($self, $model, $obj_idx) = @_; - # make method idempotent - $self->thumbnail->clear; - # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. - my $mesh = $model->objects->[$obj_idx]->raw_mesh; -#FIXME The "correct" variant could be extremely slow. -# if ($mesh->facets_count <= 5000) { -# # remove polygons with area <= 1mm -# my $area_threshold = Slic3r::Geometry::scale 1; -# $self->thumbnail->append( -# grep $_->area >= $area_threshold, -# @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons -# ); -# $self->thumbnail->simplify(0.5); -# } else { - my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull); - $self->thumbnail->append($convex_hull); -# } - return $self->thumbnail; -} - -sub transform_thumbnail { - my ($self, $model, $obj_idx) = @_; - - return unless defined $self->thumbnail; - - my $model_object = $model->objects->[$obj_idx]; - my $model_instance = $model_object->instances->[0]; - - # the order of these transformations MUST be the same everywhere, including - # in Slic3r::Print->add_model_object() - my $t = $self->thumbnail->clone; - $t->rotate($model_instance->rotation, Slic3r::Point->new(0,0)); - $t->scale($model_instance->scaling_factor); - - $self->transformed_thumbnail($t); -} +#sub make_thumbnail { +# my ($self, $model, $obj_idx) = @_; +# # make method idempotent +# $self->thumbnail->clear; +# # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. +# my $mesh = $model->objects->[$obj_idx]->raw_mesh; +##FIXME The "correct" variant could be extremely slow. +## if ($mesh->facets_count <= 5000) { +## # remove polygons with area <= 1mm +## my $area_threshold = Slic3r::Geometry::scale 1; +## $self->thumbnail->append( +## grep $_->area >= $area_threshold, +## @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons +## ); +## $self->thumbnail->simplify(0.5); +## } else { +# my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull); +# $self->thumbnail->append($convex_hull); +## } +# return $self->thumbnail; +#} +# +#sub transform_thumbnail { +# my ($self, $model, $obj_idx) = @_; +# +# return unless defined $self->thumbnail; +# +# my $model_object = $model->objects->[$obj_idx]; +# my $model_instance = $model_object->instances->[0]; +# +# # the order of these transformations MUST be the same everywhere, including +# # in Slic3r::Print->add_model_object() +# my $t = $self->thumbnail->clone; +# $t->rotate($model_instance->rotation, Slic3r::Point->new(0,0)); +# $t->scale($model_instance->scaling_factor); +# +# $self->transformed_thumbnail($t); +#} 1; From efbc1cce2511c0a47d0dee7fd45df897e27ca982 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 25 Jul 2018 11:49:38 +0200 Subject: [PATCH 5/9] Fixed rotate gizmo update with multimaterial objects --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 42 ++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 3ee1fdb02c..5ad9da9c4e 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2887,7 +2887,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!volumes.empty()) { - const BoundingBoxf3& bb = volumes[0]->transformed_bounding_box(); + BoundingBoxf3 bb; + for (const GLVolume* volume : volumes) + { + bb.merge(volume->transformed_bounding_box()); + } const Pointf3& size = bb.size(); m_on_update_geometry_info_callback.call(size.x, size.y, size.z, m_gizmos.get_scale()); } @@ -3155,11 +3159,45 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box() const BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const { BoundingBoxf3 bb; + + std::vector selected_volumes; for (const GLVolume* volume : m_volumes.volumes) { if ((volume != nullptr) && !volume->is_wipe_tower && volume->selected) - bb.merge(volume->transformed_bounding_box()); + selected_volumes.push_back(volume); } + + bool use_drag_group_id = selected_volumes.size() > 1; + if (use_drag_group_id) + { + int drag_group_id = selected_volumes[0]->drag_group_id; + for (const GLVolume* volume : selected_volumes) + { + if (drag_group_id != volume->drag_group_id) + { + use_drag_group_id = false; + break; + } + } + } + + if (use_drag_group_id) + { + for (const GLVolume* volume : selected_volumes) + { + bb.merge(volume->bounding_box); + } + + bb = bb.transformed(selected_volumes[0]->world_matrix()); + } + else + { + for (const GLVolume* volume : selected_volumes) + { + bb.merge(volume->transformed_bounding_box()); + } + } + return bb; } From dd014136b00569f9ad7f1ba72676b9f8d3d8fea6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 26 Jul 2018 12:51:31 +0200 Subject: [PATCH 6/9] Remove hovering on objects when mouse leaves 3D scene --- xs/src/slic3r/GUI/GLCanvas3D.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 5ad9da9c4e..79ec73625d 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -2678,6 +2678,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_2D_as_invalid(); #endif } + else if (evt.Leaving()) + { + // to remove hover when mouse goes out of this canvas + m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y); + render(); + } else if (evt.LeftDClick() && (m_hover_volume_id != -1)) m_on_double_click_callback.call(); else if (evt.LeftDown() || evt.RightDown()) From b5b7894a6f6ac57b3a3f2b2546fc1c98b77f4935 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 26 Jul 2018 13:12:09 +0200 Subject: [PATCH 7/9] Fixed color of all toolpaths when detected as out of print bed volume --- xs/src/slic3r/GUI/3DScene.cpp | 10 +++++----- xs/src/slic3r/GUI/3DScene.hpp | 4 ++-- xs/src/slic3r/GUI/GLCanvas3D.cpp | 4 ---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index e23641cb18..2d405e54ad 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -210,7 +210,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , selected(false) , is_active(true) , zoom_to_volumes(true) - , outside_printer_detection_enabled(true) + , shader_outside_printer_detection_enabled(false) , is_outside(false) , hover(false) , is_modifier(false) @@ -250,7 +250,7 @@ void GLVolume::set_render_color() set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4); else if (hover) set_render_color(HOVER_COLOR, 4); - else if (is_outside && outside_printer_detection_enabled) + else if (is_outside && shader_outside_printer_detection_enabled) set_render_color(OUTSIDE_COLOR, 4); else set_render_color(color, 4); @@ -441,7 +441,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]); if (detection_id != -1) - ::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0); + ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0); if (worldmatrix_id != -1) ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data()); @@ -460,7 +460,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]); if (detection_id != -1) - ::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0); + ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0); if (worldmatrix_id != -1) ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data()); @@ -633,7 +633,7 @@ std::vector GLVolumeCollection::load_object( v.extruder_id = extruder_id; } v.is_modifier = model_volume->modifier; - v.outside_printer_detection_enabled = !model_volume->modifier; + v.shader_outside_printer_detection_enabled = !model_volume->modifier; v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0)); v.set_angle_z(instance->rotation); v.set_scale_factor(instance->scaling_factor); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 0cd2d81f0e..242487195e 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -289,8 +289,8 @@ public: bool is_active; // Whether or not to use this volume when applying zoom_to_volumes() bool zoom_to_volumes; - // Wheter or not this volume is enabled for outside print volume detection. - bool outside_printer_detection_enabled; + // Wheter or not this volume is enabled for outside print volume detection in shader. + bool shader_outside_printer_detection_enabled; // Wheter or not this volume is outside print volume. bool is_outside; // Boolean: Is mouse over this object? diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 79ec73625d..6bca173755 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -3910,7 +3910,6 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; m_volumes.volumes.emplace_back(volume); new_volume_mutex.unlock(); return volume; @@ -4063,7 +4062,6 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; m_volumes.volumes.emplace_back(volume); new_volume_mutex.unlock(); return volume; @@ -4691,8 +4689,6 @@ void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& previe for (std::vector::iterator it = begin; it != end; ++it) { GLVolume* volume = *it; - // to avoid the shader to change the color of this volume if outside the print volume - volume->outside_printer_detection_enabled = false; switch (m_gcode_preview_volume_index.first_volumes[i].type) { From c2ab8c2ae3af6bd5489a7f1525b65fb51862b724 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 27 Jul 2018 08:49:58 +0200 Subject: [PATCH 8/9] Out of print volume detection for extrusion toolpaths only --- xs/src/slic3r/GUI/3DScene.cpp | 1 + xs/src/slic3r/GUI/3DScene.hpp | 2 ++ xs/src/slic3r/GUI/GLCanvas3D.cpp | 13 +++++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 2d405e54ad..601d10aaa0 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -215,6 +215,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , hover(false) , is_modifier(false) , is_wipe_tower(false) + , is_extrusion_path(false) , tverts_range(0, size_t(-1)) , qverts_range(0, size_t(-1)) { diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 242487195e..a1227d8ddb 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -299,6 +299,8 @@ public: bool is_modifier; // Wheter or not this volume has been generated from the wipe tower bool is_wipe_tower; + // Wheter or not this volume has been generated from an extrusion path + bool is_extrusion_path; // Interleaved triangles & normals with indexed triangles & quads. GLIndexedVertexArray indexed_vertex_array; diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 6bca173755..bcd4e65ba6 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1828,7 +1828,6 @@ unsigned int GLCanvas3D::get_volumes_count() const void GLCanvas3D::reset_volumes() { - if (!m_volumes.empty()) { // ensures this canvas is current @@ -1839,6 +1838,9 @@ void GLCanvas3D::reset_volumes() m_volumes.clear(); m_dirty = true; } + + enable_warning_texture(false); + _reset_warning_texture(); } void GLCanvas3D::deselect_volumes() @@ -2377,6 +2379,12 @@ void GLCanvas3D::load_preview(const std::vector& str_tool_colors) if (object != nullptr) _load_print_object_toolpaths(*object, str_tool_colors); } + + for (GLVolume* volume : m_volumes.volumes) + { + volume->is_extrusion_path = true; + } + _update_toolpath_volumes_outside_state(); _show_warning_texture_if_needed(); reset_legend_texture(); @@ -4276,6 +4284,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat if (volume != nullptr) { filter.volume = volume; + volume->is_extrusion_path = true; m_volumes.volumes.emplace_back(volume); } else @@ -4757,7 +4766,7 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() for (GLVolume* volume : m_volumes.volumes) { - volume->is_outside = (print_volume.radius() > 0.0) ? !print_volume.contains(volume->transformed_bounding_box()) : false; + volume->is_outside = ((print_volume.radius() > 0.0) && volume->is_extrusion_path) ? !print_volume.contains(volume->bounding_box) : false; } } From 3a1ec8285eef3fd1709b40abd0504778a370fcbb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 27 Jul 2018 09:38:39 +0200 Subject: [PATCH 9/9] Reddish background when detected out of print volume toolpaths --- lib/Slic3r/GUI/Plater.pm | 1 + xs/src/slic3r/GUI/3DScene.cpp | 5 +++ xs/src/slic3r/GUI/3DScene.hpp | 1 + xs/src/slic3r/GUI/GLCanvas3D.cpp | 49 ++++++++++++++++--------- xs/src/slic3r/GUI/GLCanvas3D.hpp | 4 ++ xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 7 ++++ xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 1 + xs/xsp/GUI_3DScene.xsp | 7 ++++ 8 files changed, 57 insertions(+), 18 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 0433deac66..3bcf3b3e6b 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -215,6 +215,7 @@ sub new { if ($Slic3r::GUI::have_OpenGL) { $self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config}); Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1); + Slic3r::GUI::_3DScene::enable_dynamic_background($self->{preview3D}->canvas, 1); Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); }); $self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview')); $self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 601d10aaa0..6ec3391539 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1787,6 +1787,11 @@ void _3DScene::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable) s_canvas_mgr.enable_force_zoom_to_bed(canvas, enable); } +void _3DScene::enable_dynamic_background(wxGLCanvas* canvas, bool enable) +{ + s_canvas_mgr.enable_dynamic_background(canvas, enable); +} + void _3DScene::allow_multisample(wxGLCanvas* canvas, bool allow) { s_canvas_mgr.allow_multisample(canvas, allow); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index a1227d8ddb..a2050e5a15 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -499,6 +499,7 @@ public: static void enable_gizmos(wxGLCanvas* canvas, bool enable); static void enable_shader(wxGLCanvas* canvas, bool enable); static void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable); + static void enable_dynamic_background(wxGLCanvas* canvas, bool enable); static void allow_multisample(wxGLCanvas* canvas, bool allow); static void zoom_to_bed(wxGLCanvas* canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index bcd4e65ba6..d53436969c 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -51,6 +51,9 @@ static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; +static const float DEFAULT_BG_COLOR[3] = { 10.0f / 255.0f, 98.0f / 255.0f, 144.0f / 255.0f }; +static const float ERROR_BG_COLOR[3] = { 144.0f / 255.0f, 49.0f / 255.0f, 10.0f / 255.0f }; + namespace Slic3r { namespace GUI { @@ -1703,6 +1706,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_picking_enabled(false) , m_moving_enabled(false) , m_shader_enabled(false) + , m_dynamic_background_enabled(false) , m_multisample_allowed(false) , m_color_by("volume") , m_select_by("object") @@ -2067,6 +2071,11 @@ void GLCanvas3D::enable_force_zoom_to_bed(bool enable) m_force_zoom_to_bed_enabled = enable; } +void GLCanvas3D::enable_dynamic_background(bool enable) +{ + m_dynamic_background_enabled = enable; +} + void GLCanvas3D::allow_multisample(bool allow) { m_multisample_allowed = allow; @@ -3431,8 +3440,6 @@ void GLCanvas3D::_render_background() const { ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - static const float COLOR[3] = { 10.0f / 255.0f, 98.0f / 255.0f, 144.0f / 255.0f }; - ::glPushMatrix(); ::glLoadIdentity(); ::glMatrixMode(GL_PROJECTION); @@ -3444,11 +3451,16 @@ void GLCanvas3D::_render_background() const ::glBegin(GL_QUADS); ::glColor3f(0.0f, 0.0f, 0.0f); - ::glVertex3f(-1.0f, -1.0f, 1.0f); - ::glVertex3f(1.0f, -1.0f, 1.0f); - ::glColor3f(COLOR[0], COLOR[1], COLOR[2]); - ::glVertex3f(1.0f, 1.0f, 1.0f); - ::glVertex3f(-1.0f, 1.0f, 1.0f); + ::glVertex2f(-1.0f, -1.0f); + ::glVertex2f(1.0f, -1.0f); + + if (m_dynamic_background_enabled && _is_any_volume_outside()) + ::glColor3f(ERROR_BG_COLOR[0], ERROR_BG_COLOR[1], ERROR_BG_COLOR[2]); + else + ::glColor3f(DEFAULT_BG_COLOR[0], DEFAULT_BG_COLOR[1], DEFAULT_BG_COLOR[2]); + + ::glVertex2f(1.0f, 1.0f); + ::glVertex2f(-1.0f, 1.0f); ::glEnd(); ::glEnable(GL_DEPTH_TEST); @@ -4772,17 +4784,7 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() void GLCanvas3D::_show_warning_texture_if_needed() { - bool detected_outside = false; - for (const GLVolume* volume : m_volumes.volumes) - { - if ((volume != nullptr) && volume->is_outside) - { - detected_outside = true; - break; - } - } - - if (detected_outside) + if (_is_any_volume_outside()) { enable_warning_texture(true); _generate_warning_texture(L("Detected toolpath outside print volume")); @@ -4899,5 +4901,16 @@ void GLCanvas3D::_reset_warning_texture() m_warning_texture.reset(); } +bool GLCanvas3D::_is_any_volume_outside() const +{ + for (const GLVolume* volume : m_volumes.volumes) + { + if ((volume != nullptr) && volume->is_outside) + return true; + } + + return false; +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 0d8cf8855e..a874862613 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -449,6 +449,7 @@ private: bool m_picking_enabled; bool m_moving_enabled; bool m_shader_enabled; + bool m_dynamic_background_enabled; bool m_multisample_allowed; std::string m_color_by; @@ -539,6 +540,7 @@ public: void enable_gizmos(bool enable); void enable_shader(bool enable); void enable_force_zoom_to_bed(bool enable); + void enable_dynamic_background(bool enable); void allow_multisample(bool allow); void zoom_to_bed(); @@ -682,6 +684,8 @@ private: void _generate_warning_texture(const std::string& msg); void _reset_warning_texture(); + bool _is_any_volume_outside() const; + static std::vector _parse_colors(const std::vector& colors); }; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 25733c7a26..5249f6dc4f 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -418,6 +418,13 @@ void GLCanvas3DManager::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable it->second->enable_force_zoom_to_bed(enable); } +void GLCanvas3DManager::enable_dynamic_background(wxGLCanvas* canvas, bool enable) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->enable_dynamic_background(enable); +} + void GLCanvas3DManager::allow_multisample(wxGLCanvas* canvas, bool allow) { CanvasesMap::iterator it = _get_canvas(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index f27293273e..55c42fda69 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -112,6 +112,7 @@ public: void enable_gizmos(wxGLCanvas* canvas, bool enable); void enable_shader(wxGLCanvas* canvas, bool enable); void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable); + void enable_dynamic_background(wxGLCanvas* canvas, bool enable); void allow_multisample(wxGLCanvas* canvas, bool allow); void zoom_to_bed(wxGLCanvas* canvas); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index e094941462..a91f32d293 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -430,6 +430,13 @@ enable_force_zoom_to_bed(canvas, enable) CODE: _3DScene::enable_force_zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); +void +enable_dynamic_background(canvas, enable) + SV *canvas; + bool enable; + CODE: + _3DScene::enable_dynamic_background((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable); + void allow_multisample(canvas, allow) SV *canvas;