From 9dbe2eea37eb2b6a219bff7c12852df25d07bee8 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 15:46:22 +0100 Subject: [PATCH] Menu option for coloring toolpaths by extruder using the configured filament colors --- lib/Slic3r/GUI.pm | 1 + lib/Slic3r/GUI/3DScene.pm | 288 ++++++++++++++--------------- lib/Slic3r/GUI/MainFrame.pm | 30 ++- lib/Slic3r/GUI/Plater.pm | 120 ++++++------ lib/Slic3r/GUI/Plater/3DPreview.pm | 10 + lib/Slic3r/Print/GCode.pm | 6 +- xs/src/libslic3r/Print.cpp | 12 ++ xs/src/libslic3r/Print.hpp | 1 + xs/xsp/Print.xsp | 1 + 9 files changed, 256 insertions(+), 213 deletions(-) diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 2459ef9c5c..0ab4112778 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -75,6 +75,7 @@ our $Settings = { # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. no_controller => 0, threads => $Slic3r::Config::Options->{threads}{default}, + color_toolpaths_by => 'role', }, }; diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 67046853f1..7c9ae2deeb 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -748,10 +748,10 @@ sub InitGL { # Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. glShadeModel(GL_SMOOTH); - glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 0.5, 0.3, 0.3, 1); + glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 0.3, 0.3, 0.3, 1); glMaterialfv_p(GL_FRONT_AND_BACK, GL_SPECULAR, 1, 1, 1, 1); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50); - glMaterialfv_p(GL_FRONT_AND_BACK, GL_EMISSION, 0.1, 0, 0, 0.9); + glMaterialfv_p(GL_FRONT_AND_BACK, GL_EMISSION, 0.1, 0.1, 0.1, 0.9); # A handy trick -- have surface material mirror the color. glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -1152,21 +1152,25 @@ use List::Util qw(first min max); use Slic3r::Geometry qw(scale unscale epsilon); use Slic3r::Print::State ':steps'; -use constant COLORS => [ [1,1,0,1], [1,0.5,0.5,1], [0.5,1,0.5,1], [0.5,0.5,1,1] ]; - __PACKAGE__->mk_accessors(qw( + colors color_by + color_toolpaths_by select_by drag_by volumes_by_object _objects_by_volumes )); +sub default_colors { [1,0.95,0.2,1], [1,0.45,0.45,1], [0.5,1,0.5,1], [0.5,0.5,1,1] } + sub new { my $class = shift; my $self = $class->SUPER::new(@_); + $self->colors([ $self->default_colors ]); $self->color_by('volume'); # object | volume + $self->color_toolpaths_by('role'); # role | extruder $self->select_by('object'); # object | volume | instance $self->drag_by('instance'); # object | instance $self->volumes_by_object({}); # obj_idx => [ volume_idx, volume_idx ... ] @@ -1204,7 +1208,7 @@ sub load_object { $color_idx = $obj_idx; } - my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; + my $color = [ @{$self->colors->[ $color_idx % scalar(@{$self->colors}) ]} ]; $color->[3] = $volume->modifier ? 0.5 : 1; push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new( bounding_box => $mesh->bounding_box, @@ -1281,7 +1285,7 @@ sub load_print_object_slices { push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new( bounding_box => $bb, - color => COLORS->[0], + color => $self->colors->[0], verts => OpenGL::Array->new_list(GL_FLOAT, @verts), norms => OpenGL::Array->new_list(GL_FLOAT, @norms), quad_verts => OpenGL::Array->new_list(GL_FLOAT, @quad_verts), @@ -1299,66 +1303,75 @@ sub load_print_toolpaths { && $print->config->interior_brim_width == 0 && $print->config->brim_connections_width == 0; - my $qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my %offsets = (); # print_z => [ qverts, tverts ] - - my $skirt_height = 0; # number of layers - if ($print->has_infinite_skirt) { - $skirt_height = $print->total_layer_count; - } else { - $skirt_height = min($print->config->skirt_height, $print->total_layer_count); - } - $skirt_height ||= 1 if $print->config->brim_width > 0 || $print->config->interior_brim_width; - - # get first $skirt_height layers (maybe this should be moved to a PrintObject method?) - my $object0 = $print->get_object(0); - my @layers = (); - push @layers, map $object0->get_layer($_-1), 1..min($skirt_height, $object0->layer_count); - push @layers, map $object0->get_support_layer($_-1), 1..min($skirt_height, $object0->support_layer_count); - @layers = sort { $a->print_z <=> $b->print_z } @layers; - @layers = @layers[0..($skirt_height-1)]; - - foreach my $i (0..($skirt_height-1)) { - my $top_z = $layers[$i]->print_z; - $offsets{$top_z} = [$qverts->size, $tverts->size]; - - if ($i == 0) { - $self->_extrusionentity_to_verts($print->brim, $top_z, Slic3r::Point->new(0,0), $qverts, $tverts); - } - - $self->_extrusionentity_to_verts($print->skirt, $top_z, Slic3r::Point->new(0,0), $qverts, $tverts); - } - my $bb = Slic3r::Geometry::BoundingBoxf3->new; { my $pbb = $print->bounding_box; $bb->merge_point(Slic3r::Pointf3->new_unscale(@{$pbb->min_point})); $bb->merge_point(Slic3r::Pointf3->new_unscale(@{$pbb->max_point})); } - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[2], - qverts => $qverts, - tverts => $tverts, - offsets => { %offsets }, - ); + + my $color_by_extruder = $self->color_toolpaths_by eq 'extruder'; + + if (!$print->brim->empty) { + my $color = $color_by_extruder + ? $self->colors->[ ($print->brim_extruder-1) % @{$self->colors} ] + : $self->colors->[2]; + + push @{$self->volumes}, my $volume = Slic3r::GUI::3DScene::Volume->new( + bounding_box => $bb, + color => $color, + qverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + tverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + offsets => {}, # print_z => [ qverts, tverts ] + ); + + my $top_z = $print->get_object(0)->get_layer(0)->print_z; + $volume->offsets->{$top_z} = [0, 0]; + $self->_extrusionentity_to_verts($print->brim, $top_z, Slic3r::Point->new(0,0), + $volume->qverts, $volume->tverts); + } + + if (!$print->skirt->empty) { + # TODO: it's a bit difficult to predict skirt extruders with the current skirt logic. + # We need to rewrite it anyway. + my $color = +($self->default_colors)[0]; + push @{$self->volumes}, my $volume = Slic3r::GUI::3DScene::Volume->new( + bounding_box => $bb, + color => $color, + qverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + tverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + offsets => {}, # print_z => [ qverts, tverts ] + ); + + my $skirt_height = 0; # number of layers + if ($print->has_infinite_skirt) { + $skirt_height = $print->total_layer_count; + } else { + $skirt_height = min($print->config->skirt_height, $print->total_layer_count); + } + $skirt_height ||= 1 if $print->config->brim_width > 0 || $print->config->interior_brim_width; + + # get first $skirt_height layers (maybe this should be moved to a PrintObject method?) + my $object0 = $print->get_object(0); + my @layers = (); + push @layers, map $object0->get_layer($_-1), 1..min($skirt_height, $object0->layer_count); + push @layers, map $object0->get_support_layer($_-1), 1..min($skirt_height, $object0->support_layer_count); + @layers = sort { $a->print_z <=> $b->print_z } @layers; + @layers = @layers[0..($skirt_height-1)]; + + foreach my $i (0..($skirt_height-1)) { + my $top_z = $layers[$i]->print_z; + $volume->offsets->{$top_z} = [$volume->qverts->size, $volume->tverts->size]; + + $self->_extrusionentity_to_verts($print->skirt, $top_z, Slic3r::Point->new(0,0), + $volume->qverts, $volume->tverts); + } + } } sub load_print_object_toolpaths { my ($self, $object) = @_; - my $perim_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $perim_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $infill_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $infill_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $support_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - my $support_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - - my %perim_offsets = (); # print_z => [ qverts, tverts ] - my %infill_offsets = (); - my %support_offsets = (); - # order layers by print_z my @layers = sort { $a->print_z <=> $b->print_z } @{$object->layers}, @{$object->support_layers}; @@ -1374,122 +1387,91 @@ sub load_print_object_toolpaths { $bb->merge_point(Slic3r::Pointf3->new_unscale(@{$cbb->max_point}, $object->size->z)); } } - + + my %volumes = (); # color => Volume + # Maximum size of an allocation block: 32MB / sizeof(float) my $alloc_size_max = 32 * 1048576 / 4; + my $add = sub { + my ($coll, $top_z, $copy, $color) = @_; + + my $volume = $volumes{$color}; + if (!$volume) { + push @{$self->volumes}, $volumes{$color} = $volume = Slic3r::GUI::3DScene::Volume->new( + bounding_box => $bb, + color => $color, + qverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + tverts => Slic3r::GUI::_3DScene::GLVertexArray->new, + offsets => {}, # print_z => [ qverts, tverts ] + ); + } + + $volume->offsets->{$top_z} //= [ $volume->qverts->size, $volume->tverts->size ]; + $self->_extrusionentity_to_verts($coll, $top_z, $copy, $volume->qverts, $volume->tverts); + }; + + my $color_by_extruder = $self->color_toolpaths_by eq 'extruder'; + foreach my $layer (@layers) { my $top_z = $layer->print_z; - - if (!exists $perim_offsets{$top_z}) { - $perim_offsets{$top_z} = [ - $perim_qverts->size, $perim_tverts->size, - ]; - } - if (!exists $infill_offsets{$top_z}) { - $infill_offsets{$top_z} = [ - $infill_qverts->size, $infill_tverts->size, - ]; - } - if (!exists $support_offsets{$top_z}) { - $support_offsets{$top_z} = [ - $support_qverts->size, $support_tverts->size, - ]; - } - foreach my $copy (@{ $object->_shifted_copies }) { foreach my $layerm (@{$layer->regions}) { if ($object->step_done(STEP_PERIMETERS)) { - $self->_extrusionentity_to_verts($layerm->perimeters, $top_z, $copy, - $perim_qverts, $perim_tverts); + my $color = $color_by_extruder + ? $self->colors->[ ($layerm->region->config->perimeter_extruder-1) % @{$self->colors} ] + : $self->colors->[0]; + $add->($layerm->perimeters, $top_z, $copy, $color); } if ($object->step_done(STEP_INFILL)) { - $self->_extrusionentity_to_verts($layerm->fills, $top_z, $copy, - $infill_qverts, $infill_tverts); + my $color = $color_by_extruder + ? $self->colors->[ ($layerm->region->config->infill_extruder-1) % @{$self->colors} ] + : $self->colors->[1]; + + if ($color_by_extruder && $layerm->region->config->infill_extruder != $layerm->region->config->solid_infill_extruder) { + # divide solid and non-solid infill + my $solid = Slic3r::ExtrusionPath::Collection->new; + my $non_solid = Slic3r::ExtrusionPath::Collection->new; + foreach my $fill (@{$layerm->fills}) { + if ($fill->[0]->is_solid_infill) { + $solid->append($fill); + } else { + $non_solid->append($fill); + } + } + $add->($non_solid, $top_z, $copy, $color); + $color = $self->colors->[ ($layerm->region->config->solid_infill_extruder-1) % @{&COLORS} ]; + $add->($solid, $top_z, $copy, $color); + } else { + $add->($layerm->fills, $top_z, $copy, $color); + } } } if ($layer->isa('Slic3r::Layer::Support') && $object->step_done(STEP_SUPPORTMATERIAL)) { - $self->_extrusionentity_to_verts($layer->support_fills, $top_z, $copy, - $support_qverts, $support_tverts); - - $self->_extrusionentity_to_verts($layer->support_interface_fills, $top_z, $copy, - $support_qverts, $support_tverts); + { + my $color = $color_by_extruder + ? $self->colors->[ ($layer->object->config->support_material_extruder-1) % @{$self->colors} ] + : $self->colors->[2]; + $add->($layer->support_fills, $top_z, $copy, $color); + } + { + my $color = ($color_by_extruder) + ? $self->colors->[ ($layer->object->config->support_material_interface_extruder-1) % @{$self->colors} ] + : $self->colors->[2]; + $add->($layer->support_interface_fills, $top_z, $copy, $color); + } } } - - if ($perim_qverts->size() > $alloc_size_max || $perim_tverts->size() > $alloc_size_max) { - # Store the vertex arrays and restart their containers. - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[0], - qverts => $perim_qverts, - tverts => $perim_tverts, - offsets => { %perim_offsets }, - ); - $perim_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - $perim_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - %perim_offsets = (); + + foreach my $color (keys %volumes) { + my $volume = $volumes{$color}; + if ($volume->qverts->size() > $alloc_size_max || $volume->tverts->size() > $alloc_size_max) { + # stop appending to this volume; create a new one next time + delete $volumes{$color}; + } } - - if ($infill_qverts->size() > $alloc_size_max || $infill_tverts->size() > $alloc_size_max) { - # Store the vertex arrays and restart their containers. - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[1], - qverts => $infill_qverts, - tverts => $infill_tverts, - offsets => { %infill_offsets }, - ); - $infill_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - $infill_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - %infill_offsets = (); - } - - if ($support_qverts->size() > $alloc_size_max || $support_tverts->size() > $alloc_size_max) { - # Store the vertex arrays and restart their containers. - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[2], - qverts => $support_qverts, - tverts => $support_tverts, - offsets => { %support_offsets }, - ); - $support_qverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - $support_tverts = Slic3r::GUI::_3DScene::GLVertexArray->new; - %support_offsets = (); - } - } - - if ($perim_qverts->size() > 0 || $perim_tverts->size() > 0) { - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[0], - qverts => $perim_qverts, - tverts => $perim_tverts, - offsets => { %perim_offsets }, - ); - } - - if ($infill_qverts->size() > 0 || $infill_tverts->size() > 0) { - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[1], - qverts => $infill_qverts, - tverts => $infill_tverts, - offsets => { %infill_offsets }, - ); - } - - if ($support_qverts->size() > 0 || $support_tverts->size() > 0) { - push @{$self->volumes}, Slic3r::GUI::3DScene::Volume->new( - bounding_box => $bb, - color => COLORS->[2], - qverts => $support_qverts, - tverts => $support_tverts, - offsets => { %support_offsets }, - ); } } diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 390ab2edb9..92ee27954d 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -303,6 +303,32 @@ sub _init_menubar { $self->_append_menu_item($self->{viewMenu}, "Rear" , 'Rear View' , sub { $self->select_view('rear' ); }); $self->_append_menu_item($self->{viewMenu}, "Left" , 'Left View' , sub { $self->select_view('left' ); }); $self->_append_menu_item($self->{viewMenu}, "Right" , 'Right View' , sub { $self->select_view('right' ); }); + $self->{viewMenu}->AppendSeparator(); + $self->{color_toolpaths_by_role} = $self->_append_menu_item($self->{viewMenu}, + "Color Toolpaths by Role", + 'Color toolpaths according to perimeter/infill/support material', + sub { + $Slic3r::GUI::Settings->{_}{color_toolpaths_by} = 'role'; + wxTheApp->save_settings; + $self->{plater}{preview3D}->reload_print; + }, + undef, undef, wxITEM_RADIO + ); + $self->{color_toolpaths_by_extruder} = $self->_append_menu_item($self->{viewMenu}, + "Color Toolpaths by Filament", + 'Color toolpaths using the configured extruder/filament color', + sub { + $Slic3r::GUI::Settings->{_}{color_toolpaths_by} = 'extruder'; + wxTheApp->save_settings; + $self->{plater}{preview3D}->reload_print; + }, + undef, undef, wxITEM_RADIO + ); + if ($Slic3r::GUI::Settings->{_}{color_toolpaths_by} eq 'role') { + $self->{color_toolpaths_by_role}->Check(1); + } else { + $self->{color_toolpaths_by_extruder}->Check(1); + } } # Help menu @@ -800,10 +826,10 @@ sub select_view { } sub _append_menu_item { - my ($self, $menu, $string, $description, $cb, $id, $icon) = @_; + my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_; $id //= &Wx::NewId(); - my $item = $menu->Append($id, $string, $description); + my $item = $menu->Append($id, $string, $description, $kind); $self->_set_menu_item_icon($item, $icon); EVT_MENU($self, $id, $cb); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index c72350def0..efda7aedf1 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -50,7 +50,7 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{config} = Slic3r::Config->new_from_defaults(qw( bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width - serial_port serial_speed octoprint_host octoprint_apikey + serial_port serial_speed octoprint_host octoprint_apikey filament_colour )); $self->{model} = Slic3r::Model->new; $self->{print} = Slic3r::Print->new; @@ -90,7 +90,7 @@ sub new { $menu->Destroy; }; my $on_instances_moved = sub { - $self->update; + $self->on_model_change; }; # Initialize 3D plater @@ -374,7 +374,7 @@ sub new { if ($self->{preview3D}) { $self->{preview3D}->set_bed_shape($self->{config}->bed_shape); } - $self->update; + $self->on_model_change; { my $presets; @@ -522,13 +522,12 @@ sub _on_select_preset { $Slic3r::GUI::Settings->{presets}{"filament_${_}"} = $choice->GetString($filament_presets[$_]) for 1 .. $#filament_presets; wxTheApp->save_settings; - return; + } else { + # call GetSelection() in scalar context as it's context-aware + $self->{on_select_preset}->($group, scalar $choice->GetSelection) + if $self->{on_select_preset}; } - # call GetSelection() in scalar context as it's context-aware - $self->{on_select_preset}->($group, scalar $choice->GetSelection) - if $self->{on_select_preset}; - # get new config and generate on_config_change() event for updating plater and other things $self->on_config_change($self->GetFrame->config); } @@ -735,7 +734,7 @@ sub load_model_objects { $self->make_thumbnail($obj_idx); } $self->arrange if $need_arrange; - $self->update; + $self->on_model_change; # zoom to objects $self->{canvas3D}->zoom_to_volumes @@ -745,8 +744,6 @@ sub load_model_objects { $self->{list}->Select($obj_idx[-1], 1); $self->object_list_changed; - $self->schedule_background_process; - return @obj_idx; } @@ -780,8 +777,7 @@ sub remove { $self->object_list_changed; $self->select_object(undef); - $self->update; - $self->schedule_background_process; + $self->on_model_change; } sub reset { @@ -800,7 +796,7 @@ sub reset { $self->object_list_changed; $self->select_object(undef); - $self->update; + $self->on_model_change; } sub increase { @@ -825,9 +821,8 @@ sub increase { if ($Slic3r::GUI::Settings->{_}{autocenter}) { $self->arrange; } else { - $self->update; + $self->on_model_change; } - $self->schedule_background_process; } sub decrease { @@ -852,8 +847,7 @@ sub decrease { $self->{list}->Select($obj_idx, 0); $self->{list}->Select($obj_idx, 1); } - $self->update; - $self->schedule_background_process; + $self->on_model_change; } sub set_number_of_copies { @@ -925,8 +919,7 @@ sub rotate { $self->{print}->add_model_object($model_object, $obj_idx); $self->selection_changed; # refresh info (size etc.) - $self->update; - $self->schedule_background_process; + $self->on_model_change; } sub mirror { @@ -953,8 +946,7 @@ sub mirror { $self->{print}->add_model_object($model_object, $obj_idx); $self->selection_changed; # refresh info (size etc.) - $self->update; - $self->schedule_background_process; + $self->on_model_change; } sub changescale { @@ -1035,8 +1027,7 @@ sub changescale { $self->{print}->add_model_object($model_object, $obj_idx); $self->selection_changed(1); # refresh info (size, volume etc.) - $self->update; - $self->schedule_background_process; + $self->on_model_change; } sub arrange { @@ -1049,7 +1040,7 @@ sub arrange { # ignore arrange failures on purpose: user has visual feedback and we don't need to warn him # when parts don't fit in print bed - $self->update(1); + $self->on_model_change(1); } sub split_object { @@ -1099,14 +1090,10 @@ sub split_object { sub schedule_background_process { my ($self) = @_; - $self->{processed} = 0; + warn 'schedule_background_process() is not supposed to be called when background processing is disabled' + if !$Slic3r::GUI::Settings->{_}{background_processing}; - if (!$Slic3r::GUI::Settings->{_}{background_processing}) { - my $sel = $self->{preview_notebook}->GetSelection; - if ($sel == $self->{preview3D_page_idx} || $sel == $self->{toolpaths2D_page_idx}) { - $self->{preview_notebook}->SetSelection(0); - } - } + $self->{processed} = 0; if (defined $self->{apply_config_timer}) { $self->{apply_config_timer}->Start(PROCESS_DELAY, 1); # 1 = one shot @@ -1118,10 +1105,6 @@ sub schedule_background_process { sub async_apply_config { my ($self) = @_; - # reset preview canvases - $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; - $self->{preview3D}->reload_print if $self->{preview3D}; - # pause process thread before applying new config # since we don't want to touch data that is being used by the threads $self->pause_background_process; @@ -1129,9 +1112,16 @@ sub async_apply_config { # apply new config my $invalidated = $self->{print}->apply_config($self->GetFrame->config); - return if !$Slic3r::GUI::Settings->{_}{background_processing}; + # reset preview canvases (invalidated contents will be hidden) + $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; + $self->{preview3D}->reload_print if $self->{preview3D}; if ($invalidated) { + if (!$Slic3r::GUI::Settings->{_}{background_processing}) { + $self->hide_preview; + return; + } + # kill current thread if any $self->stop_background_process; # remove the sliced statistics box because something changed. @@ -1629,30 +1619,45 @@ sub on_thumbnail_made { # 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) -sub update { +sub on_model_change { my ($self, $force_autocenter) = @_; + my $running = $self->pause_background_process; + if ($Slic3r::GUI::Settings->{_}{autocenter} || $force_autocenter) { $self->{model}->center_instances_around_point($self->bed_centerf); } + $self->refresh_canvases; - my $running = $self->pause_background_process; my $invalidated = $self->{print}->reload_model_instances(); - # The mere fact that no steps were invalidated when reloading model instances - # doesn't mean that all steps were done: for example, validation might have - # failed upon previous instance move, so we have no running thread and no steps - # are invalidated on this move, thus we need to schedule a new run. - if ($invalidated || !$running) { - $self->schedule_background_process; + if ($Slic3r::GUI::Settings->{_}{background_processing}) { + if ($invalidated || !$running) { + # The mere fact that no steps were invalidated when reloading model instances + # doesn't mean that all steps were done: for example, validation might have + # failed upon previous instance move, so we have no running thread and no steps + # are invalidated on this move, thus we need to schedule a new run. + $self->schedule_background_process; + if ($self->{"right_sizer"}) { + $self->{"right_sizer"}->Hide($self->{"sliced_info_box"}); + $self->{"right_sizer"}->Layout; + } + } else { + $self->resume_background_process; + } } else { - $self->resume_background_process; + $self->hide_preview; } - if ($self->{"right_sizer"}) { - $self->{"right_sizer"}->Hide($self->{"sliced_info_box"}); - $self->{"right_sizer"}->Layout; +} + +sub hide_preview { + my ($self) = @_; + + my $sel = $self->{preview_notebook}->GetSelection; + if ($sel == $self->{preview3D_page_idx} || $sel == $self->{toolpaths2D_page_idx}) { + $self->{preview_notebook}->SetSelection(0); } - $self->refresh_canvases; + $self->{processed} = 0; } sub on_extruders_change { @@ -1701,6 +1706,7 @@ sub on_config_change { my $self = shift; my ($config) = @_; + # Apply changes to the plater-specific config options. foreach my $opt_key (@{$self->{config}->diff($config)}) { $self->{config}->set($opt_key, $config->get($opt_key)); if ($opt_key eq 'bed_shape') { @@ -1708,7 +1714,7 @@ sub on_config_change { $self->{canvas3D}->update_bed_size if $self->{canvas3D}; $self->{preview3D}->set_bed_shape($self->{config}->bed_shape) if $self->{preview3D}; - $self->update; + $self->on_model_change; } elsif ($opt_key eq 'serial_port') { if ($config->get('serial_port')) { $self->{btn_print}->Show; @@ -1723,8 +1729,12 @@ sub on_config_change { $self->{btn_send_gcode}->Hide; } $self->Layout; + } elsif (0 && $opt_key eq 'filament_colour') { + $self->{print}->config->set('filament_colour', $config->filament_colour); + $self->{preview3D}->reload_print if $self->{preview3D}; } } + if ($self->{"right_sizer"}) { $self->{"right_sizer"}->Hide($self->{"sliced_info_box"}); $self->{"right_sizer"}->Layout; @@ -1732,8 +1742,12 @@ sub on_config_change { return if !$self->GetFrame->is_loaded; - # (re)start timer - $self->schedule_background_process; + if ($Slic3r::GUI::Settings->{_}{background_processing}) { + # (re)start timer + $self->schedule_background_process; + } else { + $self->async_apply_config; + } } sub list_item_deselected { diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index c1d1cf57e9..dddefee013 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -117,6 +117,16 @@ sub load_print { } if ($self->IsShown) { + # set colors + $self->canvas->color_toolpaths_by($Slic3r::GUI::Settings->{_}{color_toolpaths_by}); + if ($self->canvas->color_toolpaths_by eq 'extruder') { + my @filament_colors = map { s/^#//; [ map $_/255, (unpack 'C*', pack 'H*', $_), 255 ] } + @{$self->print->config->filament_colour}; + $self->canvas->colors->[$_] = $filament_colors[$_] for 0..$#filament_colors; + } else { + $self->canvas->colors([ $self->canvas->default_colors ]); + } + # load skirt and brim $self->canvas->load_print_toolpaths($self->print); diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index 9a653e89d9..3faad83172 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -462,11 +462,7 @@ sub process_layer { # extrude brim if (!$self->_brim_done) { - my $extr = $self->print->regions->[0]->config->perimeter_extruder-1; - if (my $o = first { $_->config->raft_layers > 0 } @{$self->objects}) { - $extr = $o->config->support_material_extruder-1; - } - $gcode .= $self->_gcodegen->set_extruder($extr); + $gcode .= $self->_gcodegen->set_extruder($self->print->brim_extruder-1); $self->_gcodegen->set_origin(Slic3r::Pointf->new(0,0)); $self->_gcodegen->avoid_crossing_perimeters->set_use_external_mp(1); $gcode .= $self->_gcodegen->extrude($_, 'brim', $object->config->support_material_speed) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index be6f24f381..807d58b45e 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -187,6 +187,7 @@ Print::invalidate_state_by_config_options(const std::vector || *opt_key == "extrusion_multiplier" || *opt_key == "fan_always_on" || *opt_key == "fan_below_layer_time" + || *opt_key == "filament_colour" || *opt_key == "filament_diameter" || *opt_key == "first_layer_acceleration" || *opt_key == "first_layer_bed_temperature" @@ -348,6 +349,17 @@ Print::extruders() const return extruders; } +size_t +Print::brim_extruder() const +{ + size_t e = this->get_region(0)->config.perimeter_extruder; + for (const PrintObject* object : this->objects) { + if (object->config.raft_layers > 0) + e = object->config.support_material_extruder; + } + return e; +} + void Print::_simplify_slices(double distance) { diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index a5bc63defa..b68ea6e35d 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -214,6 +214,7 @@ class Print std::set object_extruders() const; std::set support_material_extruders() const; std::set extruders() const; + size_t brim_extruder() const; void _simplify_slices(double distance); double max_allowed_layer_height() const; bool has_support_material() const; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 1bd25edb42..c4590a69e3 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -224,6 +224,7 @@ _constant() RETVAL.push_back(*e); } %}; + int brim_extruder(); void clear_filament_stats() %code%{ THIS->filament_stats.clear();