mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 17:27:52 -06:00
Faster gizmos update
This commit is contained in:
commit
550f6e307f
40 changed files with 1415 additions and 753 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
|
@ -117,6 +117,8 @@ sub new {
|
||||||
my $model_object = $self->{model}->objects->[$obj_idx];
|
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||||
my $model_instance = $model_object->instances->[0];
|
my $model_instance = $model_object->instances->[0];
|
||||||
|
|
||||||
|
$self->stop_background_process;
|
||||||
|
|
||||||
my $variation = $scale / $model_instance->scaling_factor;
|
my $variation = $scale / $model_instance->scaling_factor;
|
||||||
#FIXME Scale the layer height profile?
|
#FIXME Scale the layer height profile?
|
||||||
foreach my $range (@{ $model_object->layer_height_ranges }) {
|
foreach my $range (@{ $model_object->layer_height_ranges }) {
|
||||||
|
@ -127,7 +129,6 @@ sub new {
|
||||||
$object->transform_thumbnail($self->{model}, $obj_idx);
|
$object->transform_thumbnail($self->{model}, $obj_idx);
|
||||||
|
|
||||||
#update print and start background processing
|
#update print and start background processing
|
||||||
$self->stop_background_process;
|
|
||||||
$self->{print}->add_model_object($model_object, $obj_idx);
|
$self->{print}->add_model_object($model_object, $obj_idx);
|
||||||
|
|
||||||
$self->selection_changed(1); # refresh info (size, volume etc.)
|
$self->selection_changed(1); # refresh info (size, volume etc.)
|
||||||
|
|
|
@ -22,8 +22,8 @@ struct PrintBoxDetection
|
||||||
{
|
{
|
||||||
vec3 min;
|
vec3 min;
|
||||||
vec3 max;
|
vec3 max;
|
||||||
// xyz contains the offset, if w == 1.0 detection needs to be performed
|
bool volume_detection;
|
||||||
vec4 volume_origin;
|
mat4 volume_world_matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform PrintBoxDetection print_box;
|
uniform PrintBoxDetection print_box;
|
||||||
|
@ -54,9 +54,9 @@ void main()
|
||||||
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||||
|
|
||||||
// compute deltas for out of print volume detection (world coordinates)
|
// compute deltas for out of print volume detection (world coordinates)
|
||||||
if (print_box.volume_origin.w == 1.0)
|
if (print_box.volume_detection)
|
||||||
{
|
{
|
||||||
vec3 v = gl_Vertex.xyz + print_box.volume_origin.xyz;
|
vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz;
|
||||||
delta_box_min = v - print_box.min;
|
delta_box_min = v - print_box.min;
|
||||||
delta_box_max = v - print_box.max;
|
delta_box_max = v - print_box.max;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||||
|
|
||||||
#define INTENSITY_AMBIENT 0.3
|
#define INTENSITY_AMBIENT 0.3
|
||||||
|
|
||||||
|
uniform mat4 volume_world_matrix;
|
||||||
|
|
||||||
// x = tainted, y = specular;
|
// x = tainted, y = specular;
|
||||||
varying vec2 intensity;
|
varying vec2 intensity;
|
||||||
|
|
||||||
|
@ -40,7 +42,6 @@ void main()
|
||||||
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||||
|
|
||||||
// Scaled to widths of the Z texture.
|
// Scaled to widths of the Z texture.
|
||||||
object_z = gl_Vertex.z;
|
object_z = (volume_world_matrix * gl_Vertex).z;
|
||||||
|
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,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)
|
||||||
|
@ -240,6 +247,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
|
||||||
|
@ -344,8 +353,6 @@ add_library(semver STATIC
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
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(
|
||||||
|
@ -508,12 +515,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})
|
||||||
|
@ -521,6 +528,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
|
||||||
|
|
|
@ -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]() {
|
||||||
|
if (self->p->run_fn) {
|
||||||
|
self->p->run_fn();
|
||||||
|
}
|
||||||
|
|
||||||
auto res = self->p->run();
|
auto res = self->p->run();
|
||||||
|
|
||||||
if (self->p->complete_fn) {
|
if (self->p->complete_fn) {
|
||||||
self->p->complete_fn(res);
|
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,15 +811,34 @@ 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);
|
||||||
|
|
||||||
|
for (i = 0; i < n_bytes; ++ i)
|
||||||
|
if (m->buf[addr + i] == ';') {
|
||||||
|
has_semicolon = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2 : 1); ++ prusa3d_semicolon_workaround_round) {
|
||||||
/* build command block and avoid multiple send commands as it leads to a crash
|
/* build command block and avoid multiple send commands as it leads to a crash
|
||||||
of the silabs usb serial driver on mac os x */
|
of the silabs usb serial driver on mac os x */
|
||||||
i = 0;
|
i = 0;
|
||||||
buf[i++] = Cmnd_STK_PROG_PAGE;
|
buf[i++] = Cmnd_STK_PROG_PAGE;
|
||||||
buf[i++] = (block_size >> 8) & 0xff;
|
// Workaround for the infamous ';' bug in the Prusa3D usb to serial converter.
|
||||||
buf[i++] = block_size & 0xff;
|
// Send the binary data by nibbles to avoid transmitting the ';' character.
|
||||||
|
buf[i++] = (block_size >> 8) & 0xf0;
|
||||||
|
buf[i++] = (block_size >> 8) & 0x0f;
|
||||||
|
buf[i++] = block_size & 0xf0;
|
||||||
|
buf[i++] = block_size & 0x0f;
|
||||||
buf[i++] = memtype;
|
buf[i++] = memtype;
|
||||||
|
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);
|
memcpy(&buf[i], &m->buf[addr], block_size);
|
||||||
i += block_size;
|
i += block_size;
|
||||||
|
}
|
||||||
buf[i++] = Sync_CRC_EOP;
|
buf[i++] = Sync_CRC_EOP;
|
||||||
stk500_send( pgm, buf, i);
|
stk500_send( pgm, buf, i);
|
||||||
|
|
||||||
|
@ -846,6 +870,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return n_bytes;
|
return n_bytes;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
|
template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
|
||||||
|
@ -251,4 +253,41 @@ void BoundingBox::align_to_grid(const coord_t cell_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BoundingBoxf3 BoundingBoxf3::transformed(const std::vector<float>& matrix) const
|
||||||
|
{
|
||||||
|
Eigen::Matrix<float, 3, 8> vertices;
|
||||||
|
|
||||||
|
vertices(0, 0) = (float)min.x; vertices(1, 0) = (float)min.y; vertices(2, 0) = (float)min.z;
|
||||||
|
vertices(0, 1) = (float)max.x; vertices(1, 1) = (float)min.y; vertices(2, 1) = (float)min.z;
|
||||||
|
vertices(0, 2) = (float)max.x; vertices(1, 2) = (float)max.y; vertices(2, 2) = (float)min.z;
|
||||||
|
vertices(0, 3) = (float)min.x; vertices(1, 3) = (float)max.y; vertices(2, 3) = (float)min.z;
|
||||||
|
vertices(0, 4) = (float)min.x; vertices(1, 4) = (float)min.y; vertices(2, 4) = (float)max.z;
|
||||||
|
vertices(0, 5) = (float)max.x; vertices(1, 5) = (float)min.y; vertices(2, 5) = (float)max.z;
|
||||||
|
vertices(0, 6) = (float)max.x; vertices(1, 6) = (float)max.y; vertices(2, 6) = (float)max.z;
|
||||||
|
vertices(0, 7) = (float)min.x; vertices(1, 7) = (float)max.y; vertices(2, 7) = (float)max.z;
|
||||||
|
|
||||||
|
Eigen::Transform<float, 3, Eigen::Affine> m;
|
||||||
|
::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
|
||||||
|
Eigen::Matrix<float, 3, 8> transf_vertices = m * vertices.colwise().homogeneous();
|
||||||
|
|
||||||
|
float min_x = transf_vertices(0, 0);
|
||||||
|
float max_x = transf_vertices(0, 0);
|
||||||
|
float min_y = transf_vertices(1, 0);
|
||||||
|
float max_y = transf_vertices(1, 0);
|
||||||
|
float min_z = transf_vertices(2, 0);
|
||||||
|
float max_z = transf_vertices(2, 0);
|
||||||
|
|
||||||
|
for (int i = 1; i < 8; ++i)
|
||||||
|
{
|
||||||
|
min_x = std::min(min_x, transf_vertices(0, i));
|
||||||
|
max_x = std::max(max_x, transf_vertices(0, i));
|
||||||
|
min_y = std::min(min_y, transf_vertices(1, i));
|
||||||
|
max_y = std::max(max_y, transf_vertices(1, i));
|
||||||
|
min_z = std::min(min_z, transf_vertices(2, i));
|
||||||
|
max_z = std::max(max_z, transf_vertices(2, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,8 @@ public:
|
||||||
BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
|
BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
|
||||||
BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
|
BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
|
||||||
BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
|
BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
|
||||||
|
|
||||||
|
BoundingBoxf3 transformed(const std::vector<float>& matrix) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename VT>
|
template<typename VT>
|
||||||
|
|
|
@ -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,7 @@
|
||||||
|
|
||||||
#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 +667,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <boost/nowide/iostream.hpp>
|
#include <boost/nowide/iostream.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
unsigned int Model::s_auto_extruder_id = 1;
|
unsigned int Model::s_auto_extruder_id = 1;
|
||||||
|
@ -603,10 +605,7 @@ 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
|
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;
|
||||||
|
@ -1048,32 +1047,16 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
|
||||||
|
|
||||||
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
||||||
{
|
{
|
||||||
// rotate around mesh origin
|
Eigen::Transform<float, 3, Eigen::Affine> matrix = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
||||||
double c = cos(this->rotation);
|
if (!dont_translate)
|
||||||
double s = sin(this->rotation);
|
matrix.translate(Eigen::Vector3f((float)offset.x, (float)offset.y, 0.0f));
|
||||||
Pointf3 pts[4] = {
|
|
||||||
bbox.min,
|
matrix.rotate(Eigen::AngleAxisf(rotation, Eigen::Vector3f::UnitZ()));
|
||||||
bbox.max,
|
matrix.scale(scaling_factor);
|
||||||
Pointf3(bbox.min.x, bbox.max.y, bbox.min.z),
|
|
||||||
Pointf3(bbox.max.x, bbox.min.y, bbox.max.z)
|
std::vector<float> m(16, 0.0f);
|
||||||
};
|
::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
|
||||||
BoundingBoxf3 out;
|
return bbox.transformed(m);
|
||||||
for (int i = 0; i < 4; ++ i) {
|
|
||||||
Pointf3 &v = pts[i];
|
|
||||||
double xold = v.x;
|
|
||||||
double yold = v.y;
|
|
||||||
v.x = float(c * xold - s * yold);
|
|
||||||
v.y = float(s * xold + c * yold);
|
|
||||||
v.x *= this->scaling_factor;
|
|
||||||
v.y *= this->scaling_factor;
|
|
||||||
v.z *= this->scaling_factor;
|
|
||||||
if (! dont_translate) {
|
|
||||||
v.x += this->offset.x;
|
|
||||||
v.y += this->offset.y;
|
|
||||||
}
|
|
||||||
out.merge(v);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelInstance::transform_polygon(Polygon* polygon) const
|
void ModelInstance::transform_polygon(Polygon* polygon) const
|
||||||
|
|
|
@ -103,10 +103,7 @@ 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;
|
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.
|
||||||
|
@ -148,10 +145,9 @@ private:
|
||||||
// Parent object, owning this ModelObject.
|
// Parent object, owning this ModelObject.
|
||||||
Model *m_model;
|
Model *m_model;
|
||||||
// Bounding box, cached.
|
// Bounding box, cached.
|
||||||
//========================================================================================================
|
|
||||||
mutable BoundingBoxf3 m_bounding_box;
|
mutable BoundingBoxf3 m_bounding_box;
|
||||||
mutable bool m_bounding_box_valid;
|
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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
|
|
||||||
#include "../../libslic3r/libslic3r.h"
|
|
||||||
#include "../../libslic3r/ExtrusionEntity.hpp"
|
#include "../../libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "../../libslic3r/ExtrusionEntityCollection.hpp"
|
#include "../../libslic3r/ExtrusionEntityCollection.hpp"
|
||||||
#include "../../libslic3r/Geometry.hpp"
|
#include "../../libslic3r/Geometry.hpp"
|
||||||
|
@ -28,8 +27,15 @@
|
||||||
#include <wx/image.h>
|
#include <wx/image.h>
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
#include "GUI.hpp"
|
#include "GUI.hpp"
|
||||||
|
|
||||||
|
static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
|
void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
|
||||||
|
@ -198,6 +204,34 @@ const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
||||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
||||||
|
|
||||||
|
GLVolume::GLVolume(float r, float g, float b, float a)
|
||||||
|
: m_angle_z(0.0f)
|
||||||
|
, m_scale_factor(1.0f)
|
||||||
|
, m_dirty(true)
|
||||||
|
, composite_id(-1)
|
||||||
|
, select_group_id(-1)
|
||||||
|
, drag_group_id(-1)
|
||||||
|
, extruder_id(0)
|
||||||
|
, selected(false)
|
||||||
|
, is_active(true)
|
||||||
|
, zoom_to_volumes(true)
|
||||||
|
, outside_printer_detection_enabled(true)
|
||||||
|
, is_outside(false)
|
||||||
|
, hover(false)
|
||||||
|
, is_modifier(false)
|
||||||
|
, is_wipe_tower(false)
|
||||||
|
, tverts_range(0, size_t(-1))
|
||||||
|
, qverts_range(0, size_t(-1))
|
||||||
|
{
|
||||||
|
m_world_mat = std::vector<float>(UNIT_MATRIX, std::end(UNIT_MATRIX));
|
||||||
|
|
||||||
|
color[0] = r;
|
||||||
|
color[1] = g;
|
||||||
|
color[2] = b;
|
||||||
|
color[3] = a;
|
||||||
|
set_render_color(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
void GLVolume::set_render_color(float r, float g, float b, float a)
|
void GLVolume::set_render_color(float r, float g, float b, float a)
|
||||||
{
|
{
|
||||||
render_color[0] = r;
|
render_color[0] = r;
|
||||||
|
@ -218,12 +252,7 @@ void GLVolume::set_render_color(const float* rgba, unsigned int size)
|
||||||
void GLVolume::set_render_color()
|
void GLVolume::set_render_color()
|
||||||
{
|
{
|
||||||
if (selected)
|
if (selected)
|
||||||
{
|
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
|
||||||
if (is_outside)
|
|
||||||
set_render_color(SELECTED_OUTSIDE_COLOR, 4);
|
|
||||||
else
|
|
||||||
set_render_color(SELECTED_COLOR, 4);
|
|
||||||
}
|
|
||||||
else if (hover)
|
else if (hover)
|
||||||
set_render_color(HOVER_COLOR, 4);
|
set_render_color(HOVER_COLOR, 4);
|
||||||
else if (is_outside)
|
else if (is_outside)
|
||||||
|
@ -232,6 +261,52 @@ void GLVolume::set_render_color()
|
||||||
set_render_color(color, 4);
|
set_render_color(color, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Pointf3& GLVolume::get_origin() const
|
||||||
|
{
|
||||||
|
return m_origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLVolume::set_origin(const Pointf3& origin)
|
||||||
|
{
|
||||||
|
m_origin = origin;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLVolume::set_angle_z(float angle_z)
|
||||||
|
{
|
||||||
|
m_angle_z = angle_z;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLVolume::set_scale_factor(float scale_factor)
|
||||||
|
{
|
||||||
|
m_scale_factor = scale_factor;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<float>& GLVolume::world_matrix() const
|
||||||
|
{
|
||||||
|
if (m_dirty)
|
||||||
|
{
|
||||||
|
Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
|
||||||
|
m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
|
||||||
|
m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
|
||||||
|
m.scale(m_scale_factor);
|
||||||
|
::memcpy((void*)m_world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_world_mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBoxf3 GLVolume::transformed_bounding_box() const
|
||||||
|
{
|
||||||
|
if (m_dirty)
|
||||||
|
m_transformed_bounding_box = bounding_box.transformed(world_matrix());
|
||||||
|
|
||||||
|
return m_transformed_bounding_box;
|
||||||
|
}
|
||||||
|
|
||||||
void GLVolume::set_range(double min_z, double max_z)
|
void GLVolume::set_range(double min_z, double max_z)
|
||||||
{
|
{
|
||||||
this->qverts_range.first = 0;
|
this->qverts_range.first = 0;
|
||||||
|
@ -272,14 +347,16 @@ void GLVolume::render() const
|
||||||
if (!is_active)
|
if (!is_active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
glCullFace(GL_BACK);
|
::glCullFace(GL_BACK);
|
||||||
glPushMatrix();
|
::glPushMatrix();
|
||||||
glTranslated(this->origin.x, this->origin.y, this->origin.z);
|
::glTranslated(m_origin.x, m_origin.y, m_origin.z);
|
||||||
|
::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
|
||||||
|
::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
|
||||||
if (this->indexed_vertex_array.indexed())
|
if (this->indexed_vertex_array.indexed())
|
||||||
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
|
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
|
||||||
else
|
else
|
||||||
this->indexed_vertex_array.render();
|
this->indexed_vertex_array.render();
|
||||||
glPopMatrix();
|
::glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLVolume::render_using_layer_height() const
|
void GLVolume::render_using_layer_height() const
|
||||||
|
@ -297,6 +374,7 @@ void GLVolume::render_using_layer_height() const
|
||||||
GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1;
|
GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1;
|
||||||
GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1;
|
GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1;
|
||||||
GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1;
|
GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1;
|
||||||
|
GLint world_matrix_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "volume_world_matrix") : -1;
|
||||||
|
|
||||||
if (z_to_texture_row_id >= 0)
|
if (z_to_texture_row_id >= 0)
|
||||||
glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id());
|
glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id());
|
||||||
|
@ -310,14 +388,19 @@ void GLVolume::render_using_layer_height() const
|
||||||
if (z_cursor_band_width_id >= 0)
|
if (z_cursor_band_width_id >= 0)
|
||||||
glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
|
glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
|
||||||
|
|
||||||
unsigned int w = layer_height_texture_width();
|
if (world_matrix_id >= 0)
|
||||||
unsigned int h = layer_height_texture_height();
|
::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
|
||||||
|
|
||||||
|
GLsizei w = (GLsizei)layer_height_texture_width();
|
||||||
|
GLsizei h = (GLsizei)layer_height_texture_height();
|
||||||
|
GLsizei half_w = w / 2;
|
||||||
|
GLsizei half_h = h / 2;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id);
|
glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w / 2, h / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0());
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0());
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, w / 2, h / 2, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1());
|
glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1());
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|
||||||
|
@ -327,6 +410,128 @@ void GLVolume::render_using_layer_height() const
|
||||||
glUseProgram(current_program_id);
|
glUseProgram(current_program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const
|
||||||
|
{
|
||||||
|
if (!is_active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (layer_height_texture_data.can_use())
|
||||||
|
{
|
||||||
|
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
render_using_layer_height();
|
||||||
|
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
|
||||||
|
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
|
||||||
|
if (n_triangles + n_quads == 0)
|
||||||
|
{
|
||||||
|
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
if (color_id >= 0)
|
||||||
|
{
|
||||||
|
float color[4];
|
||||||
|
::memcpy((void*)color, (const void*)render_color, 4 * sizeof(float));
|
||||||
|
::glUniform4fv(color_id, 1, (const GLfloat*)color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
|
||||||
|
|
||||||
|
if (detection_id != -1)
|
||||||
|
::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0);
|
||||||
|
|
||||||
|
if (worldmatrix_id != -1)
|
||||||
|
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color_id >= 0)
|
||||||
|
::glUniform4fv(color_id, 1, (const GLfloat*)render_color);
|
||||||
|
else
|
||||||
|
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
|
||||||
|
|
||||||
|
if (detection_id != -1)
|
||||||
|
::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0);
|
||||||
|
|
||||||
|
if (worldmatrix_id != -1)
|
||||||
|
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
|
||||||
|
|
||||||
|
::glBindBuffer(GL_ARRAY_BUFFER, indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
|
||||||
|
::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
|
||||||
|
::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr);
|
||||||
|
|
||||||
|
::glPushMatrix();
|
||||||
|
::glTranslated(m_origin.x, m_origin.y, m_origin.z);
|
||||||
|
::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
|
||||||
|
::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
|
||||||
|
|
||||||
|
if (n_triangles > 0)
|
||||||
|
{
|
||||||
|
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexed_vertex_array.triangle_indices_VBO_id);
|
||||||
|
::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4));
|
||||||
|
}
|
||||||
|
if (n_quads > 0)
|
||||||
|
{
|
||||||
|
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexed_vertex_array.quad_indices_VBO_id);
|
||||||
|
::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
::glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLVolume::render_legacy() const
|
||||||
|
{
|
||||||
|
assert(!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
|
||||||
|
if (!is_active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
|
||||||
|
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
|
||||||
|
if (n_triangles + n_quads == 0)
|
||||||
|
{
|
||||||
|
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
|
||||||
|
render();
|
||||||
|
|
||||||
|
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
::glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
|
||||||
|
::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), indexed_vertex_array.vertices_and_normals_interleaved.data() + 3);
|
||||||
|
::glNormalPointer(GL_FLOAT, 6 * sizeof(float), indexed_vertex_array.vertices_and_normals_interleaved.data());
|
||||||
|
|
||||||
|
::glPushMatrix();
|
||||||
|
::glTranslated(m_origin.x, m_origin.y, m_origin.z);
|
||||||
|
::glRotatef(m_angle_z * 180.0f / PI, 0.0f, 0.0f, 1.0f);
|
||||||
|
::glScalef(m_scale_factor, m_scale_factor, m_scale_factor);
|
||||||
|
|
||||||
|
if (n_triangles > 0)
|
||||||
|
::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, indexed_vertex_array.triangle_indices.data() + tverts_range.first);
|
||||||
|
|
||||||
|
if (n_quads > 0)
|
||||||
|
::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first);
|
||||||
|
|
||||||
|
::glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
double GLVolume::layer_height_texture_z_to_row_id() const
|
double GLVolume::layer_height_texture_z_to_row_id() const
|
||||||
{
|
{
|
||||||
return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max.z);
|
return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max.z);
|
||||||
|
@ -399,7 +604,6 @@ std::vector<int> GLVolumeCollection::load_object(
|
||||||
for (int instance_idx : instance_idxs) {
|
for (int instance_idx : instance_idxs) {
|
||||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||||
TriangleMesh mesh = model_volume->mesh;
|
TriangleMesh mesh = model_volume->mesh;
|
||||||
instance->transform_mesh(&mesh);
|
|
||||||
volumes_idx.push_back(int(this->volumes.size()));
|
volumes_idx.push_back(int(this->volumes.size()));
|
||||||
float color[4];
|
float color[4];
|
||||||
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
|
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
|
||||||
|
@ -433,13 +637,15 @@ std::vector<int> GLVolumeCollection::load_object(
|
||||||
v.extruder_id = extruder_id;
|
v.extruder_id = extruder_id;
|
||||||
}
|
}
|
||||||
v.is_modifier = model_volume->modifier;
|
v.is_modifier = model_volume->modifier;
|
||||||
|
v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0));
|
||||||
|
v.set_angle_z(instance->rotation);
|
||||||
|
v.set_scale_factor(instance->scaling_factor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return volumes_idx;
|
return volumes_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GLVolumeCollection::load_wipe_tower_preview(
|
int GLVolumeCollection::load_wipe_tower_preview(
|
||||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs)
|
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs)
|
||||||
{
|
{
|
||||||
|
@ -460,7 +666,8 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
||||||
else
|
else
|
||||||
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
|
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
|
||||||
|
|
||||||
v.origin = Pointf3(pos_x, pos_y, 0.);
|
v.set_origin(Pointf3(pos_x, pos_y, 0.));
|
||||||
|
|
||||||
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
||||||
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
||||||
v.indexed_vertex_array.finalize_geometry(use_VBOs);
|
v.indexed_vertex_array.finalize_geometry(use_VBOs);
|
||||||
|
@ -485,102 +692,23 @@ void GLVolumeCollection::render_VBOs() const
|
||||||
GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
||||||
GLint print_box_min_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.min") : -1;
|
GLint print_box_min_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.min") : -1;
|
||||||
GLint print_box_max_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.max") : -1;
|
GLint print_box_max_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.max") : -1;
|
||||||
GLint print_box_origin_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_origin") : -1;
|
GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
|
||||||
|
GLint print_box_worldmatrix_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
|
||||||
|
|
||||||
for (GLVolume *volume : this->volumes) {
|
if (print_box_min_id != -1)
|
||||||
if (!volume->is_active)
|
::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
|
if (print_box_max_id != -1)
|
||||||
continue;
|
::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
|
||||||
|
|
||||||
if (volume->layer_height_texture_data.can_use())
|
for (GLVolume *volume : this->volumes)
|
||||||
{
|
{
|
||||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
if (volume->layer_height_texture_data.can_use())
|
||||||
::glDisableClientState(GL_NORMAL_ARRAY);
|
|
||||||
volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false);
|
volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false);
|
||||||
volume->render_using_layer_height();
|
else
|
||||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
::glEnableClientState(GL_NORMAL_ARRAY);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
volume->set_render_color();
|
volume->set_render_color();
|
||||||
|
|
||||||
GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first));
|
volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
|
||||||
GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first));
|
|
||||||
if (n_triangles + n_quads == 0)
|
|
||||||
{
|
|
||||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
::glDisableClientState(GL_NORMAL_ARRAY);
|
|
||||||
|
|
||||||
if (color_id >= 0)
|
|
||||||
{
|
|
||||||
float color[4];
|
|
||||||
::memcpy((void*)color, (const void*)volume->render_color, 4 * sizeof(float));
|
|
||||||
::glUniform4fv(color_id, 1, (const GLfloat*)color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
|
|
||||||
|
|
||||||
if (print_box_min_id != -1)
|
|
||||||
::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
|
|
||||||
|
|
||||||
if (print_box_max_id != -1)
|
|
||||||
::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
|
|
||||||
|
|
||||||
if (print_box_origin_id != -1)
|
|
||||||
{
|
|
||||||
float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f };
|
|
||||||
::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
volume->render();
|
|
||||||
|
|
||||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
::glEnableClientState(GL_NORMAL_ARRAY);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color_id >= 0)
|
|
||||||
::glUniform4fv(color_id, 1, (const GLfloat*)volume->render_color);
|
|
||||||
else
|
|
||||||
::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
|
|
||||||
|
|
||||||
if (print_box_min_id != -1)
|
|
||||||
::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
|
|
||||||
|
|
||||||
if (print_box_max_id != -1)
|
|
||||||
::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
|
|
||||||
|
|
||||||
if (print_box_origin_id != -1)
|
|
||||||
{
|
|
||||||
float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f };
|
|
||||||
::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
|
|
||||||
::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
|
|
||||||
::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr);
|
|
||||||
|
|
||||||
bool has_offset = (volume->origin.x != 0) || (volume->origin.y != 0) || (volume->origin.z != 0);
|
|
||||||
if (has_offset) {
|
|
||||||
::glPushMatrix();
|
|
||||||
::glTranslated(volume->origin.x, volume->origin.y, volume->origin.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_triangles > 0) {
|
|
||||||
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id);
|
|
||||||
::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(volume->tverts_range.first * 4));
|
|
||||||
}
|
|
||||||
if (n_quads > 0) {
|
|
||||||
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id);
|
|
||||||
::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(volume->qverts_range.first * 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_offset)
|
|
||||||
::glPopMatrix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::glBindBuffer(GL_ARRAY_BUFFER, 0);
|
::glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
@ -601,43 +729,10 @@ void GLVolumeCollection::render_legacy() const
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
for (GLVolume *volume : this->volumes) {
|
for (GLVolume *volume : this->volumes)
|
||||||
assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
|
|
||||||
if (!volume->is_active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
volume->set_render_color();
|
|
||||||
|
|
||||||
GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first));
|
|
||||||
GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first));
|
|
||||||
if (n_triangles + n_quads == 0)
|
|
||||||
{
|
{
|
||||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
volume->set_render_color();
|
||||||
::glDisableClientState(GL_NORMAL_ARRAY);
|
volume->render_legacy();
|
||||||
|
|
||||||
::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
|
|
||||||
volume->render();
|
|
||||||
|
|
||||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
::glEnableClientState(GL_NORMAL_ARRAY);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
|
|
||||||
glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data() + 3);
|
|
||||||
glNormalPointer(GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data());
|
|
||||||
bool has_offset = volume->origin.x != 0 || volume->origin.y != 0 || volume->origin.z != 0;
|
|
||||||
if (has_offset) {
|
|
||||||
glPushMatrix();
|
|
||||||
glTranslated(volume->origin.x, volume->origin.y, volume->origin.z);
|
|
||||||
}
|
|
||||||
if (n_triangles > 0)
|
|
||||||
glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, volume->indexed_vertex_array.triangle_indices.data() + volume->tverts_range.first);
|
|
||||||
if (n_quads > 0)
|
|
||||||
glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, volume->indexed_vertex_array.quad_indices.data() + volume->qverts_range.first);
|
|
||||||
if (has_offset)
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
|
@ -240,7 +240,7 @@ class GLVolume {
|
||||||
edit_band_width = 0.0f;
|
edit_band_width = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_use() { return (texture_id > 0) && (shader_id > 0) && (print_object != nullptr); }
|
bool can_use() const { return (texture_id > 0) && (shader_id > 0) && (print_object != nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -249,44 +249,27 @@ public:
|
||||||
static const float OUTSIDE_COLOR[4];
|
static const float OUTSIDE_COLOR[4];
|
||||||
static const float SELECTED_OUTSIDE_COLOR[4];
|
static const float SELECTED_OUTSIDE_COLOR[4];
|
||||||
|
|
||||||
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) :
|
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
|
||||||
composite_id(-1),
|
|
||||||
select_group_id(-1),
|
|
||||||
drag_group_id(-1),
|
|
||||||
extruder_id(0),
|
|
||||||
selected(false),
|
|
||||||
is_active(true),
|
|
||||||
zoom_to_volumes(true),
|
|
||||||
outside_printer_detection_enabled(true),
|
|
||||||
is_outside(false),
|
|
||||||
hover(false),
|
|
||||||
is_modifier(false),
|
|
||||||
is_wipe_tower(false),
|
|
||||||
tverts_range(0, size_t(-1)),
|
|
||||||
qverts_range(0, size_t(-1))
|
|
||||||
{
|
|
||||||
color[0] = r;
|
|
||||||
color[1] = g;
|
|
||||||
color[2] = b;
|
|
||||||
color[3] = a;
|
|
||||||
set_render_color(r, g, b, a);
|
|
||||||
}
|
|
||||||
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
|
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
|
||||||
|
|
||||||
std::vector<int> load_object(
|
private:
|
||||||
const ModelObject *model_object,
|
// Offset of the volume to be rendered.
|
||||||
const std::vector<int> &instance_idxs,
|
Pointf3 m_origin;
|
||||||
const std::string &color_by,
|
// Rotation around Z axis of the volume to be rendered.
|
||||||
const std::string &select_by,
|
float m_angle_z;
|
||||||
const std::string &drag_by);
|
// Scale factor of the volume to be rendered.
|
||||||
|
float m_scale_factor;
|
||||||
|
// World matrix of the volume to be rendered.
|
||||||
|
std::vector<float> m_world_mat;
|
||||||
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
|
mutable BoundingBoxf3 m_transformed_bounding_box;
|
||||||
|
// Whether or not is needed to recalculate the world matrix.
|
||||||
|
mutable bool m_dirty;
|
||||||
|
|
||||||
int load_wipe_tower_preview(
|
public:
|
||||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
|
||||||
|
|
||||||
// Bounding box of this volume, in unscaled coordinates.
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
BoundingBoxf3 bounding_box;
|
BoundingBoxf3 bounding_box;
|
||||||
// Offset of the volume to be rendered.
|
|
||||||
Pointf3 origin;
|
|
||||||
// Color of the triangles / quads held by this volume.
|
// Color of the triangles / quads held by this volume.
|
||||||
float color[4];
|
float color[4];
|
||||||
// Color used to render this volume.
|
// Color used to render this volume.
|
||||||
|
@ -333,10 +316,17 @@ public:
|
||||||
// Sets render color in dependence of current state
|
// Sets render color in dependence of current state
|
||||||
void set_render_color();
|
void set_render_color();
|
||||||
|
|
||||||
|
const Pointf3& get_origin() const;
|
||||||
|
void set_origin(const Pointf3& origin);
|
||||||
|
void set_angle_z(float angle_z);
|
||||||
|
void set_scale_factor(float scale_factor);
|
||||||
|
|
||||||
int object_idx() const { return this->composite_id / 1000000; }
|
int object_idx() const { return this->composite_id / 1000000; }
|
||||||
int volume_idx() const { return (this->composite_id / 1000) % 1000; }
|
int volume_idx() const { return (this->composite_id / 1000) % 1000; }
|
||||||
int instance_idx() const { return this->composite_id % 1000; }
|
int instance_idx() const { return this->composite_id % 1000; }
|
||||||
BoundingBoxf3 transformed_bounding_box() const { BoundingBoxf3 bb = this->bounding_box; bb.translate(this->origin); return bb; }
|
|
||||||
|
const std::vector<float>& world_matrix() const;
|
||||||
|
BoundingBoxf3 transformed_bounding_box() const;
|
||||||
|
|
||||||
bool empty() const { return this->indexed_vertex_array.empty(); }
|
bool empty() const { return this->indexed_vertex_array.empty(); }
|
||||||
bool indexed() const { return this->indexed_vertex_array.indexed(); }
|
bool indexed() const { return this->indexed_vertex_array.indexed(); }
|
||||||
|
@ -344,6 +334,9 @@ public:
|
||||||
void set_range(coordf_t low, coordf_t high);
|
void set_range(coordf_t low, coordf_t high);
|
||||||
void render() const;
|
void render() const;
|
||||||
void render_using_layer_height() const;
|
void render_using_layer_height() const;
|
||||||
|
void render_VBOs(int color_id, int detection_id, int worldmatrix_id) const;
|
||||||
|
void render_legacy() const;
|
||||||
|
|
||||||
void finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); }
|
void finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); }
|
||||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||||
|
|
||||||
|
|
|
@ -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,9 +122,8 @@ 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());
|
||||||
|
@ -127,11 +132,15 @@ void FirmwareDialog::priv::flashing_status(bool value, AvrDudeComplete complete)
|
||||||
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(200); // See progress callback below
|
progressbar->SetRange(flashing_l10n ? 500 : 200); // See progress callback below
|
||||||
progressbar->SetValue(0);
|
progressbar->SetValue(0);
|
||||||
progress_tasks_done = 0;
|
progress_tasks_done = 0;
|
||||||
cancelled = false;
|
cancelled = false;
|
||||||
} else {
|
timer_pulse.Start(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete)
|
||||||
|
{
|
||||||
auto text_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
auto text_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||||
port_picker->Enable();
|
port_picker->Enable();
|
||||||
btn_rescan->Enable();
|
btn_rescan->Enable();
|
||||||
|
@ -139,14 +148,45 @@ void FirmwareDialog::priv::flashing_status(bool value, AvrDudeComplete complete)
|
||||||
btn_close->Enable();
|
btn_close->Enable();
|
||||||
btn_flash->SetLabel(btn_flash_label_ready);
|
btn_flash->SetLabel(btn_flash_label_ready);
|
||||||
txt_status->SetForegroundColour(text_color);
|
txt_status->SetForegroundColour(text_color);
|
||||||
progressbar->SetValue(200);
|
timer_pulse.Stop();
|
||||||
|
progressbar->SetValue(progressbar->GetRange());
|
||||||
|
|
||||||
switch (complete) {
|
switch (complete) {
|
||||||
case AC_SUCCESS: txt_status->SetLabel(_(L("Flashing succeeded!"))); break;
|
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_FAILURE: txt_status->SetLabel(_(L("Flashing failed. Please see the avrdude log below."))); break;
|
||||||
case AC_CANCEL: txt_status->SetLabel(_(L("Flashing cancelled."))); 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()
|
||||||
|
@ -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) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "GLCanvas3D.hpp"
|
#include "GLCanvas3D.hpp"
|
||||||
|
|
||||||
|
#include "../../libslic3r/libslic3r.h"
|
||||||
#include "../../slic3r/GUI/3DScene.hpp"
|
#include "../../slic3r/GUI/3DScene.hpp"
|
||||||
#include "../../slic3r/GUI/GLShader.hpp"
|
#include "../../slic3r/GUI/GLShader.hpp"
|
||||||
#include "../../slic3r/GUI/GUI.hpp"
|
#include "../../slic3r/GUI/GUI.hpp"
|
||||||
|
@ -41,6 +42,11 @@ static const float VIEW_REAR[2] = { 180.0f, 90.0f };
|
||||||
static const float VARIABLE_LAYER_THICKNESS_BAR_WIDTH = 70.0f;
|
static const float VARIABLE_LAYER_THICKNESS_BAR_WIDTH = 70.0f;
|
||||||
static const float VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
static const float VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
||||||
|
|
||||||
|
static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
@ -719,6 +725,12 @@ void GLCanvas3D::Shader::set_uniform(const std::string& name, float value) const
|
||||||
m_shader->set_uniform(name.c_str(), value);
|
m_shader->set_uniform(name.c_str(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLCanvas3D::Shader::set_uniform(const std::string& name, const float* matrix) const
|
||||||
|
{
|
||||||
|
if (m_shader != nullptr)
|
||||||
|
m_shader->set_uniform(name.c_str(), matrix);
|
||||||
|
}
|
||||||
|
|
||||||
const GLShader* GLCanvas3D::Shader::get_shader() const
|
const GLShader* GLCanvas3D::Shader::get_shader() const
|
||||||
{
|
{
|
||||||
return m_shader;
|
return m_shader;
|
||||||
|
@ -952,6 +964,8 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
|
||||||
m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)volume.layer_height_texture_height());
|
m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)volume.layer_height_texture_height());
|
||||||
m_shader.set_uniform("z_cursor", max_z * get_cursor_z_relative(canvas));
|
m_shader.set_uniform("z_cursor", max_z * get_cursor_z_relative(canvas));
|
||||||
m_shader.set_uniform("z_cursor_band_width", band_width);
|
m_shader.set_uniform("z_cursor_band_width", band_width);
|
||||||
|
// The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix
|
||||||
|
m_shader.set_uniform("volume_world_matrix", UNIT_MATRIX);
|
||||||
|
|
||||||
GLsizei w = (GLsizei)volume.layer_height_texture_width();
|
GLsizei w = (GLsizei)volume.layer_height_texture_width();
|
||||||
GLsizei h = (GLsizei)volume.layer_height_texture_height();
|
GLsizei h = (GLsizei)volume.layer_height_texture_height();
|
||||||
|
@ -1042,7 +1056,9 @@ const Pointf3 GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MA
|
||||||
GLCanvas3D::Mouse::Drag::Drag()
|
GLCanvas3D::Mouse::Drag::Drag()
|
||||||
: start_position_2D(Invalid_2D_Point)
|
: start_position_2D(Invalid_2D_Point)
|
||||||
, start_position_3D(Invalid_3D_Point)
|
, start_position_3D(Invalid_3D_Point)
|
||||||
, volume_idx(-1)
|
, move_with_ctrl(false)
|
||||||
|
, move_volume_idx(-1)
|
||||||
|
, gizmo_volume_idx(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2765,6 +2781,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
{
|
{
|
||||||
update_gizmos_data();
|
update_gizmos_data();
|
||||||
m_gizmos.start_dragging();
|
m_gizmos.start_dragging();
|
||||||
|
m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id();
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2812,7 +2829,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
if (volume_bbox.contains(pos3d))
|
if (volume_bbox.contains(pos3d))
|
||||||
{
|
{
|
||||||
// The dragging operation is initiated.
|
// The dragging operation is initiated.
|
||||||
m_mouse.drag.volume_idx = volume_idx;
|
m_mouse.drag.move_with_ctrl = evt.ControlDown();
|
||||||
|
m_mouse.drag.move_volume_idx = volume_idx;
|
||||||
m_mouse.drag.start_position_3D = pos3d;
|
m_mouse.drag.start_position_3D = pos3d;
|
||||||
// Remember the shift to to the object center.The object center will later be used
|
// Remember the shift to to the object center.The object center will later be used
|
||||||
// to limit the object placement close to the bed.
|
// to limit the object placement close to the bed.
|
||||||
|
@ -2828,7 +2846,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown) && (m_mouse.drag.volume_idx != -1))
|
else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown) && (m_mouse.drag.move_volume_idx != -1))
|
||||||
{
|
{
|
||||||
m_mouse.dragging = true;
|
m_mouse.dragging = true;
|
||||||
|
|
||||||
|
@ -2851,24 +2869,30 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
// Calculate the translation vector.
|
// Calculate the translation vector.
|
||||||
Vectorf3 vector = m_mouse.drag.start_position_3D.vector_to(cur_pos);
|
Vectorf3 vector = m_mouse.drag.start_position_3D.vector_to(cur_pos);
|
||||||
// Get the volume being dragged.
|
// Get the volume being dragged.
|
||||||
GLVolume* volume = m_volumes.volumes[m_mouse.drag.volume_idx];
|
GLVolume* volume = m_volumes.volumes[m_mouse.drag.move_volume_idx];
|
||||||
// Get all volumes belonging to the same group, if any.
|
// Get all volumes belonging to the same group, if any.
|
||||||
std::vector<GLVolume*> volumes;
|
std::vector<GLVolume*> volumes;
|
||||||
if (volume->drag_group_id == -1)
|
int group_id = m_mouse.drag.move_with_ctrl ? volume->select_group_id : volume->drag_group_id;
|
||||||
|
if (group_id == -1)
|
||||||
volumes.push_back(volume);
|
volumes.push_back(volume);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (GLVolume* v : m_volumes.volumes)
|
for (GLVolume* v : m_volumes.volumes)
|
||||||
{
|
{
|
||||||
if ((v != nullptr) && (v->drag_group_id == volume->drag_group_id))
|
if (v != nullptr)
|
||||||
|
{
|
||||||
|
if ((m_mouse.drag.move_with_ctrl && (v->select_group_id == group_id)) || (v->drag_group_id == group_id))
|
||||||
volumes.push_back(v);
|
volumes.push_back(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Apply new temporary volume origin and ignore Z.
|
// Apply new temporary volume origin and ignore Z.
|
||||||
for (GLVolume* v : volumes)
|
for (GLVolume* v : volumes)
|
||||||
{
|
{
|
||||||
v->origin.translate(vector.x, vector.y, 0.0);
|
Pointf3 origin = v->get_origin();
|
||||||
|
origin.translate(vector.x, vector.y, 0.0);
|
||||||
|
v->set_origin(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mouse.drag.start_position_3D = cur_pos;
|
m_mouse.drag.start_position_3D = cur_pos;
|
||||||
|
@ -2882,16 +2906,43 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
const Pointf3& cur_pos = _mouse_to_bed_3d(pos);
|
const Pointf3& cur_pos = _mouse_to_bed_3d(pos);
|
||||||
m_gizmos.update(Pointf(cur_pos.x, cur_pos.y));
|
m_gizmos.update(Pointf(cur_pos.x, cur_pos.y));
|
||||||
|
|
||||||
|
std::vector<GLVolume*> volumes;
|
||||||
|
if (m_mouse.drag.gizmo_volume_idx != -1)
|
||||||
|
{
|
||||||
|
GLVolume* volume = m_volumes.volumes[m_mouse.drag.gizmo_volume_idx];
|
||||||
|
// Get all volumes belonging to the same group, if any.
|
||||||
|
if (volume->select_group_id == -1)
|
||||||
|
volumes.push_back(volume);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (GLVolume* v : m_volumes.volumes)
|
||||||
|
{
|
||||||
|
if ((v != nullptr) && (v->select_group_id == volume->select_group_id))
|
||||||
|
volumes.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_gizmos.get_current_type())
|
switch (m_gizmos.get_current_type())
|
||||||
{
|
{
|
||||||
case Gizmos::Scale:
|
case Gizmos::Scale:
|
||||||
{
|
{
|
||||||
m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
|
// Apply new temporary scale factor
|
||||||
|
float scale_factor = m_gizmos.get_scale();
|
||||||
|
for (GLVolume* v : volumes)
|
||||||
|
{
|
||||||
|
v->set_scale_factor(scale_factor);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Gizmos::Rotate:
|
case Gizmos::Rotate:
|
||||||
{
|
{
|
||||||
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
|
// Apply new temporary angle_z
|
||||||
|
float angle_z = m_gizmos.get_angle_z();
|
||||||
|
for (GLVolume* v : volumes)
|
||||||
|
{
|
||||||
|
v->set_angle_z(angle_z);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -2954,19 +3005,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
if (layer_editing_object_idx != -1)
|
if (layer_editing_object_idx != -1)
|
||||||
m_on_model_update_callback.call();
|
m_on_model_update_callback.call();
|
||||||
}
|
}
|
||||||
else if ((m_mouse.drag.volume_idx != -1) && m_mouse.dragging)
|
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
|
||||||
{
|
{
|
||||||
// get all volumes belonging to the same group, if any
|
// get all volumes belonging to the same group, if any
|
||||||
std::vector<int> volume_idxs;
|
std::vector<int> volume_idxs;
|
||||||
int vol_id = m_mouse.drag.volume_idx;
|
int vol_id = m_mouse.drag.move_volume_idx;
|
||||||
int group_id = m_volumes.volumes[vol_id]->drag_group_id;
|
int group_id = m_mouse.drag.move_with_ctrl ? m_volumes.volumes[vol_id]->select_group_id : m_volumes.volumes[vol_id]->drag_group_id;
|
||||||
if (group_id == -1)
|
if (group_id == -1)
|
||||||
volume_idxs.push_back(vol_id);
|
volume_idxs.push_back(vol_id);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)m_volumes.volumes.size(); ++i)
|
for (int i = 0; i < (int)m_volumes.volumes.size(); ++i)
|
||||||
{
|
{
|
||||||
if (m_volumes.volumes[i]->drag_group_id == group_id)
|
if ((m_mouse.drag.move_with_ctrl && (m_volumes.volumes[i]->select_group_id == group_id)) || (m_volumes.volumes[i]->drag_group_id == group_id))
|
||||||
volume_idxs.push_back(i);
|
volume_idxs.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2984,10 +3035,26 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() && m_gizmos.is_dragging())
|
else if (evt.LeftUp() && m_gizmos.is_dragging())
|
||||||
{
|
{
|
||||||
|
switch (m_gizmos.get_current_type())
|
||||||
|
{
|
||||||
|
case Gizmos::Scale:
|
||||||
|
{
|
||||||
|
m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Gizmos::Rotate:
|
||||||
|
{
|
||||||
|
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
m_gizmos.stop_dragging();
|
m_gizmos.stop_dragging();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mouse.drag.volume_idx = -1;
|
m_mouse.drag.move_volume_idx = -1;
|
||||||
|
m_mouse.drag.gizmo_volume_idx = -1;
|
||||||
m_mouse.set_start_position_3D_as_invalid();
|
m_mouse.set_start_position_3D_as_invalid();
|
||||||
m_mouse.set_start_position_2D_as_invalid();
|
m_mouse.set_start_position_2D_as_invalid();
|
||||||
m_mouse.dragging = false;
|
m_mouse.dragging = false;
|
||||||
|
@ -3706,6 +3773,35 @@ int GLCanvas3D::_get_first_selected_object_id() const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GLCanvas3D::_get_first_selected_volume_id() const
|
||||||
|
{
|
||||||
|
if (m_print != nullptr)
|
||||||
|
{
|
||||||
|
int objects_count = (int)m_print->objects.size();
|
||||||
|
|
||||||
|
for (const GLVolume* vol : m_volumes.volumes)
|
||||||
|
{
|
||||||
|
if ((vol != nullptr) && vol->selected)
|
||||||
|
{
|
||||||
|
int object_id = vol->select_group_id / 1000000;
|
||||||
|
// Objects with object_id >= 1000 have a specific meaning, for example the wipe tower proxy.
|
||||||
|
if (object_id < 10000)
|
||||||
|
{
|
||||||
|
int volume_id = 0;
|
||||||
|
for (int i = 0; i < object_id; ++i)
|
||||||
|
{
|
||||||
|
const PrintObject* obj = m_print->objects[i];
|
||||||
|
const ModelObject* model = obj->model_object();
|
||||||
|
volume_id += model->instances.size();
|
||||||
|
}
|
||||||
|
return volume_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int hex_digit_to_int(const char c)
|
static inline int hex_digit_to_int(const char c)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
@ -4311,13 +4407,14 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs)
|
||||||
{
|
{
|
||||||
// Move a regular object.
|
// Move a regular object.
|
||||||
ModelObject* model_object = m_model->objects[obj_idx];
|
ModelObject* model_object = m_model->objects[obj_idx];
|
||||||
model_object->instances[instance_idx]->offset.translate(volume->origin.x, volume->origin.y);
|
const Pointf3& origin = volume->get_origin();
|
||||||
|
model_object->instances[instance_idx]->offset = Pointf(origin.x, origin.y);
|
||||||
model_object->invalidate_bounding_box();
|
model_object->invalidate_bounding_box();
|
||||||
object_moved = true;
|
object_moved = true;
|
||||||
}
|
}
|
||||||
else if (obj_idx == 1000)
|
else if (obj_idx == 1000)
|
||||||
// Move a wipe tower proxy.
|
// Move a wipe tower proxy.
|
||||||
wipe_tower_origin = volume->origin;
|
wipe_tower_origin = volume->get_origin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object_moved)
|
if (object_moved)
|
||||||
|
|
|
@ -225,6 +225,7 @@ public:
|
||||||
void stop_using() const;
|
void stop_using() const;
|
||||||
|
|
||||||
void set_uniform(const std::string& name, float value) const;
|
void set_uniform(const std::string& name, float value) const;
|
||||||
|
void set_uniform(const std::string& name, const float* matrix) const;
|
||||||
|
|
||||||
const GLShader* get_shader() const;
|
const GLShader* get_shader() const;
|
||||||
|
|
||||||
|
@ -302,7 +303,10 @@ public:
|
||||||
Point start_position_2D;
|
Point start_position_2D;
|
||||||
Pointf3 start_position_3D;
|
Pointf3 start_position_3D;
|
||||||
Vectorf3 volume_center_offset;
|
Vectorf3 volume_center_offset;
|
||||||
int volume_idx;
|
|
||||||
|
bool move_with_ctrl;
|
||||||
|
int move_volume_idx;
|
||||||
|
int gizmo_volume_idx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Drag();
|
Drag();
|
||||||
|
@ -617,6 +621,7 @@ private:
|
||||||
void _stop_timer();
|
void _stop_timer();
|
||||||
|
|
||||||
int _get_first_selected_object_id() const;
|
int _get_first_selected_object_id() const;
|
||||||
|
int _get_first_selected_volume_id() const;
|
||||||
|
|
||||||
// generates gcode extrusion paths geometry
|
// generates gcode extrusion paths geometry
|
||||||
void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||||
|
|
|
@ -214,6 +214,17 @@ bool GLShader::set_uniform(const char *name, float value) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLShader::set_uniform(const char* name, const float* matrix) const
|
||||||
|
{
|
||||||
|
int id = get_uniform_location(name);
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
::glUniformMatrix4fv(id, 1, GL_FALSE, (const GLfloat*)matrix);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
# Set shader vector
|
# Set shader vector
|
||||||
sub SetVector
|
sub SetVector
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
int get_uniform_location(const char *name) const;
|
int get_uniform_location(const char *name) const;
|
||||||
|
|
||||||
bool set_uniform(const char *name, float value) const;
|
bool set_uniform(const char *name, float value) const;
|
||||||
|
bool set_uniform(const char* name, const float* matrix) const;
|
||||||
|
|
||||||
void enable() const;
|
void enable() const;
|
||||||
void disable() const;
|
void disable() const;
|
||||||
|
|
|
@ -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
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
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");
|
||||||
|
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;
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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); %};
|
||||||
|
|
|
@ -56,9 +56,13 @@
|
||||||
int volume_idx() const;
|
int volume_idx() const;
|
||||||
int instance_idx() const;
|
int instance_idx() const;
|
||||||
Clone<Pointf3> origin() const
|
Clone<Pointf3> origin() const
|
||||||
%code%{ RETVAL = THIS->origin; %};
|
%code%{ RETVAL = THIS->get_origin(); %};
|
||||||
void translate(double x, double y, double z)
|
void translate(double x, double y, double z)
|
||||||
%code%{ THIS->origin.translate(x, y, z); %};
|
%code%{
|
||||||
|
Pointf3 o = THIS->get_origin();
|
||||||
|
o.translate(x, y, z);
|
||||||
|
THIS->set_origin(o);
|
||||||
|
%};
|
||||||
Clone<BoundingBoxf3> bounding_box() const
|
Clone<BoundingBoxf3> bounding_box() const
|
||||||
%code%{ RETVAL = THIS->bounding_box; %};
|
%code%{ RETVAL = THIS->bounding_box; %};
|
||||||
Clone<BoundingBoxf3> transformed_bounding_box() const;
|
Clone<BoundingBoxf3> transformed_bounding_box() const;
|
||||||
|
|
|
@ -54,7 +54,6 @@ _constant()
|
||||||
|
|
||||||
int region_volumes_count()
|
int region_volumes_count()
|
||||||
%code%{ RETVAL = THIS->region_volumes.size(); %};
|
%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()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue