Merge remote-tracking branch 'origin/master' into feature_slice_to_png
# Conflicts: # lib/Slic3r/GUI/MainFrame.pm
@ -49,6 +49,22 @@ if(NOT DEFINED CMAKE_PREFIX_PATH)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
|
||||||
|
# We pick it from environment if it is not defined in another way
|
||||||
|
if(WIN32)
|
||||||
|
if(NOT DEFINED WIN10SDK_PATH)
|
||||||
|
if(DEFINED ENV{WIN10SDK_PATH})
|
||||||
|
set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(DEFINED WIN10SDK_PATH AND NOT EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h")
|
||||||
|
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||||
|
message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
|
||||||
|
message("STL fixing by the Netfabb service will not be compiled")
|
||||||
|
unset(WIN10SDK_PATH)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(xs)
|
add_subdirectory(xs)
|
||||||
|
|
||||||
get_filename_component(PERL_BIN_PATH "${PERL_EXECUTABLE}" DIRECTORY)
|
get_filename_component(PERL_BIN_PATH "${PERL_EXECUTABLE}" DIRECTORY)
|
||||||
|
@ -7,7 +7,6 @@ use File::Basename qw(basename);
|
|||||||
use FindBin;
|
use FindBin;
|
||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Slic3r::GUI::2DBed;
|
use Slic3r::GUI::2DBed;
|
||||||
use Slic3r::GUI::BedShapeDialog;
|
|
||||||
use Slic3r::GUI::Controller;
|
use Slic3r::GUI::Controller;
|
||||||
use Slic3r::GUI::Controller::ManualControlDialog;
|
use Slic3r::GUI::Controller::ManualControlDialog;
|
||||||
use Slic3r::GUI::Controller::PrinterPanel;
|
use Slic3r::GUI::Controller::PrinterPanel;
|
||||||
@ -223,8 +222,8 @@ sub system_info {
|
|||||||
my $opengl_info_txt = '';
|
my $opengl_info_txt = '';
|
||||||
if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) &&
|
if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) &&
|
||||||
defined($self->{mainframe}->{plater}->{canvas3D})) {
|
defined($self->{mainframe}->{plater}->{canvas3D})) {
|
||||||
$opengl_info = $self->{mainframe}->{plater}->{canvas3D}->opengl_info(format => 'html');
|
$opengl_info = Slic3r::GUI::_3DScene::get_gl_info(1, 1);
|
||||||
$opengl_info_txt = $self->{mainframe}->{plater}->{canvas3D}->opengl_info;
|
$opengl_info_txt = Slic3r::GUI::_3DScene::get_gl_info(0, 1);
|
||||||
}
|
}
|
||||||
my $about = Slic3r::GUI::SystemInfo->new(
|
my $about = Slic3r::GUI::SystemInfo->new(
|
||||||
parent => undef,
|
parent => undef,
|
||||||
|
@ -1,316 +0,0 @@
|
|||||||
# The bed shape dialog.
|
|
||||||
# The dialog opens from Print Settins tab -> Bed Shape: Set...
|
|
||||||
|
|
||||||
package Slic3r::GUI::BedShapeDialog;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use utf8;
|
|
||||||
|
|
||||||
use List::Util qw(min max);
|
|
||||||
use Slic3r::Geometry qw(X Y unscale);
|
|
||||||
use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL);
|
|
||||||
use Wx::Event qw(EVT_CLOSE);
|
|
||||||
use base 'Wx::Dialog';
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $class = shift;
|
|
||||||
my ($parent, $default) = @_;
|
|
||||||
my $self = $class->SUPER::new($parent, -1, "Bed Shape", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
|
|
||||||
|
|
||||||
$self->{panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $default);
|
|
||||||
|
|
||||||
my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
|
|
||||||
$main_sizer->Add($panel, 1, wxEXPAND);
|
|
||||||
$main_sizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND);
|
|
||||||
|
|
||||||
$self->SetSizer($main_sizer);
|
|
||||||
$self->SetMinSize($self->GetSize);
|
|
||||||
$main_sizer->SetSizeHints($self);
|
|
||||||
|
|
||||||
# needed to actually free memory
|
|
||||||
EVT_CLOSE($self, sub {
|
|
||||||
$self->EndModal(wxID_OK);
|
|
||||||
$self->Destroy;
|
|
||||||
});
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub GetValue {
|
|
||||||
my ($self) = @_;
|
|
||||||
return $self->{panel}->GetValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
package Slic3r::GUI::BedShapePanel;
|
|
||||||
|
|
||||||
use List::Util qw(min max sum first);
|
|
||||||
use Scalar::Util qw(looks_like_number);
|
|
||||||
use Slic3r::Geometry qw(PI X Y unscale scaled_epsilon);
|
|
||||||
use Wx qw(:font :id :misc :sizer :choicebook :filedialog :pen :brush wxTAB_TRAVERSAL);
|
|
||||||
use Wx::Event qw(EVT_CLOSE EVT_CHOICEBOOK_PAGE_CHANGED EVT_BUTTON);
|
|
||||||
use base 'Wx::Panel';
|
|
||||||
|
|
||||||
use constant SHAPE_RECTANGULAR => 0;
|
|
||||||
use constant SHAPE_CIRCULAR => 1;
|
|
||||||
use constant SHAPE_CUSTOM => 2;
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $class = shift;
|
|
||||||
my ($parent, $default) = @_;
|
|
||||||
my $self = $class->SUPER::new($parent, -1);
|
|
||||||
|
|
||||||
$self->on_change(undef);
|
|
||||||
|
|
||||||
my $box = Wx::StaticBox->new($self, -1, "Shape");
|
|
||||||
my $sbsizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
|
|
||||||
|
|
||||||
# shape options
|
|
||||||
$self->{shape_options_book} = Wx::Choicebook->new($self, -1, wxDefaultPosition, [300,-1], wxCHB_TOP);
|
|
||||||
$sbsizer->Add($self->{shape_options_book});
|
|
||||||
|
|
||||||
$self->{optgroups} = [];
|
|
||||||
{
|
|
||||||
my $optgroup = $self->_init_shape_options_page('Rectangular');
|
|
||||||
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
|
|
||||||
opt_id => 'rect_size',
|
|
||||||
type => 'point',
|
|
||||||
label => 'Size',
|
|
||||||
tooltip => 'Size in X and Y of the rectangular plate.',
|
|
||||||
default => [200,200],
|
|
||||||
));
|
|
||||||
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
|
|
||||||
opt_id => 'rect_origin',
|
|
||||||
type => 'point',
|
|
||||||
label => 'Origin',
|
|
||||||
tooltip => 'Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.',
|
|
||||||
default => [0,0],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
my $optgroup = $self->_init_shape_options_page('Circular');
|
|
||||||
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
|
|
||||||
opt_id => 'diameter',
|
|
||||||
type => 'f',
|
|
||||||
label => 'Diameter',
|
|
||||||
tooltip => 'Diameter of the print bed. It is assumed that origin (0,0) is located in the center.',
|
|
||||||
sidetext => 'mm',
|
|
||||||
default => 200,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
my $optgroup = $self->_init_shape_options_page('Custom');
|
|
||||||
$optgroup->append_line(Slic3r::GUI::OptionsGroup::Line->new(
|
|
||||||
full_width => 1,
|
|
||||||
widget => sub {
|
|
||||||
my ($parent) = @_;
|
|
||||||
|
|
||||||
my $btn = Wx::Button->new($parent, -1, "Load shape from STL...", wxDefaultPosition, wxDefaultSize);
|
|
||||||
EVT_BUTTON($self, $btn, sub { $self->_load_stl });
|
|
||||||
return $btn;
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
EVT_CHOICEBOOK_PAGE_CHANGED($self, -1, sub {
|
|
||||||
$self->_update_shape;
|
|
||||||
});
|
|
||||||
|
|
||||||
# right pane with preview canvas
|
|
||||||
my $canvas = $self->{canvas} = Slic3r::GUI::2DBed->new($self);
|
|
||||||
|
|
||||||
# main sizer
|
|
||||||
my $top_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
|
|
||||||
$top_sizer->Add($sbsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
|
|
||||||
$top_sizer->Add($canvas, 1, wxEXPAND | wxALL, 10) if $canvas;
|
|
||||||
|
|
||||||
$self->SetSizerAndFit($top_sizer);
|
|
||||||
|
|
||||||
$self->_set_shape($default);
|
|
||||||
$self->_update_preview;
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub on_change {
|
|
||||||
my ($self, $cb) = @_;
|
|
||||||
$self->{on_change} = $cb // sub {};
|
|
||||||
}
|
|
||||||
|
|
||||||
# Called from the constructor.
|
|
||||||
# Set the initial bed shape from a list of points.
|
|
||||||
# Deduce the bed shape type (rect, circle, custom)
|
|
||||||
# This routine shall be smart enough if the user messes up
|
|
||||||
# with the list of points in the ini file directly.
|
|
||||||
sub _set_shape {
|
|
||||||
my ($self, $points) = @_;
|
|
||||||
|
|
||||||
# is this a rectangle?
|
|
||||||
if (@$points == 4) {
|
|
||||||
my $polygon = Slic3r::Polygon->new_scale(@$points);
|
|
||||||
my $lines = $polygon->lines;
|
|
||||||
if ($lines->[0]->parallel_to_line($lines->[2]) && $lines->[1]->parallel_to_line($lines->[3])) {
|
|
||||||
# okay, it's a rectangle
|
|
||||||
|
|
||||||
# find origin
|
|
||||||
# the || 0 hack prevents "-0" which might confuse the user
|
|
||||||
my $x_min = min(map $_->[X], @$points) || 0;
|
|
||||||
my $x_max = max(map $_->[X], @$points) || 0;
|
|
||||||
my $y_min = min(map $_->[Y], @$points) || 0;
|
|
||||||
my $y_max = max(map $_->[Y], @$points) || 0;
|
|
||||||
my $origin = [-$x_min, -$y_min];
|
|
||||||
|
|
||||||
$self->{shape_options_book}->SetSelection(SHAPE_RECTANGULAR);
|
|
||||||
my $optgroup = $self->{optgroups}[SHAPE_RECTANGULAR];
|
|
||||||
$optgroup->set_value('rect_size', [ $x_max-$x_min, $y_max-$y_min ]);
|
|
||||||
$optgroup->set_value('rect_origin', $origin);
|
|
||||||
$self->_update_shape;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# is this a circle?
|
|
||||||
{
|
|
||||||
# Analyze the array of points. Do they reside on a circle?
|
|
||||||
my $polygon = Slic3r::Polygon->new_scale(@$points);
|
|
||||||
my $center = $polygon->bounding_box->center;
|
|
||||||
my @vertex_distances = map $center->distance_to($_), @$polygon;
|
|
||||||
my $avg_dist = sum(@vertex_distances)/@vertex_distances;
|
|
||||||
if (!defined first { abs($_ - $avg_dist) > 10*scaled_epsilon } @vertex_distances) {
|
|
||||||
# all vertices are equidistant to center
|
|
||||||
$self->{shape_options_book}->SetSelection(SHAPE_CIRCULAR);
|
|
||||||
my $optgroup = $self->{optgroups}[SHAPE_CIRCULAR];
|
|
||||||
$optgroup->set_value('diameter', sprintf("%.0f", unscale($avg_dist*2)));
|
|
||||||
$self->_update_shape;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@$points < 3) {
|
|
||||||
# Invalid polygon. Revert to default bed dimensions.
|
|
||||||
$self->{shape_options_book}->SetSelection(SHAPE_RECTANGULAR);
|
|
||||||
my $optgroup = $self->{optgroups}[SHAPE_RECTANGULAR];
|
|
||||||
$optgroup->set_value('rect_size', [200, 200]);
|
|
||||||
$optgroup->set_value('rect_origin', [0, 0]);
|
|
||||||
$self->_update_shape;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# This is a custom bed shape, use the polygon provided.
|
|
||||||
$self->{shape_options_book}->SetSelection(SHAPE_CUSTOM);
|
|
||||||
# Copy the polygon to the canvas, make a copy of the array.
|
|
||||||
$self->{canvas}->bed_shape([@$points]);
|
|
||||||
$self->_update_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Update the bed shape from the dialog fields.
|
|
||||||
sub _update_shape {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
my $page_idx = $self->{shape_options_book}->GetSelection;
|
|
||||||
if ($page_idx == SHAPE_RECTANGULAR) {
|
|
||||||
my $rect_size = $self->{optgroups}[SHAPE_RECTANGULAR]->get_value('rect_size');
|
|
||||||
my $rect_origin = $self->{optgroups}[SHAPE_RECTANGULAR]->get_value('rect_origin');
|
|
||||||
my ($x, $y) = @$rect_size;
|
|
||||||
return if !looks_like_number($x) || !looks_like_number($y); # empty strings or '-' or other things
|
|
||||||
return if !$x || !$y or $x == 0 or $y == 0;
|
|
||||||
my ($x0, $y0) = (0,0);
|
|
||||||
my ($x1, $y1) = ($x ,$y);
|
|
||||||
{
|
|
||||||
my ($dx, $dy) = @$rect_origin;
|
|
||||||
return if !looks_like_number($dx) || !looks_like_number($dy); # empty strings or '-' or other things
|
|
||||||
$x0 -= $dx;
|
|
||||||
$x1 -= $dx;
|
|
||||||
$y0 -= $dy;
|
|
||||||
$y1 -= $dy;
|
|
||||||
}
|
|
||||||
$self->{canvas}->bed_shape([
|
|
||||||
[$x0,$y0],
|
|
||||||
[$x1,$y0],
|
|
||||||
[$x1,$y1],
|
|
||||||
[$x0,$y1],
|
|
||||||
]);
|
|
||||||
} elsif ($page_idx == SHAPE_CIRCULAR) {
|
|
||||||
my $diameter = $self->{optgroups}[SHAPE_CIRCULAR]->get_value('diameter');
|
|
||||||
return if !$diameter or $diameter == 0;
|
|
||||||
my $r = $diameter/2;
|
|
||||||
my $twopi = 2*PI;
|
|
||||||
my $edges = 60;
|
|
||||||
my $polygon = Slic3r::Polygon->new_scale(
|
|
||||||
map [ $r * cos $_, $r * sin $_ ],
|
|
||||||
map { $twopi/$edges*$_ } 1..$edges
|
|
||||||
);
|
|
||||||
$self->{canvas}->bed_shape([
|
|
||||||
map [ unscale($_->x), unscale($_->y) ], @$polygon #))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{on_change}->();
|
|
||||||
$self->_update_preview;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _update_preview {
|
|
||||||
my ($self) = @_;
|
|
||||||
$self->{canvas}->Refresh if $self->{canvas};
|
|
||||||
$self->Refresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Called from the constructor.
|
|
||||||
# Create a panel for a rectangular / circular / custom bed shape.
|
|
||||||
sub _init_shape_options_page {
|
|
||||||
my ($self, $title) = @_;
|
|
||||||
|
|
||||||
my $panel = Wx::Panel->new($self->{shape_options_book});
|
|
||||||
my $optgroup;
|
|
||||||
push @{$self->{optgroups}}, $optgroup = Slic3r::GUI::OptionsGroup->new(
|
|
||||||
parent => $panel,
|
|
||||||
title => 'Settings',
|
|
||||||
label_width => 100,
|
|
||||||
on_change => sub {
|
|
||||||
my ($opt_id) = @_;
|
|
||||||
#$self->{"_$opt_id"} = $optgroup->get_value($opt_id);
|
|
||||||
$self->_update_shape;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
$panel->SetSizerAndFit($optgroup->sizer);
|
|
||||||
$self->{shape_options_book}->AddPage($panel, $title);
|
|
||||||
|
|
||||||
return $optgroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Loads an stl file, projects it to the XY plane and calculates a polygon.
|
|
||||||
sub _load_stl {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
my $dialog = Wx::FileDialog->new($self, 'Choose a file to import bed shape from (STL/OBJ/AMF/PRUSA):', "", "", &Slic3r::GUI::MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
||||||
if ($dialog->ShowModal != wxID_OK) {
|
|
||||||
$dialog->Destroy;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
my $input_file = $dialog->GetPaths;
|
|
||||||
$dialog->Destroy;
|
|
||||||
|
|
||||||
my $model = Slic3r::Model->read_from_file($input_file);
|
|
||||||
my $mesh = $model->mesh;
|
|
||||||
my $expolygons = $mesh->horizontal_projection;
|
|
||||||
|
|
||||||
if (@$expolygons == 0) {
|
|
||||||
Slic3r::GUI::show_error($self, "The selected file contains no geometry.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (@$expolygons > 1) {
|
|
||||||
Slic3r::GUI::show_error($self, "The selected file contains several disjoint areas. This is not supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $polygon = $expolygons->[0]->contour;
|
|
||||||
$self->{canvas}->bed_shape([ map [ unscale($_->x), unscale($_->y) ], @$polygon ]);
|
|
||||||
$self->_update_preview();
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the resulting bed shape polygon. This value will be stored to the ini file.
|
|
||||||
sub GetValue {
|
|
||||||
my ($self) = @_;
|
|
||||||
return $self->{canvas}->bed_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -29,9 +29,9 @@ our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
|
|||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %params) = @_;
|
my ($class, %params) = @_;
|
||||||
|
|
||||||
my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
|
||||||
Slic3r::GUI::set_main_frame($self);
|
Slic3r::GUI::set_main_frame($self);
|
||||||
$appController = Slic3r::AppController->new();
|
$appController = Slic3r::AppController->new();
|
||||||
|
|
||||||
if ($^O eq 'MSWin32') {
|
if ($^O eq 'MSWin32') {
|
||||||
@ -42,7 +42,7 @@ sub new {
|
|||||||
} else {
|
} else {
|
||||||
$self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));
|
$self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));
|
||||||
}
|
}
|
||||||
|
|
||||||
# store input params
|
# store input params
|
||||||
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
|
# If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
|
||||||
$self->{no_controller} = $params{no_controller};
|
$self->{no_controller} = $params{no_controller};
|
||||||
@ -50,7 +50,7 @@ sub new {
|
|||||||
$self->{loaded} = 0;
|
$self->{loaded} = 0;
|
||||||
$self->{lang_ch_event} = $params{lang_ch_event};
|
$self->{lang_ch_event} = $params{lang_ch_event};
|
||||||
$self->{preferences_event} = $params{preferences_event};
|
$self->{preferences_event} = $params{preferences_event};
|
||||||
|
|
||||||
# initialize tabpanel and menubar
|
# initialize tabpanel and menubar
|
||||||
$self->_init_tabpanel;
|
$self->_init_tabpanel;
|
||||||
$self->_init_menubar;
|
$self->_init_menubar;
|
||||||
@ -75,7 +75,7 @@ sub new {
|
|||||||
$appController->set_print($self->{plater}->{print});
|
$appController->set_print($self->{plater}->{print});
|
||||||
|
|
||||||
$self->{loaded} = 1;
|
$self->{loaded} = 1;
|
||||||
|
|
||||||
# initialize layout
|
# initialize layout
|
||||||
{
|
{
|
||||||
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
@ -102,6 +102,8 @@ sub new {
|
|||||||
# Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
|
# Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
|
||||||
# but in rare cases it may not have been called yet.
|
# but in rare cases it may not have been called yet.
|
||||||
wxTheApp->{app_config}->save;
|
wxTheApp->{app_config}->save;
|
||||||
|
$self->{plater}->{print} = undef if($self->{plater});
|
||||||
|
Slic3r::GUI::_3DScene::remove_all_canvases();
|
||||||
# propagate event
|
# propagate event
|
||||||
$event->Skip;
|
$event->Skip;
|
||||||
});
|
});
|
||||||
|
@ -78,19 +78,19 @@ sub new {
|
|||||||
my $on_select_object = sub {
|
my $on_select_object = sub {
|
||||||
my ($obj_idx) = @_;
|
my ($obj_idx) = @_;
|
||||||
# Ignore the special objects (the wipe tower proxy and such).
|
# Ignore the special objects (the wipe tower proxy and such).
|
||||||
$self->select_object((defined($obj_idx) && $obj_idx < 1000) ? $obj_idx : undef);
|
$self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef);
|
||||||
};
|
};
|
||||||
my $on_double_click = sub {
|
my $on_double_click = sub {
|
||||||
$self->object_settings_dialog if $self->selected_object;
|
$self->object_settings_dialog if $self->selected_object;
|
||||||
};
|
};
|
||||||
my $on_right_click = sub {
|
my $on_right_click = sub {
|
||||||
my ($canvas, $click_pos) = @_;
|
my ($canvas, $click_pos_x, $click_pos_y) = @_;
|
||||||
|
|
||||||
my ($obj_idx, $object) = $self->selected_object;
|
my ($obj_idx, $object) = $self->selected_object;
|
||||||
return if !defined $obj_idx;
|
return if !defined $obj_idx;
|
||||||
|
|
||||||
my $menu = $self->object_menu;
|
my $menu = $self->object_menu;
|
||||||
$canvas->PopupMenu($menu, $click_pos);
|
$canvas->PopupMenu($menu, $click_pos_x, $click_pos_y);
|
||||||
$menu->Destroy;
|
$menu->Destroy;
|
||||||
};
|
};
|
||||||
my $on_instances_moved = sub {
|
my $on_instances_moved = sub {
|
||||||
@ -105,32 +105,65 @@ sub new {
|
|||||||
$self->{btn_print}->Enable($enable);
|
$self->{btn_print}->Enable($enable);
|
||||||
$self->{btn_send_gcode}->Enable($enable);
|
$self->{btn_send_gcode}->Enable($enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# callback to react to gizmo scale
|
||||||
|
my $on_gizmo_scale_uniformly = sub {
|
||||||
|
my ($scale) = @_;
|
||||||
|
|
||||||
|
my ($obj_idx, $object) = $self->selected_object;
|
||||||
|
return if !defined $obj_idx;
|
||||||
|
|
||||||
|
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||||
|
my $model_instance = $model_object->instances->[0];
|
||||||
|
|
||||||
|
my $variation = $scale / $model_instance->scaling_factor;
|
||||||
|
#FIXME Scale the layer height profile?
|
||||||
|
foreach my $range (@{ $model_object->layer_height_ranges }) {
|
||||||
|
$range->[0] *= $variation;
|
||||||
|
$range->[1] *= $variation;
|
||||||
|
}
|
||||||
|
$_->set_scaling_factor($scale) for @{ $model_object->instances };
|
||||||
|
$object->transform_thumbnail($self->{model}, $obj_idx);
|
||||||
|
|
||||||
|
#update print and start background processing
|
||||||
|
$self->stop_background_process;
|
||||||
|
$self->{print}->add_model_object($model_object, $obj_idx);
|
||||||
|
|
||||||
|
$self->selection_changed(1); # refresh info (size, volume etc.)
|
||||||
|
$self->update;
|
||||||
|
$self->schedule_background_process;
|
||||||
|
};
|
||||||
|
|
||||||
# Initialize 3D plater
|
# Initialize 3D plater
|
||||||
if ($Slic3r::GUI::have_OpenGL) {
|
if ($Slic3r::GUI::have_OpenGL) {
|
||||||
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config});
|
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config});
|
||||||
$self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D'));
|
$self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D'));
|
||||||
$self->{canvas3D}->set_on_select_object($on_select_object);
|
Slic3r::GUI::_3DScene::register_on_select_object_callback($self->{canvas3D}, $on_select_object);
|
||||||
$self->{canvas3D}->set_on_double_click($on_double_click);
|
Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click);
|
||||||
$self->{canvas3D}->set_on_right_click(sub { $on_right_click->($self->{canvas3D}, @_); });
|
Slic3r::GUI::_3DScene::register_on_right_click_callback($self->{canvas3D}, sub { $on_right_click->($self->{canvas3D}, @_); });
|
||||||
$self->{canvas3D}->set_on_arrange(sub { $self->arrange });
|
Slic3r::GUI::_3DScene::register_on_arrange_callback($self->{canvas3D}, sub { $self->arrange });
|
||||||
$self->{canvas3D}->set_on_rotate_object_left(sub { $self->rotate(-45, Z, 'relative') });
|
Slic3r::GUI::_3DScene::register_on_rotate_object_left_callback($self->{canvas3D}, sub { $self->rotate(-45, Z, 'relative') });
|
||||||
$self->{canvas3D}->set_on_rotate_object_right(sub { $self->rotate( 45, Z, 'relative') });
|
Slic3r::GUI::_3DScene::register_on_rotate_object_right_callback($self->{canvas3D}, sub { $self->rotate( 45, Z, 'relative') });
|
||||||
$self->{canvas3D}->set_on_scale_object_uniformly(sub { $self->changescale(undef) });
|
Slic3r::GUI::_3DScene::register_on_scale_object_uniformly_callback($self->{canvas3D}, sub { $self->changescale(undef) });
|
||||||
$self->{canvas3D}->set_on_increase_objects(sub { $self->increase() });
|
Slic3r::GUI::_3DScene::register_on_increase_objects_callback($self->{canvas3D}, sub { $self->increase() });
|
||||||
$self->{canvas3D}->set_on_decrease_objects(sub { $self->decrease() });
|
Slic3r::GUI::_3DScene::register_on_decrease_objects_callback($self->{canvas3D}, sub { $self->decrease() });
|
||||||
$self->{canvas3D}->set_on_remove_object(sub { $self->remove() });
|
Slic3r::GUI::_3DScene::register_on_remove_object_callback($self->{canvas3D}, sub { $self->remove() });
|
||||||
$self->{canvas3D}->set_on_instances_moved($on_instances_moved);
|
Slic3r::GUI::_3DScene::register_on_instance_moved_callback($self->{canvas3D}, $on_instances_moved);
|
||||||
$self->{canvas3D}->set_on_enable_action_buttons($enable_action_buttons);
|
Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons);
|
||||||
$self->{canvas3D}->use_plain_shader(1);
|
Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly);
|
||||||
$self->{canvas3D}->set_on_wipe_tower_moved(sub {
|
# Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1);
|
||||||
my ($new_pos_3f) = @_;
|
Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1);
|
||||||
|
Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1);
|
||||||
|
|
||||||
|
Slic3r::GUI::_3DScene::register_on_wipe_tower_moved_callback($self->{canvas3D}, sub {
|
||||||
|
my ($x, $y) = @_;
|
||||||
my $cfg = Slic3r::Config->new;
|
my $cfg = Slic3r::Config->new;
|
||||||
$cfg->set('wipe_tower_x', $new_pos_3f->x);
|
$cfg->set('wipe_tower_x', $x);
|
||||||
$cfg->set('wipe_tower_y', $new_pos_3f->y);
|
$cfg->set('wipe_tower_y', $y);
|
||||||
$self->GetFrame->{options_tabs}{print}->load_config($cfg);
|
$self->GetFrame->{options_tabs}{print}->load_config($cfg);
|
||||||
});
|
});
|
||||||
$self->{canvas3D}->set_on_model_update(sub {
|
|
||||||
|
Slic3r::GUI::_3DScene::register_on_model_update_callback($self->{canvas3D}, sub {
|
||||||
if (wxTheApp->{app_config}->get("background_processing")) {
|
if (wxTheApp->{app_config}->get("background_processing")) {
|
||||||
$self->schedule_background_process;
|
$self->schedule_background_process;
|
||||||
} else {
|
} else {
|
||||||
@ -138,9 +171,8 @@ sub new {
|
|||||||
$self->{"print_info_box_show"}->(0);
|
$self->{"print_info_box_show"}->(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$self->{canvas3D}->on_viewport_changed(sub {
|
|
||||||
$self->{preview3D}->canvas->set_viewport_from_scene($self->{canvas3D});
|
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Initialize 2D preview canvas
|
# Initialize 2D preview canvas
|
||||||
@ -154,9 +186,8 @@ sub new {
|
|||||||
# Initialize 3D toolpaths preview
|
# Initialize 3D toolpaths preview
|
||||||
if ($Slic3r::GUI::have_OpenGL) {
|
if ($Slic3r::GUI::have_OpenGL) {
|
||||||
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
|
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
|
||||||
$self->{preview3D}->canvas->on_viewport_changed(sub {
|
Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 0);
|
||||||
$self->{canvas3D}->set_viewport_from_scene($self->{preview3D}->canvas);
|
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); });
|
||||||
});
|
|
||||||
$self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview'));
|
$self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview'));
|
||||||
$self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1;
|
$self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1;
|
||||||
}
|
}
|
||||||
@ -171,13 +202,25 @@ sub new {
|
|||||||
my $preview = $self->{preview_notebook}->GetCurrentPage;
|
my $preview = $self->{preview_notebook}->GetCurrentPage;
|
||||||
if ($preview == $self->{preview3D})
|
if ($preview == $self->{preview3D})
|
||||||
{
|
{
|
||||||
$self->{preview3D}->canvas->set_legend_enabled(1);
|
Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 1);
|
||||||
|
Slic3r::GUI::_3DScene::set_active($self->{canvas3D}, 0);
|
||||||
|
Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1);
|
||||||
$self->{preview3D}->load_print(1);
|
$self->{preview3D}->load_print(1);
|
||||||
} else {
|
} else {
|
||||||
$self->{preview3D}->canvas->set_legend_enabled(0);
|
Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$preview->OnActivate if $preview->can('OnActivate');
|
if ($preview == $self->{canvas3D}) {
|
||||||
|
Slic3r::GUI::_3DScene::set_active($self->{canvas3D}, 1);
|
||||||
|
Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 0);
|
||||||
|
if (Slic3r::GUI::_3DScene::is_reload_delayed($self->{canvas3D})) {
|
||||||
|
my $selections = $self->collect_selections;
|
||||||
|
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
|
||||||
|
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$preview->OnActivate if $preview->can('OnActivate');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
# toolbar for object manipulation
|
# toolbar for object manipulation
|
||||||
@ -314,7 +357,7 @@ sub new {
|
|||||||
EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog });
|
EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog });
|
||||||
EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog });
|
EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog });
|
||||||
EVT_TOOL($self, TB_LAYER_EDITING, sub {
|
EVT_TOOL($self, TB_LAYER_EDITING, sub {
|
||||||
my $state = $self->{canvas3D}->layer_editing_enabled;
|
my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
|
||||||
$self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state);
|
$self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state);
|
||||||
$self->on_layer_editing_toggled(! $state);
|
$self->on_layer_editing_toggled(! $state);
|
||||||
});
|
});
|
||||||
@ -369,11 +412,11 @@ sub new {
|
|||||||
|
|
||||||
$self->{canvas}->update_bed_size;
|
$self->{canvas}->update_bed_size;
|
||||||
if ($self->{canvas3D}) {
|
if ($self->{canvas3D}) {
|
||||||
$self->{canvas3D}->update_bed_size;
|
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape);
|
||||||
$self->{canvas3D}->zoom_to_bed;
|
Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D});
|
||||||
}
|
}
|
||||||
if ($self->{preview3D}) {
|
if ($self->{preview3D}) {
|
||||||
$self->{preview3D}->set_bed_shape($self->{config}->bed_shape);
|
Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape);
|
||||||
}
|
}
|
||||||
$self->update;
|
$self->update;
|
||||||
|
|
||||||
@ -590,8 +633,8 @@ sub _on_select_preset {
|
|||||||
|
|
||||||
sub on_layer_editing_toggled {
|
sub on_layer_editing_toggled {
|
||||||
my ($self, $new_state) = @_;
|
my ($self, $new_state) = @_;
|
||||||
$self->{canvas3D}->layer_editing_enabled($new_state);
|
Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state);
|
||||||
if ($new_state && ! $self->{canvas3D}->layer_editing_enabled) {
|
if ($new_state && ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D})) {
|
||||||
# Initialization of the OpenGL shaders failed. Disable the tool.
|
# Initialization of the OpenGL shaders failed. Disable the tool.
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
|
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
|
||||||
@ -825,8 +868,7 @@ sub load_model_objects {
|
|||||||
$self->update;
|
$self->update;
|
||||||
|
|
||||||
# zoom to objects
|
# zoom to objects
|
||||||
$self->{canvas3D}->zoom_to_volumes
|
Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
|
||||||
if $self->{canvas3D};
|
|
||||||
|
|
||||||
$self->{list}->Update;
|
$self->{list}->Update;
|
||||||
$self->{list}->Select($obj_idx[-1], 1);
|
$self->{list}->Select($obj_idx[-1], 1);
|
||||||
@ -1217,8 +1259,7 @@ sub async_apply_config {
|
|||||||
my $invalidated = $self->{print}->apply_config(wxTheApp->{preset_bundle}->full_config);
|
my $invalidated = $self->{print}->apply_config(wxTheApp->{preset_bundle}->full_config);
|
||||||
|
|
||||||
# Just redraw the 3D canvas without reloading the scene.
|
# Just redraw the 3D canvas without reloading the scene.
|
||||||
# $self->{canvas3D}->Refresh if ($invalidated && $self->{canvas3D}->layer_editing_enabled);
|
$self->{canvas3D}->Refresh if Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
|
||||||
$self->{canvas3D}->Refresh if ($self->{canvas3D}->layer_editing_enabled);
|
|
||||||
|
|
||||||
# Hide the slicing results if the current slicing status is no more valid.
|
# Hide the slicing results if the current slicing status is no more valid.
|
||||||
$self->{"print_info_box_show"}->(0) if $invalidated;
|
$self->{"print_info_box_show"}->(0) if $invalidated;
|
||||||
@ -1619,6 +1660,34 @@ sub export_object_stl {
|
|||||||
$self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
|
$self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub fix_through_netfabb {
|
||||||
|
my ($self) = @_;
|
||||||
|
my ($obj_idx, $object) = $self->selected_object;
|
||||||
|
return if !defined $obj_idx;
|
||||||
|
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||||
|
my $model_fixed = Slic3r::Model->new;
|
||||||
|
Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
|
||||||
|
|
||||||
|
my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
|
||||||
|
return if !@new_obj_idx;
|
||||||
|
|
||||||
|
foreach my $new_obj_idx (@new_obj_idx) {
|
||||||
|
my $o = $self->{model}->objects->[$new_obj_idx];
|
||||||
|
$o->clear_instances;
|
||||||
|
$o->add_instance($_) for @{$model_object->instances};
|
||||||
|
#$o->invalidate_bounding_box;
|
||||||
|
|
||||||
|
if ($o->volumes_count == $model_object->volumes_count) {
|
||||||
|
for my $i (0..($o->volumes_count-1)) {
|
||||||
|
$o->get_volume($i)->config->apply($model_object->get_volume($i)->config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->remove($obj_idx);
|
||||||
|
}
|
||||||
|
|
||||||
sub export_amf {
|
sub export_amf {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
return if !@{$self->{objects}};
|
return if !@{$self->{objects}};
|
||||||
@ -1723,7 +1792,9 @@ sub update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$self->{canvas}->reload_scene if $self->{canvas};
|
$self->{canvas}->reload_scene if $self->{canvas};
|
||||||
$self->{canvas3D}->reload_scene if $self->{canvas3D};
|
my $selections = $self->collect_selections;
|
||||||
|
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
|
||||||
|
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
|
||||||
$self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
|
$self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
|
||||||
$self->{preview3D}->reload_print if $self->{preview3D};
|
$self->{preview3D}->reload_print if $self->{preview3D};
|
||||||
}
|
}
|
||||||
@ -1778,9 +1849,8 @@ sub on_config_change {
|
|||||||
$self->{config}->set($opt_key, $config->get($opt_key));
|
$self->{config}->set($opt_key, $config->get($opt_key));
|
||||||
if ($opt_key eq 'bed_shape') {
|
if ($opt_key eq 'bed_shape') {
|
||||||
$self->{canvas}->update_bed_size;
|
$self->{canvas}->update_bed_size;
|
||||||
$self->{canvas3D}->update_bed_size if $self->{canvas3D};
|
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D};
|
||||||
$self->{preview3D}->set_bed_shape($self->{config}->bed_shape)
|
Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
|
||||||
if $self->{preview3D};
|
|
||||||
$update_scheduled = 1;
|
$update_scheduled = 1;
|
||||||
} elsif ($opt_key =~ '^wipe_tower' || $opt_key eq 'single_extruder_multi_material') {
|
} elsif ($opt_key =~ '^wipe_tower' || $opt_key eq 'single_extruder_multi_material') {
|
||||||
$update_scheduled = 1;
|
$update_scheduled = 1;
|
||||||
@ -1799,10 +1869,10 @@ sub on_config_change {
|
|||||||
$self->{"btn_layer_editing"}->Disable;
|
$self->{"btn_layer_editing"}->Disable;
|
||||||
$self->{"btn_layer_editing"}->SetValue(0);
|
$self->{"btn_layer_editing"}->SetValue(0);
|
||||||
}
|
}
|
||||||
$self->{canvas3D}->layer_editing_enabled(0);
|
Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, 0);
|
||||||
$self->{canvas3D}->Refresh;
|
$self->{canvas3D}->Refresh;
|
||||||
$self->{canvas3D}->Update;
|
$self->{canvas3D}->Update;
|
||||||
} elsif ($self->{canvas3D}->layer_editing_allowed) {
|
} elsif (Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D})) {
|
||||||
# Want to allow the layer editing, but do it only if the OpenGL supports it.
|
# Want to allow the layer editing, but do it only if the OpenGL supports it.
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
|
$self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
|
||||||
@ -1834,8 +1904,8 @@ sub list_item_deselected {
|
|||||||
if ($self->{list}->GetFirstSelected == -1) {
|
if ($self->{list}->GetFirstSelected == -1) {
|
||||||
$self->select_object(undef);
|
$self->select_object(undef);
|
||||||
$self->{canvas}->Refresh;
|
$self->{canvas}->Refresh;
|
||||||
$self->{canvas3D}->deselect_volumes if $self->{canvas3D};
|
Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D};
|
||||||
$self->{canvas3D}->Render if $self->{canvas3D};
|
Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D};
|
||||||
}
|
}
|
||||||
undef $self->{_lecursor};
|
undef $self->{_lecursor};
|
||||||
}
|
}
|
||||||
@ -1847,11 +1917,23 @@ sub list_item_selected {
|
|||||||
my $obj_idx = $event->GetIndex;
|
my $obj_idx = $event->GetIndex;
|
||||||
$self->select_object($obj_idx);
|
$self->select_object($obj_idx);
|
||||||
$self->{canvas}->Refresh;
|
$self->{canvas}->Refresh;
|
||||||
$self->{canvas3D}->update_volumes_selection if $self->{canvas3D};
|
if ($self->{canvas3D}) {
|
||||||
$self->{canvas3D}->Render if $self->{canvas3D};
|
my $selections = $self->collect_selections;
|
||||||
|
Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
|
||||||
|
Slic3r::GUI::_3DScene::render($self->{canvas3D});
|
||||||
|
}
|
||||||
undef $self->{_lecursor};
|
undef $self->{_lecursor};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub collect_selections {
|
||||||
|
my ($self) = @_;
|
||||||
|
my $selections = [];
|
||||||
|
foreach my $o (@{$self->{objects}}) {
|
||||||
|
push(@$selections, $o->selected);
|
||||||
|
}
|
||||||
|
return $selections;
|
||||||
|
}
|
||||||
|
|
||||||
sub list_item_activated {
|
sub list_item_activated {
|
||||||
my ($self, $event, $obj_idx) = @_;
|
my ($self, $event, $obj_idx) = @_;
|
||||||
|
|
||||||
@ -1908,7 +1990,7 @@ sub object_cut_dialog {
|
|||||||
$self->remove($obj_idx);
|
$self->remove($obj_idx);
|
||||||
$self->load_model_objects(grep defined($_), @new_objects);
|
$self->load_model_objects(grep defined($_), @new_objects);
|
||||||
$self->arrange;
|
$self->arrange;
|
||||||
$self->{canvas3D}->zoom_to_volumes if $self->{canvas3D};
|
Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1944,7 +2026,9 @@ sub object_settings_dialog {
|
|||||||
$self->{print}->reload_object($obj_idx);
|
$self->{print}->reload_object($obj_idx);
|
||||||
$self->schedule_background_process;
|
$self->schedule_background_process;
|
||||||
$self->{canvas}->reload_scene if $self->{canvas};
|
$self->{canvas}->reload_scene if $self->{canvas};
|
||||||
$self->{canvas3D}->reload_scene if $self->{canvas3D};
|
my $selections = $self->collect_selections;
|
||||||
|
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
|
||||||
|
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
|
||||||
} else {
|
} else {
|
||||||
$self->resume_background_process;
|
$self->resume_background_process;
|
||||||
}
|
}
|
||||||
@ -1957,7 +2041,7 @@ sub object_list_changed {
|
|||||||
|
|
||||||
# Enable/disable buttons depending on whether there are any objects on the platter.
|
# Enable/disable buttons depending on whether there are any objects on the platter.
|
||||||
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
my $have_objects = @{$self->{objects}} ? 1 : 0;
|
||||||
my $variable_layer_height_allowed = $self->{config}->variable_layer_height && $self->{canvas3D}->layer_editing_allowed;
|
my $variable_layer_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D});
|
||||||
if ($self->{htoolbar}) {
|
if ($self->{htoolbar}) {
|
||||||
# On OSX or Linux
|
# On OSX or Linux
|
||||||
$self->{htoolbar}->EnableTool($_, $have_objects)
|
$self->{htoolbar}->EnableTool($_, $have_objects)
|
||||||
@ -1972,7 +2056,7 @@ sub object_list_changed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
||||||
my $model_fits = $self->{canvas3D} ? $self->{canvas3D}->volumes->check_outside_state($self->{config}) : 1;
|
my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1;
|
||||||
my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable';
|
my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable';
|
||||||
$self->{"btn_$_"}->$method
|
$self->{"btn_$_"}->$method
|
||||||
for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
|
for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
|
||||||
@ -2177,6 +2261,11 @@ sub object_menu {
|
|||||||
$frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
|
$frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
|
||||||
$self->export_object_stl;
|
$self->export_object_stl;
|
||||||
}, undef, 'brick_go.png');
|
}, undef, 'brick_go.png');
|
||||||
|
if (Slic3r::GUI::is_windows10) {
|
||||||
|
$frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub {
|
||||||
|
$self->fix_through_netfabb;
|
||||||
|
}, undef, 'brick_go.png');
|
||||||
|
}
|
||||||
|
|
||||||
return $menu;
|
return $menu;
|
||||||
}
|
}
|
||||||
@ -2187,11 +2276,11 @@ sub select_view {
|
|||||||
my $idx_page = $self->{preview_notebook}->GetSelection;
|
my $idx_page = $self->{preview_notebook}->GetSelection;
|
||||||
my $page = ($idx_page == &Wx::wxNOT_FOUND) ? L('3D') : $self->{preview_notebook}->GetPageText($idx_page);
|
my $page = ($idx_page == &Wx::wxNOT_FOUND) ? L('3D') : $self->{preview_notebook}->GetPageText($idx_page);
|
||||||
if ($page eq L('Preview')) {
|
if ($page eq L('Preview')) {
|
||||||
$self->{preview3D}->canvas->select_view($direction);
|
Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction);
|
||||||
$self->{canvas3D}->set_viewport_from_scene($self->{preview3D}->canvas);
|
Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas);
|
||||||
} else {
|
} else {
|
||||||
$self->{canvas3D}->select_view($direction);
|
Slic3r::GUI::_3DScene::select_view($self->{canvas3D}, $direction);
|
||||||
$self->{preview3D}->canvas->set_viewport_from_scene($self->{canvas3D});
|
Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ sub mouse_event {
|
|||||||
];
|
];
|
||||||
$self->{drag_object} = [ $obj_idx, $instance_idx ];
|
$self->{drag_object} = [ $obj_idx, $instance_idx ];
|
||||||
} elsif ($event->RightDown) {
|
} elsif ($event->RightDown) {
|
||||||
$self->{on_right_click}->($pos);
|
$self->{on_right_click}->($pos->x, $pos->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
last OBJECTS;
|
last OBJECTS;
|
||||||
|
@ -5,264 +5,279 @@ use utf8;
|
|||||||
|
|
||||||
use List::Util qw();
|
use List::Util qw();
|
||||||
use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL);
|
use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL);
|
||||||
use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR);
|
#==============================================================================================================================
|
||||||
|
#use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR);
|
||||||
|
#==============================================================================================================================
|
||||||
use base qw(Slic3r::GUI::3DScene Class::Accessor);
|
use base qw(Slic3r::GUI::3DScene Class::Accessor);
|
||||||
|
|
||||||
use Wx::Locale gettext => 'L';
|
#==============================================================================================================================
|
||||||
|
#use Wx::Locale gettext => 'L';
|
||||||
__PACKAGE__->mk_accessors(qw(
|
#
|
||||||
on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly
|
#__PACKAGE__->mk_accessors(qw(
|
||||||
on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons));
|
# on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly
|
||||||
|
# on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons));
|
||||||
|
#==============================================================================================================================
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my ($parent, $objects, $model, $print, $config) = @_;
|
my ($parent, $objects, $model, $print, $config) = @_;
|
||||||
|
|
||||||
my $self = $class->SUPER::new($parent);
|
my $self = $class->SUPER::new($parent);
|
||||||
$self->enable_picking(1);
|
#==============================================================================================================================
|
||||||
$self->enable_moving(1);
|
Slic3r::GUI::_3DScene::enable_picking($self, 1);
|
||||||
$self->select_by('object');
|
Slic3r::GUI::_3DScene::enable_moving($self, 1);
|
||||||
$self->drag_by('instance');
|
Slic3r::GUI::_3DScene::set_select_by($self, 'object');
|
||||||
|
Slic3r::GUI::_3DScene::set_drag_by($self, 'instance');
|
||||||
$self->{objects} = $objects;
|
Slic3r::GUI::_3DScene::set_model($self, $model);
|
||||||
$self->{model} = $model;
|
Slic3r::GUI::_3DScene::set_print($self, $print);
|
||||||
$self->{print} = $print;
|
Slic3r::GUI::_3DScene::set_config($self, $config);
|
||||||
$self->{config} = $config;
|
# $self->enable_picking(1);
|
||||||
$self->{on_select_object} = sub {};
|
# $self->enable_moving(1);
|
||||||
$self->{on_instances_moved} = sub {};
|
# $self->select_by('object');
|
||||||
$self->{on_wipe_tower_moved} = sub {};
|
# $self->drag_by('instance');
|
||||||
|
#
|
||||||
$self->{objects_volumes_idxs} = [];
|
# $self->{objects} = $objects;
|
||||||
|
# $self->{model} = $model;
|
||||||
$self->on_select(sub {
|
# $self->{print} = $print;
|
||||||
my ($volume_idx) = @_;
|
# $self->{config} = $config;
|
||||||
$self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx)
|
# $self->{on_select_object} = sub {};
|
||||||
if ($self->{on_select_object});
|
# $self->{on_instances_moved} = sub {};
|
||||||
});
|
# $self->{on_wipe_tower_moved} = sub {};
|
||||||
$self->on_move(sub {
|
#
|
||||||
my @volume_idxs = @_;
|
# $self->{objects_volumes_idxs} = [];
|
||||||
|
#
|
||||||
my %done = (); # prevent moving instances twice
|
# $self->on_select(sub {
|
||||||
my $object_moved;
|
# my ($volume_idx) = @_;
|
||||||
my $wipe_tower_moved;
|
# $self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx)
|
||||||
foreach my $volume_idx (@volume_idxs) {
|
# if ($self->{on_select_object});
|
||||||
my $volume = $self->volumes->[$volume_idx];
|
# });
|
||||||
my $obj_idx = $volume->object_idx;
|
#
|
||||||
my $instance_idx = $volume->instance_idx;
|
# $self->on_move(sub {
|
||||||
next if $done{"${obj_idx}_${instance_idx}"};
|
# my @volume_idxs = @_;
|
||||||
$done{"${obj_idx}_${instance_idx}"} = 1;
|
# my %done = (); # prevent moving instances twice
|
||||||
if ($obj_idx < 1000) {
|
# my $object_moved;
|
||||||
# Move a regular object.
|
# my $wipe_tower_moved;
|
||||||
my $model_object = $self->{model}->get_object($obj_idx);
|
# foreach my $volume_idx (@volume_idxs) {
|
||||||
$model_object
|
# my $volume = $self->volumes->[$volume_idx];
|
||||||
->instances->[$instance_idx]
|
# my $obj_idx = $volume->object_idx;
|
||||||
->offset
|
# my $instance_idx = $volume->instance_idx;
|
||||||
->translate($volume->origin->x, $volume->origin->y); #))
|
# next if $done{"${obj_idx}_${instance_idx}"};
|
||||||
$model_object->invalidate_bounding_box;
|
# $done{"${obj_idx}_${instance_idx}"} = 1;
|
||||||
$object_moved = 1;
|
# if ($obj_idx < 1000) {
|
||||||
} elsif ($obj_idx == 1000) {
|
# # Move a regular object.
|
||||||
# Move a wipe tower proxy.
|
# my $model_object = $self->{model}->get_object($obj_idx);
|
||||||
$wipe_tower_moved = $volume->origin;
|
# $model_object
|
||||||
}
|
# ->instances->[$instance_idx]
|
||||||
}
|
# ->offset
|
||||||
|
# ->translate($volume->origin->x, $volume->origin->y); #))
|
||||||
$self->{on_instances_moved}->()
|
# $model_object->invalidate_bounding_box;
|
||||||
if $object_moved && $self->{on_instances_moved};
|
# $object_moved = 1;
|
||||||
$self->{on_wipe_tower_moved}->($wipe_tower_moved)
|
# } elsif ($obj_idx == 1000) {
|
||||||
if $wipe_tower_moved && $self->{on_wipe_tower_moved};
|
# # Move a wipe tower proxy.
|
||||||
});
|
# $wipe_tower_moved = $volume->origin;
|
||||||
|
# }
|
||||||
EVT_KEY_DOWN($self, sub {
|
# }
|
||||||
my ($s, $event) = @_;
|
#
|
||||||
if ($event->HasModifiers) {
|
# $self->{on_instances_moved}->()
|
||||||
$event->Skip;
|
# if $object_moved && $self->{on_instances_moved};
|
||||||
} else {
|
# $self->{on_wipe_tower_moved}->($wipe_tower_moved)
|
||||||
my $key = $event->GetKeyCode;
|
# if $wipe_tower_moved && $self->{on_wipe_tower_moved};
|
||||||
if ($key == WXK_DELETE) {
|
# });
|
||||||
$self->on_remove_object->() if $self->on_remove_object;
|
#
|
||||||
} else {
|
# EVT_KEY_DOWN($self, sub {
|
||||||
$event->Skip;
|
# my ($s, $event) = @_;
|
||||||
}
|
# if ($event->HasModifiers) {
|
||||||
}
|
# $event->Skip;
|
||||||
});
|
# } else {
|
||||||
|
# my $key = $event->GetKeyCode;
|
||||||
EVT_CHAR($self, sub {
|
# if ($key == WXK_DELETE) {
|
||||||
my ($s, $event) = @_;
|
# $self->on_remove_object->() if $self->on_remove_object;
|
||||||
if ($event->HasModifiers) {
|
# } else {
|
||||||
$event->Skip;
|
# $event->Skip;
|
||||||
} else {
|
# }
|
||||||
my $key = $event->GetKeyCode;
|
# }
|
||||||
if ($key == ord('a')) {
|
# });
|
||||||
$self->on_arrange->() if $self->on_arrange;
|
#
|
||||||
} elsif ($key == ord('l')) {
|
# EVT_CHAR($self, sub {
|
||||||
$self->on_rotate_object_left->() if $self->on_rotate_object_left;
|
# my ($s, $event) = @_;
|
||||||
} elsif ($key == ord('r')) {
|
# if ($event->HasModifiers) {
|
||||||
$self->on_rotate_object_right->() if $self->on_rotate_object_right;
|
# $event->Skip;
|
||||||
} elsif ($key == ord('s')) {
|
# } else {
|
||||||
$self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly;
|
# my $key = $event->GetKeyCode;
|
||||||
} elsif ($key == ord('+')) {
|
# if ($key == ord('a')) {
|
||||||
$self->on_increase_objects->() if $self->on_increase_objects;
|
# $self->on_arrange->() if $self->on_arrange;
|
||||||
} elsif ($key == ord('-')) {
|
# } elsif ($key == ord('l')) {
|
||||||
$self->on_decrease_objects->() if $self->on_decrease_objects;
|
# $self->on_rotate_object_left->() if $self->on_rotate_object_left;
|
||||||
} else {
|
# } elsif ($key == ord('r')) {
|
||||||
$event->Skip;
|
# $self->on_rotate_object_right->() if $self->on_rotate_object_right;
|
||||||
}
|
# } elsif ($key == ord('s')) {
|
||||||
}
|
# $self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly;
|
||||||
});
|
# } elsif ($key == ord('+')) {
|
||||||
|
# $self->on_increase_objects->() if $self->on_increase_objects;
|
||||||
|
# } elsif ($key == ord('-')) {
|
||||||
|
# $self->on_decrease_objects->() if $self->on_decrease_objects;
|
||||||
|
# } else {
|
||||||
|
# $event->Skip;
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# });
|
||||||
|
#==============================================================================================================================
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_on_select_object {
|
#==============================================================================================================================
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_select_object {
|
||||||
$self->{on_select_object} = $cb;
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->{on_select_object} = $cb;
|
||||||
|
#}
|
||||||
sub set_on_double_click {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_double_click {
|
||||||
$self->on_double_click($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_double_click($cb);
|
||||||
|
#}
|
||||||
sub set_on_right_click {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_right_click {
|
||||||
$self->on_right_click($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_right_click($cb);
|
||||||
|
#}
|
||||||
sub set_on_arrange {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_arrange {
|
||||||
$self->on_arrange($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_arrange($cb);
|
||||||
|
#}
|
||||||
sub set_on_rotate_object_left {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_rotate_object_left {
|
||||||
$self->on_rotate_object_left($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_rotate_object_left($cb);
|
||||||
|
#}
|
||||||
sub set_on_rotate_object_right {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_rotate_object_right {
|
||||||
$self->on_rotate_object_right($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_rotate_object_right($cb);
|
||||||
|
#}
|
||||||
sub set_on_scale_object_uniformly {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_scale_object_uniformly {
|
||||||
$self->on_scale_object_uniformly($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_scale_object_uniformly($cb);
|
||||||
|
#}
|
||||||
sub set_on_increase_objects {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_increase_objects {
|
||||||
$self->on_increase_objects($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_increase_objects($cb);
|
||||||
|
#}
|
||||||
sub set_on_decrease_objects {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_decrease_objects {
|
||||||
$self->on_decrease_objects($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_decrease_objects($cb);
|
||||||
|
#}
|
||||||
sub set_on_remove_object {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_remove_object {
|
||||||
$self->on_remove_object($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_remove_object($cb);
|
||||||
|
#}
|
||||||
sub set_on_instances_moved {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_instances_moved {
|
||||||
$self->{on_instances_moved} = $cb;
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->{on_instances_moved} = $cb;
|
||||||
|
#}
|
||||||
sub set_on_wipe_tower_moved {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_wipe_tower_moved {
|
||||||
$self->{on_wipe_tower_moved} = $cb;
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->{on_wipe_tower_moved} = $cb;
|
||||||
|
#}
|
||||||
sub set_on_model_update {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_model_update {
|
||||||
$self->on_model_update($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_model_update($cb);
|
||||||
|
#}
|
||||||
sub set_on_enable_action_buttons {
|
#
|
||||||
my ($self, $cb) = @_;
|
#sub set_on_enable_action_buttons {
|
||||||
$self->on_enable_action_buttons($cb);
|
# my ($self, $cb) = @_;
|
||||||
}
|
# $self->on_enable_action_buttons($cb);
|
||||||
|
#}
|
||||||
sub update_volumes_selection {
|
#
|
||||||
my ($self) = @_;
|
#sub update_volumes_selection {
|
||||||
|
# my ($self) = @_;
|
||||||
foreach my $obj_idx (0..$#{$self->{model}->objects}) {
|
#
|
||||||
if ($self->{objects}[$obj_idx]->selected) {
|
# foreach my $obj_idx (0..$#{$self->{model}->objects}) {
|
||||||
my $volume_idxs = $self->{objects_volumes_idxs}->[$obj_idx];
|
# if ($self->{objects}[$obj_idx]->selected) {
|
||||||
$self->select_volume($_) for @{$volume_idxs};
|
# my $volume_idxs = $self->{objects_volumes_idxs}->[$obj_idx];
|
||||||
}
|
# $self->select_volume($_) for @{$volume_idxs};
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
|
#}
|
||||||
sub reload_scene {
|
#
|
||||||
my ($self, $force) = @_;
|
#sub reload_scene {
|
||||||
|
# my ($self, $force) = @_;
|
||||||
$self->reset_objects;
|
#
|
||||||
$self->update_bed_size;
|
# $self->reset_objects;
|
||||||
|
# $self->update_bed_size;
|
||||||
if (! $self->IsShown && ! $force) {
|
#
|
||||||
$self->{reload_delayed} = 1;
|
# if (! $self->IsShown && ! $force) {
|
||||||
return;
|
# $self->{reload_delayed} = 1;
|
||||||
}
|
# return;
|
||||||
|
# }
|
||||||
$self->{reload_delayed} = 0;
|
#
|
||||||
|
# $self->{reload_delayed} = 0;
|
||||||
$self->{objects_volumes_idxs} = [];
|
#
|
||||||
foreach my $obj_idx (0..$#{$self->{model}->objects}) {
|
# $self->{objects_volumes_idxs} = [];
|
||||||
my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx);
|
# foreach my $obj_idx (0..$#{$self->{model}->objects}) {
|
||||||
push(@{$self->{objects_volumes_idxs}}, \@volume_idxs);
|
# my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx);
|
||||||
}
|
# push(@{$self->{objects_volumes_idxs}}, \@volume_idxs);
|
||||||
|
# }
|
||||||
$self->update_volumes_selection;
|
#
|
||||||
|
# $self->update_volumes_selection;
|
||||||
if (defined $self->{config}->nozzle_diameter) {
|
#
|
||||||
# Should the wipe tower be visualized?
|
# if (defined $self->{config}->nozzle_diameter) {
|
||||||
my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
|
# # Should the wipe tower be visualized?
|
||||||
# Height of a print.
|
# my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
|
||||||
my $height = $self->{model}->bounding_box->z_max;
|
# # Height of a print.
|
||||||
# Show at least a slab.
|
# my $height = $self->{model}->bounding_box->z_max;
|
||||||
$height = 10 if $height < 10;
|
# # Show at least a slab.
|
||||||
if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
|
# $height = 10 if $height < 10;
|
||||||
! $self->{config}->complete_objects) {
|
# if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
|
||||||
$self->volumes->load_wipe_tower_preview(1000,
|
# ! $self->{config}->complete_objects) {
|
||||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
|
# $self->volumes->load_wipe_tower_preview(1000,
|
||||||
#$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
|
# $self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
|
||||||
15 * ($extruders_count - 1),
|
# #$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
|
||||||
$self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
|
# 15 * ($extruders_count - 1),
|
||||||
}
|
# $self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
|
||||||
}
|
# }
|
||||||
|
# }
|
||||||
$self->update_volumes_colors_by_extruder($self->{config});
|
#
|
||||||
|
# $self->update_volumes_colors_by_extruder($self->{config});
|
||||||
# checks for geometry outside the print volume to render it accordingly
|
#
|
||||||
if (scalar @{$self->volumes} > 0)
|
# # checks for geometry outside the print volume to render it accordingly
|
||||||
{
|
# if (scalar @{$self->volumes} > 0)
|
||||||
my $contained = $self->volumes->check_outside_state($self->{config});
|
# {
|
||||||
if (!$contained) {
|
# my $contained = $self->volumes->check_outside_state($self->{config});
|
||||||
$self->set_warning_enabled(1);
|
# if (!$contained) {
|
||||||
Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume"));
|
# $self->set_warning_enabled(1);
|
||||||
$self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons);
|
# Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume"));
|
||||||
} else {
|
# $self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons);
|
||||||
$self->set_warning_enabled(0);
|
# } else {
|
||||||
$self->volumes->reset_outside_state();
|
# $self->set_warning_enabled(0);
|
||||||
Slic3r::GUI::_3DScene::reset_warning_texture();
|
# $self->volumes->reset_outside_state();
|
||||||
$self->on_enable_action_buttons->(scalar @{$self->{model}->objects} > 0) if ($self->on_enable_action_buttons);
|
# Slic3r::GUI::_3DScene::reset_warning_texture();
|
||||||
}
|
# $self->on_enable_action_buttons->(scalar @{$self->{model}->objects} > 0) if ($self->on_enable_action_buttons);
|
||||||
} else {
|
# }
|
||||||
$self->set_warning_enabled(0);
|
# } else {
|
||||||
Slic3r::GUI::_3DScene::reset_warning_texture();
|
# $self->set_warning_enabled(0);
|
||||||
}
|
# Slic3r::GUI::_3DScene::reset_warning_texture();
|
||||||
}
|
# }
|
||||||
|
#}
|
||||||
sub update_bed_size {
|
#
|
||||||
my ($self) = @_;
|
#sub update_bed_size {
|
||||||
$self->set_bed_shape($self->{config}->bed_shape);
|
# my ($self) = @_;
|
||||||
}
|
# $self->set_bed_shape($self->{config}->bed_shape);
|
||||||
|
#}
|
||||||
# Called by the Platter wxNotebook when this page is activated.
|
#
|
||||||
sub OnActivate {
|
## Called by the Platter wxNotebook when this page is activated.
|
||||||
my ($self) = @_;
|
#sub OnActivate {
|
||||||
$self->reload_scene(1) if ($self->{reload_delayed});
|
# my ($self) = @_;
|
||||||
}
|
# $self->reload_scene(1) if ($self->{reload_delayed});
|
||||||
|
#}
|
||||||
|
#==============================================================================================================================
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -24,7 +24,7 @@ sub new {
|
|||||||
|
|
||||||
# init GUI elements
|
# init GUI elements
|
||||||
my $canvas = Slic3r::GUI::3DScene->new($self);
|
my $canvas = Slic3r::GUI::3DScene->new($self);
|
||||||
$canvas->use_plain_shader(1);
|
Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
|
||||||
$self->canvas($canvas);
|
$self->canvas($canvas);
|
||||||
my $slider_low = Wx::Slider->new(
|
my $slider_low = Wx::Slider->new(
|
||||||
$self, -1,
|
$self, -1,
|
||||||
@ -277,8 +277,8 @@ sub new {
|
|||||||
|
|
||||||
sub reload_print {
|
sub reload_print {
|
||||||
my ($self, $force) = @_;
|
my ($self, $force) = @_;
|
||||||
|
|
||||||
$self->canvas->reset_objects;
|
Slic3r::GUI::_3DScene::reset_volumes($self->canvas);
|
||||||
$self->_loaded(0);
|
$self->_loaded(0);
|
||||||
|
|
||||||
if (! $self->IsShown && ! $force) {
|
if (! $self->IsShown && ! $force) {
|
||||||
@ -304,7 +304,7 @@ sub refresh_print {
|
|||||||
sub reset_gcode_preview_data {
|
sub reset_gcode_preview_data {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
$self->gcode_preview_data->reset;
|
$self->gcode_preview_data->reset;
|
||||||
$self->canvas->reset_legend_texture();
|
Slic3r::GUI::_3DScene::reset_legend_texture();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_print {
|
sub load_print {
|
||||||
@ -329,7 +329,7 @@ sub load_print {
|
|||||||
|
|
||||||
if ($n_layers == 0) {
|
if ($n_layers == 0) {
|
||||||
$self->reset_sliders;
|
$self->reset_sliders;
|
||||||
$self->canvas->reset_legend_texture();
|
Slic3r::GUI::_3DScene::reset_legend_texture();
|
||||||
$self->canvas->Refresh; # clears canvas
|
$self->canvas->Refresh; # clears canvas
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -364,23 +364,25 @@ sub load_print {
|
|||||||
|
|
||||||
if ($self->gcode_preview_data->empty) {
|
if ($self->gcode_preview_data->empty) {
|
||||||
# load skirt and brim
|
# load skirt and brim
|
||||||
$self->canvas->load_print_toolpaths($self->print, \@colors);
|
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
|
||||||
$self->canvas->load_wipe_tower_toolpaths($self->print, \@colors);
|
Slic3r::GUI::_3DScene::load_print_toolpaths($self->canvas);
|
||||||
|
Slic3r::GUI::_3DScene::load_wipe_tower_toolpaths($self->canvas, \@colors);
|
||||||
foreach my $object (@{$self->print->objects}) {
|
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);
|
||||||
# Show the objects in very transparent color.
|
# Show the objects in very transparent color.
|
||||||
#my @volume_ids = $self->canvas->load_object($object->model_object);
|
#my @volume_ids = $self->canvas->load_object($object->model_object);
|
||||||
#$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids;
|
#$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids;
|
||||||
}
|
}
|
||||||
$self->show_hide_ui_elements('simple');
|
$self->show_hide_ui_elements('simple');
|
||||||
$self->canvas->reset_legend_texture();
|
Slic3r::GUI::_3DScene::reset_legend_texture();
|
||||||
} else {
|
} else {
|
||||||
$self->{force_sliders_full_range} = (scalar(@{$self->canvas->volumes}) == 0);
|
$self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0);
|
||||||
$self->canvas->load_gcode_preview($self->print, $self->gcode_preview_data, \@colors);
|
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
|
||||||
|
Slic3r::GUI::_3DScene::load_gcode_preview($self->canvas, $self->gcode_preview_data, \@colors);
|
||||||
$self->show_hide_ui_elements('full');
|
$self->show_hide_ui_elements('full');
|
||||||
|
|
||||||
# recalculates zs and update sliders accordingly
|
# recalculates zs and update sliders accordingly
|
||||||
$self->{layers_z} = $self->canvas->get_current_print_zs(1);
|
$self->{layers_z} = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 1);
|
||||||
$n_layers = scalar(@{$self->{layers_z}});
|
$n_layers = scalar(@{$self->{layers_z}});
|
||||||
if ($n_layers == 0) {
|
if ($n_layers == 0) {
|
||||||
# all layers filtered out
|
# all layers filtered out
|
||||||
@ -466,7 +468,7 @@ sub set_z_range
|
|||||||
$self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low);
|
$self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low);
|
||||||
$self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high);
|
$self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high);
|
||||||
|
|
||||||
my $layers_z = $self->canvas->get_current_print_zs(0);
|
my $layers_z = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 0);
|
||||||
for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
|
for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
|
||||||
if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) {
|
if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) {
|
||||||
$self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1);
|
$self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1);
|
||||||
@ -480,7 +482,7 @@ sub set_z_range
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->canvas->set_toolpaths_range($z_low - 1e-6, $z_high + 1e-6);
|
Slic3r::GUI::_3DScene::set_toolpaths_range($self->canvas, $z_low - 1e-6, $z_high + 1e-6);
|
||||||
$self->canvas->Refresh if $self->IsShown;
|
$self->canvas->Refresh if $self->IsShown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,11 +512,6 @@ sub set_z_idx_high
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_bed_shape {
|
|
||||||
my ($self, $bed_shape) = @_;
|
|
||||||
$self->canvas->set_bed_shape($bed_shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_number_extruders {
|
sub set_number_extruders {
|
||||||
my ($self, $number_extruders) = @_;
|
my ($self, $number_extruders) = @_;
|
||||||
if ($self->{number_extruders} != $number_extruders) {
|
if ($self->{number_extruders} != $number_extruders) {
|
||||||
|
@ -9,6 +9,7 @@ use utf8;
|
|||||||
use Slic3r::Geometry qw(PI X);
|
use Slic3r::Geometry qw(PI X);
|
||||||
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
|
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
|
||||||
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
|
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
|
||||||
|
use List::Util qw(max);
|
||||||
use base 'Wx::Dialog';
|
use base 'Wx::Dialog';
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
@ -112,10 +113,13 @@ sub new {
|
|||||||
my $canvas;
|
my $canvas;
|
||||||
if ($Slic3r::GUI::have_OpenGL) {
|
if ($Slic3r::GUI::have_OpenGL) {
|
||||||
$canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
|
$canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
|
||||||
$canvas->load_object($self->{model_object}, undef, undef, [0]);
|
Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
|
||||||
$canvas->set_auto_bed_shape;
|
Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
|
||||||
|
Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ Slic3r::GUI::_3DScene::get_volumes_bounding_box($canvas)->size }));
|
||||||
$canvas->SetSize([500,500]);
|
$canvas->SetSize([500,500]);
|
||||||
$canvas->SetMinSize($canvas->GetSize);
|
$canvas->SetMinSize($canvas->GetSize);
|
||||||
|
Slic3r::GUI::_3DScene::set_config($canvas, $self->GetParent->{config});
|
||||||
|
Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($canvas, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||||
@ -144,6 +148,7 @@ sub new {
|
|||||||
# Note that the window was already closed, so a pending update will not be executed.
|
# Note that the window was already closed, so a pending update will not be executed.
|
||||||
$self->{already_closed} = 1;
|
$self->{already_closed} = 1;
|
||||||
$self->EndModal(wxID_OK);
|
$self->EndModal(wxID_OK);
|
||||||
|
$self->{canvas}->Destroy;
|
||||||
$self->Destroy();
|
$self->Destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -151,6 +156,7 @@ sub new {
|
|||||||
# Note that the window was already closed, so a pending update will not be executed.
|
# Note that the window was already closed, so a pending update will not be executed.
|
||||||
$self->{already_closed} = 1;
|
$self->{already_closed} = 1;
|
||||||
$self->EndModal(wxID_CANCEL);
|
$self->EndModal(wxID_CANCEL);
|
||||||
|
$self->{canvas}->Destroy;
|
||||||
$self->Destroy();
|
$self->Destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -241,15 +247,12 @@ sub _update {
|
|||||||
for @$expolygon;
|
for @$expolygon;
|
||||||
$expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
|
$expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{canvas}->reset_objects;
|
Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
|
||||||
$self->{canvas}->load_object($_, undef, undef, [0]) for @objects;
|
Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $_, 0, [0]) for @objects;
|
||||||
$self->{canvas}->SetCuttingPlane(
|
Slic3r::GUI::_3DScene::set_cutting_plane($self->{canvas}, $self->{cut_options}{z}, [@expolygons]);
|
||||||
$self->{cut_options}{z},
|
Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
|
||||||
[@expolygons],
|
Slic3r::GUI::_3DScene::render($self->{canvas});
|
||||||
);
|
|
||||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->{config});
|
|
||||||
$self->{canvas}->Render;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use File::Basename qw(basename);
|
|||||||
use Wx qw(:misc :sizer :treectrl :button :keycode wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL wxMOD_CONTROL
|
use Wx qw(:misc :sizer :treectrl :button :keycode wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL wxMOD_CONTROL
|
||||||
wxTheApp);
|
wxTheApp);
|
||||||
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN EVT_KEY_DOWN);
|
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN EVT_KEY_DOWN);
|
||||||
|
use List::Util qw(max);
|
||||||
use base 'Wx::Panel';
|
use base 'Wx::Panel';
|
||||||
|
|
||||||
use constant ICON_OBJECT => 0;
|
use constant ICON_OBJECT => 0;
|
||||||
@ -150,19 +151,19 @@ sub new {
|
|||||||
my $canvas;
|
my $canvas;
|
||||||
if ($Slic3r::GUI::have_OpenGL) {
|
if ($Slic3r::GUI::have_OpenGL) {
|
||||||
$canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
|
$canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
|
||||||
$canvas->enable_picking(1);
|
Slic3r::GUI::_3DScene::enable_picking($canvas, 1);
|
||||||
$canvas->select_by('volume');
|
Slic3r::GUI::_3DScene::set_select_by($canvas, 'volume');
|
||||||
|
Slic3r::GUI::_3DScene::register_on_select_object_callback($canvas, sub {
|
||||||
$canvas->on_select(sub {
|
|
||||||
my ($volume_idx) = @_;
|
my ($volume_idx) = @_;
|
||||||
# convert scene volume to model object volume
|
$self->reload_tree($volume_idx);
|
||||||
$self->reload_tree(($volume_idx == -1) ? undef : $canvas->volumes->[$volume_idx]->volume_idx);
|
|
||||||
});
|
});
|
||||||
|
Slic3r::GUI::_3DScene::load_model_object($canvas, $self->{model_object}, 0, [0]);
|
||||||
$canvas->load_object($self->{model_object}, undef, undef, [0]);
|
Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
|
||||||
$canvas->set_auto_bed_shape;
|
Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ Slic3r::GUI::_3DScene::get_volumes_bounding_box($canvas)->size }));
|
||||||
$canvas->SetSize([500,700]);
|
$canvas->SetSize([500,700]);
|
||||||
$canvas->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
Slic3r::GUI::_3DScene::set_config($canvas, $self->GetParent->GetParent->GetParent->{config});
|
||||||
|
Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($canvas);
|
||||||
|
Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($canvas, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||||
@ -262,7 +263,7 @@ sub selection_changed {
|
|||||||
|
|
||||||
# deselect all meshes
|
# deselect all meshes
|
||||||
if ($self->{canvas}) {
|
if ($self->{canvas}) {
|
||||||
$_->set_selected(0) for @{$self->{canvas}->volumes};
|
Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas});
|
||||||
}
|
}
|
||||||
|
|
||||||
# disable things as if nothing is selected
|
# disable things as if nothing is selected
|
||||||
@ -290,7 +291,7 @@ sub selection_changed {
|
|||||||
if ($itemData->{type} eq 'volume') {
|
if ($itemData->{type} eq 'volume') {
|
||||||
# select volume in 3D preview
|
# select volume in 3D preview
|
||||||
if ($self->{canvas}) {
|
if ($self->{canvas}) {
|
||||||
$self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1);
|
Slic3r::GUI::_3DScene::select_volume($self->{canvas}, $itemData->{volume_id});
|
||||||
}
|
}
|
||||||
$self->{btn_delete}->Enable;
|
$self->{btn_delete}->Enable;
|
||||||
$self->{btn_split}->Enable;
|
$self->{btn_split}->Enable;
|
||||||
@ -333,7 +334,7 @@ sub selection_changed {
|
|||||||
$self->{settings_panel}->enable;
|
$self->{settings_panel}->enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{canvas}->Render if $self->{canvas};
|
Slic3r::GUI::_3DScene::render($self->{canvas}) if $self->{canvas};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub on_btn_load {
|
sub on_btn_load {
|
||||||
@ -429,7 +430,7 @@ sub on_btn_move_up {
|
|||||||
if ($itemData && $itemData->{type} eq 'volume') {
|
if ($itemData && $itemData->{type} eq 'volume') {
|
||||||
my $volume_id = $itemData->{volume_id};
|
my $volume_id = $itemData->{volume_id};
|
||||||
if ($self->{model_object}->move_volume_up($volume_id)) {
|
if ($self->{model_object}->move_volume_up($volume_id)) {
|
||||||
$self->{canvas}->volumes->move_volume_up($volume_id);
|
Slic3r::GUI::_3DScene::move_volume_up($self->{canvas}, $volume_id);
|
||||||
$self->{parts_changed} = 1;
|
$self->{parts_changed} = 1;
|
||||||
$self->reload_tree($volume_id - 1);
|
$self->reload_tree($volume_id - 1);
|
||||||
}
|
}
|
||||||
@ -442,7 +443,7 @@ sub on_btn_move_down {
|
|||||||
if ($itemData && $itemData->{type} eq 'volume') {
|
if ($itemData && $itemData->{type} eq 'volume') {
|
||||||
my $volume_id = $itemData->{volume_id};
|
my $volume_id = $itemData->{volume_id};
|
||||||
if ($self->{model_object}->move_volume_down($volume_id)) {
|
if ($self->{model_object}->move_volume_down($volume_id)) {
|
||||||
$self->{canvas}->volumes->move_volume_down($volume_id);
|
Slic3r::GUI::_3DScene::move_volume_down($self->{canvas}, $volume_id);
|
||||||
$self->{parts_changed} = 1;
|
$self->{parts_changed} = 1;
|
||||||
$self->reload_tree($volume_id + 1);
|
$self->reload_tree($volume_id + 1);
|
||||||
}
|
}
|
||||||
@ -487,11 +488,11 @@ sub _parts_changed {
|
|||||||
|
|
||||||
$self->reload_tree;
|
$self->reload_tree;
|
||||||
if ($self->{canvas}) {
|
if ($self->{canvas}) {
|
||||||
$self->{canvas}->reset_objects;
|
Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
|
||||||
$self->{canvas}->load_object($self->{model_object});
|
Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
|
||||||
$self->{canvas}->zoom_to_volumes;
|
Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas});
|
||||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
|
||||||
$self->{canvas}->Render;
|
Slic3r::GUI::_3DScene::render($self->{canvas});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,6 +512,11 @@ sub CanClose {
|
|||||||
return ! Slic3r::GUI::catch_error($self);
|
return ! Slic3r::GUI::catch_error($self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub Destroy {
|
||||||
|
my ($self) = @_;
|
||||||
|
$self->{canvas}->Destroy if ($self->{canvas});
|
||||||
|
}
|
||||||
|
|
||||||
sub PartsChanged {
|
sub PartsChanged {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
return $self->{parts_changed};
|
return $self->{parts_changed};
|
||||||
@ -525,18 +531,18 @@ sub _update_canvas {
|
|||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
if ($self->{canvas}) {
|
if ($self->{canvas}) {
|
||||||
$self->{canvas}->reset_objects;
|
Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
|
||||||
$self->{canvas}->load_object($self->{model_object});
|
Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
|
||||||
|
|
||||||
# restore selection, if any
|
# restore selection, if any
|
||||||
if (my $itemData = $self->get_selection) {
|
if (my $itemData = $self->get_selection) {
|
||||||
if ($itemData->{type} eq 'volume') {
|
if ($itemData->{type} eq 'volume') {
|
||||||
$self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1);
|
Slic3r::GUI::_3DScene::select_volume($self->{canvas}, $itemData->{volume_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
|
||||||
$self->{canvas}->Render;
|
Slic3r::GUI::_3DScene::render($self->{canvas});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,10 +564,10 @@ sub _update {
|
|||||||
$self->{parts_changed} = 1;
|
$self->{parts_changed} = 1;
|
||||||
my @objects = ();
|
my @objects = ();
|
||||||
push @objects, $self->{model_object};
|
push @objects, $self->{model_object};
|
||||||
$self->{canvas}->reset_objects;
|
Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
|
||||||
$self->{canvas}->load_object($_, undef, [0]) for @objects;
|
Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $_, 0, [0]) for @objects;
|
||||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
|
||||||
$self->{canvas}->Render;
|
Slic3r::GUI::_3DScene::render($self->{canvas});
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -36,6 +36,7 @@ sub new {
|
|||||||
wxTheApp->save_window_pos($self, "object_settings");
|
wxTheApp->save_window_pos($self, "object_settings");
|
||||||
|
|
||||||
$self->EndModal(wxID_OK);
|
$self->EndModal(wxID_OK);
|
||||||
|
$self->{parts}->Destroy;
|
||||||
$self->Destroy;
|
$self->Destroy;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BIN
resources/icons/bed/mk2_bottom.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
resources/icons/bed/mk2_top.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
resources/icons/bed/mk3_bottom.png
Normal file
After Width: | Height: | Size: 170 KiB |
BIN
resources/icons/bed/mk3_top.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
resources/icons/overlay/rotate_hover.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
resources/icons/overlay/rotate_off.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
resources/icons/overlay/rotate_on.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
resources/icons/overlay/scale_hover.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/icons/overlay/scale_off.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/icons/overlay/scale_on.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
@ -97,7 +97,7 @@ msgstr " jako:"
|
|||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:226
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:226
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid " at filament speed %3.2f mm/s."
|
msgid " at filament speed %3.2f mm/s."
|
||||||
msgstr " z prędkocią filamentu %3.2f mm/s."
|
msgstr " z prędkością filamentu %3.2f mm/s."
|
||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:1035
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:1035
|
||||||
msgid " Browse "
|
msgid " Browse "
|
||||||
@ -574,7 +574,7 @@ msgstr "G-code wykonywany przy przejściach pomiędzy modelami (druk sekwencyjny
|
|||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:68
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:68
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:370
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:370
|
||||||
msgid "Bottom"
|
msgid "Bottom"
|
||||||
msgstr "Spód"
|
msgstr "Dolne"
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:72
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:72
|
||||||
msgid "Bottom solid layers"
|
msgid "Bottom solid layers"
|
||||||
@ -834,7 +834,7 @@ msgstr "Własne ustawienia"
|
|||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:205
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:205
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2102
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2102
|
||||||
msgid "Cut…"
|
msgid "Cut…"
|
||||||
msgstr "Tnij…"
|
msgstr "Obcinanie..."
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2027
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2027
|
||||||
msgid "Decrease copies"
|
msgid "Decrease copies"
|
||||||
@ -859,7 +859,7 @@ msgstr "Domyślny kąt linii wypełnienia. Mosty będą wypełniane z użyciem n
|
|||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:376
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:376
|
||||||
msgid "Default extrusion width"
|
msgid "Default extrusion width"
|
||||||
msgstr "Domyślna szerokość ekstrudowanej linii"
|
msgstr "Domyślna szerokość linii"
|
||||||
|
|
||||||
#: xs/src/slic3r/GUI/Tab.cpp:767
|
#: xs/src/slic3r/GUI/Tab.cpp:767
|
||||||
msgid "default filament profile"
|
msgid "default filament profile"
|
||||||
@ -1166,7 +1166,7 @@ msgstr "Funkcja eksperymentalna mająca zapobiegać tworzeniu podpór pod mostam
|
|||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:942
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:942
|
||||||
msgid "Experimental option to adjust flow for overhangs (bridge flow will be used), to apply bridge speed to them and enable fan."
|
msgid "Experimental option to adjust flow for overhangs (bridge flow will be used), to apply bridge speed to them and enable fan."
|
||||||
msgstr "Opcja eksperymentalna dostosowująca przepływ przy zwisach (zostanie zastosowany przepływ taki jak dla mostów), zastosuje również prędkość taką jak dla mostów i chłodzenie."
|
msgstr "Opcja eksperymentalna dostosowująca przepływ przy zwisach (zostanie zastosowany przepływ taki jak dla mostów), zastosuje również prędkość i chłodzenie takie jak dla mostów."
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:263
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:263
|
||||||
msgid "Export all presets to file"
|
msgid "Export all presets to file"
|
||||||
@ -1248,7 +1248,7 @@ msgstr "Obrysy zewnętrzne"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:151
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:151
|
||||||
msgid "external perimeters"
|
msgid "external perimeters"
|
||||||
msgstr "obrysy zewnętrzne"
|
msgstr "obrysów zewnętrznych"
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:289
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:289
|
||||||
msgid "External perimeters first"
|
msgid "External perimeters first"
|
||||||
@ -1399,7 +1399,7 @@ msgstr "Właściwości filamentu"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.hpp:202
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.hpp:202
|
||||||
msgid "Filament Settings"
|
msgid "Filament Settings"
|
||||||
msgstr "Ustawienia filamentu"
|
msgstr "Ustawienia Filamentu"
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:450
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:450
|
||||||
msgid "Filament type"
|
msgid "Filament type"
|
||||||
@ -1478,7 +1478,7 @@ msgstr "Prędkość pierwszej warstwy"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:214
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:214
|
||||||
msgid "First layer volumetric"
|
msgid "First layer volumetric"
|
||||||
msgstr "Objętościowa pierwszej warstwy"
|
msgstr "Na pierwszej warstwie"
|
||||||
|
|
||||||
#: xs/src/slic3r/GUI/GUI.cpp:326
|
#: xs/src/slic3r/GUI/GUI.cpp:326
|
||||||
msgid "Flash printer firmware"
|
msgid "Flash printer firmware"
|
||||||
@ -1651,7 +1651,7 @@ msgstr "Włączenie powoduje pobieranie wbudowanych systemowych zestawów ustawi
|
|||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:26
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:26
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "If estimated layer time is below ~%ds, fan will run at %d%% and print speed will be reduced so that no less than %ds are spent on that layer (however, speed will never be reduced below %dmm/s)."
|
msgid "If estimated layer time is below ~%ds, fan will run at %d%% and print speed will be reduced so that no less than %ds are spent on that layer (however, speed will never be reduced below %dmm/s)."
|
||||||
msgstr "Jeśli szacowany czas druku warstwy jest mniejszy niż ~%d s, wentylator będzie pracował na %d %% a prędkość druku zostanie obniżona tak, aby warstwa była drukowana przez nie mniej niż %d s (jednakże prędkość nie zostanie obniżona poniżej %d mm/s)."
|
msgstr "Jeśli szacowany czas druku warstwy jest niższy niż ~%d s, wentylator będzie pracował na %d %% a prędkość druku zostanie obniżona tak, aby warstwa była drukowana przez nie mniej niż %d s (jednakże prędkość nie zejdzie poniżej %d mm/s)."
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:616
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:616
|
||||||
msgid "If expressed as absolute value in mm/s, this speed will be applied to all the print moves of the first layer, regardless of their type. If expressed as a percentage (for example: 40%) it will scale the default speeds."
|
msgid "If expressed as absolute value in mm/s, this speed will be applied to all the print moves of the first layer, regardless of their type. If expressed as a percentage (for example: 40%) it will scale the default speeds."
|
||||||
@ -1659,11 +1659,11 @@ msgstr "Jeśli ustawisz wartość bezwzględną wyrażoną w mm/s, taka prędko
|
|||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:395
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:395
|
||||||
msgid "If layer print time is estimated below this number of seconds, fan will be enabled and its speed will be calculated by interpolating the minimum and maximum speeds."
|
msgid "If layer print time is estimated below this number of seconds, fan will be enabled and its speed will be calculated by interpolating the minimum and maximum speeds."
|
||||||
msgstr "Jeśli szacowany czas druku warstwy będzie mniejszy niż ta wartość to wentylator będzie włączony a jego prędkość będzie interpolowana na podstawie górnego i dolnego limitu prędkości."
|
msgstr "Jeśli szacowany czas druku warstwy będzie niższy niż ta wartość to wentylator będzie włączony a jego prędkość będzie interpolowana na podstawie górnego i dolnego limitu prędkości."
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:1240
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:1240
|
||||||
msgid "If layer print time is estimated below this number of seconds, print moves speed will be scaled down to extend duration to this value."
|
msgid "If layer print time is estimated below this number of seconds, print moves speed will be scaled down to extend duration to this value."
|
||||||
msgstr "Jeśli szacowany czas druku warstwy będzie mniejszy niż ta wartość to prędkość ruchów drukujących będzie zmniejszona aby wydłużyć czas druku."
|
msgstr "Jeśli szacowany czas druku warstwy będzie niższy niż ta wartość to prędkość ruchów drukujących będzie zmniejszona aby wydłużyć czas druku."
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:388
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:388
|
||||||
msgid "If this is enabled, fan will never be disabled and will be kept running at least at its minimum speed. Useful for PLA, harmful for ABS."
|
msgid "If this is enabled, fan will never be disabled and will be kept running at least at its minimum speed. Useful for PLA, harmful for ABS."
|
||||||
@ -1742,7 +1742,7 @@ msgstr "Wypełnienie"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:169
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:169
|
||||||
msgid "infill"
|
msgid "infill"
|
||||||
msgstr "wypełnienie"
|
msgstr "wypełnienia"
|
||||||
|
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:720
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:720
|
||||||
msgid "Infill before perimeters"
|
msgid "Infill before perimeters"
|
||||||
@ -1987,7 +1987,7 @@ msgstr "Maksymalny objętościowo kąt pozytywny"
|
|||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:421
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:421
|
||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:817
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:817
|
||||||
msgid "Max volumetric speed"
|
msgid "Max volumetric speed"
|
||||||
msgstr "Maksymalna prędkość objętościowa"
|
msgstr "Maksymalny przepływ"
|
||||||
|
|
||||||
#: xs/src/libslic3r/PrintConfig.cpp:1854
|
#: xs/src/libslic3r/PrintConfig.cpp:1854
|
||||||
msgid "Maximal bridging distance"
|
msgid "Maximal bridging distance"
|
||||||
@ -2220,7 +2220,7 @@ msgstr "Nowa wersja:"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:469
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:469
|
||||||
msgid "No previously sliced file."
|
msgid "No previously sliced file."
|
||||||
msgstr "Brak poprzednio pociętych pliku."
|
msgstr "Brak poprzednio pociętych plików."
|
||||||
|
|
||||||
#: xs/src/slic3r/GUI/RammingChart.cpp:28
|
#: xs/src/slic3r/GUI/RammingChart.cpp:28
|
||||||
msgid "NO RAMMING AT ALL"
|
msgid "NO RAMMING AT ALL"
|
||||||
@ -2325,7 +2325,7 @@ msgstr "Retrakcja tylko przy przechodzeniu nad obrysami"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:438
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:438
|
||||||
msgid "Ooze prevention"
|
msgid "Ooze prevention"
|
||||||
msgstr "Zapobieganie wyciekom"
|
msgstr "Zapobieganie wyciekom (ooze)"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:251
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:251
|
||||||
msgid "Open a model"
|
msgid "Open a model"
|
||||||
@ -2341,7 +2341,7 @@ msgstr "Otwórz plik STL/OBJ/AMF/3MF... \tCrtl+O"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2102
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2102
|
||||||
msgid "Open the 3D cutting tool"
|
msgid "Open the 3D cutting tool"
|
||||||
msgstr "Otwórz narzędzie do przecinania 3D"
|
msgstr "Otwórz narzędzie do wycinania 3D"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2106
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:2106
|
||||||
msgid "Open the object editor dialog"
|
msgid "Open the object editor dialog"
|
||||||
@ -2463,7 +2463,7 @@ msgstr "Umieść jedną kopię zaznaczonego modelu"
|
|||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:118
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:118
|
||||||
msgid "Plater"
|
msgid "Plater"
|
||||||
msgstr "Zawartość stołu"
|
msgstr "Zawartość Stołu"
|
||||||
|
|
||||||
#: lib/Slic3r/GUI/Plater.pm:1897
|
#: lib/Slic3r/GUI/Plater.pm:1897
|
||||||
msgid "Please install the OpenGL modules to use this feature (see build instructions)."
|
msgid "Please install the OpenGL modules to use this feature (see build instructions)."
|
||||||
@ -2691,7 +2691,7 @@ msgstr "Widok z tyłu"
|
|||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:262
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:262
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Recommended object thin wall thickness for layer height %.2f and "
|
msgid "Recommended object thin wall thickness for layer height %.2f and "
|
||||||
msgstr "Zalecana grubość ściany obiektu dla danej wysokości warstwy %.2f i "
|
msgstr "Zalecana grubość ściany modelu dla wysokości warstwy %.2f i "
|
||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:245
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:245
|
||||||
msgid "Recommended object thin wall thickness: Not available due to invalid layer height."
|
msgid "Recommended object thin wall thickness: Not available due to invalid layer height."
|
||||||
@ -3265,23 +3265,23 @@ msgstr "Slic3r nie będzie skalował prędkości poniżej tej wartości."
|
|||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:268
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:268
|
||||||
msgid "Slice a file into a G-code"
|
msgid "Slice a file into a G-code"
|
||||||
msgstr "Potnij plik jako G-code"
|
msgstr "Cięcie jako G-code"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:274
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:274
|
||||||
msgid "Slice a file into a G-code, save as"
|
msgid "Slice a file into a G-code, save as"
|
||||||
msgstr "Potnij plik jako G-code, zapisz jako"
|
msgstr "Cięcie jako G-code, zapisz jako"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:287
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:287
|
||||||
msgid "Slice file to a multi-layer SVG"
|
msgid "Slice file to a multi-layer SVG"
|
||||||
msgstr "Potnij plik jako wielowarstwowy SVG"
|
msgstr "Cięcie jako wielowarstwowy SVG"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:237
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:237
|
||||||
msgid "Slice now"
|
msgid "Slice now"
|
||||||
msgstr "Potnij teraz"
|
msgstr "Cięcie"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:287
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:287
|
||||||
msgid "Slice to SV&G…\tCtrl+G"
|
msgid "Slice to SV&G…\tCtrl+G"
|
||||||
msgstr "Tnij do SV&G...\tCtrl+G"
|
msgstr "Cięcie do SV&G...\tCtrl+G"
|
||||||
|
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:438
|
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater.pm:438
|
||||||
msgid "Sliced Info"
|
msgid "Sliced Info"
|
||||||
@ -3485,7 +3485,7 @@ msgstr "podpora"
|
|||||||
|
|
||||||
#: xs/src/slic3r/GUI/GUI.cpp:879
|
#: xs/src/slic3r/GUI/GUI.cpp:879
|
||||||
msgid "Support"
|
msgid "Support"
|
||||||
msgstr "Wsparcie"
|
msgstr "Podpory"
|
||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:620
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\Tab.cpp:620
|
||||||
msgid "Support Generator"
|
msgid "Support Generator"
|
||||||
@ -4011,7 +4011,7 @@ msgstr "Parametry zmiany narzędzia dla drukarek MM z jednym ekstruderem"
|
|||||||
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:1638
|
#: C:\src\Slic3r\xs\src\libslic3r\PrintConfig.cpp:1638
|
||||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:369
|
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:369
|
||||||
msgid "Top"
|
msgid "Top"
|
||||||
msgstr "Szczyt"
|
msgstr "Górne"
|
||||||
|
|
||||||
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:187
|
#: c:\src\Slic3r\xs\src\slic3r\GUI\PresetHints.cpp:187
|
||||||
msgid "top solid infill"
|
msgid "top solid infill"
|
||||||
|
18
resources/shaders/gouraud.fs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
// x = tainted, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
varying vec3 delta_box_min;
|
||||||
|
varying vec3 delta_box_max;
|
||||||
|
|
||||||
|
uniform vec4 uniform_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// if the fragment is outside the print volume -> use darker color
|
||||||
|
vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb;
|
||||||
|
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a);
|
||||||
|
}
|
70
resources/shaders/gouraud.vs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
#define INTENSITY_CORRECTION 0.6
|
||||||
|
|
||||||
|
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||||
|
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||||
|
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SHININESS 20.0
|
||||||
|
|
||||||
|
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
|
||||||
|
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||||
|
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SHININESS 5.0
|
||||||
|
|
||||||
|
#define INTENSITY_AMBIENT 0.3
|
||||||
|
|
||||||
|
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
struct PrintBoxDetection
|
||||||
|
{
|
||||||
|
vec3 min;
|
||||||
|
vec3 max;
|
||||||
|
// xyz contains the offset, if w == 1.0 detection needs to be performed
|
||||||
|
vec4 volume_origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform PrintBoxDetection print_box;
|
||||||
|
|
||||||
|
// x = tainted, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
varying vec3 delta_box_min;
|
||||||
|
varying vec3 delta_box_max;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// First transform the normal into camera space and normalize the result.
|
||||||
|
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||||
|
|
||||||
|
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
|
||||||
|
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
|
||||||
|
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
|
||||||
|
|
||||||
|
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||||
|
intensity.y = 0.0;
|
||||||
|
|
||||||
|
if (NdotL > 0.0)
|
||||||
|
intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||||
|
|
||||||
|
// Perform the same lighting calculation for the 2nd light source (no specular applied).
|
||||||
|
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
|
||||||
|
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||||
|
|
||||||
|
// compute deltas for out of print volume detection (world coordinates)
|
||||||
|
if (print_box.volume_origin.w == 1.0)
|
||||||
|
{
|
||||||
|
vec3 v = gl_Vertex.xyz + print_box.volume_origin.xyz;
|
||||||
|
delta_box_min = v - print_box.min;
|
||||||
|
delta_box_max = v - print_box.max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delta_box_min = ZERO;
|
||||||
|
delta_box_max = ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_Position = ftransform();
|
||||||
|
}
|
40
resources/shaders/variable_layer_height.fs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
#define M_PI 3.1415926535897932384626433832795
|
||||||
|
|
||||||
|
// 2D texture (1D texture split by the rows) of color along the object Z axis.
|
||||||
|
uniform sampler2D z_texture;
|
||||||
|
// Scaling from the Z texture rows coordinate to the normalized texture row coordinate.
|
||||||
|
uniform float z_to_texture_row;
|
||||||
|
uniform float z_texture_row_to_normalized;
|
||||||
|
uniform float z_cursor;
|
||||||
|
uniform float z_cursor_band_width;
|
||||||
|
|
||||||
|
// x = tainted, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
varying float object_z;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float object_z_row = z_to_texture_row * object_z;
|
||||||
|
// Index of the row in the texture.
|
||||||
|
float z_texture_row = floor(object_z_row);
|
||||||
|
// Normalized coordinate from 0. to 1.
|
||||||
|
float z_texture_col = object_z_row - z_texture_row;
|
||||||
|
float z_blend = 0.25 * cos(min(M_PI, abs(M_PI * (object_z - z_cursor) * 1.8 / z_cursor_band_width))) + 0.25;
|
||||||
|
// Calculate level of detail from the object Z coordinate.
|
||||||
|
// This makes the slowly sloping surfaces to be show with high detail (with stripes),
|
||||||
|
// and the vertical surfaces to be shown with low detail (no stripes)
|
||||||
|
float z_in_cells = object_z_row * 190.;
|
||||||
|
// Gradient of Z projected on the screen.
|
||||||
|
float dx_vtc = dFdx(z_in_cells);
|
||||||
|
float dy_vtc = dFdy(z_in_cells);
|
||||||
|
float lod = clamp(0.5 * log2(max(dx_vtc * dx_vtc, dy_vtc * dy_vtc)), 0., 1.);
|
||||||
|
// Sample the Z texture. Texture coordinates are normalized to <0, 1>.
|
||||||
|
vec4 color = mix(texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row + 0.5 )), -10000.),
|
||||||
|
texture2D(z_texture, vec2(z_texture_col, z_texture_row_to_normalized * (z_texture_row * 2. + 1.)), 10000.), lod);
|
||||||
|
|
||||||
|
// Mix the final color.
|
||||||
|
gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 1.0) + intensity.x * mix(color, vec4(1.0, 1.0, 0.0, 1.0), z_blend);
|
||||||
|
}
|
46
resources/shaders/variable_layer_height.vs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#version 110
|
||||||
|
|
||||||
|
#define INTENSITY_CORRECTION 0.6
|
||||||
|
|
||||||
|
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||||
|
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||||
|
#define LIGHT_TOP_SHININESS 20.0
|
||||||
|
|
||||||
|
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||||
|
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION)
|
||||||
|
//#define LIGHT_FRONT_SHININESS 5.0
|
||||||
|
|
||||||
|
#define INTENSITY_AMBIENT 0.3
|
||||||
|
|
||||||
|
// x = tainted, y = specular;
|
||||||
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
varying float object_z;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// First transform the normal into camera space and normalize the result.
|
||||||
|
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||||
|
|
||||||
|
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
|
||||||
|
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
|
||||||
|
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
|
||||||
|
|
||||||
|
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||||
|
intensity.y = 0.0;
|
||||||
|
|
||||||
|
if (NdotL > 0.0)
|
||||||
|
intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(normal, reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||||
|
|
||||||
|
// Perform the same lighting calculation for the 2nd light source (no specular)
|
||||||
|
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
|
||||||
|
|
||||||
|
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||||
|
|
||||||
|
// Scaled to widths of the Z texture.
|
||||||
|
object_z = gl_Vertex.z;
|
||||||
|
|
||||||
|
gl_Position = ftransform();
|
||||||
|
}
|
@ -31,6 +31,13 @@ if(WIN32)
|
|||||||
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
|
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
|
||||||
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB)
|
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB)
|
||||||
# -D_ITERATOR_DEBUG_LEVEL)
|
# -D_ITERATOR_DEBUG_LEVEL)
|
||||||
|
if(WIN10SDK_PATH)
|
||||||
|
message("Building with Win10 Netfabb STL fixing service support")
|
||||||
|
add_definitions(-DHAS_WIN10SDK)
|
||||||
|
include_directories("${WIN10SDK_PATH}/Include")
|
||||||
|
else()
|
||||||
|
message("Building without Win10 Netfabb STL fixing service support")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO)
|
add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO)
|
||||||
@ -186,7 +193,15 @@ add_library(libslic3r_gui STATIC
|
|||||||
${LIBDIR}/slic3r/GUI/3DScene.cpp
|
${LIBDIR}/slic3r/GUI/3DScene.cpp
|
||||||
${LIBDIR}/slic3r/GUI/3DScene.hpp
|
${LIBDIR}/slic3r/GUI/3DScene.hpp
|
||||||
${LIBDIR}/slic3r/GUI/GLShader.cpp
|
${LIBDIR}/slic3r/GUI/GLShader.cpp
|
||||||
${LIBDIR}/slic3r/GUI/GLShader.hpp
|
${LIBDIR}/slic3r/GUI/GLShader.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLCanvas3D.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLCanvas3D.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLCanvas3DManager.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLCanvas3DManager.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLGizmo.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLGizmo.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLTexture.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLTexture.cpp
|
||||||
${LIBDIR}/slic3r/GUI/Preferences.cpp
|
${LIBDIR}/slic3r/GUI/Preferences.cpp
|
||||||
${LIBDIR}/slic3r/GUI/Preferences.hpp
|
${LIBDIR}/slic3r/GUI/Preferences.hpp
|
||||||
${LIBDIR}/slic3r/GUI/Preset.cpp
|
${LIBDIR}/slic3r/GUI/Preset.cpp
|
||||||
@ -237,6 +252,8 @@ add_library(libslic3r_gui STATIC
|
|||||||
${LIBDIR}/slic3r/GUI/FirmwareDialog.hpp
|
${LIBDIR}/slic3r/GUI/FirmwareDialog.hpp
|
||||||
${LIBDIR}/slic3r/Utils/Http.cpp
|
${LIBDIR}/slic3r/Utils/Http.cpp
|
||||||
${LIBDIR}/slic3r/Utils/Http.hpp
|
${LIBDIR}/slic3r/Utils/Http.hpp
|
||||||
|
${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
|
||||||
|
${LIBDIR}/slic3r/Utils/FixModelByWin10.hpp
|
||||||
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
||||||
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
||||||
${LIBDIR}/slic3r/Utils/Bonjour.cpp
|
${LIBDIR}/slic3r/Utils/Bonjour.cpp
|
||||||
@ -245,6 +262,7 @@ add_library(libslic3r_gui STATIC
|
|||||||
${LIBDIR}/slic3r/Utils/PresetUpdater.hpp
|
${LIBDIR}/slic3r/Utils/PresetUpdater.hpp
|
||||||
${LIBDIR}/slic3r/Utils/Time.cpp
|
${LIBDIR}/slic3r/Utils/Time.cpp
|
||||||
${LIBDIR}/slic3r/Utils/Time.hpp
|
${LIBDIR}/slic3r/Utils/Time.hpp
|
||||||
|
${LIBDIR}/slic3r/IProgressIndicator.hpp
|
||||||
${LIBDIR}/slic3r/AppController.hpp
|
${LIBDIR}/slic3r/AppController.hpp
|
||||||
${LIBDIR}/slic3r/AppController.cpp
|
${LIBDIR}/slic3r/AppController.cpp
|
||||||
)
|
)
|
||||||
@ -386,8 +404,6 @@ target_link_libraries(libslic3r rasterizer )
|
|||||||
|
|
||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
|
|
||||||
add_subdirectory(src/avrdude)
|
|
||||||
|
|
||||||
# Generate the Slic3r Perl module (XS) typemap file.
|
# Generate the Slic3r Perl module (XS) typemap file.
|
||||||
set(MyTypemap ${CMAKE_CURRENT_BINARY_DIR}/typemap)
|
set(MyTypemap ${CMAKE_CURRENT_BINARY_DIR}/typemap)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
@ -551,12 +567,12 @@ if (WIN32 AND ";${PerlEmbed_CCFLAGS};" MATCHES ";[-/]Od;")
|
|||||||
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
|
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
|
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
|
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||||
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG")
|
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||||
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG")
|
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DNDEBUG /DWIN32")
|
||||||
set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG")
|
set(CMAKE_C_FLAGS "/MD /Od /Zi /DNDEBUG /DWIN32")
|
||||||
endif()
|
endif()
|
||||||
# The following line will add -fPIC on Linux to make the XS.so rellocable.
|
# The following line will add -fPIC on Linux to make the XS.so rellocable.
|
||||||
add_definitions(${PerlEmbed_CCCDLFLAGS})
|
add_definitions(${PerlEmbed_CCCDLFLAGS})
|
||||||
@ -564,6 +580,8 @@ if (WIN32)
|
|||||||
target_link_libraries(XS ${PERL_LIBRARY})
|
target_link_libraries(XS ${PERL_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(src/avrdude)
|
||||||
|
|
||||||
## REQUIRED packages
|
## REQUIRED packages
|
||||||
|
|
||||||
# Find and configure boost
|
# Find and configure boost
|
||||||
@ -608,13 +626,13 @@ if (SLIC3R_PRUSACONTROL)
|
|||||||
set(wxWidgets_UseAlienWx 1)
|
set(wxWidgets_UseAlienWx 1)
|
||||||
if (wxWidgets_UseAlienWx)
|
if (wxWidgets_UseAlienWx)
|
||||||
set(AlienWx_DEBUG 1)
|
set(AlienWx_DEBUG 1)
|
||||||
find_package(AlienWx REQUIRED COMPONENTS base core adv html)
|
find_package(AlienWx REQUIRED COMPONENTS base core adv html gl)
|
||||||
include_directories(${AlienWx_INCLUDE_DIRS})
|
include_directories(${AlienWx_INCLUDE_DIRS})
|
||||||
#add_compile_options(${AlienWx_CXX_FLAGS})
|
#add_compile_options(${AlienWx_CXX_FLAGS})
|
||||||
add_definitions(${AlienWx_DEFINITIONS})
|
add_definitions(${AlienWx_DEFINITIONS})
|
||||||
set(wxWidgets_LIBRARIES ${AlienWx_LIBRARIES})
|
set(wxWidgets_LIBRARIES ${AlienWx_LIBRARIES})
|
||||||
else ()
|
else ()
|
||||||
find_package(wxWidgets REQUIRED COMPONENTS base core adv html)
|
find_package(wxWidgets REQUIRED COMPONENTS base core adv html gl)
|
||||||
include(${wxWidgets_USE_FILE})
|
include(${wxWidgets_USE_FILE})
|
||||||
endif ()
|
endif ()
|
||||||
add_definitions(-DSLIC3R_GUI -DSLIC3R_PRUS)
|
add_definitions(-DSLIC3R_GUI -DSLIC3R_PRUS)
|
||||||
|
@ -12,6 +12,8 @@ our $VERSION = '0.01';
|
|||||||
BEGIN {
|
BEGIN {
|
||||||
if ($^O eq 'MSWin32') {
|
if ($^O eq 'MSWin32') {
|
||||||
eval "use Wx";
|
eval "use Wx";
|
||||||
|
eval "use Wx::GLCanvas";
|
||||||
|
eval "use Wx::GLContext";
|
||||||
eval "use Wx::Html";
|
eval "use Wx::Html";
|
||||||
eval "use Wx::Print"; # because of some Wx bug, thread creation fails if we don't have this (looks like Wx::Printout is hard-coded in some thread cleanup code)
|
eval "use Wx::Print"; # because of some Wx bug, thread creation fails if we don't have this (looks like Wx::Printout is hard-coded in some thread cleanup code)
|
||||||
}
|
}
|
||||||
@ -280,6 +282,7 @@ for my $class (qw(
|
|||||||
Slic3r::Geometry::BoundingBox
|
Slic3r::Geometry::BoundingBox
|
||||||
Slic3r::Geometry::BoundingBoxf
|
Slic3r::Geometry::BoundingBoxf
|
||||||
Slic3r::Geometry::BoundingBoxf3
|
Slic3r::Geometry::BoundingBoxf3
|
||||||
|
Slic3r::GUI::_3DScene::GLShader
|
||||||
Slic3r::GUI::_3DScene::GLVolume
|
Slic3r::GUI::_3DScene::GLVolume
|
||||||
Slic3r::GUI::Preset
|
Slic3r::GUI::Preset
|
||||||
Slic3r::GUI::PresetCollection
|
Slic3r::GUI::PresetCollection
|
||||||
|
@ -80,6 +80,49 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prusa_init_external_flash(PROGRAMMER * pgm)
|
||||||
|
{
|
||||||
|
// Note: send/receive as in _the firmare_ send & receives
|
||||||
|
const char entry_magic_send [] = "start\n";
|
||||||
|
const char entry_magic_receive[] = "w25x20cl_enter\n";
|
||||||
|
const char entry_magic_cfm [] = "w25x20cl_cfm\n";
|
||||||
|
const size_t buffer_len = 32; // Should be large enough for the above messages
|
||||||
|
|
||||||
|
int res;
|
||||||
|
size_t recv_size;
|
||||||
|
char *buffer = alloca(buffer_len);
|
||||||
|
|
||||||
|
// 1. receive the "start" command
|
||||||
|
recv_size = sizeof(entry_magic_send) - 1;
|
||||||
|
res = serial_recv(&pgm->fd, buffer, recv_size);
|
||||||
|
if (res < 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
|
||||||
|
return -1;
|
||||||
|
} else if (strncmp(buffer, entry_magic_send, recv_size) != 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer emitted incorrect start code\n", progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Send the external flash programmer enter command
|
||||||
|
if (serial_send(&pgm->fd, entry_magic_receive, sizeof(entry_magic_receive) - 1) < 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): Failed to send command to the printer\n",progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Receive the entry confirmation command
|
||||||
|
recv_size = sizeof(entry_magic_cfm) - 1;
|
||||||
|
res = serial_recv(&pgm->fd, buffer, recv_size);
|
||||||
|
if (res < 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
|
||||||
|
return -1;
|
||||||
|
} else if (strncmp(buffer, entry_magic_cfm, recv_size) != 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer emitted incorrect start code\n", progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int arduino_open(PROGRAMMER * pgm, char * port)
|
static int arduino_open(PROGRAMMER * pgm, char * port)
|
||||||
{
|
{
|
||||||
union pinfo pinfo;
|
union pinfo pinfo;
|
||||||
@ -102,6 +145,12 @@ static int arduino_open(PROGRAMMER * pgm, char * port)
|
|||||||
*/
|
*/
|
||||||
stk500_drain(pgm, 0);
|
stk500_drain(pgm, 0);
|
||||||
|
|
||||||
|
// Initialization sequence for programming the external FLASH on the Prusa MK3
|
||||||
|
if (prusa_init_external_flash(pgm) < 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: arduino_open(): Failed to initialize MK3 external flash programming mode\n", progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stk500_getsync(pgm) < 0)
|
if (stk500_getsync(pgm) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "avrdude-slic3r.hpp"
|
#include "avrdude-slic3r.hpp"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -33,17 +34,22 @@ static void avrdude_progress_handler_closure(const char *task, unsigned progress
|
|||||||
struct AvrDude::priv
|
struct AvrDude::priv
|
||||||
{
|
{
|
||||||
std::string sys_config;
|
std::string sys_config;
|
||||||
std::vector<std::string> args;
|
std::deque<std::vector<std::string>> args;
|
||||||
|
size_t current_args_set = 0;
|
||||||
|
RunFn run_fn;
|
||||||
MessageFn message_fn;
|
MessageFn message_fn;
|
||||||
ProgressFn progress_fn;
|
ProgressFn progress_fn;
|
||||||
CompleteFn complete_fn;
|
CompleteFn complete_fn;
|
||||||
|
|
||||||
std::thread avrdude_thread;
|
std::thread avrdude_thread;
|
||||||
|
|
||||||
|
priv(std::string &&sys_config) : sys_config(sys_config) {}
|
||||||
|
|
||||||
|
int run_one(const std::vector<std::string> &args);
|
||||||
int run();
|
int run();
|
||||||
};
|
};
|
||||||
|
|
||||||
int AvrDude::priv::run() {
|
int AvrDude::priv::run_one(const std::vector<std::string> &args) {
|
||||||
std::vector<char*> c_args {{ const_cast<char*>(PACKAGE_NAME) }};
|
std::vector<char*> c_args {{ const_cast<char*>(PACKAGE_NAME) }};
|
||||||
for (const auto &arg : args) {
|
for (const auto &arg : args) {
|
||||||
c_args.push_back(const_cast<char*>(arg.data()));
|
c_args.push_back(const_cast<char*>(arg.data()));
|
||||||
@ -68,10 +74,22 @@ int AvrDude::priv::run() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AvrDude::priv::run() {
|
||||||
|
for (; args.size() > 0; current_args_set++) {
|
||||||
|
int res = run_one(args.front());
|
||||||
|
args.pop_front();
|
||||||
|
if (res != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Public
|
// Public
|
||||||
|
|
||||||
AvrDude::AvrDude() : p(new priv()) {}
|
AvrDude::AvrDude(std::string sys_config) : p(new priv(std::move(sys_config))) {}
|
||||||
|
|
||||||
AvrDude::AvrDude(AvrDude &&other) : p(std::move(other.p)) {}
|
AvrDude::AvrDude(AvrDude &&other) : p(std::move(other.p)) {}
|
||||||
|
|
||||||
@ -82,15 +100,15 @@ AvrDude::~AvrDude()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AvrDude& AvrDude::sys_config(std::string sys_config)
|
AvrDude& AvrDude::push_args(std::vector<std::string> args)
|
||||||
{
|
{
|
||||||
if (p) { p->sys_config = std::move(sys_config); }
|
if (p) { p->args.push_back(std::move(args)); }
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvrDude& AvrDude::args(std::vector<std::string> args)
|
AvrDude& AvrDude::on_run(RunFn fn)
|
||||||
{
|
{
|
||||||
if (p) { p->args = std::move(args); }
|
if (p) { p->run_fn = std::move(fn); }
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,11 +141,17 @@ AvrDude::Ptr AvrDude::run()
|
|||||||
|
|
||||||
if (self->p) {
|
if (self->p) {
|
||||||
auto avrdude_thread = std::thread([self]() {
|
auto avrdude_thread = std::thread([self]() {
|
||||||
auto res = self->p->run();
|
if (self->p->run_fn) {
|
||||||
if (self->p->complete_fn) {
|
self->p->run_fn();
|
||||||
self->p->complete_fn(res);
|
}
|
||||||
}
|
|
||||||
});
|
auto res = self->p->run();
|
||||||
|
|
||||||
|
if (self->p->complete_fn) {
|
||||||
|
self->p->complete_fn(res, self->p->current_args_set);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
self->p->avrdude_thread = std::move(avrdude_thread);
|
self->p->avrdude_thread = std::move(avrdude_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,22 +12,28 @@ class AvrDude
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<AvrDude> Ptr;
|
typedef std::shared_ptr<AvrDude> Ptr;
|
||||||
|
typedef std::function<void()> RunFn;
|
||||||
typedef std::function<void(const char * /* msg */, unsigned /* size */)> MessageFn;
|
typedef std::function<void(const char * /* msg */, unsigned /* size */)> MessageFn;
|
||||||
typedef std::function<void(const char * /* task */, unsigned /* progress */)> ProgressFn;
|
typedef std::function<void(const char * /* task */, unsigned /* progress */)> ProgressFn;
|
||||||
typedef std::function<void(int /* exit status */)> CompleteFn;
|
typedef std::function<void(int /* exit status */, size_t /* args_id */)> CompleteFn;
|
||||||
|
|
||||||
AvrDude();
|
// Main c-tor, sys_config is the location of avrdude's main configuration file
|
||||||
|
AvrDude(std::string sys_config);
|
||||||
AvrDude(AvrDude &&);
|
AvrDude(AvrDude &&);
|
||||||
AvrDude(const AvrDude &) = delete;
|
AvrDude(const AvrDude &) = delete;
|
||||||
AvrDude &operator=(AvrDude &&) = delete;
|
AvrDude &operator=(AvrDude &&) = delete;
|
||||||
AvrDude &operator=(const AvrDude &) = delete;
|
AvrDude &operator=(const AvrDude &) = delete;
|
||||||
~AvrDude();
|
~AvrDude();
|
||||||
|
|
||||||
// Set location of avrdude's main configuration file
|
// Push a set of avrdude cli arguments
|
||||||
AvrDude& sys_config(std::string sys_config);
|
// Each set makes one avrdude invocation - use this method multiple times to push
|
||||||
|
// more than one avrdude invocations.
|
||||||
|
AvrDude& push_args(std::vector<std::string> args);
|
||||||
|
|
||||||
// Set avrdude cli arguments
|
// Set a callback to be called just after run() before avrdude is ran
|
||||||
AvrDude& args(std::vector<std::string> args);
|
// This can be used to perform any needed setup tasks from the background thread.
|
||||||
|
// This has no effect when using run_sync().
|
||||||
|
AvrDude& on_run(RunFn fn);
|
||||||
|
|
||||||
// Set message output callback
|
// Set message output callback
|
||||||
AvrDude& on_message(MessageFn fn);
|
AvrDude& on_message(MessageFn fn);
|
||||||
@ -36,7 +42,10 @@ public:
|
|||||||
// Progress is reported per each task (reading / writing) in percents.
|
// Progress is reported per each task (reading / writing) in percents.
|
||||||
AvrDude& on_progress(ProgressFn fn);
|
AvrDude& on_progress(ProgressFn fn);
|
||||||
|
|
||||||
// Called when avrdude's main function finishes
|
// Called when the last avrdude invocation finishes with the exit status of zero,
|
||||||
|
// or earlier, if one of the invocations return a non-zero status.
|
||||||
|
// The second argument contains the sequential id of the last avrdude invocation argument set.
|
||||||
|
// This has no effect when using run_sync().
|
||||||
AvrDude& on_complete(CompleteFn fn);
|
AvrDude& on_complete(CompleteFn fn);
|
||||||
|
|
||||||
int run_sync();
|
int run_sync();
|
||||||
|
@ -378,7 +378,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
|
|||||||
char * optr;
|
char * optr;
|
||||||
|
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
fprintf(f,
|
avrdude_message(MSG_INFO,
|
||||||
"%s Block Poll Page Polled\n"
|
"%s Block Poll Page Polled\n"
|
||||||
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
||||||
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
||||||
@ -386,13 +386,13 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (verbose > 2) {
|
if (verbose > 2) {
|
||||||
fprintf(f,
|
avrdude_message(MSG_INFO,
|
||||||
"%s Block Poll Page Polled\n"
|
"%s Block Poll Page Polled\n"
|
||||||
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
||||||
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
||||||
prefix, prefix, prefix);
|
prefix, prefix, prefix);
|
||||||
}
|
}
|
||||||
fprintf(f,
|
avrdude_message(MSG_INFO,
|
||||||
"%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
|
"%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
|
||||||
prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex,
|
prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex,
|
||||||
m->paged ? "yes" : "no",
|
m->paged ? "yes" : "no",
|
||||||
@ -415,7 +415,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
|
|||||||
optr = avr_op_str(i);
|
optr = avr_op_str(i);
|
||||||
else
|
else
|
||||||
optr = " ";
|
optr = " ";
|
||||||
fprintf(f,
|
avrdude_message(MSG_INFO,
|
||||||
"%s %-11s %8d %8s %5d %5d\n",
|
"%s %-11s %8d %8s %5d %5d\n",
|
||||||
prefix, optr, j,
|
prefix, optr, j,
|
||||||
bittype(m->op[i]->bit[j].type),
|
bittype(m->op[i]->bit[j].type),
|
||||||
@ -620,7 +620,7 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
|
|||||||
LNODEID ln;
|
LNODEID ln;
|
||||||
AVRMEM * m;
|
AVRMEM * m;
|
||||||
|
|
||||||
fprintf(f,
|
avrdude_message(MSG_INFO,
|
||||||
"%sAVR Part : %s\n"
|
"%sAVR Part : %s\n"
|
||||||
"%sChip Erase delay : %d us\n"
|
"%sChip Erase delay : %d us\n"
|
||||||
"%sPAGEL : P%02X\n"
|
"%sPAGEL : P%02X\n"
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
|
|
||||||
#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */
|
#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */
|
||||||
|
|
||||||
|
#define MAX_MODE_LEN 32 // For fopen_and_seek()
|
||||||
|
|
||||||
|
|
||||||
struct ihexrec {
|
struct ihexrec {
|
||||||
unsigned char reclen;
|
unsigned char reclen;
|
||||||
@ -96,10 +98,42 @@ static int fileio_num(struct fioparms * fio,
|
|||||||
char * filename, FILE * f, AVRMEM * mem, int size,
|
char * filename, FILE * f, AVRMEM * mem, int size,
|
||||||
FILEFMT fmt);
|
FILEFMT fmt);
|
||||||
|
|
||||||
static int fmt_autodetect(char * fname);
|
static int fmt_autodetect(char * fname, size_t offset);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static FILE *fopen_and_seek(const char *filename, const char *mode, size_t offset)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
// On Windows we need to convert the filename to UTF-16
|
||||||
|
#if defined(WIN32NATIVE)
|
||||||
|
static wchar_t fname_buffer[PATH_MAX];
|
||||||
|
static wchar_t mode_buffer[MAX_MODE_LEN];
|
||||||
|
|
||||||
|
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, fname_buffer, PATH_MAX) == 0) { return NULL; }
|
||||||
|
if (MultiByteToWideChar(CP_ACP, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; }
|
||||||
|
|
||||||
|
file = _wfopen(fname_buffer, mode_buffer);
|
||||||
|
#else
|
||||||
|
file = fopen(filename, mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file != NULL) {
|
||||||
|
// Some systems allow seeking past the end of file, so we need check for that first and disallow
|
||||||
|
if (fseek(file, 0, SEEK_END) != 0
|
||||||
|
|| offset >= ftell(file)
|
||||||
|
|| fseek(file, offset, SEEK_SET) != 0
|
||||||
|
) {
|
||||||
|
fclose(file);
|
||||||
|
file = NULL;
|
||||||
|
errno = EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char * fmtstr(FILEFMT format)
|
char * fmtstr(FILEFMT format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@ -1358,7 +1392,7 @@ int fileio_setparms(int op, struct fioparms * fp,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int fmt_autodetect(char * fname)
|
static int fmt_autodetect(char * fname, size_t offset)
|
||||||
{
|
{
|
||||||
FILE * f;
|
FILE * f;
|
||||||
unsigned char buf[MAX_LINE_LEN];
|
unsigned char buf[MAX_LINE_LEN];
|
||||||
@ -1368,10 +1402,11 @@ static int fmt_autodetect(char * fname)
|
|||||||
int first = 1;
|
int first = 1;
|
||||||
|
|
||||||
#if defined(WIN32NATIVE)
|
#if defined(WIN32NATIVE)
|
||||||
f = fopen(fname, "r");
|
f = fopen_and_seek(fname, "r", offset);
|
||||||
#else
|
#else
|
||||||
f = fopen(fname, "rb");
|
f = fopen_and_seek(fname, "rb", offset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
avrdude_message(MSG_INFO, "%s: error opening %s: %s\n",
|
avrdude_message(MSG_INFO, "%s: error opening %s: %s\n",
|
||||||
progname, fname, strerror(errno));
|
progname, fname, strerror(errno));
|
||||||
@ -1445,7 +1480,7 @@ static int fmt_autodetect(char * fname)
|
|||||||
|
|
||||||
|
|
||||||
int fileio(int op, char * filename, FILEFMT format,
|
int fileio(int op, char * filename, FILEFMT format,
|
||||||
struct avrpart * p, char * memtype, int size)
|
struct avrpart * p, char * memtype, int size, size_t offset)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
FILE * f;
|
FILE * f;
|
||||||
@ -1477,15 +1512,17 @@ int fileio(int op, char * filename, FILEFMT format,
|
|||||||
using_stdio = 0;
|
using_stdio = 0;
|
||||||
|
|
||||||
if (strcmp(filename, "-")==0) {
|
if (strcmp(filename, "-")==0) {
|
||||||
if (fio.op == FIO_READ) {
|
return -1;
|
||||||
fname = "<stdin>";
|
// Note: we don't want to read stdin or write to stdout as part of Slic3r
|
||||||
f = stdin;
|
// if (fio.op == FIO_READ) {
|
||||||
}
|
// fname = "<stdin>";
|
||||||
else {
|
// f = stdin;
|
||||||
fname = "<stdout>";
|
// }
|
||||||
f = stdout;
|
// else {
|
||||||
}
|
// fname = "<stdout>";
|
||||||
using_stdio = 1;
|
// f = stdout;
|
||||||
|
// }
|
||||||
|
// using_stdio = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fname = filename;
|
fname = filename;
|
||||||
@ -1502,7 +1539,7 @@ int fileio(int op, char * filename, FILEFMT format,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
format_detect = fmt_autodetect(fname);
|
format_detect = fmt_autodetect(fname, offset);
|
||||||
if (format_detect < 0) {
|
if (format_detect < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
|
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
|
||||||
progname, fname);
|
progname, fname);
|
||||||
@ -1533,7 +1570,7 @@ int fileio(int op, char * filename, FILEFMT format,
|
|||||||
|
|
||||||
if (format != FMT_IMM) {
|
if (format != FMT_IMM) {
|
||||||
if (!using_stdio) {
|
if (!using_stdio) {
|
||||||
f = fopen(fname, fio.mode);
|
f = fopen_and_seek(fname, fio.mode, offset);
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
avrdude_message(MSG_INFO, "%s: can't open %s file %s: %s\n",
|
avrdude_message(MSG_INFO, "%s: can't open %s file %s: %s\n",
|
||||||
progname, fio.iodesc, fname, strerror(errno));
|
progname, fio.iodesc, fname, strerror(errno));
|
||||||
|
@ -737,7 +737,7 @@ extern bool cancel_flag;
|
|||||||
#define RETURN_IF_CANCEL() \
|
#define RETURN_IF_CANCEL() \
|
||||||
do { \
|
do { \
|
||||||
if (cancel_flag) { \
|
if (cancel_flag) { \
|
||||||
avrdude_message(MSG_INFO, "%s(): Cancelled, exiting...\n", __func__); \
|
avrdude_message(MSG_INFO, "avrdude: %s(): Cancelled, exiting...\n", __func__); \
|
||||||
return -99; \
|
return -99; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -821,7 +821,7 @@ extern "C" {
|
|||||||
char * fmtstr(FILEFMT format);
|
char * fmtstr(FILEFMT format);
|
||||||
|
|
||||||
int fileio(int op, char * filename, FILEFMT format,
|
int fileio(int op, char * filename, FILEFMT format,
|
||||||
struct avrpart * p, char * memtype, int size);
|
struct avrpart * p, char * memtype, int size, size_t offset);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -870,6 +870,7 @@ enum updateflags {
|
|||||||
typedef struct update_t {
|
typedef struct update_t {
|
||||||
char * memtype;
|
char * memtype;
|
||||||
int op;
|
int op;
|
||||||
|
size_t offset;
|
||||||
char * filename;
|
char * filename;
|
||||||
int format;
|
int format;
|
||||||
} UPDATE;
|
} UPDATE;
|
||||||
@ -881,7 +882,7 @@ extern "C" {
|
|||||||
extern UPDATE * parse_op(char * s);
|
extern UPDATE * parse_op(char * s);
|
||||||
extern UPDATE * dup_update(UPDATE * upd);
|
extern UPDATE * dup_update(UPDATE * upd);
|
||||||
extern UPDATE * new_update(int op, char * memtype, int filefmt,
|
extern UPDATE * new_update(int op, char * memtype, int filefmt,
|
||||||
char * filename);
|
char * filename, size_t offset);
|
||||||
extern void free_update(UPDATE * upd);
|
extern void free_update(UPDATE * upd);
|
||||||
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
|
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
|
||||||
enum updateflags flags);
|
enum updateflags flags);
|
||||||
|
@ -194,7 +194,7 @@ static void usage(void)
|
|||||||
" -F Override invalid signature check.\n"
|
" -F Override invalid signature check.\n"
|
||||||
" -e Perform a chip erase.\n"
|
" -e Perform a chip erase.\n"
|
||||||
" -O Perform RC oscillator calibration (see AVR053). \n"
|
" -O Perform RC oscillator calibration (see AVR053). \n"
|
||||||
" -U <memtype>:r|w|v:<filename>[:format]\n"
|
" -U <memtype>:r|w|v:<offset>:<filename>[:format]\n"
|
||||||
" Memory operation specification.\n"
|
" Memory operation specification.\n"
|
||||||
" Multiple -U options are allowed, each request\n"
|
" Multiple -U options are allowed, each request\n"
|
||||||
" is performed in the order specified.\n"
|
" is performed in the order specified.\n"
|
||||||
@ -374,7 +374,7 @@ static void list_parts(FILE * f, const char *prefix, LISTID avrparts)
|
|||||||
|
|
||||||
static int cleanup_main(int status)
|
static int cleanup_main(int status)
|
||||||
{
|
{
|
||||||
if (pgm_setup && pgm->teardown) {
|
if (pgm_setup && pgm != NULL && pgm->teardown) {
|
||||||
pgm->teardown(pgm);
|
pgm->teardown(pgm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +376,10 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen
|
|||||||
FD_SET(fd->ifd, &rfds);
|
FD_SET(fd->ifd, &rfds);
|
||||||
|
|
||||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
||||||
|
// FIXME: The timeout has different behaviour on Linux vs other Unices
|
||||||
|
// On Linux, the timeout is modified by subtracting the time spent,
|
||||||
|
// on OS X (for example), it is not modified.
|
||||||
|
// POSIX recommends re-initializing it before selecting.
|
||||||
if (nfds == 0) {
|
if (nfds == 0) {
|
||||||
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n",
|
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n",
|
||||||
progname);
|
progname);
|
||||||
|
@ -716,11 +716,14 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = Cmnd_STK_LOAD_ADDRESS;
|
buf[0] = Cmnd_STK_LOAD_ADDRESS;
|
||||||
buf[1] = addr & 0xff;
|
// Workaround for the infamous ';' bug in the Prusa3D usb to serial converter.
|
||||||
buf[2] = (addr >> 8) & 0xff;
|
// Send the binary data by nibbles to avoid transmitting the ';' character.
|
||||||
buf[3] = Sync_CRC_EOP;
|
buf[1] = addr & 0x0f;
|
||||||
|
buf[2] = addr & 0xf0;
|
||||||
stk500_send(pgm, buf, 4);
|
buf[3] = (addr >> 8) & 0x0f;
|
||||||
|
buf[4] = (addr >> 8) & 0xf0;
|
||||||
|
buf[5] = Sync_CRC_EOP;
|
||||||
|
stk500_send(pgm, buf, 6);
|
||||||
|
|
||||||
if (stk500_recv(pgm, buf, 1) < 0)
|
if (stk500_recv(pgm, buf, 1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -765,7 +768,9 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||||||
int block_size;
|
int block_size;
|
||||||
int tries;
|
int tries;
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
unsigned int i;
|
unsigned int i, j;
|
||||||
|
unsigned int prusa3d_semicolon_workaround_round = 0;
|
||||||
|
bool has_semicolon = false;
|
||||||
|
|
||||||
if (strcmp(m->desc, "flash") == 0) {
|
if (strcmp(m->desc, "flash") == 0) {
|
||||||
memtype = 'F';
|
memtype = 'F';
|
||||||
@ -806,44 +811,64 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||||||
tries++;
|
tries++;
|
||||||
stk500_loadaddr(pgm, m, addr/a_div);
|
stk500_loadaddr(pgm, m, addr/a_div);
|
||||||
|
|
||||||
/* build command block and avoid multiple send commands as it leads to a crash
|
for (i = 0; i < n_bytes; ++ i)
|
||||||
of the silabs usb serial driver on mac os x */
|
if (m->buf[addr + i] == ';') {
|
||||||
i = 0;
|
has_semicolon = true;
|
||||||
buf[i++] = Cmnd_STK_PROG_PAGE;
|
break;
|
||||||
buf[i++] = (block_size >> 8) & 0xff;
|
}
|
||||||
buf[i++] = block_size & 0xff;
|
|
||||||
buf[i++] = memtype;
|
for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2 : 1); ++ prusa3d_semicolon_workaround_round) {
|
||||||
memcpy(&buf[i], &m->buf[addr], block_size);
|
/* build command block and avoid multiple send commands as it leads to a crash
|
||||||
i += block_size;
|
of the silabs usb serial driver on mac os x */
|
||||||
buf[i++] = Sync_CRC_EOP;
|
i = 0;
|
||||||
stk500_send( pgm, buf, i);
|
buf[i++] = Cmnd_STK_PROG_PAGE;
|
||||||
|
// Workaround for the infamous ';' bug in the Prusa3D usb to serial converter.
|
||||||
if (stk500_recv(pgm, buf, 1) < 0)
|
// Send the binary data by nibbles to avoid transmitting the ';' character.
|
||||||
return -1;
|
buf[i++] = (block_size >> 8) & 0xf0;
|
||||||
if (buf[0] == Resp_STK_NOSYNC) {
|
buf[i++] = (block_size >> 8) & 0x0f;
|
||||||
if (tries > 33) {
|
buf[i++] = block_size & 0xf0;
|
||||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): can't get into sync\n",
|
buf[i++] = block_size & 0x0f;
|
||||||
progname);
|
buf[i++] = memtype;
|
||||||
return -3;
|
if (has_semicolon) {
|
||||||
|
for (j = 0; j < block_size; ++i, ++ j) {
|
||||||
|
buf[i] = m->buf[addr + j];
|
||||||
|
if (buf[i] == ';')
|
||||||
|
buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&buf[i], &m->buf[addr], block_size);
|
||||||
|
i += block_size;
|
||||||
|
}
|
||||||
|
buf[i++] = Sync_CRC_EOP;
|
||||||
|
stk500_send( pgm, buf, i);
|
||||||
|
|
||||||
|
if (stk500_recv(pgm, buf, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
if (buf[0] == Resp_STK_NOSYNC) {
|
||||||
|
if (tries > 33) {
|
||||||
|
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): can't get into sync\n",
|
||||||
|
progname);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if (stk500_getsync(pgm) < 0)
|
||||||
|
return -1;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
else if (buf[0] != Resp_STK_INSYNC) {
|
||||||
|
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, "
|
||||||
|
"expect=0x%02x, resp=0x%02x\n",
|
||||||
|
progname, Resp_STK_INSYNC, buf[0]);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stk500_recv(pgm, buf, 1) < 0)
|
||||||
|
return -1;
|
||||||
|
if (buf[0] != Resp_STK_OK) {
|
||||||
|
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, "
|
||||||
|
"expect=0x%02x, resp=0x%02x\n",
|
||||||
|
progname, Resp_STK_INSYNC, buf[0]);
|
||||||
|
return -5;
|
||||||
}
|
}
|
||||||
if (stk500_getsync(pgm) < 0)
|
|
||||||
return -1;
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
else if (buf[0] != Resp_STK_INSYNC) {
|
|
||||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, "
|
|
||||||
"expect=0x%02x, resp=0x%02x\n",
|
|
||||||
progname, Resp_STK_INSYNC, buf[0]);
|
|
||||||
return -4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stk500_recv(pgm, buf, 1) < 0)
|
|
||||||
return -1;
|
|
||||||
if (buf[0] != Resp_STK_OK) {
|
|
||||||
avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, "
|
|
||||||
"expect=0x%02x, resp=0x%02x\n",
|
|
||||||
progname, Resp_STK_INSYNC, buf[0]);
|
|
||||||
return -5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -893,11 +918,15 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||||||
tries++;
|
tries++;
|
||||||
stk500_loadaddr(pgm, m, addr/a_div);
|
stk500_loadaddr(pgm, m, addr/a_div);
|
||||||
buf[0] = Cmnd_STK_READ_PAGE;
|
buf[0] = Cmnd_STK_READ_PAGE;
|
||||||
buf[1] = (block_size >> 8) & 0xff;
|
// Workaround for the infamous ';' bug in the Prusa3D usb to serial converter.
|
||||||
buf[2] = block_size & 0xff;
|
// Send the binary data by nibbles to avoid transmitting the ';' character.
|
||||||
buf[3] = memtype;
|
buf[1] = (block_size >> 8) & 0xf0;
|
||||||
buf[4] = Sync_CRC_EOP;
|
buf[2] = (block_size >> 8) & 0x0f;
|
||||||
stk500_send(pgm, buf, 5);
|
buf[3] = block_size & 0xf0;
|
||||||
|
buf[4] = block_size & 0x0f;
|
||||||
|
buf[5] = memtype;
|
||||||
|
buf[6] = Sync_CRC_EOP;
|
||||||
|
stk500_send(pgm, buf, 7);
|
||||||
|
|
||||||
if (stk500_recv(pgm, buf, 1) < 0)
|
if (stk500_recv(pgm, buf, 1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
#define SERIAL_TIMEOUT 2
|
#define SERIAL_TIMEOUT 2
|
||||||
|
|
||||||
// Retry count
|
// Retry count
|
||||||
#define RETRIES 5
|
#define RETRIES 0
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define DEBUG(...) avrdude_message(MSG_INFO, __VA_ARGS__)
|
#define DEBUG(...) avrdude_message(MSG_INFO, __VA_ARGS__)
|
||||||
@ -745,7 +745,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char *msg, size_t maxsize) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int stk500v2_getsync_internal(PROGRAMMER * pgm, int retries) {
|
int stk500v2_getsync(PROGRAMMER * pgm) {
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
unsigned char buf[1], resp[32];
|
unsigned char buf[1], resp[32];
|
||||||
int status;
|
int status;
|
||||||
@ -804,7 +804,7 @@ retry:
|
|||||||
progname, pgmname[PDATA(pgm)->pgmtype]);
|
progname, pgmname[PDATA(pgm)->pgmtype]);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (tries > retries) {
|
if (tries > RETRIES) {
|
||||||
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): can't communicate with device: resp=0x%02x\n",
|
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): can't communicate with device: resp=0x%02x\n",
|
||||||
progname, resp[0]);
|
progname, resp[0]);
|
||||||
return -6;
|
return -6;
|
||||||
@ -814,7 +814,7 @@ retry:
|
|||||||
|
|
||||||
// or if we got a timeout
|
// or if we got a timeout
|
||||||
} else if (status == -1) {
|
} else if (status == -1) {
|
||||||
if (tries > retries) {
|
if (tries > RETRIES) {
|
||||||
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): timeout communicating with programmer\n",
|
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): timeout communicating with programmer\n",
|
||||||
progname);
|
progname);
|
||||||
return -1;
|
return -1;
|
||||||
@ -823,7 +823,7 @@ retry:
|
|||||||
|
|
||||||
// or any other error
|
// or any other error
|
||||||
} else {
|
} else {
|
||||||
if (tries > retries) {
|
if (tries > RETRIES) {
|
||||||
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): error communicating with programmer: (%d)\n",
|
avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): error communicating with programmer: (%d)\n",
|
||||||
progname,status);
|
progname,status);
|
||||||
} else
|
} else
|
||||||
@ -833,11 +833,6 @@ retry:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stk500v2_getsync(PROGRAMMER * pgm) {
|
|
||||||
// This is to avoid applying RETRIES exponentially
|
|
||||||
return stk500v2_getsync_internal(pgm, RETRIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf,
|
static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf,
|
||||||
size_t len, size_t maxlen) {
|
size_t len, size_t maxlen) {
|
||||||
int i;
|
int i;
|
||||||
@ -947,7 +942,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise try to sync up again
|
// otherwise try to sync up again
|
||||||
status = stk500v2_getsync_internal(pgm, 1);
|
status = stk500v2_getsync(pgm);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
if (tries > RETRIES) {
|
if (tries > RETRIES) {
|
||||||
avrdude_message(MSG_INFO, "%s: stk500v2_command(): failed miserably to execute command 0x%02x\n",
|
avrdude_message(MSG_INFO, "%s: stk500v2_command(): failed miserably to execute command 0x%02x\n",
|
||||||
|
@ -101,6 +101,24 @@ UPDATE * parse_op(char * s)
|
|||||||
|
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
// Extension: Parse file contents offset
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
for (; *p != ':'; p++) {
|
||||||
|
if (*p >= '0' && *p <= '9') {
|
||||||
|
offset *= 10;
|
||||||
|
offset += *p - 0x30;
|
||||||
|
} else {
|
||||||
|
avrdude_message(MSG_INFO, "%s: invalid update specification: offset is not a number\n", progname);
|
||||||
|
free(upd->memtype);
|
||||||
|
free(upd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upd->offset = offset;
|
||||||
|
p++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now, parse the filename component. Instead of looking for the
|
* Now, parse the filename component. Instead of looking for the
|
||||||
* leftmost possible colon delimiter, we look for the rightmost one.
|
* leftmost possible colon delimiter, we look for the rightmost one.
|
||||||
@ -176,7 +194,7 @@ UPDATE * dup_update(UPDATE * upd)
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
|
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename, size_t offset)
|
||||||
{
|
{
|
||||||
UPDATE * u;
|
UPDATE * u;
|
||||||
|
|
||||||
@ -190,6 +208,7 @@ UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
|
|||||||
u->filename = strdup(filename);
|
u->filename = strdup(filename);
|
||||||
u->op = op;
|
u->op = op;
|
||||||
u->format = filefmt;
|
u->format = filefmt;
|
||||||
|
u->offset = offset;
|
||||||
|
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
@ -250,7 +269,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
|||||||
progname,
|
progname,
|
||||||
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
|
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
|
||||||
}
|
}
|
||||||
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
|
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n",
|
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n",
|
||||||
progname, upd->filename);
|
progname, upd->filename);
|
||||||
@ -267,7 +286,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
|||||||
progname,
|
progname,
|
||||||
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
|
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
|
||||||
}
|
}
|
||||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||||
progname, upd->filename);
|
progname, upd->filename);
|
||||||
@ -296,11 +315,11 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
|||||||
report_progress(1,1,NULL);
|
report_progress(1,1,NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/*
|
// /*
|
||||||
* test mode, don't actually write to the chip, output the buffer
|
// * test mode, don't actually write to the chip, output the buffer
|
||||||
* to stdout in intel hex instead
|
// * to stdout in intel hex instead
|
||||||
*/
|
// */
|
||||||
rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
|
// rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@ -332,7 +351,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
|||||||
progname, mem->desc, upd->filename);
|
progname, mem->desc, upd->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||||
progname, upd->filename);
|
progname, upd->filename);
|
||||||
|
@ -222,6 +222,14 @@ BoundingBox3Base<PointClass>::center() const
|
|||||||
}
|
}
|
||||||
template Pointf3 BoundingBox3Base<Pointf3>::center() const;
|
template Pointf3 BoundingBox3Base<Pointf3>::center() const;
|
||||||
|
|
||||||
|
template <class PointClass> coordf_t
|
||||||
|
BoundingBox3Base<PointClass>::max_size() const
|
||||||
|
{
|
||||||
|
PointClass s = size();
|
||||||
|
return std::max(s.x, std::max(s.y, s.z));
|
||||||
|
}
|
||||||
|
template coordf_t BoundingBox3Base<Pointf3>::max_size() const;
|
||||||
|
|
||||||
// Align a coordinate to a grid. The coordinate may be negative,
|
// Align a coordinate to a grid. The coordinate may be negative,
|
||||||
// the aligned value will never be bigger than the original one.
|
// the aligned value will never be bigger than the original one.
|
||||||
static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
|
static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
|
||||||
|
@ -94,6 +94,7 @@ public:
|
|||||||
void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); }
|
void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); }
|
||||||
void offset(coordf_t delta);
|
void offset(coordf_t delta);
|
||||||
PointClass center() const;
|
PointClass center() const;
|
||||||
|
coordf_t max_size() const;
|
||||||
|
|
||||||
bool contains(const PointClass &point) const {
|
bool contains(const PointClass &point) const {
|
||||||
return BoundingBoxBase<PointClass>::contains(point) && point.z >= this->min.z && point.z <= this->max.z;
|
return BoundingBoxBase<PointClass>::contains(point) && point.z >= this->min.z && point.z <= this->max.z;
|
||||||
|
@ -1271,6 +1271,7 @@ namespace Slic3r {
|
|||||||
if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001))
|
if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if 0 // use quaternions
|
||||||
// rotations (extracted using quaternion)
|
// rotations (extracted using quaternion)
|
||||||
double inv_sx = 1.0 / sx;
|
double inv_sx = 1.0 / sx;
|
||||||
double inv_sy = 1.0 / sy;
|
double inv_sy = 1.0 / sy;
|
||||||
@ -1331,6 +1332,25 @@ namespace Slic3r {
|
|||||||
if (angle_z < 0.0)
|
if (angle_z < 0.0)
|
||||||
angle_z += 2.0 * PI;
|
angle_z += 2.0 * PI;
|
||||||
}
|
}
|
||||||
|
#else // use eigen library
|
||||||
|
double inv_sx = 1.0 / sx;
|
||||||
|
double inv_sy = 1.0 / sy;
|
||||||
|
double inv_sz = 1.0 / sz;
|
||||||
|
|
||||||
|
Eigen::Matrix3d m3x3;
|
||||||
|
m3x3 << (double)matrix(0, 0) * inv_sx, (double)matrix(0, 1) * inv_sy, (double)matrix(0, 2) * inv_sz,
|
||||||
|
(double)matrix(1, 0) * inv_sx, (double)matrix(1, 1) * inv_sy, (double)matrix(1, 2) * inv_sz,
|
||||||
|
(double)matrix(2, 0) * inv_sx, (double)matrix(2, 1) * inv_sy, (double)matrix(2, 2) * inv_sz;
|
||||||
|
|
||||||
|
Eigen::AngleAxisd rotation;
|
||||||
|
rotation.fromRotationMatrix(m3x3);
|
||||||
|
|
||||||
|
// invalid rotation axis, we currently handle only rotations around Z axis
|
||||||
|
if ((rotation.angle() != 0.0) && (rotation.axis() != Eigen::Vector3d::UnitZ()) && (rotation.axis() != -Eigen::Vector3d::UnitZ()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
double angle_z = (rotation.axis() == Eigen::Vector3d::UnitZ()) ? rotation.angle() : -rotation.angle();
|
||||||
|
#endif
|
||||||
|
|
||||||
instance.offset.x = offset_x;
|
instance.offset.x = offset_x;
|
||||||
instance.offset.y = offset_y;
|
instance.offset.y = offset_y;
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
//############################################################################################################################################
|
||||||
|
#include <boost/nowide/fstream.hpp>
|
||||||
|
//############################################################################################################################################
|
||||||
#include <miniz/miniz_zip.h>
|
#include <miniz/miniz_zip.h>
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -666,10 +669,21 @@ bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model)
|
|||||||
// If bundle is not a null pointer, updates it if the amf file/archive contains config data
|
// If bundle is not a null pointer, updates it if the amf file/archive contains config data
|
||||||
bool load_amf(const char *path, PresetBundle* bundle, Model *model)
|
bool load_amf(const char *path, PresetBundle* bundle, Model *model)
|
||||||
{
|
{
|
||||||
if (boost::iends_with(path, ".zip.amf"))
|
if (boost::iends_with(path, ".amf.xml"))
|
||||||
return load_amf_archive(path, bundle, model);
|
// backward compatibility with older slic3r output
|
||||||
else if (boost::iends_with(path, ".amf") || boost::iends_with(path, ".amf.xml"))
|
|
||||||
return load_amf_file(path, bundle, model);
|
return load_amf_file(path, bundle, model);
|
||||||
|
else if (boost::iends_with(path, ".amf"))
|
||||||
|
{
|
||||||
|
boost::nowide::ifstream file(path, boost::nowide::ifstream::binary);
|
||||||
|
if (!file.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string zip_mask(2, '\0');
|
||||||
|
file.read(const_cast<char*>(zip_mask.data()), 2);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return (zip_mask == "PK") ? load_amf_archive(path, bundle, model) : load_amf_file(path, bundle, model);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,10 @@ void ModelObject::clear_instances()
|
|||||||
|
|
||||||
// Returns the bounding box of the transformed instances.
|
// Returns the bounding box of the transformed instances.
|
||||||
// This bounding box is approximate and not snug.
|
// This bounding box is approximate and not snug.
|
||||||
const BoundingBoxf3& ModelObject::bounding_box()
|
//========================================================================================================
|
||||||
|
const BoundingBoxf3& ModelObject::bounding_box() const
|
||||||
|
//const BoundingBoxf3& ModelObject::bounding_box()
|
||||||
|
//========================================================================================================
|
||||||
{
|
{
|
||||||
if (! m_bounding_box_valid) {
|
if (! m_bounding_box_valid) {
|
||||||
BoundingBoxf3 raw_bbox;
|
BoundingBoxf3 raw_bbox;
|
||||||
|
@ -103,7 +103,10 @@ public:
|
|||||||
// Returns the bounding box of the transformed instances.
|
// Returns the bounding box of the transformed instances.
|
||||||
// This bounding box is approximate and not snug.
|
// This bounding box is approximate and not snug.
|
||||||
// This bounding box is being cached.
|
// This bounding box is being cached.
|
||||||
const BoundingBoxf3& bounding_box();
|
//========================================================================================================
|
||||||
|
const BoundingBoxf3& bounding_box() const;
|
||||||
|
// const BoundingBoxf3& bounding_box();
|
||||||
|
//========================================================================================================
|
||||||
void invalidate_bounding_box() { m_bounding_box_valid = false; }
|
void invalidate_bounding_box() { m_bounding_box_valid = false; }
|
||||||
// Returns a snug bounding box of the transformed instances.
|
// Returns a snug bounding box of the transformed instances.
|
||||||
// This bounding box is not being cached.
|
// This bounding box is not being cached.
|
||||||
@ -145,8 +148,10 @@ private:
|
|||||||
// Parent object, owning this ModelObject.
|
// Parent object, owning this ModelObject.
|
||||||
Model *m_model;
|
Model *m_model;
|
||||||
// Bounding box, cached.
|
// Bounding box, cached.
|
||||||
BoundingBoxf3 m_bounding_box;
|
//========================================================================================================
|
||||||
bool m_bounding_box_valid;
|
mutable BoundingBoxf3 m_bounding_box;
|
||||||
|
mutable bool m_bounding_box_valid;
|
||||||
|
//========================================================================================================
|
||||||
};
|
};
|
||||||
|
|
||||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||||
|
@ -238,6 +238,11 @@ inline coordf_t dot(const Pointf &v1, const Pointf &v2) { return v1.x * v2.x + v
|
|||||||
inline coordf_t dot(const Pointf &v) { return v.x * v.x + v.y * v.y; }
|
inline coordf_t dot(const Pointf &v) { return v.x * v.x + v.y * v.y; }
|
||||||
inline double length(const Vectorf &v) { return sqrt(dot(v)); }
|
inline double length(const Vectorf &v) { return sqrt(dot(v)); }
|
||||||
inline double l2(const Vectorf &v) { return dot(v); }
|
inline double l2(const Vectorf &v) { return dot(v); }
|
||||||
|
inline Vectorf normalize(const Vectorf& v)
|
||||||
|
{
|
||||||
|
coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y));
|
||||||
|
return (len != 0.0) ? 1.0 / len * v : Vectorf(0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
class Pointf3 : public Pointf
|
class Pointf3 : public Pointf
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,7 @@ double Polygon::area() const
|
|||||||
|
|
||||||
double a = 0.;
|
double a = 0.;
|
||||||
for (size_t i = 0, j = n - 1; i < n; ++i) {
|
for (size_t i = 0, j = n - 1; i < n; ++i) {
|
||||||
a += double(points[j].x + points[i].x) * double(points[i].y - points[j].y);
|
a += ((double)points[j].x + (double)points[i].x) * ((double)points[i].y - (double)points[j].y);
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
return 0.5 * a;
|
return 0.5 * a;
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
#include <tbb/spin_mutex.h>//#include "tbb/mutex.h"
|
||||||
|
|
||||||
|
#include "slic3r/IProgressIndicator.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
template class PrintState<PrintStep, psCount>;
|
template class PrintState<PrintStep, psCount>;
|
||||||
@ -1254,8 +1256,11 @@ std::string Print::output_filepath(const std::string &path)
|
|||||||
|
|
||||||
void Print::set_status(int percent, const std::string &message)
|
void Print::set_status(int percent, const std::string &message)
|
||||||
{
|
{
|
||||||
printf("Print::status %d => %s\n", percent, message.c_str());
|
if(progressindicator) progressindicator->update(unsigned(percent), message);
|
||||||
std::cout.flush();
|
else {
|
||||||
|
printf("Print::status %d => %s\n", percent, message.c_str());
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1279,8 +1284,8 @@ public:
|
|||||||
// Get the number of layers in the print.
|
// Get the number of layers in the print.
|
||||||
unsigned layers() const;
|
unsigned layers() const;
|
||||||
|
|
||||||
/* Switch the a particular layer. If there where less layers then the
|
/* Switch to a particular layer. If there where less layers then the
|
||||||
* specified layer number than an appripriate number of layers will be
|
* specified layer number than an appropriate number of layers will be
|
||||||
* allocated in the printer.
|
* allocated in the printer.
|
||||||
*/
|
*/
|
||||||
void beginLayer(unsigned layer);
|
void beginLayer(unsigned layer);
|
||||||
@ -1382,7 +1387,7 @@ public:
|
|||||||
wxFFileOutputStream zipfile(path);
|
wxFFileOutputStream zipfile(path);
|
||||||
|
|
||||||
if(!zipfile.IsOk()) {
|
if(!zipfile.IsOk()) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers!";
|
std::cout /*BOOST_LOG_TRIVIAL(error)*/ << "Can't create zip file for layers! " << path << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +184,8 @@ public:
|
|||||||
|
|
||||||
void reset_layer_height_profile();
|
void reset_layer_height_profile();
|
||||||
|
|
||||||
|
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action);
|
||||||
|
|
||||||
// Collect the slicing parameters, to be used by variable layer thickness algorithm,
|
// Collect the slicing parameters, to be used by variable layer thickness algorithm,
|
||||||
// by the interactive layer height editor and by the printing process itself.
|
// by the interactive layer height editor and by the printing process itself.
|
||||||
// The slicing parameters are dependent on various configuration values
|
// The slicing parameters are dependent on various configuration values
|
||||||
@ -222,6 +224,9 @@ private:
|
|||||||
typedef std::vector<PrintObject*> PrintObjectPtrs;
|
typedef std::vector<PrintObject*> PrintObjectPtrs;
|
||||||
typedef std::vector<PrintRegion*> PrintRegionPtrs;
|
typedef std::vector<PrintRegion*> PrintRegionPtrs;
|
||||||
|
|
||||||
|
class IProgressIndicator;
|
||||||
|
using ProgressIndicatorPtr = std::shared_ptr<IProgressIndicator>;
|
||||||
|
|
||||||
// The complete print tray with possibly multiple objects.
|
// The complete print tray with possibly multiple objects.
|
||||||
class Print
|
class Print
|
||||||
{
|
{
|
||||||
@ -232,7 +237,10 @@ public:
|
|||||||
PrintObjectPtrs objects;
|
PrintObjectPtrs objects;
|
||||||
PrintRegionPtrs regions;
|
PrintRegionPtrs regions;
|
||||||
PlaceholderParser placeholder_parser;
|
PlaceholderParser placeholder_parser;
|
||||||
|
|
||||||
// TODO: status_cb
|
// TODO: status_cb
|
||||||
|
ProgressIndicatorPtr progressindicator;
|
||||||
|
|
||||||
std::string estimated_print_time;
|
std::string estimated_print_time;
|
||||||
double total_used_filament, total_extruded_volume, total_cost, total_weight;
|
double total_used_filament, total_extruded_volume, total_cost, total_weight;
|
||||||
std::map<size_t, float> filament_stats;
|
std::map<size_t, float> filament_stats;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "SupportMaterial.hpp"
|
#include "SupportMaterial.hpp"
|
||||||
#include "Surface.hpp"
|
#include "Surface.hpp"
|
||||||
|
#include "Slicing.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
@ -1961,4 +1962,12 @@ void PrintObject::reset_layer_height_profile()
|
|||||||
this->model_object()->layer_height_profile_valid = false;
|
this->model_object()->layer_height_profile_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
|
||||||
|
{
|
||||||
|
update_layer_height_profile(_model_object->layer_height_profile);
|
||||||
|
Slic3r::adjust_layer_height_profile(slicing_parameters(), _model_object->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
|
||||||
|
_model_object->layer_height_profile_valid = true;
|
||||||
|
layer_height_profile_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -91,10 +91,13 @@ public:
|
|||||||
~PerlCallback() { this->deregister_callback(); }
|
~PerlCallback() { this->deregister_callback(); }
|
||||||
void register_callback(void *sv);
|
void register_callback(void *sv);
|
||||||
void deregister_callback();
|
void deregister_callback();
|
||||||
void call();
|
void call() const;
|
||||||
void call(int i);
|
void call(int i) const;
|
||||||
void call(int i, int j);
|
void call(int i, int j) const;
|
||||||
// void call(const std::vector<int> &ints);
|
void call(const std::vector<int>& ints) const;
|
||||||
|
void call(double d) const;
|
||||||
|
void call(double x, double y) const;
|
||||||
|
void call(bool b) const;
|
||||||
private:
|
private:
|
||||||
void *m_callback;
|
void *m_callback;
|
||||||
};
|
};
|
||||||
|
@ -184,7 +184,7 @@ void PerlCallback::deregister_callback()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerlCallback::call()
|
void PerlCallback::call() const
|
||||||
{
|
{
|
||||||
if (! m_callback)
|
if (! m_callback)
|
||||||
return;
|
return;
|
||||||
@ -198,7 +198,7 @@ void PerlCallback::call()
|
|||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerlCallback::call(int i)
|
void PerlCallback::call(int i) const
|
||||||
{
|
{
|
||||||
if (! m_callback)
|
if (! m_callback)
|
||||||
return;
|
return;
|
||||||
@ -213,7 +213,7 @@ void PerlCallback::call(int i)
|
|||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerlCallback::call(int i, int j)
|
void PerlCallback::call(int i, int j) const
|
||||||
{
|
{
|
||||||
if (! m_callback)
|
if (! m_callback)
|
||||||
return;
|
return;
|
||||||
@ -229,8 +229,7 @@ void PerlCallback::call(int i, int j)
|
|||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void PerlCallback::call(const std::vector<int>& ints) const
|
||||||
void PerlCallback::call(const std::vector<int> &ints)
|
|
||||||
{
|
{
|
||||||
if (! m_callback)
|
if (! m_callback)
|
||||||
return;
|
return;
|
||||||
@ -238,16 +237,51 @@ void PerlCallback::call(const std::vector<int> &ints)
|
|||||||
ENTER;
|
ENTER;
|
||||||
SAVETMPS;
|
SAVETMPS;
|
||||||
PUSHMARK(SP);
|
PUSHMARK(SP);
|
||||||
AV* av = newAV();
|
|
||||||
for (int i : ints)
|
for (int i : ints)
|
||||||
av_push(av, newSViv(i));
|
{
|
||||||
XPUSHs(av);
|
XPUSHs(sv_2mortal(newSViv(i)));
|
||||||
|
}
|
||||||
PUTBACK;
|
PUTBACK;
|
||||||
perl_call_sv(SvRV((SV*)m_callback), G_DISCARD);
|
perl_call_sv(SvRV((SV*)m_callback), G_DISCARD);
|
||||||
FREETMPS;
|
FREETMPS;
|
||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
void PerlCallback::call(double d) const
|
||||||
|
{
|
||||||
|
if (!m_callback)
|
||||||
|
return;
|
||||||
|
dSP;
|
||||||
|
ENTER;
|
||||||
|
SAVETMPS;
|
||||||
|
PUSHMARK(SP);
|
||||||
|
XPUSHs(sv_2mortal(newSVnv(d)));
|
||||||
|
PUTBACK;
|
||||||
|
perl_call_sv(SvRV((SV*)m_callback), G_DISCARD);
|
||||||
|
FREETMPS;
|
||||||
|
LEAVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlCallback::call(double x, double y) const
|
||||||
|
{
|
||||||
|
if (!m_callback)
|
||||||
|
return;
|
||||||
|
dSP;
|
||||||
|
ENTER;
|
||||||
|
SAVETMPS;
|
||||||
|
PUSHMARK(SP);
|
||||||
|
XPUSHs(sv_2mortal(newSVnv(x)));
|
||||||
|
XPUSHs(sv_2mortal(newSVnv(y)));
|
||||||
|
PUTBACK;
|
||||||
|
perl_call_sv(SvRV((SV*)m_callback), G_DISCARD);
|
||||||
|
FREETMPS;
|
||||||
|
LEAVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerlCallback::call(bool b) const
|
||||||
|
{
|
||||||
|
call(b ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
|
@ -55,14 +55,21 @@ AppControllerBoilerplate::query_destination_paths(
|
|||||||
AppControllerBoilerplate::Path
|
AppControllerBoilerplate::Path
|
||||||
AppControllerBoilerplate::query_destination_path(
|
AppControllerBoilerplate::query_destination_path(
|
||||||
const std::string &title,
|
const std::string &title,
|
||||||
const std::string &extensions) const
|
const std::string &extensions,
|
||||||
|
const std::string& hint) const
|
||||||
{
|
{
|
||||||
wxFileDialog dlg(wxTheApp->GetTopWindow(), title );
|
wxFileDialog dlg(wxTheApp->GetTopWindow(), title );
|
||||||
dlg.SetWildcard(extensions);
|
dlg.SetWildcard(extensions);
|
||||||
|
|
||||||
dlg.ShowModal();
|
dlg.SetFilename(hint);
|
||||||
|
|
||||||
Path ret(dlg.GetFilename());
|
Path ret;
|
||||||
|
|
||||||
|
if(dlg.ShowModal() == wxID_OK) {
|
||||||
|
ret = Path(dlg.GetPath());
|
||||||
|
|
||||||
|
std::cout << "Filename: " << ret << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -88,9 +95,9 @@ AppControllerBoilerplate::createProgressIndicator(unsigned statenum,
|
|||||||
const std::string& title,
|
const std::string& title,
|
||||||
const std::string& firstmsg) const
|
const std::string& firstmsg) const
|
||||||
{
|
{
|
||||||
class GuiProgressIndicator: public ProgressIndicator {
|
class GuiProgressIndicator: public IProgressIndicator {
|
||||||
wxProgressDialog gauge_;
|
wxProgressDialog gauge_;
|
||||||
using Base = ProgressIndicator;
|
using Base = IProgressIndicator;
|
||||||
wxString message_;
|
wxString message_;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -122,7 +129,7 @@ AppControllerBoilerplate::createProgressIndicator(unsigned statenum,
|
|||||||
message_ = _(msg);
|
message_ = _(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void messageFmt(const std::string& fmt, ...) {
|
virtual void message_fmt(const std::string& fmt, ...) {
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
va_start(arglist, fmt);
|
va_start(arglist, fmt);
|
||||||
message_ = wxString::Format(_(fmt), arglist);
|
message_ = wxString::Format(_(fmt), arglist);
|
||||||
@ -296,7 +303,7 @@ void PrintController::slice()
|
|||||||
progressIndicator()->update(70u, "Generating support material");
|
progressIndicator()->update(70u, "Generating support material");
|
||||||
for(auto obj : print_->objects) gen_support_material(obj);
|
for(auto obj : print_->objects) gen_support_material(obj);
|
||||||
|
|
||||||
progressIndicator()->messageFmt("Weight: %.1fg, Cost: %.1f",
|
progressIndicator()->message_fmt("Weight: %.1fg, Cost: %.1f",
|
||||||
print_->total_weight,
|
print_->total_weight,
|
||||||
print_->total_cost);
|
print_->total_cost);
|
||||||
|
|
||||||
@ -334,8 +341,10 @@ void PrintController::slice_to_png()
|
|||||||
// wxMilliSleep(100);
|
// wxMilliSleep(100);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// auto zipfilepath = query_destination_path( "Path to zip file...",
|
auto zipfilepath = query_destination_path( "Path to zip file...",
|
||||||
// "*.zip");
|
"*.zip");
|
||||||
|
|
||||||
|
if(zipfilepath.empty()) return;
|
||||||
|
|
||||||
auto presetbundle = GUI::get_preset_bundle();
|
auto presetbundle = GUI::get_preset_bundle();
|
||||||
|
|
||||||
@ -345,10 +354,23 @@ void PrintController::slice_to_png()
|
|||||||
|
|
||||||
conf.validate();
|
conf.validate();
|
||||||
|
|
||||||
|
try {
|
||||||
|
print_->apply_config(conf);
|
||||||
|
print_->validate();
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
report_issue(IssueType::ERR, e.what(), "Error");
|
||||||
|
}
|
||||||
|
|
||||||
auto bak = progressIndicator();
|
auto bak = progressIndicator();
|
||||||
progressIndicator(100, "Slicing to zipped png files...");
|
progressIndicator(100, "Slicing to zipped png files...");
|
||||||
std::async(std::launch::async, [this, &bak](){
|
std::async(std::launch::async, [this, bak, zipfilepath](){
|
||||||
slice();
|
slice();
|
||||||
|
|
||||||
|
auto pbak = print_->progressindicator;
|
||||||
|
print_->progressindicator = progressIndicator();
|
||||||
|
print_->print_to_png(zipfilepath);
|
||||||
|
print_->progressindicator = pbak;
|
||||||
|
|
||||||
progressIndicator(bak);
|
progressIndicator(bak);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -359,10 +381,10 @@ void AppController::set_global_progress_indicator_id(
|
|||||||
unsigned sid)
|
unsigned sid)
|
||||||
{
|
{
|
||||||
|
|
||||||
class Wrapper: public ProgressIndicator {
|
class Wrapper: public IProgressIndicator {
|
||||||
wxGauge *gauge_;
|
wxGauge *gauge_;
|
||||||
wxStatusBar *stbar_;
|
wxStatusBar *stbar_;
|
||||||
using Base = ProgressIndicator;
|
using Base = IProgressIndicator;
|
||||||
std::string message_;
|
std::string message_;
|
||||||
|
|
||||||
void showProgress(bool show = true) {
|
void showProgress(bool show = true) {
|
||||||
@ -406,7 +428,7 @@ void AppController::set_global_progress_indicator_id(
|
|||||||
message_ = msg;
|
message_ = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void messageFmt(const std::string& fmt, ...) {
|
virtual void message_fmt(const std::string& fmt, ...) {
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
va_start(arglist, fmt);
|
va_start(arglist, fmt);
|
||||||
message_ = wxString::Format(_(fmt), arglist);
|
message_ = wxString::Format(_(fmt), arglist);
|
||||||
@ -427,7 +449,7 @@ void AppController::set_global_progress_indicator_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppControllerBoilerplate::ProgressIndicator::messageFmt(
|
void IProgressIndicator::message_fmt(
|
||||||
const std::string &fmtstr, ...) {
|
const std::string &fmtstr, ...) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
va_list args;
|
va_list args;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "IProgressIndicator.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -33,40 +34,14 @@ public:
|
|||||||
|
|
||||||
Path query_destination_path(
|
Path query_destination_path(
|
||||||
const std::string& title,
|
const std::string& title,
|
||||||
const std::string& extensions) const;
|
const std::string& extensions,
|
||||||
|
const std::string& hint = "") const;
|
||||||
|
|
||||||
void report_issue(IssueType issuetype,
|
void report_issue(IssueType issuetype,
|
||||||
const std::string& description,
|
const std::string& description,
|
||||||
const std::string& brief = "");
|
const std::string& brief = "");
|
||||||
|
|
||||||
class ProgressIndicator {
|
using ProgresIndicatorPtr = std::shared_ptr<IProgressIndicator>;
|
||||||
float state_ = .0f, max_ = 1.f, step_;
|
|
||||||
public:
|
|
||||||
|
|
||||||
inline virtual ~ProgressIndicator() {}
|
|
||||||
|
|
||||||
float max() const { return max_; }
|
|
||||||
float state() const { return state_; }
|
|
||||||
|
|
||||||
virtual void max(float maxval) { max_ = maxval; }
|
|
||||||
virtual void state(float val) { state_ = val; }
|
|
||||||
virtual void state(unsigned st) { state_ = st * step_; }
|
|
||||||
virtual void states(unsigned statenum) {
|
|
||||||
step_ = max_ / statenum;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void message(const std::string&) = 0;
|
|
||||||
virtual void title(const std::string&) = 0;
|
|
||||||
|
|
||||||
virtual void messageFmt(const std::string& fmt, ...);
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void update(T st, const std::string& msg) {
|
|
||||||
message(msg); state(st);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
|
|
||||||
|
|
||||||
|
|
||||||
inline void progressIndicator(ProgresIndicatorPtr progrind) {
|
inline void progressIndicator(ProgresIndicatorPtr progrind) {
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
#include "../../libslic3r/Line.hpp"
|
#include "../../libslic3r/Line.hpp"
|
||||||
#include "../../libslic3r/TriangleMesh.hpp"
|
#include "../../libslic3r/TriangleMesh.hpp"
|
||||||
#include "../../libslic3r/Utils.hpp"
|
#include "../../libslic3r/Utils.hpp"
|
||||||
|
#include "../../slic3r/GUI/GLCanvas3DManager.hpp"
|
||||||
|
|
||||||
class wxBitmap;
|
class wxBitmap;
|
||||||
|
class wxWindow;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -17,6 +19,11 @@ class Model;
|
|||||||
class ModelObject;
|
class ModelObject;
|
||||||
class GCodePreviewData;
|
class GCodePreviewData;
|
||||||
class DynamicPrintConfig;
|
class DynamicPrintConfig;
|
||||||
|
class ExtrusionPath;
|
||||||
|
class ExtrusionMultiPath;
|
||||||
|
class ExtrusionLoop;
|
||||||
|
class ExtrusionEntity;
|
||||||
|
class ExtrusionEntityCollection;
|
||||||
|
|
||||||
// A container for interleaved arrays of 3D vertices and normals,
|
// A container for interleaved arrays of 3D vertices and normals,
|
||||||
// possibly indexed by triangles and / or quads.
|
// possibly indexed by triangles and / or quads.
|
||||||
@ -305,9 +312,9 @@ public:
|
|||||||
// Boolean: Is mouse over this object?
|
// Boolean: Is mouse over this object?
|
||||||
bool hover;
|
bool hover;
|
||||||
// Wheter or not this volume has been generated from a modifier
|
// Wheter or not this volume has been generated from a modifier
|
||||||
bool is_modifier;
|
bool is_modifier;
|
||||||
// Wheter or not this volume has been generated from the wipe tower
|
// Wheter or not this volume has been generated from the wipe tower
|
||||||
bool is_wipe_tower;
|
bool is_wipe_tower;
|
||||||
|
|
||||||
// Interleaved triangles & normals with indexed triangles & quads.
|
// Interleaved triangles & normals with indexed triangles & quads.
|
||||||
GLIndexedVertexArray indexed_vertex_array;
|
GLIndexedVertexArray indexed_vertex_array;
|
||||||
@ -437,35 +444,6 @@ private:
|
|||||||
|
|
||||||
class _3DScene
|
class _3DScene
|
||||||
{
|
{
|
||||||
struct GCodePreviewVolumeIndex
|
|
||||||
{
|
|
||||||
enum EType
|
|
||||||
{
|
|
||||||
Extrusion,
|
|
||||||
Travel,
|
|
||||||
Retraction,
|
|
||||||
Unretraction,
|
|
||||||
Shell,
|
|
||||||
Num_Geometry_Types
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FirstVolume
|
|
||||||
{
|
|
||||||
EType type;
|
|
||||||
unsigned int flag;
|
|
||||||
// Index of the first volume in a GLVolumeCollection.
|
|
||||||
unsigned int id;
|
|
||||||
|
|
||||||
FirstVolume(EType type, unsigned int flag, unsigned int id) : type(type), flag(flag), id(id) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<FirstVolume> first_volumes;
|
|
||||||
|
|
||||||
void reset() { first_volumes.clear(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
static GCodePreviewVolumeIndex s_gcode_preview_volume_index;
|
|
||||||
|
|
||||||
class TextureBase
|
class TextureBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -525,12 +503,106 @@ class _3DScene
|
|||||||
|
|
||||||
static LegendTexture s_legend_texture;
|
static LegendTexture s_legend_texture;
|
||||||
static WarningTexture s_warning_texture;
|
static WarningTexture s_warning_texture;
|
||||||
|
static GUI::GLCanvas3DManager s_canvas_mgr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void _glew_init();
|
static void init_gl();
|
||||||
|
static std::string get_gl_info(bool format_as_html, bool extensions);
|
||||||
|
static bool use_VBOs();
|
||||||
|
|
||||||
static void load_gcode_preview(const Print* print, const GCodePreviewData* preview_data, GLVolumeCollection* volumes, const std::vector<std::string>& str_tool_colors, bool use_VBOs);
|
static bool add_canvas(wxGLCanvas* canvas);
|
||||||
|
static bool remove_canvas(wxGLCanvas* canvas);
|
||||||
|
static void remove_all_canvases();
|
||||||
|
|
||||||
|
static bool init(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static void set_active(wxGLCanvas* canvas, bool active);
|
||||||
|
|
||||||
|
static unsigned int get_volumes_count(wxGLCanvas* canvas);
|
||||||
|
static void reset_volumes(wxGLCanvas* canvas);
|
||||||
|
static void deselect_volumes(wxGLCanvas* canvas);
|
||||||
|
static void select_volume(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
static void update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||||
|
static bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config);
|
||||||
|
static bool move_volume_up(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
static bool move_volume_down(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
|
||||||
|
static void set_objects_selections(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||||
|
|
||||||
|
static void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config);
|
||||||
|
static void set_print(wxGLCanvas* canvas, Print* print);
|
||||||
|
static void set_model(wxGLCanvas* canvas, Model* model);
|
||||||
|
|
||||||
|
static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape);
|
||||||
|
static void set_auto_bed_shape(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static void set_axes_length(wxGLCanvas* canvas, float length);
|
||||||
|
|
||||||
|
static void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons);
|
||||||
|
|
||||||
|
static void set_color_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
static void set_select_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
static void set_drag_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
|
||||||
|
static bool is_layers_editing_enabled(wxGLCanvas* canvas);
|
||||||
|
static bool is_layers_editing_allowed(wxGLCanvas* canvas);
|
||||||
|
static bool is_shader_enabled(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static bool is_reload_delayed(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static void enable_layers_editing(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_warning_texture(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_legend_texture(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_picking(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_moving(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_gizmos(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_shader(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
|
||||||
|
static void allow_multisample(wxGLCanvas* canvas, bool allow);
|
||||||
|
|
||||||
|
static void zoom_to_bed(wxGLCanvas* canvas);
|
||||||
|
static void zoom_to_volumes(wxGLCanvas* canvas);
|
||||||
|
static void select_view(wxGLCanvas* canvas, const std::string& direction);
|
||||||
|
static void set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other);
|
||||||
|
|
||||||
|
static void update_volumes_colors_by_extruder(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static void render(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
static std::vector<double> get_current_print_zs(wxGLCanvas* canvas, bool active_only);
|
||||||
|
static void set_toolpaths_range(wxGLCanvas* canvas, double low, double high);
|
||||||
|
|
||||||
|
static void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_double_click_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_right_click_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_select_object_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_model_update_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_remove_object_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_arrange_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_rotate_object_left_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_rotate_object_right_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_scale_object_uniformly_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_increase_objects_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_decrease_objects_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_instance_moved_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
|
||||||
|
static std::vector<int> load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector<int> instance_idxs);
|
||||||
|
static std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
|
||||||
|
|
||||||
|
static void reload_scene(wxGLCanvas* canvas, bool force);
|
||||||
|
|
||||||
|
static void load_print_toolpaths(wxGLCanvas* canvas);
|
||||||
|
static void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& str_tool_colors);
|
||||||
|
static void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
|
||||||
|
static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
|
||||||
|
|
||||||
|
// generates the legend texture in dependence of the current shown view type
|
||||||
|
static void generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||||
static unsigned int get_legend_texture_width();
|
static unsigned int get_legend_texture_width();
|
||||||
static unsigned int get_legend_texture_height();
|
static unsigned int get_legend_texture_height();
|
||||||
|
|
||||||
@ -545,42 +617,16 @@ public:
|
|||||||
static void reset_warning_texture();
|
static void reset_warning_texture();
|
||||||
static unsigned int finalize_warning_texture();
|
static unsigned int finalize_warning_texture();
|
||||||
|
|
||||||
static void _load_print_toolpaths(
|
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
|
||||||
const Print *print,
|
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
|
||||||
GLVolumeCollection *volumes,
|
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
|
||||||
const std::vector<std::string> &tool_colors,
|
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
|
||||||
bool use_VBOs);
|
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
|
||||||
|
static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GLVolume& volume);
|
||||||
static void _load_print_object_toolpaths(
|
static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GLVolume& volume);
|
||||||
const PrintObject *print_object,
|
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
|
||||||
GLVolumeCollection *volumes,
|
static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
|
||||||
const std::vector<std::string> &tool_colors,
|
static void point3_to_verts(const Point3& point, double width, double height, GLVolume& volume);
|
||||||
bool use_VBOs);
|
|
||||||
|
|
||||||
static void _load_wipe_tower_toolpaths(
|
|
||||||
const Print *print,
|
|
||||||
GLVolumeCollection *volumes,
|
|
||||||
const std::vector<std::string> &tool_colors_str,
|
|
||||||
bool use_VBOs);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// generates gcode extrusion paths geometry
|
|
||||||
static void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs);
|
|
||||||
// generates gcode travel paths geometry
|
|
||||||
static void _load_gcode_travel_paths(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs);
|
|
||||||
static bool _travel_paths_by_type(const GCodePreviewData& preview_data, GLVolumeCollection& volumes);
|
|
||||||
static bool _travel_paths_by_feedrate(const GCodePreviewData& preview_data, GLVolumeCollection& volumes);
|
|
||||||
static bool _travel_paths_by_tool(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors);
|
|
||||||
// generates gcode retractions geometry
|
|
||||||
static void _load_gcode_retractions(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, bool use_VBOs);
|
|
||||||
// generates gcode unretractions geometry
|
|
||||||
static void _load_gcode_unretractions(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, bool use_VBOs);
|
|
||||||
// sets gcode geometry visibility according to user selection
|
|
||||||
static void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data, GLVolumeCollection& volumes);
|
|
||||||
// generates the legend texture in dependence of the current shown view type
|
|
||||||
static void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
|
||||||
// generates objects and wipe tower geometry
|
|
||||||
static void _load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,11 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, cons
|
|||||||
sizer->Add(all_none_sizer, 0, wxEXPAND);
|
sizer->Add(all_none_sizer, 0, wxEXPAND);
|
||||||
|
|
||||||
SetSizer(sizer);
|
SetSizer(sizer);
|
||||||
|
|
||||||
|
if (cboxes.size() > 0) {
|
||||||
|
cboxes[0]->SetValue(true);
|
||||||
|
on_checkbox(cboxes[0], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrinterPicker::select_all(bool select)
|
void PrinterPicker::select_all(bool select)
|
||||||
@ -598,10 +603,10 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
|
|||||||
|
|
||||||
static const std::unordered_map<std::string, std::pair<std::string, std::string>> legacy_preset_map {{
|
static const std::unordered_map<std::string, std::pair<std::string, std::string>> legacy_preset_map {{
|
||||||
{ "Original Prusa i3 MK2.ini", std::make_pair("MK2S", "0.4") },
|
{ "Original Prusa i3 MK2.ini", std::make_pair("MK2S", "0.4") },
|
||||||
{ "Original Prusa i3 MK2 MM Single Mode.ini", std::make_pair("MK2S", "0.4") },
|
{ "Original Prusa i3 MK2 MM Single Mode.ini", std::make_pair("MK2SMM", "0.4") },
|
||||||
{ "Original Prusa i3 MK2 MM Single Mode 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
|
{ "Original Prusa i3 MK2 MM Single Mode 0.6 nozzle.ini", std::make_pair("MK2SMM", "0.6") },
|
||||||
{ "Original Prusa i3 MK2 MultiMaterial.ini", std::make_pair("MK2S", "0.4") },
|
{ "Original Prusa i3 MK2 MultiMaterial.ini", std::make_pair("MK2SMM", "0.4") },
|
||||||
{ "Original Prusa i3 MK2 MultiMaterial 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
|
{ "Original Prusa i3 MK2 MultiMaterial 0.6 nozzle.ini", std::make_pair("MK2SMM", "0.6") },
|
||||||
{ "Original Prusa i3 MK2 0.25 nozzle.ini", std::make_pair("MK2S", "0.25") },
|
{ "Original Prusa i3 MK2 0.25 nozzle.ini", std::make_pair("MK2S", "0.25") },
|
||||||
{ "Original Prusa i3 MK2 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
|
{ "Original Prusa i3 MK2 0.6 nozzle.ini", std::make_pair("MK2S", "0.6") },
|
||||||
{ "Original Prusa i3 MK3.ini", std::make_pair("MK3", "0.4") },
|
{ "Original Prusa i3 MK3.ini", std::make_pair("MK3", "0.4") },
|
||||||
@ -809,8 +814,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) :
|
|||||||
topsizer->AddSpacer(INDEX_MARGIN);
|
topsizer->AddSpacer(INDEX_MARGIN);
|
||||||
topsizer->Add(p->hscroll, 1, wxEXPAND);
|
topsizer->Add(p->hscroll, 1, wxEXPAND);
|
||||||
|
|
||||||
p->btn_prev = new wxButton(this, wxID_BACKWARD);
|
p->btn_prev = new wxButton(this, wxID_NONE, _(L("< &Back")));
|
||||||
p->btn_next = new wxButton(this, wxID_FORWARD);
|
p->btn_next = new wxButton(this, wxID_NONE, _(L("&Next >")));
|
||||||
p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish")));
|
p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish")));
|
||||||
p->btn_cancel = new wxButton(this, wxID_CANCEL);
|
p->btn_cancel = new wxButton(this, wxID_CANCEL);
|
||||||
p->btnsizer->AddStretchSpacer();
|
p->btnsizer->AddStretchSpacer();
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
|
#include <wx/timer.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
#include <wx/button.h>
|
#include <wx/button.h>
|
||||||
#include <wx/filepicker.h>
|
#include <wx/filepicker.h>
|
||||||
@ -36,7 +38,7 @@ namespace Slic3r {
|
|||||||
enum AvrdudeEvent
|
enum AvrdudeEvent
|
||||||
{
|
{
|
||||||
AE_MESSAGE,
|
AE_MESSAGE,
|
||||||
AE_PRORGESS,
|
AE_PROGRESS,
|
||||||
AE_EXIT,
|
AE_EXIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,7 +64,6 @@ struct FirmwareDialog::priv
|
|||||||
std::vector<Utils::SerialPortInfo> ports;
|
std::vector<Utils::SerialPortInfo> ports;
|
||||||
wxFilePickerCtrl *hex_picker;
|
wxFilePickerCtrl *hex_picker;
|
||||||
wxStaticText *txt_status;
|
wxStaticText *txt_status;
|
||||||
wxStaticText *txt_progress;
|
|
||||||
wxGauge *progressbar;
|
wxGauge *progressbar;
|
||||||
wxCollapsiblePane *spoiler;
|
wxCollapsiblePane *spoiler;
|
||||||
wxTextCtrl *txt_stdout;
|
wxTextCtrl *txt_stdout;
|
||||||
@ -72,6 +73,8 @@ struct FirmwareDialog::priv
|
|||||||
wxString btn_flash_label_ready;
|
wxString btn_flash_label_ready;
|
||||||
wxString btn_flash_label_flashing;
|
wxString btn_flash_label_flashing;
|
||||||
|
|
||||||
|
wxTimer timer_pulse;
|
||||||
|
|
||||||
// This is a shared pointer holding the background AvrDude task
|
// This is a shared pointer holding the background AvrDude task
|
||||||
// also serves as a status indication (it is set _iff_ the background task is running, otherwise it is reset).
|
// also serves as a status indication (it is set _iff_ the background task is running, otherwise it is reset).
|
||||||
AvrDude::Ptr avrdude;
|
AvrDude::Ptr avrdude;
|
||||||
@ -83,13 +86,16 @@ struct FirmwareDialog::priv
|
|||||||
q(q),
|
q(q),
|
||||||
btn_flash_label_ready(_(L("Flash!"))),
|
btn_flash_label_ready(_(L("Flash!"))),
|
||||||
btn_flash_label_flashing(_(L("Cancel"))),
|
btn_flash_label_flashing(_(L("Cancel"))),
|
||||||
|
timer_pulse(q),
|
||||||
avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()),
|
avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()),
|
||||||
progress_tasks_done(0),
|
progress_tasks_done(0),
|
||||||
cancelled(false)
|
cancelled(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void find_serial_ports();
|
void find_serial_ports();
|
||||||
void flashing_status(bool flashing, AvrDudeComplete complete = AC_NONE);
|
void flashing_start(bool flashing_l10n);
|
||||||
|
void flashing_done(AvrDudeComplete complete);
|
||||||
|
size_t hex_lang_offset(const wxString &path);
|
||||||
void perform_upload();
|
void perform_upload();
|
||||||
void cancel();
|
void cancel();
|
||||||
void on_avrdude(const wxCommandEvent &evt);
|
void on_avrdude(const wxCommandEvent &evt);
|
||||||
@ -116,42 +122,76 @@ void FirmwareDialog::priv::find_serial_ports()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareDialog::priv::flashing_status(bool value, AvrDudeComplete complete)
|
void FirmwareDialog::priv::flashing_start(bool flashing_l10n)
|
||||||
{
|
{
|
||||||
if (value) {
|
txt_stdout->Clear();
|
||||||
txt_stdout->Clear();
|
txt_status->SetLabel(_(L("Flashing in progress. Please do not disconnect the printer!")));
|
||||||
txt_status->SetLabel(_(L("Flashing in progress. Please do not disconnect the printer!")));
|
txt_status->SetForegroundColour(GUI::get_label_clr_modified());
|
||||||
txt_status->SetForegroundColour(GUI::get_label_clr_modified());
|
port_picker->Disable();
|
||||||
port_picker->Disable();
|
btn_rescan->Disable();
|
||||||
btn_rescan->Disable();
|
hex_picker->Disable();
|
||||||
hex_picker->Disable();
|
btn_close->Disable();
|
||||||
btn_close->Disable();
|
btn_flash->SetLabel(btn_flash_label_flashing);
|
||||||
btn_flash->SetLabel(btn_flash_label_flashing);
|
progressbar->SetRange(flashing_l10n ? 500 : 200); // See progress callback below
|
||||||
progressbar->SetRange(200); // See progress callback below
|
progressbar->SetValue(0);
|
||||||
progressbar->SetValue(0);
|
progress_tasks_done = 0;
|
||||||
progress_tasks_done = 0;
|
cancelled = false;
|
||||||
cancelled = false;
|
timer_pulse.Start(50);
|
||||||
} else {
|
}
|
||||||
auto text_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
|
||||||
port_picker->Enable();
|
|
||||||
btn_rescan->Enable();
|
|
||||||
hex_picker->Enable();
|
|
||||||
btn_close->Enable();
|
|
||||||
btn_flash->SetLabel(btn_flash_label_ready);
|
|
||||||
txt_status->SetForegroundColour(text_color);
|
|
||||||
progressbar->SetValue(200);
|
|
||||||
|
|
||||||
switch (complete) {
|
void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete)
|
||||||
case AC_SUCCESS: txt_status->SetLabel(_(L("Flashing succeeded!"))); break;
|
{
|
||||||
case AC_FAILURE: txt_status->SetLabel(_(L("Flashing failed. Please see the avrdude log below."))); break;
|
auto text_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||||
case AC_CANCEL: txt_status->SetLabel(_(L("Flashing cancelled."))); break;
|
port_picker->Enable();
|
||||||
|
btn_rescan->Enable();
|
||||||
|
hex_picker->Enable();
|
||||||
|
btn_close->Enable();
|
||||||
|
btn_flash->SetLabel(btn_flash_label_ready);
|
||||||
|
txt_status->SetForegroundColour(text_color);
|
||||||
|
timer_pulse.Stop();
|
||||||
|
progressbar->SetValue(progressbar->GetRange());
|
||||||
|
|
||||||
|
switch (complete) {
|
||||||
|
case AC_SUCCESS: txt_status->SetLabel(_(L("Flashing succeeded!"))); break;
|
||||||
|
case AC_FAILURE: txt_status->SetLabel(_(L("Flashing failed. Please see the avrdude log below."))); break;
|
||||||
|
case AC_CANCEL: txt_status->SetLabel(_(L("Flashing cancelled."))); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FirmwareDialog::priv::hex_lang_offset(const wxString &path)
|
||||||
|
{
|
||||||
|
fs::ifstream file(fs::path(path.wx_str()));
|
||||||
|
if (! file.good()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *hex_terminator = ":00000001FF\r";
|
||||||
|
size_t res = 0;
|
||||||
|
std::string line;
|
||||||
|
while (getline(file, line, '\n').good()) {
|
||||||
|
// Account for LF vs CRLF
|
||||||
|
if (!line.empty() && line.back() != '\r') {
|
||||||
|
line.push_back('\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == hex_terminator) {
|
||||||
|
if (res == 0) {
|
||||||
|
// This is the first terminator seen, save the position
|
||||||
|
res = file.tellg();
|
||||||
|
} else {
|
||||||
|
// We've found another terminator, return the offset just after the first one
|
||||||
|
// which is the start of the second 'section'.
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirmwareDialog::priv::perform_upload()
|
void FirmwareDialog::priv::perform_upload()
|
||||||
{
|
{
|
||||||
auto filename = hex_picker->GetPath();
|
auto filename = hex_picker->GetPath();
|
||||||
std::string port = port_picker->GetValue().ToStdString();
|
std::string port = port_picker->GetValue().ToStdString();
|
||||||
int selection = port_picker->GetSelection();
|
int selection = port_picker->GetSelection();
|
||||||
if (selection != -1) {
|
if (selection != -1) {
|
||||||
@ -161,16 +201,32 @@ void FirmwareDialog::priv::perform_upload()
|
|||||||
}
|
}
|
||||||
if (filename.IsEmpty() || port.empty()) { return; }
|
if (filename.IsEmpty() || port.empty()) { return; }
|
||||||
|
|
||||||
flashing_status(true);
|
const bool extra_verbose = false; // For debugging
|
||||||
|
const auto lang_offset = hex_lang_offset(filename);
|
||||||
|
const auto filename_utf8 = filename.utf8_str();
|
||||||
|
|
||||||
|
flashing_start(lang_offset > 0);
|
||||||
|
|
||||||
|
// It is ok here to use the q-pointer to the FirmwareDialog
|
||||||
|
// because the dialog ensures it doesn't exit before the background thread is done.
|
||||||
|
auto q = this->q;
|
||||||
|
|
||||||
|
// Init the avrdude object
|
||||||
|
AvrDude avrdude(avrdude_config);
|
||||||
|
|
||||||
|
// Build argument list(s)
|
||||||
std::vector<std::string> args {{
|
std::vector<std::string> args {{
|
||||||
"-v",
|
extra_verbose ? "-vvvvv" : "-v",
|
||||||
"-p", "atmega2560",
|
"-p", "atmega2560",
|
||||||
|
// Using the "Wiring" mode to program Rambo or Einsy, using the STK500v2 protocol (not the STK500).
|
||||||
|
// The Prusa's avrdude is patched to never send semicolons inside the data packets, as the USB to serial chip
|
||||||
|
// is flashed with a buggy firmware.
|
||||||
"-c", "wiring",
|
"-c", "wiring",
|
||||||
"-P", port,
|
"-P", port,
|
||||||
"-b", "115200", // XXX: is this ok to hardcode?
|
"-b", "115200", // TODO: Allow other rates? Ditto below.
|
||||||
"-D",
|
"-D",
|
||||||
"-U", (boost::format("flash:w:%1%:i") % filename.ToStdString()).str()
|
// XXX: Safe mode?
|
||||||
|
"-U", (boost::format("flash:w:0:%1%:i") % filename_utf8.data()).str(),
|
||||||
}};
|
}};
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: "
|
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: "
|
||||||
@ -178,26 +234,51 @@ void FirmwareDialog::priv::perform_upload()
|
|||||||
return a + ' ' + b;
|
return a + ' ' + b;
|
||||||
});
|
});
|
||||||
|
|
||||||
// It is ok here to use the q-pointer to the FirmwareDialog
|
avrdude.push_args(std::move(args));
|
||||||
// because the dialog ensures it doesn't exit before the background thread is done.
|
|
||||||
auto q = this->q;
|
if (lang_offset > 0) {
|
||||||
|
// The hex file also contains another section with l10n data to be flashed into the external flash on MK3 (Einsy)
|
||||||
|
// This is done via another avrdude invocation, here we build arg list for that:
|
||||||
|
std::vector<std::string> args_l10n {{
|
||||||
|
extra_verbose ? "-vvvvv" : "-v",
|
||||||
|
"-p", "atmega2560",
|
||||||
|
// Using the "Arduino" mode to program Einsy's external flash with languages, using the STK500 protocol (not the STK500v2).
|
||||||
|
// The Prusa's avrdude is patched again to never send semicolons inside the data packets.
|
||||||
|
"-c", "arduino",
|
||||||
|
"-P", port,
|
||||||
|
"-b", "115200",
|
||||||
|
"-D",
|
||||||
|
"-u", // disable safe mode
|
||||||
|
"-U", (boost::format("flash:w:%1%:%2%:i") % lang_offset % filename_utf8.data()).str(),
|
||||||
|
}};
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude for external flash flashing, arguments: "
|
||||||
|
<< std::accumulate(std::next(args_l10n.begin()), args_l10n.end(), args_l10n[0], [](std::string a, const std::string &b) {
|
||||||
|
return a + ' ' + b;
|
||||||
|
});
|
||||||
|
|
||||||
|
avrdude.push_args(std::move(args_l10n));
|
||||||
|
}
|
||||||
|
|
||||||
|
this->avrdude = avrdude
|
||||||
|
.on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) {
|
||||||
|
if (extra_verbose) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "avrdude: " << msg;
|
||||||
|
}
|
||||||
|
|
||||||
avrdude = AvrDude()
|
|
||||||
.sys_config(avrdude_config)
|
|
||||||
.args(args)
|
|
||||||
.on_message(std::move([q](const char *msg, unsigned /* size */) {
|
|
||||||
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
||||||
|
auto wxmsg = wxString::FromUTF8(msg);
|
||||||
evt->SetExtraLong(AE_MESSAGE);
|
evt->SetExtraLong(AE_MESSAGE);
|
||||||
evt->SetString(msg);
|
evt->SetString(std::move(wxmsg));
|
||||||
wxQueueEvent(q, evt);
|
wxQueueEvent(q, evt);
|
||||||
}))
|
}))
|
||||||
.on_progress(std::move([q](const char * /* task */, unsigned progress) {
|
.on_progress(std::move([q](const char * /* task */, unsigned progress) {
|
||||||
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
||||||
evt->SetExtraLong(AE_PRORGESS);
|
evt->SetExtraLong(AE_PROGRESS);
|
||||||
evt->SetInt(progress);
|
evt->SetInt(progress);
|
||||||
wxQueueEvent(q, evt);
|
wxQueueEvent(q, evt);
|
||||||
}))
|
}))
|
||||||
.on_complete(std::move([q](int status) {
|
.on_complete(std::move([q](int status, size_t /* args_id */) {
|
||||||
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId());
|
||||||
evt->SetExtraLong(AE_EXIT);
|
evt->SetExtraLong(AE_EXIT);
|
||||||
evt->SetInt(status);
|
evt->SetInt(status);
|
||||||
@ -224,19 +305,19 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt)
|
|||||||
txt_stdout->AppendText(evt.GetString());
|
txt_stdout->AppendText(evt.GetString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AE_PRORGESS:
|
case AE_PROGRESS:
|
||||||
// We try to track overall progress here.
|
// We try to track overall progress here.
|
||||||
// When uploading the firmware, avrdude first reads a littlebit of status data,
|
// Avrdude performs 3 tasks per one memory operation ("-U" arg),
|
||||||
// then performs write, then reading (verification).
|
// first of which is reading of status data (very short).
|
||||||
// We Pulse() during the first read and combine progress of the latter two tasks.
|
// We use the timer_pulse during the very first task to indicate intialization
|
||||||
|
// and then display overall progress during the latter tasks.
|
||||||
|
|
||||||
if (progress_tasks_done == 0) {
|
if (progress_tasks_done > 0) {
|
||||||
progressbar->Pulse();
|
|
||||||
} else {
|
|
||||||
progressbar->SetValue(progress_tasks_done - 100 + evt.GetInt());
|
progressbar->SetValue(progress_tasks_done - 100 + evt.GetInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evt.GetInt() == 100) {
|
if (evt.GetInt() == 100) {
|
||||||
|
timer_pulse.Stop();
|
||||||
progress_tasks_done += 100;
|
progress_tasks_done += 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +327,7 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt)
|
|||||||
BOOST_LOG_TRIVIAL(info) << "avrdude exit code: " << evt.GetInt();
|
BOOST_LOG_TRIVIAL(info) << "avrdude exit code: " << evt.GetInt();
|
||||||
|
|
||||||
complete_kind = cancelled ? AC_CANCEL : (evt.GetInt() == 0 ? AC_SUCCESS : AC_FAILURE);
|
complete_kind = cancelled ? AC_CANCEL : (evt.GetInt() == 0 ? AC_SUCCESS : AC_FAILURE);
|
||||||
flashing_status(false, complete_kind);
|
flashing_done(complete_kind);
|
||||||
|
|
||||||
// Make sure the background thread is collected and the AvrDude object reset
|
// Make sure the background thread is collected and the AvrDude object reset
|
||||||
if (avrdude) { avrdude->join(); }
|
if (avrdude) { avrdude->join(); }
|
||||||
@ -374,6 +455,8 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) :
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->p->progressbar->Pulse(); });
|
||||||
|
|
||||||
Bind(EVT_AVRDUDE, [this](wxCommandEvent &evt) { this->p->on_avrdude(evt); });
|
Bind(EVT_AVRDUDE, [this](wxCommandEvent &evt) { this->p->on_avrdude(evt); });
|
||||||
|
|
||||||
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &evt) {
|
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &evt) {
|
||||||
|
4308
xs/src/slic3r/GUI/GLCanvas3D.cpp
Normal file
639
xs/src/slic3r/GUI/GLCanvas3D.hpp
Normal file
@ -0,0 +1,639 @@
|
|||||||
|
#ifndef slic3r_GLCanvas3D_hpp_
|
||||||
|
#define slic3r_GLCanvas3D_hpp_
|
||||||
|
|
||||||
|
#include "../../slic3r/GUI/3DScene.hpp"
|
||||||
|
#include "../../slic3r/GUI/GLTexture.hpp"
|
||||||
|
|
||||||
|
class wxTimer;
|
||||||
|
class wxSizeEvent;
|
||||||
|
class wxIdleEvent;
|
||||||
|
class wxKeyEvent;
|
||||||
|
class wxMouseEvent;
|
||||||
|
class wxTimerEvent;
|
||||||
|
class wxPaintEvent;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class GLShader;
|
||||||
|
class ExPolygon;
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
class GLGizmoBase;
|
||||||
|
|
||||||
|
class GeometryBuffer
|
||||||
|
{
|
||||||
|
std::vector<float> m_vertices;
|
||||||
|
std::vector<float> m_tex_coords;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool set_from_triangles(const Polygons& triangles, float z, bool generate_tex_coords);
|
||||||
|
bool set_from_lines(const Lines& lines, float z);
|
||||||
|
|
||||||
|
const float* get_vertices() const;
|
||||||
|
const float* get_tex_coords() const;
|
||||||
|
|
||||||
|
unsigned int get_vertices_count() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Size
|
||||||
|
{
|
||||||
|
int m_width;
|
||||||
|
int m_height;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Size();
|
||||||
|
Size(int width, int height);
|
||||||
|
|
||||||
|
int get_width() const;
|
||||||
|
void set_width(int width);
|
||||||
|
|
||||||
|
int get_height() const;
|
||||||
|
void set_height(int height);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Rect
|
||||||
|
{
|
||||||
|
float m_left;
|
||||||
|
float m_top;
|
||||||
|
float m_right;
|
||||||
|
float m_bottom;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Rect();
|
||||||
|
Rect(float left, float top, float right, float bottom);
|
||||||
|
|
||||||
|
float get_left() const;
|
||||||
|
void set_left(float left);
|
||||||
|
|
||||||
|
float get_top() const;
|
||||||
|
void set_top(float top);
|
||||||
|
|
||||||
|
float get_right() const;
|
||||||
|
void set_right(float right);
|
||||||
|
|
||||||
|
float get_bottom() const;
|
||||||
|
void set_bottom(float bottom);
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLCanvas3D
|
||||||
|
{
|
||||||
|
struct GCodePreviewVolumeIndex
|
||||||
|
{
|
||||||
|
enum EType
|
||||||
|
{
|
||||||
|
Extrusion,
|
||||||
|
Travel,
|
||||||
|
Retraction,
|
||||||
|
Unretraction,
|
||||||
|
Shell,
|
||||||
|
Num_Geometry_Types
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FirstVolume
|
||||||
|
{
|
||||||
|
EType type;
|
||||||
|
unsigned int flag;
|
||||||
|
// Index of the first volume in a GLVolumeCollection.
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
FirstVolume(EType type, unsigned int flag, unsigned int id) : type(type), flag(flag), id(id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<FirstVolume> first_volumes;
|
||||||
|
|
||||||
|
void reset() { first_volumes.clear(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Camera
|
||||||
|
{
|
||||||
|
enum EType : unsigned char
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
// Perspective,
|
||||||
|
Ortho,
|
||||||
|
Num_types
|
||||||
|
};
|
||||||
|
|
||||||
|
EType type;
|
||||||
|
float zoom;
|
||||||
|
float phi;
|
||||||
|
// float distance;
|
||||||
|
Pointf3 target;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_theta;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Camera();
|
||||||
|
|
||||||
|
std::string get_type_as_string() const;
|
||||||
|
|
||||||
|
float get_theta() const;
|
||||||
|
void set_theta(float theta);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Bed
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum EType : unsigned char
|
||||||
|
{
|
||||||
|
MK2,
|
||||||
|
MK3,
|
||||||
|
Custom,
|
||||||
|
Num_Types
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
EType m_type;
|
||||||
|
Pointfs m_shape;
|
||||||
|
BoundingBoxf3 m_bounding_box;
|
||||||
|
Polygon m_polygon;
|
||||||
|
GeometryBuffer m_triangles;
|
||||||
|
GeometryBuffer m_gridlines;
|
||||||
|
mutable GLTexture m_top_texture;
|
||||||
|
mutable GLTexture m_bottom_texture;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Bed();
|
||||||
|
|
||||||
|
bool is_prusa() const;
|
||||||
|
bool is_custom() const;
|
||||||
|
|
||||||
|
const Pointfs& get_shape() const;
|
||||||
|
void set_shape(const Pointfs& shape);
|
||||||
|
|
||||||
|
const BoundingBoxf3& get_bounding_box() const;
|
||||||
|
bool contains(const Point& point) const;
|
||||||
|
Point point_projection(const Point& point) const;
|
||||||
|
|
||||||
|
void render(float theta) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _calc_bounding_box();
|
||||||
|
void _calc_triangles(const ExPolygon& poly);
|
||||||
|
void _calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||||
|
EType _detect_type() const;
|
||||||
|
void _render_mk2(float theta) const;
|
||||||
|
void _render_mk3(float theta) const;
|
||||||
|
void _render_prusa(float theta) const;
|
||||||
|
void _render_custom() const;
|
||||||
|
static bool _are_equal(const Pointfs& bed_1, const Pointfs& bed_2);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Axes
|
||||||
|
{
|
||||||
|
Pointf3 origin;
|
||||||
|
float length;
|
||||||
|
|
||||||
|
Axes();
|
||||||
|
|
||||||
|
void render(bool depth_test) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CuttingPlane
|
||||||
|
{
|
||||||
|
float m_z;
|
||||||
|
GeometryBuffer m_lines;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CuttingPlane();
|
||||||
|
|
||||||
|
bool set(float z, const ExPolygons& polygons);
|
||||||
|
|
||||||
|
void render(const BoundingBoxf3& bb) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _render_plane(const BoundingBoxf3& bb) const;
|
||||||
|
void _render_contour() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Shader
|
||||||
|
{
|
||||||
|
GLShader* m_shader;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Shader();
|
||||||
|
~Shader();
|
||||||
|
|
||||||
|
bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
|
||||||
|
|
||||||
|
bool is_initialized() const;
|
||||||
|
|
||||||
|
bool start_using() const;
|
||||||
|
void stop_using() const;
|
||||||
|
|
||||||
|
void set_uniform(const std::string& name, float value) const;
|
||||||
|
|
||||||
|
const GLShader* get_shader() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayersEditing
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum EState : unsigned char
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Editing,
|
||||||
|
Completed,
|
||||||
|
Num_States
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_use_legacy_opengl;
|
||||||
|
bool m_enabled;
|
||||||
|
Shader m_shader;
|
||||||
|
unsigned int m_z_texture_id;
|
||||||
|
mutable GLTexture m_tooltip_texture;
|
||||||
|
mutable GLTexture m_reset_texture;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EState state;
|
||||||
|
float band_width;
|
||||||
|
float strength;
|
||||||
|
int last_object_id;
|
||||||
|
float last_z;
|
||||||
|
unsigned int last_action;
|
||||||
|
|
||||||
|
LayersEditing();
|
||||||
|
~LayersEditing();
|
||||||
|
|
||||||
|
bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
|
||||||
|
|
||||||
|
bool is_allowed() const;
|
||||||
|
void set_use_legacy_opengl(bool use_legacy_opengl);
|
||||||
|
|
||||||
|
bool is_enabled() const;
|
||||||
|
void set_enabled(bool enabled);
|
||||||
|
|
||||||
|
unsigned int get_z_texture_id() const;
|
||||||
|
|
||||||
|
void render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const;
|
||||||
|
|
||||||
|
int get_shader_program_id() const;
|
||||||
|
|
||||||
|
static float get_cursor_z_relative(const GLCanvas3D& canvas);
|
||||||
|
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||||
|
static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||||
|
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
|
||||||
|
static Rect get_reset_rect_screen(const GLCanvas3D& canvas);
|
||||||
|
static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
|
||||||
|
static Rect get_reset_rect_viewport(const GLCanvas3D& canvas);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _is_initialized() const;
|
||||||
|
void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const;
|
||||||
|
void _render_reset_texture(const Rect& reset_rect) const;
|
||||||
|
void _render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const;
|
||||||
|
void _render_profile(const PrintObject& print_object, const Rect& bar_rect) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mouse
|
||||||
|
{
|
||||||
|
struct Drag
|
||||||
|
{
|
||||||
|
static const Point Invalid_2D_Point;
|
||||||
|
static const Pointf3 Invalid_3D_Point;
|
||||||
|
|
||||||
|
Point start_position_2D;
|
||||||
|
Pointf3 start_position_3D;
|
||||||
|
Vectorf3 volume_center_offset;
|
||||||
|
int volume_idx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Drag();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool dragging;
|
||||||
|
Pointf position;
|
||||||
|
Drag drag;
|
||||||
|
|
||||||
|
Mouse();
|
||||||
|
|
||||||
|
void set_start_position_2D_as_invalid();
|
||||||
|
void set_start_position_3D_as_invalid();
|
||||||
|
|
||||||
|
bool is_start_position_2D_defined() const;
|
||||||
|
bool is_start_position_3D_defined() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Gizmos
|
||||||
|
{
|
||||||
|
static const float OverlayOffsetX;
|
||||||
|
static const float OverlayGapY;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum EType : unsigned char
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
Scale,
|
||||||
|
Rotate,
|
||||||
|
Num_Types
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_enabled;
|
||||||
|
typedef std::map<EType, GLGizmoBase*> GizmosMap;
|
||||||
|
GizmosMap m_gizmos;
|
||||||
|
EType m_current;
|
||||||
|
bool m_dragging;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Gizmos();
|
||||||
|
~Gizmos();
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
bool is_enabled() const;
|
||||||
|
void set_enabled(bool enable);
|
||||||
|
|
||||||
|
void update_hover_state(const GLCanvas3D& canvas, const Pointf& mouse_pos);
|
||||||
|
void update_on_off_state(const GLCanvas3D& canvas, const Pointf& mouse_pos);
|
||||||
|
void reset_all_states();
|
||||||
|
|
||||||
|
void set_hover_id(int id);
|
||||||
|
|
||||||
|
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Pointf& mouse_pos) const;
|
||||||
|
bool grabber_contains_mouse() const;
|
||||||
|
void update(const Pointf& mouse_pos);
|
||||||
|
void update_data(float scale);
|
||||||
|
|
||||||
|
bool is_running() const;
|
||||||
|
bool is_dragging() const;
|
||||||
|
void start_dragging();
|
||||||
|
void stop_dragging();
|
||||||
|
|
||||||
|
float get_scale() const;
|
||||||
|
|
||||||
|
void render(const GLCanvas3D& canvas, const BoundingBoxf3& box) const;
|
||||||
|
void render_current_gizmo_for_picking_pass(const BoundingBoxf3& box) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _reset();
|
||||||
|
|
||||||
|
void _render_overlay(const GLCanvas3D& canvas) const;
|
||||||
|
void _render_current_gizmo(const BoundingBoxf3& box) const;
|
||||||
|
|
||||||
|
float _get_total_overlay_height() const;
|
||||||
|
GLGizmoBase* _get_current() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxGLCanvas* m_canvas;
|
||||||
|
wxGLContext* m_context;
|
||||||
|
wxTimer* m_timer;
|
||||||
|
Camera m_camera;
|
||||||
|
Bed m_bed;
|
||||||
|
Axes m_axes;
|
||||||
|
CuttingPlane m_cutting_plane;
|
||||||
|
LayersEditing m_layers_editing;
|
||||||
|
Shader m_shader;
|
||||||
|
Mouse m_mouse;
|
||||||
|
mutable Gizmos m_gizmos;
|
||||||
|
|
||||||
|
mutable GLVolumeCollection m_volumes;
|
||||||
|
DynamicPrintConfig* m_config;
|
||||||
|
Print* m_print;
|
||||||
|
Model* m_model;
|
||||||
|
|
||||||
|
bool m_dirty;
|
||||||
|
// the active member has been introduced to overcome a bug in wxWidgets method IsShownOnScreen() which always return true
|
||||||
|
// when a window is inside a wxNotebook
|
||||||
|
bool m_active;
|
||||||
|
bool m_initialized;
|
||||||
|
bool m_use_VBOs;
|
||||||
|
bool m_force_zoom_to_bed_enabled;
|
||||||
|
bool m_apply_zoom_to_volumes_filter;
|
||||||
|
mutable int m_hover_volume_id;
|
||||||
|
bool m_warning_texture_enabled;
|
||||||
|
bool m_legend_texture_enabled;
|
||||||
|
bool m_picking_enabled;
|
||||||
|
bool m_moving_enabled;
|
||||||
|
bool m_shader_enabled;
|
||||||
|
bool m_multisample_allowed;
|
||||||
|
|
||||||
|
std::string m_color_by;
|
||||||
|
std::string m_select_by;
|
||||||
|
std::string m_drag_by;
|
||||||
|
|
||||||
|
bool m_reload_delayed;
|
||||||
|
std::vector<std::vector<int>> m_objects_volumes_idxs;
|
||||||
|
std::vector<int> m_objects_selections;
|
||||||
|
|
||||||
|
GCodePreviewVolumeIndex m_gcode_preview_volume_index;
|
||||||
|
|
||||||
|
PerlCallback m_on_viewport_changed_callback;
|
||||||
|
PerlCallback m_on_double_click_callback;
|
||||||
|
PerlCallback m_on_right_click_callback;
|
||||||
|
PerlCallback m_on_select_object_callback;
|
||||||
|
PerlCallback m_on_model_update_callback;
|
||||||
|
PerlCallback m_on_remove_object_callback;
|
||||||
|
PerlCallback m_on_arrange_callback;
|
||||||
|
PerlCallback m_on_rotate_object_left_callback;
|
||||||
|
PerlCallback m_on_rotate_object_right_callback;
|
||||||
|
PerlCallback m_on_scale_object_uniformly_callback;
|
||||||
|
PerlCallback m_on_increase_objects_callback;
|
||||||
|
PerlCallback m_on_decrease_objects_callback;
|
||||||
|
PerlCallback m_on_instance_moved_callback;
|
||||||
|
PerlCallback m_on_wipe_tower_moved_callback;
|
||||||
|
PerlCallback m_on_enable_action_buttons_callback;
|
||||||
|
PerlCallback m_on_gizmo_scale_uniformly_callback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context);
|
||||||
|
~GLCanvas3D();
|
||||||
|
|
||||||
|
bool init(bool useVBOs, bool use_legacy_opengl);
|
||||||
|
|
||||||
|
bool set_current();
|
||||||
|
|
||||||
|
void set_active(bool active);
|
||||||
|
|
||||||
|
unsigned int get_volumes_count() const;
|
||||||
|
void reset_volumes();
|
||||||
|
void deselect_volumes();
|
||||||
|
void select_volume(unsigned int id);
|
||||||
|
void update_volumes_selection(const std::vector<int>& selections);
|
||||||
|
bool check_volumes_outside_state(const DynamicPrintConfig* config) const;
|
||||||
|
bool move_volume_up(unsigned int id);
|
||||||
|
bool move_volume_down(unsigned int id);
|
||||||
|
|
||||||
|
void set_objects_selections(const std::vector<int>& selections);
|
||||||
|
|
||||||
|
void set_config(DynamicPrintConfig* config);
|
||||||
|
void set_print(Print* print);
|
||||||
|
void set_model(Model* model);
|
||||||
|
|
||||||
|
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
||||||
|
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
||||||
|
// fills the m_bed.m_grid_lines and sets m_bed.m_origin.
|
||||||
|
// Sets m_bed.m_polygon to limit the object placement.
|
||||||
|
void set_bed_shape(const Pointfs& shape);
|
||||||
|
// Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane to support the scene objects.
|
||||||
|
void set_auto_bed_shape();
|
||||||
|
|
||||||
|
void set_axes_length(float length);
|
||||||
|
|
||||||
|
void set_cutting_plane(float z, const ExPolygons& polygons);
|
||||||
|
|
||||||
|
void set_color_by(const std::string& value);
|
||||||
|
void set_select_by(const std::string& value);
|
||||||
|
void set_drag_by(const std::string& value);
|
||||||
|
|
||||||
|
float get_camera_zoom() const;
|
||||||
|
|
||||||
|
BoundingBoxf3 volumes_bounding_box() const;
|
||||||
|
|
||||||
|
bool is_layers_editing_enabled() const;
|
||||||
|
bool is_layers_editing_allowed() const;
|
||||||
|
bool is_shader_enabled() const;
|
||||||
|
|
||||||
|
bool is_reload_delayed() const;
|
||||||
|
|
||||||
|
void enable_layers_editing(bool enable);
|
||||||
|
void enable_warning_texture(bool enable);
|
||||||
|
void enable_legend_texture(bool enable);
|
||||||
|
void enable_picking(bool enable);
|
||||||
|
void enable_moving(bool enable);
|
||||||
|
void enable_gizmos(bool enable);
|
||||||
|
void enable_shader(bool enable);
|
||||||
|
void enable_force_zoom_to_bed(bool enable);
|
||||||
|
void allow_multisample(bool allow);
|
||||||
|
|
||||||
|
void zoom_to_bed();
|
||||||
|
void zoom_to_volumes();
|
||||||
|
void select_view(const std::string& direction);
|
||||||
|
void set_viewport_from_scene(const GLCanvas3D& other);
|
||||||
|
|
||||||
|
void update_volumes_colors_by_extruder();
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
std::vector<double> get_current_print_zs(bool active_only) const;
|
||||||
|
void set_toolpaths_range(double low, double high);
|
||||||
|
|
||||||
|
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
|
||||||
|
std::vector<int> load_object(const Model& model, int obj_idx);
|
||||||
|
|
||||||
|
void reload_scene(bool force);
|
||||||
|
|
||||||
|
// Create 3D thick extrusion lines for a skirt and brim.
|
||||||
|
// Adds a new Slic3r::GUI::3DScene::Volume to volumes.
|
||||||
|
void load_print_toolpaths();
|
||||||
|
// Create 3D thick extrusion lines for object forming extrusions.
|
||||||
|
// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
|
||||||
|
// one for perimeters, one for infill and one for supports.
|
||||||
|
void load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors);
|
||||||
|
// Create 3D thick extrusion lines for wipe tower extrusions
|
||||||
|
void load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors);
|
||||||
|
void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors);
|
||||||
|
|
||||||
|
void register_on_viewport_changed_callback(void* callback);
|
||||||
|
void register_on_double_click_callback(void* callback);
|
||||||
|
void register_on_right_click_callback(void* callback);
|
||||||
|
void register_on_select_object_callback(void* callback);
|
||||||
|
void register_on_model_update_callback(void* callback);
|
||||||
|
void register_on_remove_object_callback(void* callback);
|
||||||
|
void register_on_arrange_callback(void* callback);
|
||||||
|
void register_on_rotate_object_left_callback(void* callback);
|
||||||
|
void register_on_rotate_object_right_callback(void* callback);
|
||||||
|
void register_on_scale_object_uniformly_callback(void* callback);
|
||||||
|
void register_on_increase_objects_callback(void* callback);
|
||||||
|
void register_on_decrease_objects_callback(void* callback);
|
||||||
|
void register_on_instance_moved_callback(void* callback);
|
||||||
|
void register_on_wipe_tower_moved_callback(void* callback);
|
||||||
|
void register_on_enable_action_buttons_callback(void* callback);
|
||||||
|
void register_on_gizmo_scale_uniformly_callback(void* callback);
|
||||||
|
|
||||||
|
void bind_event_handlers();
|
||||||
|
void unbind_event_handlers();
|
||||||
|
|
||||||
|
void on_size(wxSizeEvent& evt);
|
||||||
|
void on_idle(wxIdleEvent& evt);
|
||||||
|
void on_char(wxKeyEvent& evt);
|
||||||
|
void on_mouse_wheel(wxMouseEvent& evt);
|
||||||
|
void on_timer(wxTimerEvent& evt);
|
||||||
|
void on_mouse(wxMouseEvent& evt);
|
||||||
|
void on_paint(wxPaintEvent& evt);
|
||||||
|
void on_key_down(wxKeyEvent& evt);
|
||||||
|
|
||||||
|
Size get_canvas_size() const;
|
||||||
|
Point get_local_mouse_position() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _is_shown_on_screen() const;
|
||||||
|
void _force_zoom_to_bed();
|
||||||
|
|
||||||
|
void _resize(unsigned int w, unsigned int h);
|
||||||
|
|
||||||
|
BoundingBoxf3 _max_bounding_box() const;
|
||||||
|
BoundingBoxf3 _selected_volumes_bounding_box() const;
|
||||||
|
|
||||||
|
void _zoom_to_bounding_box(const BoundingBoxf3& bbox);
|
||||||
|
float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const;
|
||||||
|
|
||||||
|
void _deregister_callbacks();
|
||||||
|
|
||||||
|
void _mark_volumes_for_layer_height() const;
|
||||||
|
void _refresh_if_shown_on_screen();
|
||||||
|
|
||||||
|
void _camera_tranform() const;
|
||||||
|
void _picking_pass() const;
|
||||||
|
void _render_background() const;
|
||||||
|
void _render_bed(float theta) const;
|
||||||
|
void _render_axes(bool depth_test) const;
|
||||||
|
void _render_objects() const;
|
||||||
|
void _render_cutting_plane() const;
|
||||||
|
void _render_warning_texture() const;
|
||||||
|
void _render_legend_texture() const;
|
||||||
|
void _render_layer_editing_overlay() const;
|
||||||
|
void _render_volumes(bool fake_colors) const;
|
||||||
|
void _render_gizmo() const;
|
||||||
|
|
||||||
|
float _get_layers_editing_cursor_z_relative() const;
|
||||||
|
void _perform_layer_editing_action(wxMouseEvent* evt = nullptr);
|
||||||
|
|
||||||
|
// Convert the screen space coordinate to an object space coordinate.
|
||||||
|
// If the Z screen space coordinate is not provided, a depth buffer value is substituted.
|
||||||
|
Pointf3 _mouse_to_3d(const Point& mouse_pos, float* z = nullptr);
|
||||||
|
|
||||||
|
// Convert the screen space coordinate to world coordinate on the bed.
|
||||||
|
Pointf3 _mouse_to_bed_3d(const Point& mouse_pos);
|
||||||
|
|
||||||
|
void _start_timer();
|
||||||
|
void _stop_timer();
|
||||||
|
|
||||||
|
int _get_first_selected_object_id() const;
|
||||||
|
|
||||||
|
// generates gcode extrusion paths geometry
|
||||||
|
void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||||
|
// generates gcode travel paths geometry
|
||||||
|
void _load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||||
|
bool _travel_paths_by_type(const GCodePreviewData& preview_data);
|
||||||
|
bool _travel_paths_by_feedrate(const GCodePreviewData& preview_data);
|
||||||
|
bool _travel_paths_by_tool(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||||
|
// generates gcode retractions geometry
|
||||||
|
void _load_gcode_retractions(const GCodePreviewData& preview_data);
|
||||||
|
// generates gcode unretractions geometry
|
||||||
|
void _load_gcode_unretractions(const GCodePreviewData& preview_data);
|
||||||
|
// generates objects and wipe tower geometry
|
||||||
|
void _load_shells();
|
||||||
|
// sets gcode geometry visibility according to user selection
|
||||||
|
void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data);
|
||||||
|
|
||||||
|
void _on_move(const std::vector<int>& volume_idxs);
|
||||||
|
void _on_select(int volume_idx);
|
||||||
|
|
||||||
|
void _update_gizmos_data();
|
||||||
|
|
||||||
|
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_GLCanvas3D_hpp_
|
693
xs/src/slic3r/GUI/GLCanvas3DManager.cpp
Normal file
@ -0,0 +1,693 @@
|
|||||||
|
#include "GLCanvas3DManager.hpp"
|
||||||
|
#include "../../slic3r/GUI/GUI.hpp"
|
||||||
|
#include "../../slic3r/GUI/AppConfig.hpp"
|
||||||
|
#include "../../slic3r/GUI/GLCanvas3D.hpp"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
|
|
||||||
|
#include <wx/glcanvas.h>
|
||||||
|
#include <wx/timer.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
GLCanvas3DManager::GLInfo::GLInfo()
|
||||||
|
: version("")
|
||||||
|
, glsl_version("")
|
||||||
|
, vendor("")
|
||||||
|
, renderer("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::GLInfo::detect()
|
||||||
|
{
|
||||||
|
const char* data = (const char*)::glGetString(GL_VERSION);
|
||||||
|
if (data != nullptr)
|
||||||
|
version = data;
|
||||||
|
|
||||||
|
data = (const char*)::glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||||
|
if (data != nullptr)
|
||||||
|
glsl_version = data;
|
||||||
|
|
||||||
|
data = (const char*)::glGetString(GL_VENDOR);
|
||||||
|
if (data != nullptr)
|
||||||
|
vendor = data;
|
||||||
|
|
||||||
|
data = (const char*)::glGetString(GL_RENDERER);
|
||||||
|
if (data != nullptr)
|
||||||
|
renderer = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on);
|
||||||
|
|
||||||
|
if (tokens.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::vector<std::string> numbers;
|
||||||
|
boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on);
|
||||||
|
|
||||||
|
unsigned int gl_major = 0;
|
||||||
|
unsigned int gl_minor = 0;
|
||||||
|
|
||||||
|
if (numbers.size() > 0)
|
||||||
|
gl_major = ::atoi(numbers[0].c_str());
|
||||||
|
|
||||||
|
if (numbers.size() > 1)
|
||||||
|
gl_minor = ::atoi(numbers[1].c_str());
|
||||||
|
|
||||||
|
if (gl_major < major)
|
||||||
|
return false;
|
||||||
|
else if (gl_major > major)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return gl_minor >= minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool extensions) const
|
||||||
|
{
|
||||||
|
std::stringstream out;
|
||||||
|
|
||||||
|
std::string h2_start = format_as_html ? "<b>" : "";
|
||||||
|
std::string h2_end = format_as_html ? "</b>" : "";
|
||||||
|
std::string b_start = format_as_html ? "<b>" : "";
|
||||||
|
std::string b_end = format_as_html ? "</b>" : "";
|
||||||
|
std::string line_end = format_as_html ? "<br>" : "\n";
|
||||||
|
|
||||||
|
out << h2_start << "OpenGL installation" << h2_end << line_end;
|
||||||
|
out << b_start << "GL version: " << b_end << (version.empty() ? "N/A" : version) << line_end;
|
||||||
|
out << b_start << "Vendor: " << b_end << (vendor.empty() ? "N/A" : vendor) << line_end;
|
||||||
|
out << b_start << "Renderer: " << b_end << (renderer.empty() ? "N/A" : renderer) << line_end;
|
||||||
|
out << b_start << "GLSL version: " << b_end << (glsl_version.empty() ? "N/A" : glsl_version) << line_end;
|
||||||
|
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
out << h2_start << "Installed extensions:" << h2_end << line_end;
|
||||||
|
|
||||||
|
std::vector<std::string> extensions_list;
|
||||||
|
GLint num_extensions;
|
||||||
|
::glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||||
|
|
||||||
|
for (GLint i = 0; i < num_extensions; ++i)
|
||||||
|
{
|
||||||
|
const char* e = (const char*)::glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
extensions_list.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(extensions_list.begin(), extensions_list.end());
|
||||||
|
for (const std::string& ext : extensions_list)
|
||||||
|
{
|
||||||
|
out << ext << line_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLCanvas3DManager::GLCanvas3DManager()
|
||||||
|
: m_context(nullptr)
|
||||||
|
, m_gl_initialized(false)
|
||||||
|
, m_use_legacy_opengl(false)
|
||||||
|
, m_use_VBOs(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GLCanvas3DManager::~GLCanvas3DManager()
|
||||||
|
{
|
||||||
|
if (m_context != nullptr)
|
||||||
|
delete m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::add(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
if (canvas == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_get_canvas(canvas) != m_canvases.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_context == nullptr)
|
||||||
|
{
|
||||||
|
m_context = new wxGLContext(canvas);
|
||||||
|
if (m_context == nullptr)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLCanvas3D* canvas3D = new GLCanvas3D(canvas, m_context);
|
||||||
|
if (canvas3D == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
canvas3D->bind_event_handlers();
|
||||||
|
m_canvases.insert(CanvasesMap::value_type(canvas, canvas3D));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::remove(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it == m_canvases.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
it->second->unbind_event_handlers();
|
||||||
|
delete it->second;
|
||||||
|
m_canvases.erase(it);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::remove_all()
|
||||||
|
{
|
||||||
|
for (CanvasesMap::value_type& item : m_canvases)
|
||||||
|
{
|
||||||
|
item.second->unbind_event_handlers();
|
||||||
|
delete item.second;
|
||||||
|
}
|
||||||
|
m_canvases.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GLCanvas3DManager::count() const
|
||||||
|
{
|
||||||
|
return (unsigned int)m_canvases.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::init_gl()
|
||||||
|
{
|
||||||
|
if (!m_gl_initialized)
|
||||||
|
{
|
||||||
|
glewInit();
|
||||||
|
m_gl_info.detect();
|
||||||
|
const AppConfig* config = GUI::get_app_config();
|
||||||
|
m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1");
|
||||||
|
m_use_VBOs = !m_use_legacy_opengl && m_gl_info.is_version_greater_or_equal_to(2, 0);
|
||||||
|
m_gl_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GLCanvas3DManager::get_gl_info(bool format_as_html, bool extensions) const
|
||||||
|
{
|
||||||
|
return m_gl_info.to_string(format_as_html, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::use_VBOs() const
|
||||||
|
{
|
||||||
|
return m_use_VBOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::init(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
return (it->second != nullptr) ? _init(*it->second) : false;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_active(wxGLCanvas* canvas, bool active)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_active(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GLCanvas3DManager::get_volumes_count(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->get_volumes_count() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::reset_volumes(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->reset_volumes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::deselect_volumes(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->deselect_volumes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::select_volume(wxGLCanvas* canvas, unsigned int id)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->select_volume(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->update_volumes_selection(selections);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->check_volumes_outside_state(config) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::move_volume_up(wxGLCanvas* canvas, unsigned int id)
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->move_volume_up(id) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::move_volume_down(wxGLCanvas* canvas, unsigned int id)
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->move_volume_down(id) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_objects_selections(wxGLCanvas* canvas, const std::vector<int>& selections)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_objects_selections(selections);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_config(wxGLCanvas* canvas, DynamicPrintConfig* config)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_config(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_print(wxGLCanvas* canvas, Print* print)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_print(print);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_model(wxGLCanvas* canvas, Model* model)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_model(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_bed_shape(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_auto_bed_shape(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_auto_bed_shape();
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBoxf3 GLCanvas3DManager::get_volumes_bounding_box(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->volumes_bounding_box() : BoundingBoxf3();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_axes_length(wxGLCanvas* canvas, float length)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_axes_length(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_cutting_plane(z, polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_color_by(wxGLCanvas* canvas, const std::string& value)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_color_by(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_select_by(wxGLCanvas* canvas, const std::string& value)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_select_by(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_drag_by(wxGLCanvas* canvas, const std::string& value)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_drag_by(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::is_layers_editing_enabled(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->is_layers_editing_enabled() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::is_layers_editing_allowed(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->is_layers_editing_allowed() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::is_shader_enabled(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->is_shader_enabled() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::is_reload_delayed(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->is_reload_delayed() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_layers_editing(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_layers_editing(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_warning_texture(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_warning_texture(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_legend_texture(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_legend_texture(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_picking(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_picking(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_moving(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_moving(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_gizmos(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_gizmos(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_shader(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_shader(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->enable_force_zoom_to_bed(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::allow_multisample(wxGLCanvas* canvas, bool allow)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->allow_multisample(allow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::zoom_to_bed(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->zoom_to_bed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::zoom_to_volumes(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->zoom_to_volumes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::select_view(wxGLCanvas* canvas, const std::string& direction)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->select_view(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator other_it = _get_canvas(other);
|
||||||
|
if (other_it != m_canvases.end())
|
||||||
|
it->second->set_viewport_from_scene(*other_it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::update_volumes_colors_by_extruder(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->update_volumes_colors_by_extruder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::render(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> GLCanvas3DManager::get_current_print_zs(wxGLCanvas* canvas, bool active_only) const
|
||||||
|
{
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->get_current_print_zs(active_only) : std::vector<double>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::set_toolpaths_range(wxGLCanvas* canvas, double low, double high)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->set_toolpaths_range(low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> GLCanvas3DManager::load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector<int> instance_idxs)
|
||||||
|
{
|
||||||
|
if (model_object == nullptr)
|
||||||
|
return std::vector<int>();
|
||||||
|
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->load_object(*model_object, obj_idx, instance_idxs) : std::vector<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> GLCanvas3DManager::load_object(wxGLCanvas* canvas, const Model* model, int obj_idx)
|
||||||
|
{
|
||||||
|
if (model == nullptr)
|
||||||
|
return std::vector<int>();
|
||||||
|
|
||||||
|
CanvasesMap::const_iterator it = _get_canvas(canvas);
|
||||||
|
return (it != m_canvases.end()) ? it->second->load_object(*model, obj_idx) : std::vector<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->reload_scene(force);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::load_print_toolpaths(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->load_print_toolpaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& 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<std::string>& 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<std::string>& str_tool_colors)
|
||||||
|
{
|
||||||
|
if (preview_data == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->load_gcode_preview(*preview_data, str_tool_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_viewport_changed_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_double_click_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_double_click_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_right_click_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_right_click_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_select_object_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_select_object_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_model_update_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_model_update_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_remove_object_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_remove_object_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_arrange_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_arrange_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_rotate_object_left_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_rotate_object_left_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_rotate_object_right_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_rotate_object_right_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_scale_object_uniformly_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_scale_object_uniformly_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_increase_objects_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_increase_objects_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_decrease_objects_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_decrease_objects_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_instance_moved_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_instance_moved_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_wipe_tower_moved_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_enable_action_buttons_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3DManager::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback)
|
||||||
|
{
|
||||||
|
CanvasesMap::iterator it = _get_canvas(canvas);
|
||||||
|
if (it != m_canvases.end())
|
||||||
|
it->second->register_on_gizmo_scale_uniformly_callback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas)
|
||||||
|
{
|
||||||
|
return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLCanvas3DManager::CanvasesMap::const_iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) const
|
||||||
|
{
|
||||||
|
return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLCanvas3DManager::_init(GLCanvas3D& canvas)
|
||||||
|
{
|
||||||
|
if (!m_gl_initialized)
|
||||||
|
init_gl();
|
||||||
|
|
||||||
|
return canvas.init(m_use_VBOs, m_use_legacy_opengl);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
167
xs/src/slic3r/GUI/GLCanvas3DManager.hpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#ifndef slic3r_GLCanvas3DManager_hpp_
|
||||||
|
#define slic3r_GLCanvas3DManager_hpp_
|
||||||
|
|
||||||
|
#include "../../libslic3r/BoundingBox.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class wxGLCanvas;
|
||||||
|
class wxGLContext;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class DynamicPrintConfig;
|
||||||
|
class Print;
|
||||||
|
class Model;
|
||||||
|
class ExPolygon;
|
||||||
|
typedef std::vector<ExPolygon> ExPolygons;
|
||||||
|
class ModelObject;
|
||||||
|
class PrintObject;
|
||||||
|
class GCodePreviewData;
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
class GLCanvas3D;
|
||||||
|
|
||||||
|
class GLCanvas3DManager
|
||||||
|
{
|
||||||
|
struct GLInfo
|
||||||
|
{
|
||||||
|
std::string version;
|
||||||
|
std::string glsl_version;
|
||||||
|
std::string vendor;
|
||||||
|
std::string renderer;
|
||||||
|
|
||||||
|
GLInfo();
|
||||||
|
|
||||||
|
void detect();
|
||||||
|
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const;
|
||||||
|
|
||||||
|
std::string to_string(bool format_as_html, bool extensions) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<wxGLCanvas*, GLCanvas3D*> CanvasesMap;
|
||||||
|
|
||||||
|
wxGLContext* m_context;
|
||||||
|
CanvasesMap m_canvases;
|
||||||
|
GLInfo m_gl_info;
|
||||||
|
bool m_gl_initialized;
|
||||||
|
bool m_use_legacy_opengl;
|
||||||
|
bool m_use_VBOs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLCanvas3DManager();
|
||||||
|
~GLCanvas3DManager();
|
||||||
|
|
||||||
|
bool add(wxGLCanvas* canvas);
|
||||||
|
bool remove(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
void remove_all();
|
||||||
|
|
||||||
|
unsigned int count() const;
|
||||||
|
|
||||||
|
void init_gl();
|
||||||
|
std::string get_gl_info(bool format_as_html, bool extensions) const;
|
||||||
|
|
||||||
|
bool use_VBOs() const;
|
||||||
|
bool layer_editing_allowed() const;
|
||||||
|
|
||||||
|
bool init(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
void set_active(wxGLCanvas* canvas, bool active);
|
||||||
|
|
||||||
|
unsigned int get_volumes_count(wxGLCanvas* canvas) const;
|
||||||
|
void reset_volumes(wxGLCanvas* canvas);
|
||||||
|
void deselect_volumes(wxGLCanvas* canvas);
|
||||||
|
void select_volume(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
void update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||||
|
bool check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const;
|
||||||
|
bool move_volume_up(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
bool move_volume_down(wxGLCanvas* canvas, unsigned int id);
|
||||||
|
|
||||||
|
void set_objects_selections(wxGLCanvas* canvas, const std::vector<int>& selections);
|
||||||
|
|
||||||
|
void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config);
|
||||||
|
void set_print(wxGLCanvas* canvas, Print* print);
|
||||||
|
void set_model(wxGLCanvas* canvas, Model* model);
|
||||||
|
|
||||||
|
void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape);
|
||||||
|
void set_auto_bed_shape(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
void set_axes_length(wxGLCanvas* canvas, float length);
|
||||||
|
|
||||||
|
void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons);
|
||||||
|
|
||||||
|
void set_color_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
void set_select_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
void set_drag_by(wxGLCanvas* canvas, const std::string& value);
|
||||||
|
|
||||||
|
bool is_layers_editing_enabled(wxGLCanvas* canvas) const;
|
||||||
|
bool is_layers_editing_allowed(wxGLCanvas* canvas) const;
|
||||||
|
bool is_shader_enabled(wxGLCanvas* canvas) const;
|
||||||
|
|
||||||
|
bool is_reload_delayed(wxGLCanvas* canvas) const;
|
||||||
|
|
||||||
|
void enable_layers_editing(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_warning_texture(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_legend_texture(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_picking(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_moving(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_gizmos(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_shader(wxGLCanvas* canvas, bool enable);
|
||||||
|
void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
|
||||||
|
void allow_multisample(wxGLCanvas* canvas, bool allow);
|
||||||
|
|
||||||
|
void zoom_to_bed(wxGLCanvas* canvas);
|
||||||
|
void zoom_to_volumes(wxGLCanvas* canvas);
|
||||||
|
void select_view(wxGLCanvas* canvas, const std::string& direction);
|
||||||
|
void set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other);
|
||||||
|
|
||||||
|
void update_volumes_colors_by_extruder(wxGLCanvas* canvas);
|
||||||
|
|
||||||
|
void render(wxGLCanvas* canvas) const;
|
||||||
|
|
||||||
|
std::vector<double> get_current_print_zs(wxGLCanvas* canvas, bool active_only) const;
|
||||||
|
void set_toolpaths_range(wxGLCanvas* canvas, double low, double high);
|
||||||
|
|
||||||
|
std::vector<int> load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector<int> instance_idxs);
|
||||||
|
std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
|
||||||
|
|
||||||
|
void reload_scene(wxGLCanvas* canvas, bool force);
|
||||||
|
|
||||||
|
void load_print_toolpaths(wxGLCanvas* canvas);
|
||||||
|
void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& tool_colors);
|
||||||
|
void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
|
||||||
|
void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
|
||||||
|
|
||||||
|
void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_double_click_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_right_click_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_select_object_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_model_update_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_remove_object_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_arrange_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_rotate_object_left_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_rotate_object_right_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_scale_object_uniformly_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_increase_objects_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_decrease_objects_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_instance_moved_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas);
|
||||||
|
CanvasesMap::const_iterator _get_canvas(wxGLCanvas* canvas) const;
|
||||||
|
|
||||||
|
bool _init(GLCanvas3D& canvas);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_GLCanvas3DManager_hpp_
|
454
xs/src/slic3r/GUI/GLGizmo.cpp
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
#include "GLGizmo.hpp"
|
||||||
|
|
||||||
|
#include "../../libslic3r/Utils.hpp"
|
||||||
|
#include "../../libslic3r/BoundingBox.hpp"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
const float GLGizmoBase::Grabber::HalfSize = 2.0f;
|
||||||
|
const float GLGizmoBase::Grabber::HoverOffset = 0.5f;
|
||||||
|
const float GLGizmoBase::BaseColor[3] = { 1.0f, 1.0f, 1.0f };
|
||||||
|
const float GLGizmoBase::HighlightColor[3] = { 1.0f, 0.38f, 0.0f };
|
||||||
|
|
||||||
|
GLGizmoBase::Grabber::Grabber()
|
||||||
|
: center(Pointf(0.0, 0.0))
|
||||||
|
, angle_z(0.0f)
|
||||||
|
{
|
||||||
|
color[0] = 1.0f;
|
||||||
|
color[1] = 1.0f;
|
||||||
|
color[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::Grabber::render(bool hover) const
|
||||||
|
{
|
||||||
|
float min_x = -HalfSize;
|
||||||
|
float max_x = +HalfSize;
|
||||||
|
float min_y = -HalfSize;
|
||||||
|
float max_y = +HalfSize;
|
||||||
|
|
||||||
|
::glColor3f((GLfloat)color[0], (GLfloat)color[1], (GLfloat)color[2]);
|
||||||
|
|
||||||
|
float angle_z_in_deg = angle_z * 180.0f / (float)PI;
|
||||||
|
::glPushMatrix();
|
||||||
|
::glTranslatef((GLfloat)center.x, (GLfloat)center.y, 0.0f);
|
||||||
|
::glRotatef((GLfloat)angle_z_in_deg, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
::glDisable(GL_CULL_FACE);
|
||||||
|
::glBegin(GL_TRIANGLES);
|
||||||
|
::glVertex3f((GLfloat)min_x, (GLfloat)min_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)max_x, (GLfloat)min_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)max_x, (GLfloat)max_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)max_x, (GLfloat)max_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)min_x, (GLfloat)max_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)min_x, (GLfloat)min_y, 0.0f);
|
||||||
|
::glEnd();
|
||||||
|
::glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
if (hover)
|
||||||
|
{
|
||||||
|
min_x -= HoverOffset;
|
||||||
|
max_x += HoverOffset;
|
||||||
|
min_y -= HoverOffset;
|
||||||
|
max_y += HoverOffset;
|
||||||
|
|
||||||
|
::glBegin(GL_LINE_LOOP);
|
||||||
|
::glVertex3f((GLfloat)min_x, (GLfloat)min_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)max_x, (GLfloat)min_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)max_x, (GLfloat)max_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)min_x, (GLfloat)max_y, 0.0f);
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
::glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLGizmoBase::GLGizmoBase()
|
||||||
|
: m_state(Off)
|
||||||
|
, m_hover_id(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GLGizmoBase::~GLGizmoBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLGizmoBase::init()
|
||||||
|
{
|
||||||
|
return on_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLGizmoBase::EState GLGizmoBase::get_state() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::set_state(GLGizmoBase::EState state)
|
||||||
|
{
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GLGizmoBase::get_textures_id() const
|
||||||
|
{
|
||||||
|
return m_textures[m_state].get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GLGizmoBase::get_textures_size() const
|
||||||
|
{
|
||||||
|
return m_textures[Off].get_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GLGizmoBase::get_hover_id() const
|
||||||
|
{
|
||||||
|
return m_hover_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::set_hover_id(int id)
|
||||||
|
{
|
||||||
|
if (id < (int)m_grabbers.size())
|
||||||
|
m_hover_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::start_dragging()
|
||||||
|
{
|
||||||
|
on_start_dragging();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::update(const Pointf& mouse_pos)
|
||||||
|
{
|
||||||
|
if (m_hover_id != -1)
|
||||||
|
on_update(mouse_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::render(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
on_render(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::render_for_picking(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
on_render_for_picking(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::on_start_dragging()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoBase::render_grabbers() const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i)
|
||||||
|
{
|
||||||
|
m_grabbers[i].render(m_hover_id == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float GLGizmoRotate::Offset = 5.0f;
|
||||||
|
const unsigned int GLGizmoRotate::CircleResolution = 64;
|
||||||
|
const unsigned int GLGizmoRotate::AngleResolution = 64;
|
||||||
|
const unsigned int GLGizmoRotate::ScaleStepsCount = 60;
|
||||||
|
const float GLGizmoRotate::ScaleStepRad = 2.0f * (float)PI / GLGizmoRotate::ScaleStepsCount;
|
||||||
|
const unsigned int GLGizmoRotate::ScaleLongEvery = 5;
|
||||||
|
const float GLGizmoRotate::ScaleLongTooth = 2.0f;
|
||||||
|
const float GLGizmoRotate::ScaleShortTooth = 1.0f;
|
||||||
|
const unsigned int GLGizmoRotate::SnapRegionsCount = 8;
|
||||||
|
const float GLGizmoRotate::GrabberOffset = 5.0f;
|
||||||
|
|
||||||
|
GLGizmoRotate::GLGizmoRotate()
|
||||||
|
: GLGizmoBase()
|
||||||
|
, m_angle_z(0.0f)
|
||||||
|
, m_center(Pointf(0.0, 0.0))
|
||||||
|
, m_radius(0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLGizmoRotate::on_init()
|
||||||
|
{
|
||||||
|
std::string path = resources_dir() + "/icons/overlay/";
|
||||||
|
|
||||||
|
std::string filename = path + "rotate_off.png";
|
||||||
|
if (!m_textures[Off].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
filename = path + "rotate_hover.png";
|
||||||
|
if (!m_textures[Hover].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
filename = path + "rotate_on.png";
|
||||||
|
if (!m_textures[On].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_grabbers.push_back(Grabber());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::on_update(const Pointf& mouse_pos)
|
||||||
|
{
|
||||||
|
Vectorf orig_dir(1.0, 0.0);
|
||||||
|
Vectorf new_dir = normalize(mouse_pos - m_center);
|
||||||
|
coordf_t theta = ::acos(clamp(-1.0, 1.0, dot(new_dir, orig_dir)));
|
||||||
|
if (cross(orig_dir, new_dir) < 0.0)
|
||||||
|
theta = 2.0 * (coordf_t)PI - theta;
|
||||||
|
|
||||||
|
if (length(m_center.vector_to(mouse_pos)) < 2.0 * (double)m_radius / 3.0)
|
||||||
|
{
|
||||||
|
coordf_t step = 2.0 * (coordf_t)PI / (coordf_t)SnapRegionsCount;
|
||||||
|
theta = step * (coordf_t)std::round(theta / step);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theta == 2.0 * (coordf_t)PI)
|
||||||
|
theta = 0.0;
|
||||||
|
|
||||||
|
m_angle_z = (float)theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::on_render(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
::glDisable(GL_LIGHTING);
|
||||||
|
::glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
const Pointf3& size = box.size();
|
||||||
|
m_center = box.center();
|
||||||
|
m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y));
|
||||||
|
|
||||||
|
::glLineWidth(2.0f);
|
||||||
|
::glColor3fv(BaseColor);
|
||||||
|
|
||||||
|
_render_circle();
|
||||||
|
_render_scale();
|
||||||
|
_render_snap_radii();
|
||||||
|
_render_reference_radius();
|
||||||
|
|
||||||
|
::glColor3fv(HighlightColor);
|
||||||
|
_render_angle_z();
|
||||||
|
_render_grabber();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::on_render_for_picking(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
::glDisable(GL_LIGHTING);
|
||||||
|
::glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
m_grabbers[0].color[0] = 1.0f;
|
||||||
|
m_grabbers[0].color[1] = 1.0f;
|
||||||
|
m_grabbers[0].color[2] = 254.0f / 255.0f;
|
||||||
|
render_grabbers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_circle() const
|
||||||
|
{
|
||||||
|
::glBegin(GL_LINE_LOOP);
|
||||||
|
for (unsigned int i = 0; i < ScaleStepsCount; ++i)
|
||||||
|
{
|
||||||
|
float angle = (float)i * ScaleStepRad;
|
||||||
|
float x = m_center.x + ::cos(angle) * m_radius;
|
||||||
|
float y = m_center.y + ::sin(angle) * m_radius;
|
||||||
|
::glVertex3f((GLfloat)x, (GLfloat)y, 0.0f);
|
||||||
|
}
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_scale() const
|
||||||
|
{
|
||||||
|
float out_radius_long = m_radius + ScaleLongTooth;
|
||||||
|
float out_radius_short = m_radius + ScaleShortTooth;
|
||||||
|
|
||||||
|
::glBegin(GL_LINES);
|
||||||
|
for (unsigned int i = 0; i < ScaleStepsCount; ++i)
|
||||||
|
{
|
||||||
|
float angle = (float)i * ScaleStepRad;
|
||||||
|
float cosa = ::cos(angle);
|
||||||
|
float sina = ::sin(angle);
|
||||||
|
float in_x = m_center.x + cosa * m_radius;
|
||||||
|
float in_y = m_center.y + sina * m_radius;
|
||||||
|
float out_x = (i % ScaleLongEvery == 0) ? m_center.x + cosa * out_radius_long : m_center.x + cosa * out_radius_short;
|
||||||
|
float out_y = (i % ScaleLongEvery == 0) ? m_center.y + sina * out_radius_long : m_center.y + sina * out_radius_short;
|
||||||
|
::glVertex3f((GLfloat)in_x, (GLfloat)in_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)out_x, (GLfloat)out_y, 0.0f);
|
||||||
|
}
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_snap_radii() const
|
||||||
|
{
|
||||||
|
float step = 2.0f * (float)PI / (float)SnapRegionsCount;
|
||||||
|
|
||||||
|
float in_radius = m_radius / 3.0f;
|
||||||
|
float out_radius = 2.0f * in_radius;
|
||||||
|
|
||||||
|
::glBegin(GL_LINES);
|
||||||
|
for (unsigned int i = 0; i < SnapRegionsCount; ++i)
|
||||||
|
{
|
||||||
|
float angle = (float)i * step;
|
||||||
|
float cosa = ::cos(angle);
|
||||||
|
float sina = ::sin(angle);
|
||||||
|
float in_x = m_center.x + cosa * in_radius;
|
||||||
|
float in_y = m_center.y + sina * in_radius;
|
||||||
|
float out_x = m_center.x + cosa * out_radius;
|
||||||
|
float out_y = m_center.y + sina * out_radius;
|
||||||
|
::glVertex3f((GLfloat)in_x, (GLfloat)in_y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)out_x, (GLfloat)out_y, 0.0f);
|
||||||
|
}
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_reference_radius() const
|
||||||
|
{
|
||||||
|
::glBegin(GL_LINES);
|
||||||
|
::glVertex3f((GLfloat)m_center.x, (GLfloat)m_center.y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)m_center.x + m_radius + GrabberOffset, (GLfloat)m_center.y, 0.0f);
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_angle_z() const
|
||||||
|
{
|
||||||
|
float step_angle = m_angle_z / AngleResolution;
|
||||||
|
float ex_radius = m_radius + GrabberOffset;
|
||||||
|
|
||||||
|
::glBegin(GL_LINE_STRIP);
|
||||||
|
for (unsigned int i = 0; i <= AngleResolution; ++i)
|
||||||
|
{
|
||||||
|
float angle = (float)i * step_angle;
|
||||||
|
float x = m_center.x + ::cos(angle) * ex_radius;
|
||||||
|
float y = m_center.y + ::sin(angle) * ex_radius;
|
||||||
|
::glVertex3f((GLfloat)x, (GLfloat)y, 0.0f);
|
||||||
|
}
|
||||||
|
::glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoRotate::_render_grabber() const
|
||||||
|
{
|
||||||
|
float grabber_radius = m_radius + GrabberOffset;
|
||||||
|
m_grabbers[0].center.x = m_center.x + ::cos(m_angle_z) * grabber_radius;
|
||||||
|
m_grabbers[0].center.y = m_center.y + ::sin(m_angle_z) * grabber_radius;
|
||||||
|
m_grabbers[0].angle_z = m_angle_z;
|
||||||
|
|
||||||
|
::glColor3fv(BaseColor);
|
||||||
|
::glBegin(GL_LINES);
|
||||||
|
::glVertex3f((GLfloat)m_center.x, (GLfloat)m_center.y, 0.0f);
|
||||||
|
::glVertex3f((GLfloat)m_grabbers[0].center.x, (GLfloat)m_grabbers[0].center.y, 0.0f);
|
||||||
|
::glEnd();
|
||||||
|
|
||||||
|
::memcpy((void*)m_grabbers[0].color, (const void*)HighlightColor, 3 * sizeof(float));
|
||||||
|
render_grabbers();
|
||||||
|
}
|
||||||
|
|
||||||
|
const float GLGizmoScale::Offset = 5.0f;
|
||||||
|
|
||||||
|
GLGizmoScale::GLGizmoScale()
|
||||||
|
: GLGizmoBase()
|
||||||
|
, m_scale(1.0f)
|
||||||
|
, m_starting_scale(1.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float GLGizmoScale::get_scale() const
|
||||||
|
{
|
||||||
|
return m_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale::set_scale(float scale)
|
||||||
|
{
|
||||||
|
m_starting_scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLGizmoScale::on_init()
|
||||||
|
{
|
||||||
|
std::string path = resources_dir() + "/icons/overlay/";
|
||||||
|
|
||||||
|
std::string filename = path + "scale_off.png";
|
||||||
|
if (!m_textures[Off].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
filename = path + "scale_hover.png";
|
||||||
|
if (!m_textures[Hover].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
filename = path + "scale_on.png";
|
||||||
|
if (!m_textures[On].load_from_file(filename, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
m_grabbers.push_back(Grabber());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale::on_start_dragging()
|
||||||
|
{
|
||||||
|
if (m_hover_id != -1)
|
||||||
|
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale::on_update(const Pointf& mouse_pos)
|
||||||
|
{
|
||||||
|
Pointf center(0.5 * (m_grabbers[1].center.x + m_grabbers[0].center.x), 0.5 * (m_grabbers[3].center.y + m_grabbers[0].center.y));
|
||||||
|
|
||||||
|
coordf_t orig_len = length(m_starting_drag_position - center);
|
||||||
|
coordf_t new_len = length(mouse_pos - center);
|
||||||
|
coordf_t ratio = (orig_len != 0.0) ? new_len / orig_len : 1.0;
|
||||||
|
|
||||||
|
m_scale = m_starting_scale * (float)ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale::on_render(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
::glDisable(GL_LIGHTING);
|
||||||
|
::glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
coordf_t min_x = box.min.x - (coordf_t)Offset;
|
||||||
|
coordf_t max_x = box.max.x + (coordf_t)Offset;
|
||||||
|
coordf_t min_y = box.min.y - (coordf_t)Offset;
|
||||||
|
coordf_t max_y = box.max.y + (coordf_t)Offset;
|
||||||
|
|
||||||
|
m_grabbers[0].center.x = min_x;
|
||||||
|
m_grabbers[0].center.y = min_y;
|
||||||
|
m_grabbers[1].center.x = max_x;
|
||||||
|
m_grabbers[1].center.y = min_y;
|
||||||
|
m_grabbers[2].center.x = max_x;
|
||||||
|
m_grabbers[2].center.y = max_y;
|
||||||
|
m_grabbers[3].center.x = min_x;
|
||||||
|
m_grabbers[3].center.y = max_y;
|
||||||
|
|
||||||
|
::glLineWidth(2.0f);
|
||||||
|
::glColor3fv(BaseColor);
|
||||||
|
// draw outline
|
||||||
|
::glBegin(GL_LINE_LOOP);
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
::glVertex3f((GLfloat)m_grabbers[i].center.x, (GLfloat)m_grabbers[i].center.y, 0.0f);
|
||||||
|
}
|
||||||
|
::glEnd();
|
||||||
|
|
||||||
|
// draw grabbers
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
::memcpy((void*)m_grabbers[i].color, (const void*)HighlightColor, 3 * sizeof(float));
|
||||||
|
}
|
||||||
|
render_grabbers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLGizmoScale::on_render_for_picking(const BoundingBoxf3& box) const
|
||||||
|
{
|
||||||
|
static const GLfloat INV_255 = 1.0f / 255.0f;
|
||||||
|
|
||||||
|
::glDisable(GL_LIGHTING);
|
||||||
|
::glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
m_grabbers[i].color[0] = 1.0f;
|
||||||
|
m_grabbers[i].color[1] = 1.0f;
|
||||||
|
m_grabbers[i].color[2] = (254.0f - (float)i) * INV_255;
|
||||||
|
}
|
||||||
|
render_grabbers();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
145
xs/src/slic3r/GUI/GLGizmo.hpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#ifndef slic3r_GLGizmo_hpp_
|
||||||
|
#define slic3r_GLGizmo_hpp_
|
||||||
|
|
||||||
|
#include "../../slic3r/GUI/GLTexture.hpp"
|
||||||
|
#include "../../libslic3r/Point.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class BoundingBoxf3;
|
||||||
|
class Pointf3;
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
class GLGizmoBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static const float BaseColor[3];
|
||||||
|
static const float HighlightColor[3];
|
||||||
|
|
||||||
|
struct Grabber
|
||||||
|
{
|
||||||
|
static const float HalfSize;
|
||||||
|
static const float HoverOffset;
|
||||||
|
|
||||||
|
Pointf center;
|
||||||
|
float angle_z;
|
||||||
|
float color[3];
|
||||||
|
|
||||||
|
Grabber();
|
||||||
|
void render(bool hover) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum EState
|
||||||
|
{
|
||||||
|
Off,
|
||||||
|
Hover,
|
||||||
|
On,
|
||||||
|
Num_States
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EState m_state;
|
||||||
|
// textures are assumed to be square and all with the same size in pixels, no internal check is done
|
||||||
|
GLTexture m_textures[Num_States];
|
||||||
|
int m_hover_id;
|
||||||
|
mutable std::vector<Grabber> m_grabbers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLGizmoBase();
|
||||||
|
virtual ~GLGizmoBase();
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
EState get_state() const;
|
||||||
|
void set_state(EState state);
|
||||||
|
|
||||||
|
unsigned int get_textures_id() const;
|
||||||
|
int get_textures_size() const;
|
||||||
|
|
||||||
|
int get_hover_id() const;
|
||||||
|
void set_hover_id(int id);
|
||||||
|
|
||||||
|
void start_dragging();
|
||||||
|
void update(const Pointf& mouse_pos);
|
||||||
|
|
||||||
|
void render(const BoundingBoxf3& box) const;
|
||||||
|
void render_for_picking(const BoundingBoxf3& box) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool on_init() = 0;
|
||||||
|
virtual void on_start_dragging();
|
||||||
|
virtual void on_update(const Pointf& mouse_pos) = 0;
|
||||||
|
virtual void on_render(const BoundingBoxf3& box) const = 0;
|
||||||
|
virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0;
|
||||||
|
|
||||||
|
void render_grabbers() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLGizmoRotate : public GLGizmoBase
|
||||||
|
{
|
||||||
|
static const float Offset;
|
||||||
|
static const unsigned int CircleResolution;
|
||||||
|
static const unsigned int AngleResolution;
|
||||||
|
static const unsigned int ScaleStepsCount;
|
||||||
|
static const float ScaleStepRad;
|
||||||
|
static const unsigned int ScaleLongEvery;
|
||||||
|
static const float ScaleLongTooth;
|
||||||
|
static const float ScaleShortTooth;
|
||||||
|
static const unsigned int SnapRegionsCount;
|
||||||
|
static const float GrabberOffset;
|
||||||
|
|
||||||
|
float m_angle_z;
|
||||||
|
|
||||||
|
mutable Pointf m_center;
|
||||||
|
mutable float m_radius;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLGizmoRotate();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool on_init();
|
||||||
|
virtual void on_update(const Pointf& mouse_pos);
|
||||||
|
virtual void on_render(const BoundingBoxf3& box) const;
|
||||||
|
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _render_circle() const;
|
||||||
|
void _render_scale() const;
|
||||||
|
void _render_snap_radii() const;
|
||||||
|
void _render_reference_radius() const;
|
||||||
|
void _render_angle_z() const;
|
||||||
|
void _render_grabber() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLGizmoScale : public GLGizmoBase
|
||||||
|
{
|
||||||
|
static const float Offset;
|
||||||
|
|
||||||
|
float m_scale;
|
||||||
|
|
||||||
|
Pointf m_starting_drag_position;
|
||||||
|
float m_starting_scale;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLGizmoScale();
|
||||||
|
|
||||||
|
float get_scale() const;
|
||||||
|
void set_scale(float scale);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool on_init();
|
||||||
|
virtual void on_start_dragging();
|
||||||
|
virtual void on_update(const Pointf& mouse_pos);
|
||||||
|
virtual void on_render(const BoundingBoxf3& box) const;
|
||||||
|
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_GLGizmo_hpp_
|
||||||
|
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include "GLShader.hpp"
|
#include "GLShader.hpp"
|
||||||
|
|
||||||
|
#include "../../libslic3r/Utils.hpp"
|
||||||
|
#include <boost/nowide/fstream.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -22,7 +25,7 @@ inline std::string gl_get_string_safe(GLenum param)
|
|||||||
return std::string(value ? value : "N/A");
|
return std::string(value ? value : "N/A");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLShader::load(const char *fragment_shader, const char *vertex_shader)
|
bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_shader)
|
||||||
{
|
{
|
||||||
std::string gl_version = gl_get_string_safe(GL_VERSION);
|
std::string gl_version = gl_get_string_safe(GL_VERSION);
|
||||||
int major = atoi(gl_version.c_str());
|
int major = atoi(gl_version.c_str());
|
||||||
@ -123,6 +126,41 @@ bool GLShader::load(const char *fragment_shader, const char *vertex_shader)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLShader::load_from_file(const char* fragment_shader_filename, const char* vertex_shader_filename)
|
||||||
|
{
|
||||||
|
const std::string& path = resources_dir() + "/shaders/";
|
||||||
|
|
||||||
|
boost::nowide::ifstream vs(path + std::string(vertex_shader_filename), boost::nowide::ifstream::binary);
|
||||||
|
if (!vs.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vs.seekg(0, vs.end);
|
||||||
|
int file_length = vs.tellg();
|
||||||
|
vs.seekg(0, vs.beg);
|
||||||
|
std::string vertex_shader(file_length, '\0');
|
||||||
|
vs.read(const_cast<char*>(vertex_shader.data()), file_length);
|
||||||
|
if (!vs.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
vs.close();
|
||||||
|
|
||||||
|
boost::nowide::ifstream fs(path + std::string(fragment_shader_filename), boost::nowide::ifstream::binary);
|
||||||
|
if (!fs.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fs.seekg(0, fs.end);
|
||||||
|
file_length = fs.tellg();
|
||||||
|
fs.seekg(0, fs.beg);
|
||||||
|
std::string fragment_shader(file_length, '\0');
|
||||||
|
fs.read(const_cast<char*>(fragment_shader.data()), file_length);
|
||||||
|
if (!fs.good())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fs.close();
|
||||||
|
|
||||||
|
return load_from_text(fragment_shader.c_str(), vertex_shader.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void GLShader::release()
|
void GLShader::release()
|
||||||
{
|
{
|
||||||
if (this->shader_program_id) {
|
if (this->shader_program_id) {
|
||||||
|
@ -16,7 +16,9 @@ public:
|
|||||||
{}
|
{}
|
||||||
~GLShader();
|
~GLShader();
|
||||||
|
|
||||||
bool load(const char *fragment_shader, const char *vertex_shader);
|
bool load_from_text(const char *fragment_shader, const char *vertex_shader);
|
||||||
|
bool load_from_file(const char* fragment_shader_filename, const char* vertex_shader_filename);
|
||||||
|
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
int get_attrib_location(const char *name) const;
|
int get_attrib_location(const char *name) const;
|
||||||
|
185
xs/src/slic3r/GUI/GLTexture.cpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#include "GLTexture.hpp"
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
#include <wx/image.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
GLTexture::GLTexture()
|
||||||
|
: m_id(0)
|
||||||
|
, m_width(0)
|
||||||
|
, m_height(0)
|
||||||
|
, m_source("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture::~GLTexture()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmaps)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
|
||||||
|
// Load a PNG with an alpha channel.
|
||||||
|
wxImage image;
|
||||||
|
if (!image.LoadFile(filename, wxBITMAP_TYPE_PNG))
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_width = image.GetWidth();
|
||||||
|
m_height = image.GetHeight();
|
||||||
|
int n_pixels = m_width * m_height;
|
||||||
|
|
||||||
|
if (n_pixels <= 0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get RGB & alpha raw data from wxImage, pack them into an array.
|
||||||
|
unsigned char* img_rgb = image.GetData();
|
||||||
|
if (img_rgb == nullptr)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* img_alpha = image.GetAlpha();
|
||||||
|
|
||||||
|
std::vector<unsigned char> data(n_pixels * 4, 0);
|
||||||
|
for (int i = 0; i < n_pixels; ++i)
|
||||||
|
{
|
||||||
|
int data_id = i * 4;
|
||||||
|
int img_id = i * 3;
|
||||||
|
data[data_id + 0] = img_rgb[img_id + 0];
|
||||||
|
data[data_id + 1] = img_rgb[img_id + 1];
|
||||||
|
data[data_id + 2] = img_rgb[img_id + 2];
|
||||||
|
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends data to gpu
|
||||||
|
::glGenTextures(1, &m_id);
|
||||||
|
::glBindTexture(GL_TEXTURE_2D, m_id);
|
||||||
|
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||||
|
if (generate_mipmaps)
|
||||||
|
{
|
||||||
|
// we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
|
||||||
|
_generate_mipmaps(image);
|
||||||
|
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||||
|
}
|
||||||
|
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
m_source = filename;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::reset()
|
||||||
|
{
|
||||||
|
if (m_id != 0)
|
||||||
|
::glDeleteTextures(1, &m_id);
|
||||||
|
|
||||||
|
m_id = 0;
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
|
m_source = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GLTexture::get_id() const
|
||||||
|
{
|
||||||
|
return m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GLTexture::get_width() const
|
||||||
|
{
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GLTexture::get_height() const
|
||||||
|
{
|
||||||
|
return m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GLTexture::get_source() const
|
||||||
|
{
|
||||||
|
return m_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top)
|
||||||
|
{
|
||||||
|
::glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
::glDisable(GL_LIGHTING);
|
||||||
|
::glEnable(GL_BLEND);
|
||||||
|
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
::glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id);
|
||||||
|
|
||||||
|
::glBegin(GL_QUADS);
|
||||||
|
::glTexCoord2d(0.0f, 1.0f); ::glVertex3f(left, bottom, 0.0f);
|
||||||
|
::glTexCoord2d(1.0f, 1.0f); ::glVertex3f(right, bottom, 0.0f);
|
||||||
|
::glTexCoord2d(1.0f, 0.0f); ::glVertex3f(right, top, 0.0f);
|
||||||
|
::glTexCoord2d(0.0f, 0.0f); ::glVertex3f(left, top, 0.0f);
|
||||||
|
::glEnd();
|
||||||
|
|
||||||
|
::glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
::glDisable(GL_TEXTURE_2D);
|
||||||
|
::glDisable(GL_BLEND);
|
||||||
|
::glEnable(GL_LIGHTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTexture::_generate_mipmaps(wxImage& image)
|
||||||
|
{
|
||||||
|
int w = image.GetWidth();
|
||||||
|
int h = image.GetHeight();
|
||||||
|
GLint level = 0;
|
||||||
|
std::vector<unsigned char> data(w * h * 4, 0);
|
||||||
|
|
||||||
|
while ((w > 1) && (h > 1))
|
||||||
|
{
|
||||||
|
++level;
|
||||||
|
|
||||||
|
w = std::max(w / 2, 1);
|
||||||
|
h = std::max(h / 2, 1);
|
||||||
|
|
||||||
|
int n_pixels = w * h;
|
||||||
|
|
||||||
|
image = image.ResampleBicubic(w, h);
|
||||||
|
|
||||||
|
unsigned char* img_rgb = image.GetData();
|
||||||
|
unsigned char* img_alpha = image.GetAlpha();
|
||||||
|
|
||||||
|
data.resize(n_pixels * 4);
|
||||||
|
for (int i = 0; i < n_pixels; ++i)
|
||||||
|
{
|
||||||
|
int data_id = i * 4;
|
||||||
|
int img_id = i * 3;
|
||||||
|
data[data_id + 0] = img_rgb[img_id + 0];
|
||||||
|
data[data_id + 1] = img_rgb[img_id + 1];
|
||||||
|
data[data_id + 2] = img_rgb[img_id + 2];
|
||||||
|
data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
41
xs/src/slic3r/GUI/GLTexture.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef slic3r_GLTexture_hpp_
|
||||||
|
#define slic3r_GLTexture_hpp_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class wxImage;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
class GLTexture
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
unsigned int m_id;
|
||||||
|
int m_width;
|
||||||
|
int m_height;
|
||||||
|
std::string m_source;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLTexture();
|
||||||
|
~GLTexture();
|
||||||
|
|
||||||
|
bool load_from_file(const std::string& filename, bool generate_mipmaps);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
unsigned int get_id() const;
|
||||||
|
int get_width() const;
|
||||||
|
int get_height() const;
|
||||||
|
const std::string& get_source() const;
|
||||||
|
|
||||||
|
static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _generate_mipmaps(wxImage& image);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_GLTexture_hpp_
|
||||||
|
|
@ -423,7 +423,7 @@ bool check_unsaved_changes()
|
|||||||
|
|
||||||
bool config_wizard_startup(bool app_config_exists)
|
bool config_wizard_startup(bool app_config_exists)
|
||||||
{
|
{
|
||||||
if (! app_config_exists || g_PresetBundle->has_defauls_only()) {
|
if (! app_config_exists || g_PresetBundle->printers.size() <= 1) {
|
||||||
config_wizard(ConfigWizard::RR_DATA_EMPTY);
|
config_wizard(ConfigWizard::RR_DATA_EMPTY);
|
||||||
return true;
|
return true;
|
||||||
} else if (g_AppConfig->legacy_datadir()) {
|
} else if (g_AppConfig->legacy_datadir()) {
|
||||||
|
402
xs/src/slic3r/Utils/FixModelByWin10.cpp
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
#ifdef HAS_WIN10SDK
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
# define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FixModelByWin10.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/nowide/convert.hpp>
|
||||||
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
|
||||||
|
#include <roapi.h>
|
||||||
|
// for ComPtr
|
||||||
|
#include <wrl/client.h>
|
||||||
|
// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
|
||||||
|
#include <winrt/robuffer.h>
|
||||||
|
#include <winrt/windows.storage.provider.h>
|
||||||
|
#include <winrt/windows.graphics.printing3d.h>
|
||||||
|
|
||||||
|
#include "libslic3r/Model.hpp"
|
||||||
|
#include "libslic3r/Print.hpp"
|
||||||
|
#include "libslic3r/Format/3mf.hpp"
|
||||||
|
#include "../GUI/GUI.hpp"
|
||||||
|
#include "../GUI/PresetBundle.hpp"
|
||||||
|
|
||||||
|
#include <wx/msgdlg.h>
|
||||||
|
#include <wx/progdlg.h>
|
||||||
|
|
||||||
|
extern "C"{
|
||||||
|
// from rapi.h
|
||||||
|
typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
|
||||||
|
typedef HRESULT (__stdcall* FunctionRoUninitialize)();
|
||||||
|
typedef HRESULT (__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance);
|
||||||
|
typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory);
|
||||||
|
// from winstring.h
|
||||||
|
typedef HRESULT (__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32 length, HSTRING *string);
|
||||||
|
typedef HRESULT (__stdcall* FunctionWindowsDelteString)(HSTRING string);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
HMODULE s_hRuntimeObjectLibrary = nullptr;
|
||||||
|
FunctionRoInitialize s_RoInitialize = nullptr;
|
||||||
|
FunctionRoUninitialize s_RoUninitialize = nullptr;
|
||||||
|
FunctionRoActivateInstance s_RoActivateInstance = nullptr;
|
||||||
|
FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr;
|
||||||
|
FunctionWindowsCreateString s_WindowsCreateString = nullptr;
|
||||||
|
FunctionWindowsDelteString s_WindowsDeleteString = nullptr;
|
||||||
|
|
||||||
|
bool winrt_load_runtime_object_library()
|
||||||
|
{
|
||||||
|
if (s_hRuntimeObjectLibrary == nullptr)
|
||||||
|
s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll");
|
||||||
|
if (s_hRuntimeObjectLibrary != nullptr) {
|
||||||
|
s_RoInitialize = (FunctionRoInitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize");
|
||||||
|
s_RoUninitialize = (FunctionRoUninitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize");
|
||||||
|
s_RoActivateInstance = (FunctionRoActivateInstance) GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance");
|
||||||
|
s_RoGetActivationFactory = (FunctionRoGetActivationFactory) GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory");
|
||||||
|
s_WindowsCreateString = (FunctionWindowsCreateString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString");
|
||||||
|
s_WindowsDeleteString = (FunctionWindowsDelteString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString");
|
||||||
|
}
|
||||||
|
return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst)
|
||||||
|
{
|
||||||
|
HSTRING hClassName;
|
||||||
|
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||||
|
if (S_OK != hr)
|
||||||
|
return hr;
|
||||||
|
hr = (*s_RoActivateInstance)(hClassName, pinst);
|
||||||
|
(*s_WindowsDeleteString)(hClassName);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TYPE>
|
||||||
|
static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst)
|
||||||
|
{
|
||||||
|
IInspectable *pinspectable = nullptr;
|
||||||
|
HRESULT hr = winrt_activate_instance(class_name, &pinspectable);
|
||||||
|
if (S_OK != hr)
|
||||||
|
return hr;
|
||||||
|
hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst);
|
||||||
|
pinspectable->Release();
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst)
|
||||||
|
{
|
||||||
|
HSTRING hClassName;
|
||||||
|
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||||
|
if (S_OK != hr)
|
||||||
|
return hr;
|
||||||
|
hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst);
|
||||||
|
(*s_WindowsDeleteString)(hClassName);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TYPE>
|
||||||
|
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE **pinst)
|
||||||
|
{
|
||||||
|
return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be called often to test whether to cancel the operation.
|
||||||
|
typedef std::function<void ()> ThrowOnCancelFn;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, ThrowOnCancelFn throw_on_cancel, int blocking_tick_ms = 100)
|
||||||
|
{
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||||
|
asyncAction.As(&asyncInfo);
|
||||||
|
AsyncStatus status;
|
||||||
|
// Ugly blocking loop until the RepairAsync call finishes.
|
||||||
|
//FIXME replace with a callback.
|
||||||
|
// https://social.msdn.microsoft.com/Forums/en-US/a5038fb4-b7b7-4504-969d-c102faa389fb/trying-to-block-an-async-operation-and-wait-for-a-particular-time?forum=vclanguage
|
||||||
|
for (;;) {
|
||||||
|
asyncInfo->get_Status(&status);
|
||||||
|
if (status != AsyncStatus::Started)
|
||||||
|
return status;
|
||||||
|
throw_on_cancel();
|
||||||
|
::Sleep(blocking_tick_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT winrt_open_file_stream(
|
||||||
|
const std::wstring &path,
|
||||||
|
ABI::Windows::Storage::FileAccessMode mode,
|
||||||
|
ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream,
|
||||||
|
ThrowOnCancelFn throw_on_cancel)
|
||||||
|
{
|
||||||
|
// Get the file factory.
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
|
||||||
|
HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf());
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
// Open the file asynchronously.
|
||||||
|
HSTRING hstr_path;
|
||||||
|
hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync;
|
||||||
|
hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf());
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
(*s_WindowsDeleteString)(hstr_path);
|
||||||
|
|
||||||
|
// Wait until the file gets open, get the actual file.
|
||||||
|
AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel);
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
|
||||||
|
if (status == AsyncStatus::Completed) {
|
||||||
|
hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
|
||||||
|
} else {
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||||
|
hr = fileOpenAsync.As(&asyncInfo);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
HRESULT err;
|
||||||
|
hr = asyncInfo->get_ErrorCode(&err);
|
||||||
|
return FAILED(hr) ? hr : err;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync;
|
||||||
|
hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
status = winrt_async_await(fileStreamAsync, throw_on_cancel);
|
||||||
|
if (status == AsyncStatus::Completed) {
|
||||||
|
hr = fileStreamAsync->GetResults(fileStream);
|
||||||
|
} else {
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||||
|
hr = fileStreamAsync.As(&asyncInfo);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
HRESULT err;
|
||||||
|
hr = asyncInfo->get_ErrorCode(&err);
|
||||||
|
if (!FAILED(hr))
|
||||||
|
hr = err;
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_windows10()
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey);
|
||||||
|
if (lRes == ERROR_SUCCESS) {
|
||||||
|
WCHAR szBuffer[512];
|
||||||
|
DWORD dwBufferSize = sizeof(szBuffer);
|
||||||
|
lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize);
|
||||||
|
if (lRes == ERROR_SUCCESS)
|
||||||
|
return wcsncmp(szBuffer, L"Windows 10", 10) == 0;
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress function, to be called regularly to update the progress.
|
||||||
|
typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn;
|
||||||
|
|
||||||
|
void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel)
|
||||||
|
{
|
||||||
|
if (! is_windows10())
|
||||||
|
throw std::runtime_error("fix_model_by_win10_sdk called on non Windows 10 system");
|
||||||
|
|
||||||
|
if (! winrt_load_runtime_object_library())
|
||||||
|
throw std::runtime_error("Failed to initialize the WinRT library.");
|
||||||
|
|
||||||
|
HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
|
||||||
|
{
|
||||||
|
on_progress(L("Exporting the source model"), 20);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> fileStream;
|
||||||
|
hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf(), throw_on_cancel);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
|
||||||
|
hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
|
||||||
|
hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
|
||||||
|
|
||||||
|
AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel);
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel> model;
|
||||||
|
if (status == AsyncStatus::Completed)
|
||||||
|
hr = modelAsync->GetResults(model.GetAddressOf());
|
||||||
|
else
|
||||||
|
throw std::runtime_error(L("Failed loading the input model."));
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
|
||||||
|
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||||
|
unsigned num_meshes = 0;
|
||||||
|
hr = meshes->get_Size(&num_meshes);
|
||||||
|
|
||||||
|
on_progress(L("Repairing the model by the Netfabb service"), 40);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync;
|
||||||
|
hr = model->RepairAsync(repairAsync.GetAddressOf());
|
||||||
|
status = winrt_async_await(repairAsync, throw_on_cancel);
|
||||||
|
if (status != AsyncStatus::Completed)
|
||||||
|
throw std::runtime_error(L("Mesh repair failed."));
|
||||||
|
repairAsync->GetResults();
|
||||||
|
|
||||||
|
on_progress(L("Loading the repaired model"), 60);
|
||||||
|
|
||||||
|
// Verify the number of meshes returned after the repair action.
|
||||||
|
meshes.Reset();
|
||||||
|
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||||
|
hr = meshes->get_Size(&num_meshes);
|
||||||
|
|
||||||
|
// Save model to this class' Printing3D3MFPackage.
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> saveToPackageAsync;
|
||||||
|
hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
|
||||||
|
status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
|
||||||
|
if (status != AsyncStatus::Completed)
|
||||||
|
throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
|
||||||
|
hr = saveToPackageAsync->GetResults();
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
|
||||||
|
hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
|
||||||
|
status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
|
||||||
|
if (status != AsyncStatus::Completed)
|
||||||
|
throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
|
||||||
|
hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
|
||||||
|
|
||||||
|
// Go to the beginning of the stream.
|
||||||
|
generatorStream->Seek(0);
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
|
||||||
|
hr = generatorStream.As(&inputStream);
|
||||||
|
|
||||||
|
// Get the buffer factory.
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
|
||||||
|
hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
|
||||||
|
|
||||||
|
// Open the destination file.
|
||||||
|
FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
|
||||||
|
byte *buffer_ptr;
|
||||||
|
bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
|
||||||
|
{
|
||||||
|
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
|
||||||
|
buffer.As(&bufferByteAccess);
|
||||||
|
hr = bufferByteAccess->Buffer(&buffer_ptr);
|
||||||
|
}
|
||||||
|
uint32_t length;
|
||||||
|
hr = buffer->get_Length(&length);
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
|
||||||
|
for (;;) {
|
||||||
|
hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
|
||||||
|
status = winrt_async_await(asyncRead, throw_on_cancel);
|
||||||
|
if (status != AsyncStatus::Completed)
|
||||||
|
throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
|
||||||
|
hr = buffer->get_Length(&length);
|
||||||
|
if (length == 0)
|
||||||
|
break;
|
||||||
|
fwrite(buffer_ptr, length, 1, fout);
|
||||||
|
}
|
||||||
|
fclose(fout);
|
||||||
|
// Here all the COM objects will be released through the ComPtr destructors.
|
||||||
|
}
|
||||||
|
(*s_RoUninitialize)();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RepairCanceledException : public std::exception {
|
||||||
|
public:
|
||||||
|
const char* what() const throw() { return "Model repair has been canceled"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result)
|
||||||
|
{
|
||||||
|
std::mutex mutex;
|
||||||
|
std::condition_variable condition;
|
||||||
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
struct Progress {
|
||||||
|
std::string message;
|
||||||
|
int percent = 0;
|
||||||
|
bool updated = false;
|
||||||
|
} progress;
|
||||||
|
std::atomic<bool> canceled = false;
|
||||||
|
std::atomic<bool> finished = false;
|
||||||
|
|
||||||
|
// Open a progress dialog.
|
||||||
|
wxProgressDialog progress_dialog(
|
||||||
|
_(L("Model fixing")),
|
||||||
|
_(L("Exporting model...")),
|
||||||
|
100, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||||
|
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||||
|
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||||
|
bool success = false;
|
||||||
|
auto on_progress = [&mutex, &condition, &progress](const char *msg, unsigned prcnt) {
|
||||||
|
std::lock_guard<std::mutex> lk(mutex);
|
||||||
|
progress.message = msg;
|
||||||
|
progress.percent = prcnt;
|
||||||
|
progress.updated = true;
|
||||||
|
condition.notify_all();
|
||||||
|
};
|
||||||
|
auto worker_thread = boost::thread([&model_object, &print, &result, on_progress, &success, &canceled, &finished]() {
|
||||||
|
try {
|
||||||
|
on_progress(L("Exporting the source model"), 0);
|
||||||
|
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||||
|
path_src += ".3mf";
|
||||||
|
Model model;
|
||||||
|
model.add_object(model_object);
|
||||||
|
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast<Print*>(&print), false)) {
|
||||||
|
boost::filesystem::remove(path_src);
|
||||||
|
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||||
|
}
|
||||||
|
model.clear_objects();
|
||||||
|
model.clear_materials();
|
||||||
|
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||||
|
path_dst += ".3mf";
|
||||||
|
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||||
|
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||||
|
boost::filesystem::remove(path_src);
|
||||||
|
PresetBundle bundle;
|
||||||
|
on_progress(L("Loading the repaired model"), 80);
|
||||||
|
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result);
|
||||||
|
boost::filesystem::remove(path_dst);
|
||||||
|
if (! loaded)
|
||||||
|
throw std::runtime_error(L("Import of the repaired 3mf file failed"));
|
||||||
|
success = true;
|
||||||
|
finished = true;
|
||||||
|
on_progress(L("Model repair finished"), 100);
|
||||||
|
} catch (RepairCanceledException &ex) {
|
||||||
|
canceled = true;
|
||||||
|
finished = true;
|
||||||
|
on_progress(L("Model repair canceled"), 100);
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
success = false;
|
||||||
|
finished = true;
|
||||||
|
on_progress(ex.what(), 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
while (! finished) {
|
||||||
|
condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; });
|
||||||
|
if (! progress_dialog.Update(progress.percent, _(progress.message)))
|
||||||
|
canceled = true;
|
||||||
|
progress.updated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canceled) {
|
||||||
|
// Nothing to show.
|
||||||
|
} else if (success) {
|
||||||
|
wxMessageDialog dlg(nullptr, _(L("Model repaired successfully")), _(L("Model Repair by the Netfabb service")), wxICON_INFORMATION | wxOK_DEFAULT);
|
||||||
|
dlg.ShowModal();
|
||||||
|
} else {
|
||||||
|
wxMessageDialog dlg(nullptr, _(L("Model repair failed: \n")) + _(progress.message), _(L("Model Repair by the Netfabb service")), wxICON_ERROR | wxOK_DEFAULT);
|
||||||
|
dlg.ShowModal();
|
||||||
|
}
|
||||||
|
worker_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* HAS_WIN10SDK */
|
26
xs/src/slic3r/Utils/FixModelByWin10.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||||
|
#define slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
class ModelObject;
|
||||||
|
class Print;
|
||||||
|
|
||||||
|
#ifdef HAS_WIN10SDK
|
||||||
|
|
||||||
|
extern bool is_windows10();
|
||||||
|
extern void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &print, Model &result);
|
||||||
|
|
||||||
|
#else /* HAS_WIN10SDK */
|
||||||
|
|
||||||
|
inline bool is_windows10() { return false; }
|
||||||
|
inline void fix_model_by_win10_sdk_gui(const ModelObject &, const Print &, Model &) {}
|
||||||
|
|
||||||
|
#endif /* HAS_WIN10SDK */
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* slic3r_GUI_Utils_FixModelByWin10_hpp_ */
|
@ -259,7 +259,7 @@ void PresetUpdater::priv::sync_config(const std::set<VendorProfile> vendors) con
|
|||||||
}
|
}
|
||||||
const auto recommended = recommended_it->config_version;
|
const auto recommended = recommended_it->config_version;
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << boost::format("New index for vendor: %1%: current version: %2%, recommended version: %3%")
|
BOOST_LOG_TRIVIAL(debug) << boost::format("Got index for vendor: %1%: current version: %2%, recommended version: %3%")
|
||||||
% vendor.name
|
% vendor.name
|
||||||
% vendor.config_version.to_string()
|
% vendor.config_version.to_string()
|
||||||
% recommended.to_string();
|
% recommended.to_string();
|
||||||
@ -352,20 +352,25 @@ Updates PresetUpdater::priv::get_config_updates() const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto path_in_cache = cache_path / (idx.vendor() + ".ini");
|
auto path_src = cache_path / (idx.vendor() + ".ini");
|
||||||
if (! fs::exists(path_in_cache)) {
|
if (! fs::exists(path_src)) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Index indicates update, but new bundle not found in cache: " << path_in_cache.string();
|
auto path_in_rsrc = rsrc_path / (idx.vendor() + ".ini");
|
||||||
continue;
|
if (! fs::exists(path_in_rsrc)) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update, but bundle found in neither cache nor resources")
|
||||||
|
% idx.vendor();;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
path_src = std::move(path_in_rsrc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto cached_vp = VendorProfile::from_ini(path_in_cache, false);
|
const auto new_vp = VendorProfile::from_ini(path_src, false);
|
||||||
if (cached_vp.config_version == recommended->config_version) {
|
if (new_vp.config_version == recommended->config_version) {
|
||||||
updates.updates.emplace_back(std::move(path_in_cache), std::move(bundle_path), *recommended);
|
updates.updates.emplace_back(std::move(path_src), std::move(bundle_path), *recommended);
|
||||||
} else {
|
} else {
|
||||||
BOOST_LOG_TRIVIAL(warning) << boost::format("Vendor: %1%: Index indicates update (%2%) but cached bundle has a different version: %3%")
|
BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources")
|
||||||
% idx.vendor()
|
% idx.vendor()
|
||||||
% recommended->config_version.to_string()
|
% recommended->config_version.to_string();
|
||||||
% cached_vp.config_version.to_string();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
xs/src/slic3r/iprogressindicator.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef IPROGRESSINDICATOR_HPP
|
||||||
|
#define IPROGRESSINDICATOR_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class IProgressIndicator {
|
||||||
|
public:
|
||||||
|
using CancelFn = std::function<void(void)>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float state_ = .0f, max_ = 1.f, step_;
|
||||||
|
std::function<void(void)> cancelfunc_ = [](){};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline virtual ~IProgressIndicator() {}
|
||||||
|
|
||||||
|
float max() const { return max_; }
|
||||||
|
float state() const { return state_; }
|
||||||
|
|
||||||
|
virtual void max(float maxval) { max_ = maxval; }
|
||||||
|
virtual void state(float val) { state_ = val; }
|
||||||
|
virtual void state(unsigned st) { state_ = st * step_; }
|
||||||
|
virtual void states(unsigned statenum) {
|
||||||
|
step_ = max_ / statenum;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void message(const std::string&) = 0;
|
||||||
|
virtual void title(const std::string&) = 0;
|
||||||
|
|
||||||
|
virtual void message_fmt(const std::string& fmt, ...);
|
||||||
|
|
||||||
|
inline void on_cancel(CancelFn func) { cancelfunc_ = func; }
|
||||||
|
inline void on_cancel() { cancelfunc_(); }
|
||||||
|
|
||||||
|
template<class T> void update(T st, const std::string& msg) {
|
||||||
|
message(msg); state(st);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IPROGRESSINDICATOR_HPP
|
@ -4,6 +4,7 @@
|
|||||||
#include <xsinit.h>
|
#include <xsinit.h>
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
#include "slic3r/Utils/ASCIIFolding.hpp"
|
#include "slic3r/Utils/ASCIIFolding.hpp"
|
||||||
|
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||||
#include "slic3r/Utils/Serial.hpp"
|
#include "slic3r/Utils/Serial.hpp"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
@ -28,6 +29,9 @@ bool debugged()
|
|||||||
void break_to_debugger()
|
void break_to_debugger()
|
||||||
%code{% Slic3r::GUI::break_to_debugger(); %};
|
%code{% Slic3r::GUI::break_to_debugger(); %};
|
||||||
|
|
||||||
|
bool is_windows10()
|
||||||
|
%code{% RETVAL=Slic3r::is_windows10(); %};
|
||||||
|
|
||||||
void set_wxapp(SV *ui)
|
void set_wxapp(SV *ui)
|
||||||
%code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %};
|
%code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %};
|
||||||
|
|
||||||
@ -94,3 +98,6 @@ int get_export_option(SV *ui)
|
|||||||
|
|
||||||
void desktop_open_datadir_folder()
|
void desktop_open_datadir_folder()
|
||||||
%code%{ Slic3r::GUI::desktop_open_datadir_folder(); %};
|
%code%{ Slic3r::GUI::desktop_open_datadir_folder(); %};
|
||||||
|
|
||||||
|
void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Model *model_dst)
|
||||||
|
%code%{ Slic3r::fix_model_by_win10_sdk_gui(*model_object_src, *print, *model_dst); %};
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
GLShader();
|
GLShader();
|
||||||
~GLShader();
|
~GLShader();
|
||||||
|
|
||||||
bool load(const char *fragment_shader, const char *vertex_shader);
|
bool load_from_text(const char *fragment_shader, const char *vertex_shader);
|
||||||
|
bool load_from_file(const char *fragment_shader, const char *vertex_shader);
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
int get_attrib_location(const char *name) const;
|
int get_attrib_location(const char *name) const;
|
||||||
@ -92,9 +93,6 @@
|
|||||||
int count()
|
int count()
|
||||||
%code{% RETVAL = THIS->volumes.size(); %};
|
%code{% RETVAL = THIS->volumes.size(); %};
|
||||||
|
|
||||||
std::vector<double> get_current_print_zs(bool active_only)
|
|
||||||
%code{% RETVAL = THIS->get_current_print_zs(active_only); %};
|
|
||||||
|
|
||||||
void set_range(double low, double high);
|
void set_range(double low, double high);
|
||||||
|
|
||||||
void render_VBOs() const;
|
void render_VBOs() const;
|
||||||
@ -155,11 +153,457 @@ GLVolumeCollection::arrayref()
|
|||||||
%package{Slic3r::GUI::_3DScene};
|
%package{Slic3r::GUI::_3DScene};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
|
std::string
|
||||||
|
get_gl_info(format_as_html, extensions)
|
||||||
|
bool format_as_html;
|
||||||
|
bool extensions;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::get_gl_info(format_as_html, extensions);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
use_VBOs()
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::use_VBOs();
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
add_canvas(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::add_canvas((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
remove_canvas(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::remove_canvas((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
void
|
void
|
||||||
_glew_init()
|
remove_all_canvases()
|
||||||
CODE:
|
CODE:
|
||||||
_3DScene::_glew_init();
|
_3DScene::remove_all_canvases();
|
||||||
|
|
||||||
|
void
|
||||||
|
set_active(canvas, active)
|
||||||
|
SV *canvas;
|
||||||
|
bool active;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_active((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), active);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
get_volumes_count(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::get_volumes_count((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
void
|
||||||
|
reset_volumes(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::reset_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
deselect_volumes(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::deselect_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
select_volume(canvas, id)
|
||||||
|
SV *canvas;
|
||||||
|
unsigned int id;
|
||||||
|
CODE:
|
||||||
|
_3DScene::select_volume((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);
|
||||||
|
|
||||||
|
void
|
||||||
|
update_volumes_selection(canvas, selections)
|
||||||
|
SV *canvas;
|
||||||
|
std::vector<int> selections;
|
||||||
|
CODE:
|
||||||
|
_3DScene::update_volumes_selection((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections);
|
||||||
|
|
||||||
|
bool
|
||||||
|
check_volumes_outside_state(canvas, config)
|
||||||
|
SV *canvas;
|
||||||
|
DynamicPrintConfig *config;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::check_volumes_outside_state((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), config);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
move_volume_up(canvas, id)
|
||||||
|
SV *canvas;
|
||||||
|
unsigned int id;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::move_volume_up((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
move_volume_down(canvas, id)
|
||||||
|
SV *canvas;
|
||||||
|
unsigned int id;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::move_volume_down((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
void
|
||||||
|
set_objects_selections(canvas, selections)
|
||||||
|
SV *canvas;
|
||||||
|
std::vector<int> selections;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_objects_selections((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_config(canvas, config)
|
||||||
|
SV *canvas;
|
||||||
|
DynamicPrintConfig *config;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_config((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), config);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_print(canvas, print)
|
||||||
|
SV *canvas;
|
||||||
|
Print *print;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_print((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_model(canvas, model)
|
||||||
|
SV *canvas;
|
||||||
|
Model *model;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_model((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_bed_shape(canvas, shape)
|
||||||
|
SV *canvas;
|
||||||
|
Pointfs shape;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), shape);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_auto_bed_shape(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_auto_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
Clone<BoundingBoxf3>
|
||||||
|
get_volumes_bounding_box(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::get_volumes_bounding_box((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
void
|
||||||
|
set_axes_length(canvas, length)
|
||||||
|
SV *canvas;
|
||||||
|
float length;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_axes_length((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), length);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_cutting_plane(canvas, z, polygons)
|
||||||
|
SV *canvas;
|
||||||
|
float z;
|
||||||
|
ExPolygons polygons;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_cutting_plane((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), z, polygons);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_color_by(canvas, value)
|
||||||
|
SV *canvas;
|
||||||
|
std::string value;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_color_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_select_by(canvas, value)
|
||||||
|
SV *canvas;
|
||||||
|
std::string value;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_select_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_drag_by(canvas, value)
|
||||||
|
SV *canvas;
|
||||||
|
std::string value;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_drag_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_layers_editing_enabled(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::is_layers_editing_enabled((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_layers_editing_allowed(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::is_layers_editing_allowed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_shader_enabled(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::is_shader_enabled((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_reload_delayed(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::is_reload_delayed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_layers_editing(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_layers_editing((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_warning_texture(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_warning_texture((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_legend_texture(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_legend_texture((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_picking(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_picking((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_moving(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_moving((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_gizmos(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_gizmos((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_shader(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_shader((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_force_zoom_to_bed(canvas, enable)
|
||||||
|
SV *canvas;
|
||||||
|
bool enable;
|
||||||
|
CODE:
|
||||||
|
_3DScene::enable_force_zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
|
||||||
|
|
||||||
|
void
|
||||||
|
allow_multisample(canvas, allow)
|
||||||
|
SV *canvas;
|
||||||
|
bool allow;
|
||||||
|
CODE:
|
||||||
|
_3DScene::allow_multisample((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), allow);
|
||||||
|
|
||||||
|
void
|
||||||
|
zoom_to_bed(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
zoom_to_volumes(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::zoom_to_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
select_view(canvas, direction)
|
||||||
|
SV *canvas;
|
||||||
|
std::string direction;
|
||||||
|
CODE:
|
||||||
|
_3DScene::select_view((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), direction);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_viewport_from_scene(canvas, other)
|
||||||
|
SV *canvas;
|
||||||
|
SV *other;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_viewport_from_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (wxGLCanvas*)wxPli_sv_2_object(aTHX_ other, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
update_volumes_colors_by_extruder(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::update_volumes_colors_by_extruder((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
void
|
||||||
|
render(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::render((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
|
std::vector<double>
|
||||||
|
get_current_print_zs(canvas, active_only)
|
||||||
|
SV *canvas;
|
||||||
|
bool active_only;
|
||||||
|
CODE:
|
||||||
|
RETVAL = _3DScene::get_current_print_zs((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), active_only);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
void
|
||||||
|
set_toolpaths_range(canvas, low, high)
|
||||||
|
SV *canvas;
|
||||||
|
double low;
|
||||||
|
double high;
|
||||||
|
CODE:
|
||||||
|
_3DScene::set_toolpaths_range((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), low, high);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_viewport_changed_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_viewport_changed_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_double_click_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_double_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_right_click_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_right_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_select_object_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_select_object_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_model_update_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_model_update_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_remove_object_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_remove_object_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_arrange_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_arrange_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_rotate_object_left_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_rotate_object_left_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_rotate_object_right_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_rotate_object_right_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_scale_object_uniformly_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_scale_object_uniformly_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_increase_objects_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_increase_objects_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_decrease_objects_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_decrease_objects_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_instance_moved_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_instance_moved_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_wipe_tower_moved_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_wipe_tower_moved_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_enable_action_buttons_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_enable_action_buttons_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
|
void
|
||||||
|
register_on_gizmo_scale_uniformly_callback(canvas, callback)
|
||||||
|
SV *canvas;
|
||||||
|
SV *callback;
|
||||||
|
CODE:
|
||||||
|
_3DScene::register_on_gizmo_scale_uniformly_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
finalize_legend_texture()
|
finalize_legend_texture()
|
||||||
@ -218,41 +662,61 @@ reset_warning_texture()
|
|||||||
CODE:
|
CODE:
|
||||||
_3DScene::reset_warning_texture();
|
_3DScene::reset_warning_texture();
|
||||||
|
|
||||||
void
|
std::vector<int>
|
||||||
_load_print_toolpaths(print, volumes, tool_colors, use_VBOs)
|
load_model_object(canvas, model_object, obj_idx, instance_idxs)
|
||||||
Print *print;
|
SV *canvas;
|
||||||
GLVolumeCollection *volumes;
|
ModelObject *model_object;
|
||||||
std::vector<std::string> tool_colors;
|
int obj_idx;
|
||||||
int use_VBOs;
|
std::vector<int> instance_idxs;
|
||||||
CODE:
|
CODE:
|
||||||
_3DScene::_load_print_toolpaths(print, volumes, tool_colors, use_VBOs != 0);
|
RETVAL = _3DScene::load_object((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model_object, obj_idx, instance_idxs);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
void
|
std::vector<int>
|
||||||
_load_print_object_toolpaths(print_object, volumes, tool_colors, use_VBOs)
|
load_model(canvas, model, obj_idx)
|
||||||
PrintObject *print_object;
|
SV *canvas;
|
||||||
GLVolumeCollection *volumes;
|
Model *model;
|
||||||
std::vector<std::string> tool_colors;
|
int obj_idx;
|
||||||
int use_VBOs;
|
|
||||||
CODE:
|
CODE:
|
||||||
_3DScene::_load_print_object_toolpaths(print_object, volumes, tool_colors, use_VBOs != 0);
|
RETVAL = _3DScene::load_object((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model, obj_idx);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
void
|
void
|
||||||
_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs)
|
reload_scene(canvas, force)
|
||||||
Print *print;
|
SV *canvas;
|
||||||
GLVolumeCollection *volumes;
|
bool force;
|
||||||
std::vector<std::string> tool_colors;
|
|
||||||
int use_VBOs;
|
|
||||||
CODE:
|
CODE:
|
||||||
_3DScene::_load_wipe_tower_toolpaths(print, volumes, tool_colors, use_VBOs != 0);
|
_3DScene::reload_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), force);
|
||||||
|
|
||||||
|
void
|
||||||
|
load_print_toolpaths(canvas)
|
||||||
|
SV *canvas;
|
||||||
|
CODE:
|
||||||
|
_3DScene::load_print_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
|
||||||
|
|
||||||
void
|
void
|
||||||
load_gcode_preview(print, preview_data, volumes, str_tool_colors, use_VBOs)
|
load_print_object_toolpaths(canvas, print_object, tool_colors)
|
||||||
Print *print;
|
SV *canvas;
|
||||||
|
PrintObject *print_object;
|
||||||
|
std::vector<std::string> tool_colors;
|
||||||
|
CODE:
|
||||||
|
_3DScene::load_print_object_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print_object, tool_colors);
|
||||||
|
|
||||||
|
void
|
||||||
|
load_wipe_tower_toolpaths(canvas, tool_colors)
|
||||||
|
SV *canvas;
|
||||||
|
std::vector<std::string> tool_colors;
|
||||||
|
CODE:
|
||||||
|
_3DScene::load_wipe_tower_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), tool_colors);
|
||||||
|
|
||||||
|
void
|
||||||
|
load_gcode_preview(canvas, preview_data, str_tool_colors)
|
||||||
|
SV *canvas;
|
||||||
GCodePreviewData *preview_data;
|
GCodePreviewData *preview_data;
|
||||||
GLVolumeCollection *volumes;
|
|
||||||
std::vector<std::string> str_tool_colors;
|
std::vector<std::string> str_tool_colors;
|
||||||
int use_VBOs;
|
|
||||||
CODE:
|
CODE:
|
||||||
_3DScene::load_gcode_preview(print, preview_data, volumes, str_tool_colors, use_VBOs != 0);
|
_3DScene::load_gcode_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), preview_data, str_tool_colors);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
@ -52,6 +52,8 @@ _constant()
|
|||||||
int region_count()
|
int region_count()
|
||||||
%code%{ RETVAL = THIS->print()->regions.size(); %};
|
%code%{ RETVAL = THIS->print()->regions.size(); %};
|
||||||
|
|
||||||
|
int region_volumes_count()
|
||||||
|
%code%{ RETVAL = THIS->region_volumes.size(); %};
|
||||||
Ref<Print> print();
|
Ref<Print> print();
|
||||||
Ref<ModelObject> model_object();
|
Ref<ModelObject> model_object();
|
||||||
Ref<StaticPrintConfig> config()
|
Ref<StaticPrintConfig> config()
|
||||||
@ -119,15 +121,6 @@ _constant()
|
|||||||
RETVAL.push_back(slicing_params.layer_height);
|
RETVAL.push_back(slicing_params.layer_height);
|
||||||
%};
|
%};
|
||||||
|
|
||||||
void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
|
|
||||||
%code%{
|
|
||||||
THIS->update_layer_height_profile(THIS->model_object()->layer_height_profile);
|
|
||||||
adjust_layer_height_profile(
|
|
||||||
THIS->slicing_parameters(), THIS->model_object()->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
|
|
||||||
THIS->model_object()->layer_height_profile_valid = true;
|
|
||||||
THIS->layer_height_profile_valid = false;
|
|
||||||
%};
|
|
||||||
|
|
||||||
void reset_layer_height_profile();
|
void reset_layer_height_profile();
|
||||||
|
|
||||||
int ptr()
|
int ptr()
|
||||||
|