From a8254e005317bbd9c6b95cd211adf5a6dd1fb4bd Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 5 Jun 2018 14:09:36 +0200 Subject: [PATCH] Generation of preview paths moved to c++ --- lib/Slic3r/GUI/3DScene.pm | 62 +- lib/Slic3r/GUI/Plater/3DPreview.pm | 14 +- xs/src/slic3r/GUI/3DScene.cpp | 745 ++++++++++++------------ xs/src/slic3r/GUI/3DScene.hpp | 41 +- xs/src/slic3r/GUI/GLCanvas3D.cpp | 414 ++++++++++++- xs/src/slic3r/GUI/GLCanvas3D.hpp | 13 +- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 24 + xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 3 + xs/xsp/GUI_3DScene.xsp | 26 +- 9 files changed, 879 insertions(+), 463 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 1476e8c22..a55c4ab16 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -2199,56 +2199,36 @@ sub load_object { return @{$volume_indices}; } -# Create 3D thick extrusion lines for a skirt and brim. -# Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes. -sub load_print_toolpaths { - my ($self, $print, $colors) = @_; - #============================================================================================================================== - my $useVBOs = Slic3r::GUI::_3DScene::use_VBOs(); - $self->SetCurrent($self->GetContext) if $useVBOs; - Slic3r::GUI::_3DScene::_load_print_toolpaths($print, $self->volumes, $colors, $useVBOs) - if ($print->step_done(STEP_SKIRT) && $print->step_done(STEP_BRIM)); - +## Create 3D thick extrusion lines for a skirt and brim. +## Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes. +#sub load_print_toolpaths { +# my ($self, $print, $colors) = @_; +# # $self->SetCurrent($self->GetContext) if $self->UseVBOs; # Slic3r::GUI::_3DScene::_load_print_toolpaths($print, $self->volumes, $colors, $self->UseVBOs) # if ($print->step_done(STEP_SKIRT) && $print->step_done(STEP_BRIM)); -#============================================================================================================================== -} - -# 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. -sub load_print_object_toolpaths { - my ($self, $object, $colors) = @_; - -#============================================================================================================================== - my $useVBOs = Slic3r::GUI::_3DScene::use_VBOs(); - $self->SetCurrent($self->GetContext) if $useVBOs; - Slic3r::GUI::_3DScene::_load_print_object_toolpaths($object, $self->volumes, $colors, $useVBOs); - +#} +# +## 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. +#sub load_print_object_toolpaths { +# my ($self, $object, $colors) = @_; +# # $self->SetCurrent($self->GetContext) if $self->UseVBOs; # Slic3r::GUI::_3DScene::_load_print_object_toolpaths($object, $self->volumes, $colors, $self->UseVBOs); -#============================================================================================================================== -} - -# Create 3D thick extrusion lines for wipe tower extrusions. -sub load_wipe_tower_toolpaths { - my ($self, $print, $colors) = @_; - -#============================================================================================================================== - my $useVBOs = Slic3r::GUI::_3DScene::use_VBOs(); - $self->SetCurrent($self->GetContext) if $useVBOs; - Slic3r::GUI::_3DScene::_load_wipe_tower_toolpaths($print, $self->volumes, $colors, $useVBOs) - if ($print->step_done(STEP_WIPE_TOWER)); - +#} +# +## Create 3D thick extrusion lines for wipe tower extrusions. +#sub load_wipe_tower_toolpaths { +# my ($self, $print, $colors) = @_; +# # $self->SetCurrent($self->GetContext) if $self->UseVBOs; # Slic3r::GUI::_3DScene::_load_wipe_tower_toolpaths($print, $self->volumes, $colors, $self->UseVBOs) # if ($print->step_done(STEP_WIPE_TOWER)); -#============================================================================================================================== -} - -#============================================================================================================================== +#} +# #sub load_gcode_preview { # my ($self, $print, $gcode_preview_data, $colors) = @_; # diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 9ea5069b4..7b713b46f 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -376,10 +376,18 @@ sub load_print { if ($self->gcode_preview_data->empty) { # load skirt and brim - $self->canvas->load_print_toolpaths($self->print, \@colors); - $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors); +#============================================================================================================================== + 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); +# $self->canvas->load_print_toolpaths($self->print, \@colors); +# $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors); +#============================================================================================================================== foreach my $object (@{$self->print->objects}) { - $self->canvas->load_print_object_toolpaths($object, \@colors); +#============================================================================================================================== + Slic3r::GUI::_3DScene::load_print_object_toolpaths($self->canvas, $object, \@colors); +# $self->canvas->load_print_object_toolpaths($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; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 47095e1b1..89b7d0a11 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1348,8 +1348,11 @@ static void point_to_indexed_vertex_array(const Point3& point, volume.push_triangle(idxs[0], idxs[3], idxs[4]); } -static void thick_lines_to_verts( - const Lines &lines, +//################################################################################################################## +void _3DScene::thick_lines_to_verts( +//static void thick_lines_to_verts( +//################################################################################################################## + const Lines &lines, const std::vector &widths, const std::vector &heights, bool closed, @@ -1359,7 +1362,10 @@ static void thick_lines_to_verts( thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array); } -static void thick_lines_to_verts(const Lines3& lines, +//################################################################################################################## +void _3DScene::thick_lines_to_verts(const Lines3& lines, +//static void thick_lines_to_verts(const Lines3& lines, +//################################################################################################################## const std::vector& widths, const std::vector& heights, bool closed, @@ -2010,6 +2016,21 @@ static inline std::vector parse_colors(const std::vector &sc } //################################################################################################################## +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); @@ -2102,366 +2123,366 @@ unsigned int _3DScene::finalize_warning_texture() return s_warning_texture.finalize(); } -// Create 3D thick extrusion lines for a skirt and brim. -// Adds a new Slic3r::GUI::3DScene::Volume to volumes. -void _3DScene::_load_print_toolpaths( - const Print *print, - GLVolumeCollection *volumes, - const std::vector &tool_colors, - bool use_VBOs) -{ - if (!print->has_skirt() && print->config.brim_width.value == 0) - return; - - const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish - - // number of skirt layers - size_t total_layer_count = 0; - for (const PrintObject *print_object : print->objects) - total_layer_count = std::max(total_layer_count, print_object->total_layer_count()); - size_t skirt_height = print->has_infinite_skirt() ? - total_layer_count : - std::min(print->config.skirt_height.value, total_layer_count); - if (skirt_height == 0 && 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 = 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()); - - volumes->volumes.emplace_back(new GLVolume(color)); - GLVolume &volume = *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) - extrusionentity_to_verts(print->brim, print_zs[i], Point(0, 0), volume); - extrusionentity_to_verts(print->skirt, print_zs[i], Point(0, 0), volume); - } - volume.bounding_box = volume.indexed_vertex_array.bounding_box(); - volume.indexed_vertex_array.finalize_geometry(use_VBOs); -} - -// 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 _3DScene::_load_print_object_toolpaths( - const PrintObject *print_object, - GLVolumeCollection *volumes, - const std::vector &tool_colors_str, - bool use_VBOs) -{ - std::vector tool_colors = parse_colors(tool_colors_str); - - 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 = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { - auto *volume = new GLVolume(color); - new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; - volumes->volumes.emplace_back(volume); - new_volume_mutex.unlock(); - return volume; - }; - const size_t volumes_cnt_initial = 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) - 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()) - 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) - 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. - volumes->volumes.erase( - std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - volumes->volumes.end()); - for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i) - volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); - - BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; -} - -void _3DScene::_load_wipe_tower_toolpaths( - const Print *print, - GLVolumeCollection *volumes, - const std::vector &tool_colors_str, - bool use_VBOs) -{ - if (print->m_wipe_tower_tool_changes.empty()) - return; - - std::vector tool_colors = parse_colors(tool_colors_str); - - 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 = print; - ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; - if (print->m_wipe_tower_priming) - ctxt.priming.emplace_back(*print->m_wipe_tower_priming.get()); - if (print->m_wipe_tower_final_purge) - ctxt.final.emplace_back(*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 = 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 = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { - auto *volume = new GLVolume(color); - new_volume_mutex.lock(); - volume->outside_printer_detection_enabled = false; - volumes->volumes.emplace_back(volume); - new_volume_mutex.unlock(); - return volume; - }; - const size_t volumes_cnt_initial = 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); - } - 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. - volumes->volumes.erase( - std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(), - [](const GLVolume *volume) { return volume->empty(); }), - volumes->volumes.end()); - for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i) - volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); - - BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; -} - //################################################################################################################## +//// Create 3D thick extrusion lines for a skirt and brim. +//// Adds a new Slic3r::GUI::3DScene::Volume to volumes. +//void _3DScene::_load_print_toolpaths( +// const Print *print, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors, +// bool use_VBOs) +//{ +// if (!print->has_skirt() && print->config.brim_width.value == 0) +// return; +// +// const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish +// +// // number of skirt layers +// size_t total_layer_count = 0; +// for (const PrintObject *print_object : print->objects) +// total_layer_count = std::max(total_layer_count, print_object->total_layer_count()); +// size_t skirt_height = print->has_infinite_skirt() ? +// total_layer_count : +// std::min(print->config.skirt_height.value, total_layer_count); +// if (skirt_height == 0 && 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 = 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()); +// +// volumes->volumes.emplace_back(new GLVolume(color)); +// GLVolume &volume = *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) +// extrusionentity_to_verts(print->brim, print_zs[i], Point(0, 0), volume); +// extrusionentity_to_verts(print->skirt, print_zs[i], Point(0, 0), volume); +// } +// volume.bounding_box = volume.indexed_vertex_array.bounding_box(); +// volume.indexed_vertex_array.finalize_geometry(use_VBOs); +//} +// +//// 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 _3DScene::_load_print_object_toolpaths( +// const PrintObject *print_object, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors_str, +// bool use_VBOs) +//{ +// std::vector tool_colors = parse_colors(tool_colors_str); +// +// 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 = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { +// auto *volume = new GLVolume(color); +// new_volume_mutex.lock(); +// volume->outside_printer_detection_enabled = false; +// volumes->volumes.emplace_back(volume); +// new_volume_mutex.unlock(); +// return volume; +// }; +// const size_t volumes_cnt_initial = 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) +// 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()) +// 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) +// 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. +// volumes->volumes.erase( +// std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(), +// [](const GLVolume *volume) { return volume->empty(); }), +// volumes->volumes.end()); +// for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i) +// volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); +// +// BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; +//} +// +//void _3DScene::_load_wipe_tower_toolpaths( +// const Print *print, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors_str, +// bool use_VBOs) +//{ +// if (print->m_wipe_tower_tool_changes.empty()) +// return; +// +// std::vector tool_colors = parse_colors(tool_colors_str); +// +// 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 = print; +// ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors; +// if (print->m_wipe_tower_priming) +// ctxt.priming.emplace_back(*print->m_wipe_tower_priming.get()); +// if (print->m_wipe_tower_final_purge) +// ctxt.final.emplace_back(*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 = 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 = [volumes, &new_volume_mutex](const float *color) -> GLVolume* { +// auto *volume = new GLVolume(color); +// new_volume_mutex.lock(); +// volume->outside_printer_detection_enabled = false; +// volumes->volumes.emplace_back(volume); +// new_volume_mutex.unlock(); +// return volume; +// }; +// const size_t volumes_cnt_initial = 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); +// } +// 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. +// volumes->volumes.erase( +// std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(), +// [](const GLVolume *volume) { return volume->empty(); }), +// volumes->volumes.end()); +// for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i) +// volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs); +// +// BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; +//} +// //void _3DScene::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector& tool_colors, bool use_VBOs) //{ // // helper functions to select data in dependence of the extrusion view type diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 69530b84f..ee6547657 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -611,6 +611,9 @@ public: //################################################################################################################## //################################################################################################################## + 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_gcode_preview(const Print* print, const GCodePreviewData* preview_data, GLVolumeCollection* volumes, const std::vector& str_tool_colors, bool use_VBOs); //################################################################################################################## @@ -633,25 +636,29 @@ public: static void reset_warning_texture(); static unsigned int finalize_warning_texture(); - static void _load_print_toolpaths( - const Print *print, - GLVolumeCollection *volumes, - const std::vector &tool_colors, - bool use_VBOs); - - static void _load_print_object_toolpaths( - const PrintObject *print_object, - GLVolumeCollection *volumes, - const std::vector &tool_colors, - bool use_VBOs); - - static void _load_wipe_tower_toolpaths( - const Print *print, - GLVolumeCollection *volumes, - const std::vector &tool_colors_str, - bool use_VBOs); +//################################################################################################################## +// static void _load_print_toolpaths( +// const Print *print, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors, +// bool use_VBOs); +// +// static void _load_print_object_toolpaths( +// const PrintObject *print_object, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors, +// bool use_VBOs); +// +// static void _load_wipe_tower_toolpaths( +// const Print *print, +// GLVolumeCollection *volumes, +// const std::vector &tool_colors_str, +// bool use_VBOs); +//################################################################################################################## //################################################################################################################## + static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GLVolume& volume); + static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 37f1d6b50..a06079744 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -13,6 +13,11 @@ #include #include +#include +#include + +#include + #include #include @@ -1346,6 +1351,371 @@ void GLCanvas3D::set_toolpaths_range(double low, double high) m_volumes->set_range(low, high); } +void GLCanvas3D::load_print_toolpaths() +{ + if ((m_print == nullptr) || (m_volumes == 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; + + if (m_volumes == nullptr) + return; + + 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_volumes == nullptr) || (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_volumes != nullptr) && (m_print != nullptr)) @@ -2416,28 +2786,6 @@ static inline int hex_digit_to_int(const char c) (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1; } -std::vector GLCanvas3D::_parse_colors(const std::vector& colors) -{ - std::vector output(colors.size() * 4, 1.0f); - for (size_t i = 0; i < colors.size(); ++i) { - const std::string& color = colors[i]; - const char* c = color.data() + 1; - if ((color.size() == 7) && (color.front() == '#')) - { - for (size_t j = 0; j < 3; ++j) - { - int digit1 = hex_digit_to_int(*c++); - int digit2 = hex_digit_to_int(*c++); - if ((digit1 == -1) || (digit2 == -1)) - break; - - output[i * 4 + j] = float(digit1 * 16 + digit2) / 255.0f; - } - } - } - return output; -} - void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector& tool_colors) { // helper functions to select data in dependence of the extrusion view type @@ -3008,5 +3356,27 @@ void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& previe } } +std::vector GLCanvas3D::_parse_colors(const std::vector& colors) +{ + std::vector output(colors.size() * 4, 1.0f); + for (size_t i = 0; i < colors.size(); ++i) { + const std::string& color = colors[i]; + const char* c = color.data() + 1; + if ((color.size() == 7) && (color.front() == '#')) + { + for (size_t j = 0; j < 3; ++j) + { + int digit1 = hex_digit_to_int(*c++); + int digit2 = hex_digit_to_int(*c++); + if ((digit1 == -1) || (digit2 == -1)) + break; + + output[i * 4 + j] = float(digit1 * 16 + digit2) / 255.0f; + } + } + } + return output; +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 69934a822..4b2f82d85 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -411,6 +411,15 @@ public: std::vector get_current_print_zs(bool active_only) const; void set_toolpaths_range(double low, double high); + // 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 register_on_viewport_changed_callback(void* callback); @@ -472,8 +481,6 @@ private: void _start_timer(); void _stop_timer(); - static std::vector _parse_colors(const std::vector& 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 @@ -489,6 +496,8 @@ private: void _load_shells(); // sets gcode geometry visibility according to user selection void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data); + + static std::vector _parse_colors(const std::vector& colors); }; } // namespace GUI diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 850ccc697..3f903b9b3 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -450,6 +450,30 @@ void GLCanvas3DManager::set_toolpaths_range(wxGLCanvas* canvas, double low, doub it->second->set_toolpaths_range(low, high); } +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) diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 5a874de12..0d741d550 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -95,6 +95,9 @@ public: std::vector get_current_print_zs(wxGLCanvas* canvas, bool active_only) const; void set_toolpaths_range(wxGLCanvas* canvas, double low, double high); + 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 register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 8b454d3c3..f6f5134d6 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -511,31 +511,25 @@ reset_warning_texture() _3DScene::reset_warning_texture(); void -_load_print_toolpaths(print, volumes, tool_colors, use_VBOs) - Print *print; - GLVolumeCollection *volumes; - std::vector tool_colors; - int use_VBOs; +load_print_toolpaths(canvas) + SV *canvas; CODE: - _3DScene::_load_print_toolpaths(print, volumes, tool_colors, use_VBOs != 0); + _3DScene::load_print_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); void -_load_print_object_toolpaths(print_object, volumes, tool_colors, use_VBOs) - PrintObject *print_object; - GLVolumeCollection *volumes; +load_print_object_toolpaths(canvas, print_object, tool_colors) + SV *canvas; + PrintObject *print_object; std::vector tool_colors; - int use_VBOs; CODE: - _3DScene::_load_print_object_toolpaths(print_object, volumes, tool_colors, use_VBOs != 0); + _3DScene::load_print_object_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print_object, tool_colors); void -_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs) - Print *print; - GLVolumeCollection *volumes; +load_wipe_tower_toolpaths(canvas, tool_colors) + SV *canvas; std::vector tool_colors; - int use_VBOs; CODE: - _3DScene::_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs != 0); + _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)